diff options
Diffstat (limited to 'vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go')
-rw-r--r-- | vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go | 458 |
1 files changed, 0 insertions, 458 deletions
diff --git a/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go b/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go deleted file mode 100644 index c0f43e728..000000000 --- a/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go +++ /dev/null @@ -1,458 +0,0 @@ -package replace - -import ( - "encoding/json" - "fmt" - "net/url" - "os" - "path" - "strconv" - - "github.com/go-openapi/analysis/internal/debug" - "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/spec" -) - -const definitionsPath = "#/definitions" - -var debugLog = debug.GetLogger("analysis/flatten/replace", os.Getenv("SWAGGER_DEBUG") != "") - -// RewriteSchemaToRef replaces a schema with a Ref -func RewriteSchemaToRef(sp *spec.Swagger, key string, ref spec.Ref) error { - debugLog("rewriting schema to ref for %s with %s", key, ref.String()) - _, value, err := getPointerFromKey(sp, key) - if err != nil { - return err - } - - switch refable := value.(type) { - case *spec.Schema: - return rewriteParentRef(sp, key, ref) - - case spec.Schema: - return rewriteParentRef(sp, key, ref) - - case *spec.SchemaOrArray: - if refable.Schema != nil { - refable.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - } - - case *spec.SchemaOrBool: - if refable.Schema != nil { - refable.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - } - case map[string]interface{}: // this happens e.g. if a schema points to an extension unmarshaled as map[string]interface{} - return rewriteParentRef(sp, key, ref) - default: - return fmt.Errorf("no schema with ref found at %s for %T", key, value) - } - - return nil -} - -func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error { - parent, entry, pvalue, err := getParentFromKey(sp, key) - if err != nil { - return err - } - - debugLog("rewriting holder for %T", pvalue) - switch container := pvalue.(type) { - case spec.Response: - if err := rewriteParentRef(sp, "#"+parent, ref); err != nil { - return err - } - - case *spec.Response: - container.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case *spec.Responses: - statusCode, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", key[1:], err) - } - resp := container.StatusCodeResponses[statusCode] - resp.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - container.StatusCodeResponses[statusCode] = resp - - case map[string]spec.Response: - resp := container[entry] - resp.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - container[entry] = resp - - case spec.Parameter: - if err := rewriteParentRef(sp, "#"+parent, ref); err != nil { - return err - } - - case map[string]spec.Parameter: - param := container[entry] - param.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - container[entry] = param - - case []spec.Parameter: - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", key[1:], err) - } - param := container[idx] - param.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - container[idx] = param - - case spec.Definitions: - container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case map[string]spec.Schema: - container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case []spec.Schema: - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", key[1:], err) - } - container[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case *spec.SchemaOrArray: - // NOTE: this is necessarily an array - otherwise, the parent would be *Schema - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", key[1:], err) - } - container.Schemas[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case spec.SchemaProperties: - container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case *interface{}: - *container = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - // NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema - - default: - return fmt.Errorf("unhandled parent schema rewrite %s (%T)", key, pvalue) - } - - return nil -} - -// getPointerFromKey retrieves the content of the JSON pointer "key" -func getPointerFromKey(sp interface{}, key string) (string, interface{}, error) { - switch sp.(type) { - case *spec.Schema: - case *spec.Swagger: - default: - panic("unexpected type used in getPointerFromKey") - } - if key == "#/" { - return "", sp, nil - } - // unescape chars in key, e.g. "{}" from path params - pth, _ := url.PathUnescape(key[1:]) - ptr, err := jsonpointer.New(pth) - if err != nil { - return "", nil, err - } - - value, _, err := ptr.Get(sp) - if err != nil { - debugLog("error when getting key: %s with path: %s", key, pth) - - return "", nil, err - } - - return pth, value, nil -} - -// getParentFromKey retrieves the container of the JSON pointer "key" -func getParentFromKey(sp interface{}, key string) (string, string, interface{}, error) { - switch sp.(type) { - case *spec.Schema: - case *spec.Swagger: - default: - panic("unexpected type used in getPointerFromKey") - } - // unescape chars in key, e.g. "{}" from path params - pth, _ := url.PathUnescape(key[1:]) - - parent, entry := path.Dir(pth), path.Base(pth) - debugLog("getting schema holder at: %s, with entry: %s", parent, entry) - - pptr, err := jsonpointer.New(parent) - if err != nil { - return "", "", nil, err - } - pvalue, _, err := pptr.Get(sp) - if err != nil { - return "", "", nil, fmt.Errorf("can't get parent for %s: %w", parent, err) - } - - return parent, entry, pvalue, nil -} - -// UpdateRef replaces a ref by another one -func UpdateRef(sp interface{}, key string, ref spec.Ref) error { - switch sp.(type) { - case *spec.Schema: - case *spec.Swagger: - default: - panic("unexpected type used in getPointerFromKey") - } - debugLog("updating ref for %s with %s", key, ref.String()) - pth, value, err := getPointerFromKey(sp, key) - if err != nil { - return err - } - - switch refable := value.(type) { - case *spec.Schema: - refable.Ref = ref - case *spec.SchemaOrArray: - if refable.Schema != nil { - refable.Schema.Ref = ref - } - case *spec.SchemaOrBool: - if refable.Schema != nil { - refable.Schema.Ref = ref - } - case spec.Schema: - debugLog("rewriting holder for %T", refable) - _, entry, pvalue, erp := getParentFromKey(sp, key) - if erp != nil { - return err - } - switch container := pvalue.(type) { - case spec.Definitions: - container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case map[string]spec.Schema: - container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case []spec.Schema: - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", pth, err) - } - container[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case *spec.SchemaOrArray: - // NOTE: this is necessarily an array - otherwise, the parent would be *Schema - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", pth, err) - } - container.Schemas[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - case spec.SchemaProperties: - container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} - - // NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema - - default: - return fmt.Errorf("unhandled container type at %s: %T", key, value) - } - - default: - return fmt.Errorf("no schema with ref found at %s for %T", key, value) - } - - return nil -} - -// UpdateRefWithSchema replaces a ref with a schema (i.e. re-inline schema) -func UpdateRefWithSchema(sp *spec.Swagger, key string, sch *spec.Schema) error { - debugLog("updating ref for %s with schema", key) - pth, value, err := getPointerFromKey(sp, key) - if err != nil { - return err - } - - switch refable := value.(type) { - case *spec.Schema: - *refable = *sch - case spec.Schema: - _, entry, pvalue, erp := getParentFromKey(sp, key) - if erp != nil { - return err - } - switch container := pvalue.(type) { - case spec.Definitions: - container[entry] = *sch - - case map[string]spec.Schema: - container[entry] = *sch - - case []spec.Schema: - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", pth, err) - } - container[idx] = *sch - - case *spec.SchemaOrArray: - // NOTE: this is necessarily an array - otherwise, the parent would be *Schema - idx, err := strconv.Atoi(entry) - if err != nil { - return fmt.Errorf("%s not a number: %w", pth, err) - } - container.Schemas[idx] = *sch - - case spec.SchemaProperties: - container[entry] = *sch - - // NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema - - default: - return fmt.Errorf("unhandled type for parent of [%s]: %T", key, value) - } - case *spec.SchemaOrArray: - *refable.Schema = *sch - // NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema - case *spec.SchemaOrBool: - *refable.Schema = *sch - default: - return fmt.Errorf("no schema with ref found at %s for %T", key, value) - } - - return nil -} - -// DeepestRefResult holds the results from DeepestRef analysis -type DeepestRefResult struct { - Ref spec.Ref - Schema *spec.Schema - Warnings []string -} - -// DeepestRef finds the first definition ref, from a cascade of nested refs which are not definitions. -// - if no definition is found, returns the deepest ref. -// - pointers to external files are expanded -// -// NOTE: all external $ref's are assumed to be already expanded at this stage. -func DeepestRef(sp *spec.Swagger, opts *spec.ExpandOptions, ref spec.Ref) (*DeepestRefResult, error) { - if !ref.HasFragmentOnly { - // we found an external $ref, which is odd at this stage: - // do nothing on external $refs - return &DeepestRefResult{Ref: ref}, nil - } - - currentRef := ref - visited := make(map[string]bool, 64) - warnings := make([]string, 0, 2) - -DOWNREF: - for currentRef.String() != "" { - if path.Dir(currentRef.String()) == definitionsPath { - // this is a top-level definition: stop here and return this ref - return &DeepestRefResult{Ref: currentRef}, nil - } - - if _, beenThere := visited[currentRef.String()]; beenThere { - return nil, - fmt.Errorf("cannot resolve cyclic chain of pointers under %s", currentRef.String()) - } - - visited[currentRef.String()] = true - value, _, err := currentRef.GetPointer().Get(sp) - if err != nil { - return nil, err - } - - switch refable := value.(type) { - case *spec.Schema: - if refable.Ref.String() == "" { - break DOWNREF - } - currentRef = refable.Ref - - case spec.Schema: - if refable.Ref.String() == "" { - break DOWNREF - } - currentRef = refable.Ref - - case *spec.SchemaOrArray: - if refable.Schema == nil || refable.Schema != nil && refable.Schema.Ref.String() == "" { - break DOWNREF - } - currentRef = refable.Schema.Ref - - case *spec.SchemaOrBool: - if refable.Schema == nil || refable.Schema != nil && refable.Schema.Ref.String() == "" { - break DOWNREF - } - currentRef = refable.Schema.Ref - - case spec.Response: - // a pointer points to a schema initially marshalled in responses section... - // Attempt to convert this to a schema. If this fails, the spec is invalid - asJSON, _ := refable.MarshalJSON() - var asSchema spec.Schema - - err := asSchema.UnmarshalJSON(asJSON) - if err != nil { - return nil, - fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v)", - currentRef.String(), value, err, - ) - } - warnings = append(warnings, fmt.Sprintf("found $ref %q (response) interpreted as schema", currentRef.String())) - - if asSchema.Ref.String() == "" { - break DOWNREF - } - currentRef = asSchema.Ref - - case spec.Parameter: - // a pointer points to a schema initially marshalled in parameters section... - // Attempt to convert this to a schema. If this fails, the spec is invalid - asJSON, _ := refable.MarshalJSON() - var asSchema spec.Schema - if err := asSchema.UnmarshalJSON(asJSON); err != nil { - return nil, - fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v)", - currentRef.String(), value, err, - ) - } - - warnings = append(warnings, fmt.Sprintf("found $ref %q (parameter) interpreted as schema", currentRef.String())) - - if asSchema.Ref.String() == "" { - break DOWNREF - } - currentRef = asSchema.Ref - - default: - // fallback: attempts to resolve the pointer as a schema - if refable == nil { - break DOWNREF - } - - asJSON, _ := json.Marshal(refable) - var asSchema spec.Schema - if err := asSchema.UnmarshalJSON(asJSON); err != nil { - return nil, - fmt.Errorf("unhandled type to resolve JSON pointer %s. Expected a Schema, got: %T (%v)", - currentRef.String(), value, err, - ) - } - warnings = append(warnings, fmt.Sprintf("found $ref %q (%T) interpreted as schema", currentRef.String(), refable)) - - if asSchema.Ref.String() == "" { - break DOWNREF - } - currentRef = asSchema.Ref - } - } - - // assess what schema we're ending with - sch, erv := spec.ResolveRefWithBase(sp, ¤tRef, opts) - if erv != nil { - return nil, erv - } - - if sch == nil { - return nil, fmt.Errorf("no schema found at %s", currentRef.String()) - } - - return &DeepestRefResult{Ref: currentRef, Schema: sch, Warnings: warnings}, nil -} |