@@ -119,43 +119,60 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
119119 root .Line , root .Column ), ctx
120120 }
121121
122+ origRef := rv
123+ resolvedRef := rv
124+ if scope := index .GetSchemaIdScope (ctx ); scope != nil && scope .BaseUri != "" {
125+ if resolved , err := index .ResolveRefAgainstSchemaId (rv , scope ); err == nil && resolved != "" {
126+ resolvedRef = resolved
127+ }
128+ }
129+ searchRefs := []string {origRef }
130+ if resolvedRef != origRef {
131+ searchRefs = append (searchRefs , resolvedRef )
132+ }
133+
122134 // run through everything and return as soon as we find a match.
123135 // this operates as fast as possible as ever
124136 collections := generateIndexCollection (idx )
125137 var found map [string ]* index.Reference
126138 for _ , collection := range collections {
127139 found = collection ()
128- if found != nil && found [rv ] != nil {
129- foundRef := found [rv ]
130- foundIndex := idx
131- if foundRef .Index != nil {
132- foundIndex = foundRef .Index
133- }
134- if foundIndex != nil && foundRef .RemoteLocation != "" &&
135- foundIndex .GetSpecAbsolutePath () != foundRef .RemoteLocation {
136- if rolo := foundIndex .GetRolodex (); rolo != nil {
137- for _ , candidate := range append (rolo .GetIndexes (), rolo .GetRootIndex ()) {
138- if candidate == nil {
139- continue
140- }
141- if candidate .GetSpecAbsolutePath () == foundRef .RemoteLocation {
142- foundIndex = candidate
143- break
140+ if found != nil {
141+ for _ , candidate := range searchRefs {
142+ if found [candidate ] == nil {
143+ continue
144+ }
145+ foundRef := found [candidate ]
146+ foundIndex := idx
147+ if foundRef .Index != nil {
148+ foundIndex = foundRef .Index
149+ }
150+ if foundIndex != nil && foundRef .RemoteLocation != "" &&
151+ foundIndex .GetSpecAbsolutePath () != foundRef .RemoteLocation {
152+ if rolo := foundIndex .GetRolodex (); rolo != nil {
153+ for _ , candidateIdx := range append (rolo .GetIndexes (), rolo .GetRootIndex ()) {
154+ if candidateIdx == nil {
155+ continue
156+ }
157+ if candidateIdx .GetSpecAbsolutePath () == foundRef .RemoteLocation {
158+ foundIndex = candidateIdx
159+ break
160+ }
144161 }
145162 }
146163 }
147- }
148- foundCtx := ctx
149- if foundRef . RemoteLocation != "" {
150- foundCtx = context . WithValue ( foundCtx , index . CurrentPathKey , foundRef . RemoteLocation )
151- }
152- // if this is a ref node, we need to keep diving
153- // until we hit something that isn't a ref.
154- if jh , _ , _ := utils .IsNodeRefValue (foundRef .Node ); jh {
155- // if this node is circular, stop drop and roll.
156- if ! IsCircular (foundRef .Node , foundIndex ) && foundRef .Node != root {
157- return LocateRefNodeWithContext (foundCtx , foundRef .Node , foundIndex )
158- } else {
164+ foundCtx := ctx
165+ if foundRef . RemoteLocation != "" {
166+ foundCtx = context . WithValue ( foundCtx , index . CurrentPathKey , foundRef . RemoteLocation )
167+ }
168+ foundCtx = applyResolvedSchemaIdScope ( foundCtx , foundRef , foundIndex )
169+ // if this is a ref node, we need to keep diving
170+ // until we hit something that isn't a ref.
171+ if jh , _ , _ := utils .IsNodeRefValue (foundRef .Node ); jh {
172+ // if this node is circular, stop drop and roll.
173+ if ! IsCircular (foundRef .Node , foundIndex ) && foundRef .Node != root {
174+ return LocateRefNodeWithContext (foundCtx , foundRef .Node , foundIndex )
175+ }
159176
160177 crr := GetCircularReferenceResult (foundRef .Node , foundIndex )
161178 jp := ""
@@ -168,11 +185,13 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
168185 foundRef .Node .Line ,
169186 foundRef .Node .Column ), foundCtx
170187 }
188+ return utils .NodeAlias (foundRef .Node ), foundIndex , nil , foundCtx
171189 }
172- return utils .NodeAlias (foundRef .Node ), foundIndex , nil , foundCtx
173190 }
174191 }
175192
193+ rv = resolvedRef
194+
176195 // Obtain the absolute filepath/URL of the spec in which we are trying to
177196 // resolve the reference value [rv] from. It's either available from the
178197 // index or passed down through context.
@@ -281,6 +300,7 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
281300
282301 foundRef , fIdx , newCtx := idx .SearchIndexForReferenceWithContext (ctx , rv )
283302 if foundRef != nil {
303+ newCtx = applyResolvedSchemaIdScope (newCtx , foundRef , fIdx )
284304 return utils .NodeAlias (foundRef .Node ), fIdx , nil , newCtx
285305 }
286306
@@ -303,6 +323,40 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
303323 return nil , idx , nil , ctx
304324}
305325
326+ func applyResolvedSchemaIdScope (ctx context.Context , ref * index.Reference , idx * index.SpecIndex ) context.Context {
327+ if ref == nil || ref .Node == nil {
328+ return ctx
329+ }
330+ idValue := index .FindSchemaIdInNode (ref .Node )
331+ if idValue == "" {
332+ return ctx
333+ }
334+
335+ scope := index .GetSchemaIdScope (ctx )
336+ base := ""
337+ if ref .RemoteLocation != "" {
338+ base = ref .RemoteLocation
339+ } else if idx != nil {
340+ base = idx .GetSpecAbsolutePath ()
341+ }
342+ if scope == nil {
343+ scope = index .NewSchemaIdScope (base )
344+ ctx = index .WithSchemaIdScope (ctx , scope )
345+ }
346+
347+ parentBase := scope .BaseUri
348+ if parentBase == "" {
349+ parentBase = base
350+ }
351+ resolved , err := index .ResolveSchemaId (idValue , parentBase )
352+ if err != nil || resolved == "" {
353+ resolved = idValue
354+ }
355+ updated := scope .Copy ()
356+ updated .PushId (resolved )
357+ return index .WithSchemaIdScope (ctx , updated )
358+ }
359+
306360// LocateRefNode will perform a complete lookup for a $ref node. This function searches the entire index for
307361// the reference being supplied. If there is a match found, the reference *yaml.Node is returned.
308362func LocateRefNode (root * yaml.Node , idx * index.SpecIndex ) (* yaml.Node , * index.SpecIndex , error ) {
0 commit comments