@@ -6,9 +6,11 @@ package index
66import (
77 "errors"
88 "fmt"
9+ "strings"
10+
911 "github.com/pb33f/libopenapi/utils"
12+ "golang.org/x/exp/slices"
1013 "gopkg.in/yaml.v3"
11- "strings"
1214)
1315
1416// ExtractRefs will return a deduplicated slice of references for every unique ref found in the document.
@@ -40,21 +42,26 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
4042 // check if we're dealing with an inline schema definition, that isn't part of an array
4143 // (which means it's being used as a value in an array, and it's not a label)
4244 // https://github.com/pb33f/libopenapi/issues/76
43- if i % 2 == 0 && n .Value == "schema" && ! utils .IsNodeArray (node ) && (i + 1 < len (node .Content )) {
45+ schemaContainingNodes := []string {"schema" , "items" , "additionalProperties" , "contains" , "not" , "unevaluatedItems" , "unevaluatedProperties" }
46+ if i % 2 == 0 && slices .Contains (schemaContainingNodes , n .Value ) && ! utils .IsNodeArray (node ) && (i + 1 < len (node .Content )) {
47+ ref := & Reference {
48+ Node : node .Content [i + 1 ],
49+ Path : fmt .Sprintf ("$.%s.%s" , strings .Join (seenPath , "." ), n .Value ),
50+ }
51+
4452 isRef , _ , _ := utils .IsNodeRefValue (node .Content [i + 1 ])
4553 if isRef {
4654 // record this reference
47- ref := & Reference {
48- Node : node .Content [i + 1 ],
49- Path : fmt .Sprintf ("$.%s.schema" , strings .Join (seenPath , "." )),
50- }
5155 index .allRefSchemaDefinitions = append (index .allRefSchemaDefinitions , ref )
5256 continue
5357 }
54- ref := & Reference {
55- Node : node .Content [i + 1 ],
56- Path : fmt .Sprintf ("$.%s.schema" , strings .Join (seenPath , "." )),
58+
59+ if n .Value == "additionalProperties" || n .Value == "unevaluatedProperties" {
60+ if utils .IsNodeBoolValue (node .Content [i + 1 ]) {
61+ continue
62+ }
5763 }
64+
5865 index .allInlineSchemaDefinitions = append (index .allInlineSchemaDefinitions , ref )
5966
6067 // check if the schema is an object or an array,
@@ -67,14 +74,10 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
6774 }
6875 }
6976
70- // Perform the same check for all properties in an inline schema definition
77+ // Perform the same check for all maps of schemas like properties and patternProperties
7178 // https://github.com/pb33f/libopenapi/issues/76
72- if i % 2 == 0 && n .Value == "properties" && ! utils .IsNodeArray (node ) && (i + 1 < len (node .Content )) {
73- isRef , _ , _ := utils .IsNodeRefValue (node .Content [i + 1 ])
74- if isRef {
75- continue
76- }
77-
79+ mapOfSchemaContainingNodes := []string {"properties" , "patternProperties" }
80+ if i % 2 == 0 && slices .Contains (mapOfSchemaContainingNodes , n .Value ) && ! utils .IsNodeArray (node ) && (i + 1 < len (node .Content )) {
7881 // for each property add it to our schema definitions
7982 label := ""
8083 for h , prop := range node .Content [i + 1 ].Content {
@@ -83,16 +86,51 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
8386 label = prop .Value
8487 continue
8588 }
86-
8789 ref := & Reference {
8890 Node : prop ,
89- Path : fmt .Sprintf ("$.%s.properties.%s" , strings .Join (seenPath , "." ), label ),
91+ Path : fmt .Sprintf ("$.%s.%s.%s" , strings .Join (seenPath , "." ), n .Value , label ),
92+ }
93+
94+ isRef , _ , _ := utils .IsNodeRefValue (prop )
95+ if isRef {
96+ // record this reference
97+ index .allRefSchemaDefinitions = append (index .allRefSchemaDefinitions , ref )
98+ continue
99+ }
100+
101+ index .allInlineSchemaDefinitions = append (index .allInlineSchemaDefinitions , ref )
102+
103+ // check if the schema is an object or an array,
104+ // and if so, add it to the list of inline schema object definitions.
105+ k , v := utils .FindKeyNodeTop ("type" , prop .Content )
106+ if k != nil && v != nil {
107+ if v .Value == "object" || v .Value == "array" {
108+ index .allInlineSchemaObjectDefinitions = append (index .allInlineSchemaObjectDefinitions , ref )
109+ }
110+ }
111+ }
112+ }
113+
114+ // Perform the same check for all arrays of schemas like allOf, anyOf, oneOf
115+ arrayOfSchemaContainingNodes := []string {"allOf" , "anyOf" , "oneOf" , "prefixItems" }
116+ if i % 2 == 0 && slices .Contains (arrayOfSchemaContainingNodes , n .Value ) && ! utils .IsNodeArray (node ) && (i + 1 < len (node .Content )) {
117+ // for each element in the array, add it to our schema definitions
118+ for h , element := range node .Content [i + 1 ].Content {
119+ ref := & Reference {
120+ Node : element ,
121+ Path : fmt .Sprintf ("$.%s.%s[%d]" , strings .Join (seenPath , "." ), n .Value , h ),
122+ }
123+
124+ isRef , _ , _ := utils .IsNodeRefValue (element )
125+ if isRef { // record this reference
126+ index .allRefSchemaDefinitions = append (index .allRefSchemaDefinitions , ref )
127+ continue
90128 }
91129 index .allInlineSchemaDefinitions = append (index .allInlineSchemaDefinitions , ref )
92130
93131 // check if the schema is an object or an array,
94132 // and if so, add it to the list of inline schema object definitions.
95- k , v := utils .FindKeyNodeTop ("type" , node . Content [ i + 1 ] .Content )
133+ k , v := utils .FindKeyNodeTop ("type" , element .Content )
96134 if k != nil && v != nil {
97135 if v .Value == "object" || v .Value == "array" {
98136 index .allInlineSchemaObjectDefinitions = append (index .allInlineSchemaObjectDefinitions , ref )
@@ -342,7 +380,7 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
342380 if i < len (node .Content )- 1 {
343381 next := node .Content [i + 1 ]
344382
345- if i % 2 != 0 && next != nil && ! utils .IsNodeArray (next ) && ! utils .IsNodeMap (next ) {
383+ if i % 2 != 0 && next != nil && ! utils .IsNodeArray (next ) && ! utils .IsNodeMap (next ) && len ( seenPath ) > 0 {
346384 seenPath = seenPath [:len (seenPath )- 1 ]
347385 }
348386 }
@@ -366,7 +404,7 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
366404func (index * SpecIndex ) ExtractComponentsFromRefs (refs []* Reference ) []* Reference {
367405 var found []* Reference
368406
369- //run this async because when things get recursive, it can take a while
407+ // run this async because when things get recursive, it can take a while
370408 c := make (chan bool )
371409
372410 locate := func (ref * Reference , refIndex int , sequence []* ReferenceMapped ) {
@@ -419,7 +457,7 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc
419457 for r := range refsToCheck {
420458 // expand our index of all mapped refs
421459 go locate (refsToCheck [r ], r , mappedRefsInSequence )
422- //locate(refsToCheck[r], r, mappedRefsInSequence) // used for sync testing.
460+ // locate(refsToCheck[r], r, mappedRefsInSequence) // used for sync testing.
423461 }
424462
425463 completedRefs := 0
0 commit comments