@@ -220,26 +220,46 @@ function dereference$Ref<S extends object = JSONSchema, O extends ParserOptions<
220220 //
221221 // If the cached object however is _not_ circular and there are additional keys alongside our
222222 // `$ref` pointer here we should merge them back in and return that.
223- if ( cache . circular ) {
223+ if ( ! cache . circular ) {
224+ const refKeys = Object . keys ( $ref ) ;
225+ if ( refKeys . length > 1 ) {
226+ const extraKeys = { } ;
227+ for ( const key of refKeys ) {
228+ if ( key !== "$ref" && ! ( key in cache . value ) ) {
229+ // @ts -expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
230+ extraKeys [ key ] = $ref [ key ] ;
231+ }
232+ }
233+ return {
234+ circular : cache . circular ,
235+ value : Object . assign ( { } , cache . value , extraKeys ) ,
236+ } ;
237+ }
238+
224239 return cache ;
225240 }
226241
227- const refKeys = Object . keys ( $ref ) ;
228- if ( refKeys . length > 1 ) {
229- const extraKeys = { } ;
230- for ( const key of refKeys ) {
231- if ( key !== "$ref" && ! ( key in cache . value ) ) {
232- // @ts -expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
233- extraKeys [ key ] = $ref [ key ] ;
234- }
242+ // If both our cached value and our incoming `$ref` are the same then we can return what we
243+ // got out of the cache, otherwise we should re-process this value. We need to do this because
244+ // the current dereference caching mechanism doesn't take into account that `$ref` are neither
245+ // unique or reference the same file.
246+ //
247+ // For example if `schema.yaml` references `definitions/child.yaml` and
248+ // `definitions/parent.yaml` references `child.yaml` then `$ref: 'child.yaml'` may get cached
249+ // for `definitions/child.yaml`, resulting in `schema.yaml` being having an invalid reference
250+ // to `child.yaml`.
251+ //
252+ // This check is not perfect and the design of the dereference caching mechanism needs a total
253+ // overhaul.
254+ if ( typeof cache . value === 'object' && '$ref' in cache . value && '$ref' in $ref ) {
255+ if ( cache . value . $ref === $ref . $ref ) {
256+ return cache ;
257+ } else {
258+ // no-op
235259 }
236- return {
237- circular : cache . circular ,
238- value : Object . assign ( { } , cache . value , extraKeys ) ,
239- } ;
260+ } else {
261+ return cache ;
240262 }
241-
242- return cache ;
243263 }
244264
245265 const pointer = $refs . _resolve ( $refPath , path , options ) ;
0 commit comments