diff options
Diffstat (limited to 'vendor/github.com/go-openapi/analysis/flatten.go')
-rw-r--r-- | vendor/github.com/go-openapi/analysis/flatten.go | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/vendor/github.com/go-openapi/analysis/flatten.go b/vendor/github.com/go-openapi/analysis/flatten.go index ae1eef5d19..ab3f949c30 100644 --- a/vendor/github.com/go-openapi/analysis/flatten.go +++ b/vendor/github.com/go-openapi/analysis/flatten.go @@ -41,10 +41,11 @@ type FlattenOpts struct { BasePath string // Flattening options - Expand bool // If Expand is true, we skip flattening the spec and expand it instead - Minimal bool - Verbose bool - RemoveUnused bool + Expand bool // If Expand is true, we skip flattening the spec and expand it instead + Minimal bool + Verbose bool + RemoveUnused bool + ContinueOnError bool // Continues when facing some issues /* Extra keys */ _ struct{} // require keys @@ -135,6 +136,7 @@ func newContext() *context { // - ... // func Flatten(opts FlattenOpts) error { + debugLog("FlattenOpts: %#v", opts) // Make sure opts.BasePath is an absolute path if !filepath.IsAbs(opts.BasePath) { cwd, _ := os.Getwd() @@ -148,7 +150,9 @@ func Flatten(opts FlattenOpts) error { // recursively expand responses, parameters, path items and items in simple schemas. // This simplifies the spec and leaves $ref only into schema objects. - if err := swspec.ExpandSpec(opts.Swagger(), opts.ExpandOpts(!opts.Expand)); err != nil { + expandOpts := opts.ExpandOpts(!opts.Expand) + expandOpts.ContinueOnError = opts.ContinueOnError + if err := swspec.ExpandSpec(opts.Swagger(), expandOpts); err != nil { return err } @@ -846,7 +850,7 @@ func importExternalReferences(opts *FlattenOpts) (bool, error) { enums: enumAnalysis{}, } partialAnalyzer.reset() - partialAnalyzer.analyzeSchema("", *sch, "/") + partialAnalyzer.analyzeSchema("", sch, "/") // now rewrite those refs with rebase for key, ref := range partialAnalyzer.references.allRefs { @@ -874,6 +878,7 @@ func importExternalReferences(opts *FlattenOpts) (bool, error) { if _, ok := opts.flattenContext.newRefs[key]; ok { resolved = opts.flattenContext.newRefs[key].resolved } + debugLog("keeping track of ref: %s (%s), resolved: %t", key, newName, resolved) opts.flattenContext.newRefs[key] = &newRef{ key: key, newName: newName, @@ -1308,16 +1313,55 @@ func stripPointersAndOAIGen(opts *FlattenOpts) error { return err } - // restrip + // restrip and re-analyze if hasIntroducedPointerOrInline, ers = stripOAIGen(opts); ers != nil { return ers } - - opts.Spec.reload() // re-analyze } return nil } +func updateRefParents(opts *FlattenOpts, r *newRef) { + if !r.isOAIGen || r.resolved { // bail on already resolved entries (avoid looping) + return + } + for k, v := range opts.Spec.references.allRefs { + if r.path != v.String() { + continue + } + found := false + for _, p := range r.parents { + if p == k { + found = true + break + } + } + if !found { + r.parents = append(r.parents, k) + } + } +} + +// topMostRefs is able to sort refs by hierarchical then lexicographic order, +// yielding refs ordered breadth-first. +type topmostRefs []string + +func (k topmostRefs) Len() int { return len(k) } +func (k topmostRefs) Swap(i, j int) { k[i], k[j] = k[j], k[i] } +func (k topmostRefs) Less(i, j int) bool { + li, lj := len(strings.Split(k[i], "/")), len(strings.Split(k[j], "/")) + if li == lj { + return k[i] < k[j] + } + return li < lj +} + +func topmostFirst(refs []string) []string { + res := topmostRefs(refs) + sort.Sort(res) + return res +} + // stripOAIGen strips the spec from unnecessary OAIGen constructs, initially created to dedupe flattened definitions. // // A dedupe is deemed unnecessary whenever: @@ -1325,44 +1369,25 @@ func stripPointersAndOAIGen(opts *FlattenOpts) error { // - there is a conflict with multiple parents: merge OAIGen in first parent, the rewrite other parents to point to // the first parent. // -// This function returns a true bool whenever it re-inlined a complex schema, so the caller may chose to iterate +// This function returns true whenever it re-inlined a complex schema, so the caller may chose to iterate // pointer and name resolution again. func stripOAIGen(opts *FlattenOpts) (bool, error) { debugLog("stripOAIGen") replacedWithComplex := false - // figure out referers of OAIGen definitions + // figure out referers of OAIGen definitions (doing it before the ref start mutating) for _, r := range opts.flattenContext.newRefs { - if !r.isOAIGen || r.resolved { // bail on already resolved entries (avoid looping) - continue - } - for k, v := range opts.Spec.references.allRefs { - if r.path != v.String() { - continue - } - found := false - for _, p := range r.parents { - if p == k { - found = true - break - } - } - if !found { - r.parents = append(r.parents, k) - } - } + updateRefParents(opts, r) } - for k := range opts.flattenContext.newRefs { r := opts.flattenContext.newRefs[k] - //debugLog("newRefs[%s]: isOAIGen: %t, resolved: %t, name: %s, path:%s, #parents: %d, parents: %v, ref: %s", - // k, r.isOAIGen, r.resolved, r.newName, r.path, len(r.parents), r.parents, r.schema.Ref.String()) + debugLog("newRefs[%s]: isOAIGen: %t, resolved: %t, name: %s, path:%s, #parents: %d, parents: %v, ref: %s", + k, r.isOAIGen, r.resolved, r.newName, r.path, len(r.parents), r.parents, r.schema.Ref.String()) if r.isOAIGen && len(r.parents) >= 1 { - pr := r.parents - sort.Strings(pr) + pr := topmostFirst(r.parents) - // rewrite first parent schema in lexicographical order - debugLog("rewrite first parent in lex order %s with schema", pr[0]) + // rewrite first parent schema in hierarchical then lexicographical order + debugLog("rewrite first parent %s with schema", pr[0]) if err := updateRefWithSchema(opts.Swagger(), pr[0], r.schema); err != nil { return false, err } |