summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-openapi/analysis/flatten.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-openapi/analysis/flatten.go')
-rw-r--r--vendor/github.com/go-openapi/analysis/flatten.go97
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
}