@@ -16,59 +16,42 @@ module.exports = dereference;
16
16
* @param {$RefParserOptions } options
17
17
*/
18
18
function dereference ( parser , options ) {
19
- util . debug ( 'Dereferencing $ref pointers in %s' , parser . _basePath ) ;
19
+ util . debug ( 'Dereferencing $ref pointers in %s' , parser . $refs . _basePath ) ;
20
20
parser . $refs . circular = false ;
21
- crawl ( parser . schema , parser . _basePath , [ ] , parser . $refs , options ) ;
21
+ crawl ( parser . schema , parser . $refs . _basePath , '#' , [ ] , parser . $refs , options ) ;
22
22
}
23
23
24
24
/**
25
25
* Recursively crawls the given value, and dereferences any JSON references.
26
26
*
27
27
* @param {* } obj - The value to crawl. If it's not an object or array, it will be ignored.
28
- * @param {string } path - The path to use for resolving relative JSON references
28
+ * @param {string } path - The full path of `obj`, possibly with a JSON Pointer in the hash
29
+ * @param {string } pathFromRoot - The path of `obj` from the schema root
29
30
* @param {object[] } parents - An array of the parent objects that have already been dereferenced
30
- * @param {$Refs } $refs - The resolved JSON references
31
+ * @param {$Refs } $refs
31
32
* @param {$RefParserOptions } options
32
33
* @returns {boolean } - Returns true if a circular reference was found
33
34
*/
34
- function crawl ( obj , path , parents , $refs , options ) {
35
+ function crawl ( obj , path , pathFromRoot , parents , $refs , options ) {
35
36
var isCircular = false ;
36
37
37
38
if ( obj && typeof obj === 'object' ) {
38
39
parents . push ( obj ) ;
39
40
40
41
Object . keys ( obj ) . forEach ( function ( key ) {
41
42
var keyPath = Pointer . join ( path , key ) ;
43
+ var keyPathFromRoot = Pointer . join ( pathFromRoot , key ) ;
42
44
var value = obj [ key ] ;
43
45
var circular = false ;
44
46
45
47
if ( $Ref . isAllowed$Ref ( value , options ) ) {
46
- // We found a $ref, so resolve it
47
- util . debug ( 'Dereferencing $ref pointer "%s" at %s' , value . $ref , keyPath ) ;
48
- var $refPath = url . resolve ( path , value . $ref ) ;
49
- var pointer = $refs . _resolve ( $refPath , options ) ;
50
-
51
- // Check for circular references
52
- circular = pointer . circular || parents . indexOf ( pointer . value ) !== - 1 ;
53
- circular && foundCircularReference ( keyPath , $refs , options ) ;
54
-
55
- // Dereference the JSON reference
56
- var dereferencedValue = getDereferencedValue ( value , pointer . value ) ;
57
-
58
- // Crawl the dereferenced value (unless it's circular)
59
- if ( ! circular ) {
60
- // If the `crawl` method returns true, then dereferenced value is circular
61
- circular = crawl ( dereferencedValue , pointer . path , parents , $refs , options ) ;
62
- }
63
-
64
- // Replace the JSON reference with the dereferenced value
65
- if ( ! circular || options . $refs . circular === true ) {
66
- obj [ key ] = dereferencedValue ;
67
- }
48
+ var dereferenced = dereference$Ref ( value , keyPath , keyPathFromRoot , parents , $refs , options ) ;
49
+ circular = dereferenced . circular ;
50
+ obj [ key ] = dereferenced . value ;
68
51
}
69
52
else {
70
53
if ( parents . indexOf ( value ) === - 1 ) {
71
- circular = crawl ( value , keyPath , parents , $refs , options ) ;
54
+ circular = crawl ( value , keyPath , keyPathFromRoot , parents , $refs , options ) ;
72
55
}
73
56
else {
74
57
circular = foundCircularReference ( keyPath , $refs , options ) ;
@@ -85,33 +68,51 @@ function crawl(obj, path, parents, $refs, options) {
85
68
}
86
69
87
70
/**
88
- * Returns the dereferenced value of the given JSON reference .
71
+ * Dereferences the given JSON Reference, and then crawls the resulting value .
89
72
*
90
- * @param {object } currentValue - the current value, which contains a JSON reference ("$ref" property)
91
- * @param {* } resolvedValue - the resolved value, which can be any type
92
- * @returns {* } - Returns the dereferenced value
73
+ * @param {{$ref: string} } $ref - The JSON Reference to resolve
74
+ * @param {string } path - The full path of `$ref`, possibly with a JSON Pointer in the hash
75
+ * @param {string } pathFromRoot - The path of `$ref` from the schema root
76
+ * @param {object[] } parents - An array of the parent objects that have already been dereferenced
77
+ * @param {$Refs } $refs
78
+ * @param {$RefParserOptions } options
79
+ * @returns {object }
93
80
*/
94
- function getDereferencedValue ( currentValue , resolvedValue ) {
95
- if ( resolvedValue && typeof resolvedValue === 'object' && Object . keys ( currentValue ) . length > 1 ) {
96
- // The current value has additional properties (other than "$ref"),
97
- // so merge the resolved value rather than completely replacing the reference
98
- var merged = { } ;
99
- Object . keys ( currentValue ) . forEach ( function ( key ) {
100
- if ( key !== '$ref' ) {
101
- merged [ key ] = currentValue [ key ] ;
102
- }
103
- } ) ;
104
- Object . keys ( resolvedValue ) . forEach ( function ( key ) {
105
- if ( ! ( key in merged ) ) {
106
- merged [ key ] = resolvedValue [ key ] ;
107
- }
108
- } ) ;
109
- return merged ;
81
+ function dereference$Ref ( $ref , path , pathFromRoot , parents , $refs , options ) {
82
+ util . debug ( 'Dereferencing $ref pointer "%s" at %s' , $ref . $ref , path ) ;
83
+
84
+ var $refPath = url . resolve ( path , $ref . $ref ) ;
85
+ var pointer = $refs . _resolve ( $refPath , options ) ;
86
+
87
+ // Check for circular references
88
+ var directCircular = pointer . circular ;
89
+ var circular = directCircular || parents . indexOf ( pointer . value ) !== - 1 ;
90
+ circular && foundCircularReference ( path , $refs , options ) ;
91
+
92
+ // Dereference the JSON reference
93
+ var dereferencedValue = util . dereference ( $ref , pointer . value ) ;
94
+
95
+ // Crawl the dereferenced value (unless it's circular)
96
+ if ( ! circular ) {
97
+ // If the `crawl` method returns true, then dereferenced value is circular
98
+ circular = crawl ( dereferencedValue , pointer . path , pathFromRoot , parents , $refs , options ) ;
110
99
}
111
- else {
112
- // Completely replace the original reference with the resolved value
113
- return resolvedValue ;
100
+
101
+ if ( circular && ! directCircular && options . $refs . circular === 'ignore' ) {
102
+ // The user has chosen to "ignore" circular references, so don't change the value
103
+ dereferencedValue = $ref ;
104
+ }
105
+
106
+ if ( directCircular ) {
107
+ // The pointer is a DIRECT circular reference (i.e. it references itself).
108
+ // So replace the $ref path with the absolute path from the JSON Schema root
109
+ dereferencedValue . $ref = pathFromRoot ;
114
110
}
111
+
112
+ return {
113
+ circular : circular ,
114
+ value : dereferencedValue
115
+ } ;
115
116
}
116
117
117
118
/**
0 commit comments