@apidevtools/json-schema-ref-parser 9.0.6 → 9.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/dereference.js +73 -36
  2. package/package.json +9 -9
@@ -16,7 +16,7 @@ module.exports = dereference;
16
16
  */
17
17
  function dereference (parser, options) {
18
18
  // console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
19
- let dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", [], parser.$refs, options);
19
+ let dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", [], [], {}, parser.$refs, options);
20
20
  parser.$refs.circular = dereferenced.circular;
21
21
  parser.schema = dereferenced.value;
22
22
  }
@@ -28,43 +28,38 @@ function dereference (parser, options) {
28
28
  * @param {string} path - The full path of `obj`, possibly with a JSON Pointer in the hash
29
29
  * @param {string} pathFromRoot - The path of `obj` from the schema root
30
30
  * @param {object[]} parents - An array of the parent objects that have already been dereferenced
31
+ * @param {object[]} processedObjects - An array of all the objects that have already been processed
32
+ * @param {object} dereferencedCache - An map of all the dereferenced objects
31
33
  * @param {$Refs} $refs
32
34
  * @param {$RefParserOptions} options
33
35
  * @returns {{value: object, circular: boolean}}
34
36
  */
35
- function crawl (obj, path, pathFromRoot, parents, $refs, options) {
37
+ function crawl (obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
36
38
  let dereferenced;
37
39
  let result = {
38
40
  value: obj,
39
41
  circular: false
40
42
  };
41
43
 
42
- if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
43
- parents.push(obj);
44
+ if (options.dereference.circular === "ignore" || processedObjects.indexOf(obj) === -1) {
45
+ if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
46
+ parents.push(obj);
47
+ processedObjects.push(obj);
44
48
 
45
- if ($Ref.isAllowed$Ref(obj, options)) {
46
- dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, $refs, options);
47
- result.circular = dereferenced.circular;
48
- result.value = dereferenced.value;
49
- }
50
- else {
51
- for (let key of Object.keys(obj)) {
52
- let keyPath = Pointer.join(path, key);
53
- let keyPathFromRoot = Pointer.join(pathFromRoot, key);
54
- let value = obj[key];
55
- let circular = false;
56
-
57
- if ($Ref.isAllowed$Ref(value, options)) {
58
- dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, $refs, options);
59
- circular = dereferenced.circular;
60
- // Avoid pointless mutations; breaks frozen objects to no profit
61
- if (obj[key] !== dereferenced.value) {
62
- obj[key] = dereferenced.value;
63
- }
64
- }
65
- else {
66
- if (parents.indexOf(value) === -1) {
67
- dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, $refs, options);
49
+ if ($Ref.isAllowed$Ref(obj, options)) {
50
+ dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
51
+ result.circular = dereferenced.circular;
52
+ result.value = dereferenced.value;
53
+ }
54
+ else {
55
+ for (let key of Object.keys(obj)) {
56
+ let keyPath = Pointer.join(path, key);
57
+ let keyPathFromRoot = Pointer.join(pathFromRoot, key);
58
+ let value = obj[key];
59
+ let circular = false;
60
+
61
+ if ($Ref.isAllowed$Ref(value, options)) {
62
+ dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
68
63
  circular = dereferenced.circular;
69
64
  // Avoid pointless mutations; breaks frozen objects to no profit
70
65
  if (obj[key] !== dereferenced.value) {
@@ -72,16 +67,26 @@ function crawl (obj, path, pathFromRoot, parents, $refs, options) {
72
67
  }
73
68
  }
74
69
  else {
75
- circular = foundCircularReference(keyPath, $refs, options);
70
+ if (parents.indexOf(value) === -1) {
71
+ dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
72
+ circular = dereferenced.circular;
73
+ // Avoid pointless mutations; breaks frozen objects to no profit
74
+ if (obj[key] !== dereferenced.value) {
75
+ obj[key] = dereferenced.value;
76
+ }
77
+ }
78
+ else {
79
+ circular = foundCircularReference(keyPath, $refs, options);
80
+ }
76
81
  }
77
- }
78
82
 
79
- // Set the "isCircular" flag if this or any other property is circular
80
- result.circular = result.circular || circular;
83
+ // Set the "isCircular" flag if this or any other property is circular
84
+ result.circular = result.circular || circular;
85
+ }
81
86
  }
82
- }
83
87
 
84
- parents.pop();
88
+ parents.pop();
89
+ }
85
90
  }
86
91
 
87
92
  return result;
@@ -94,14 +99,38 @@ function crawl (obj, path, pathFromRoot, parents, $refs, options) {
94
99
  * @param {string} path - The full path of `$ref`, possibly with a JSON Pointer in the hash
95
100
  * @param {string} pathFromRoot - The path of `$ref` from the schema root
96
101
  * @param {object[]} parents - An array of the parent objects that have already been dereferenced
102
+ * @param {object[]} processedObjects - An array of all the objects that have already been dereferenced
103
+ * @param {object} dereferencedCache - An map of all the dereferenced objects
97
104
  * @param {$Refs} $refs
98
105
  * @param {$RefParserOptions} options
99
106
  * @returns {{value: object, circular: boolean}}
100
107
  */
101
- function dereference$Ref ($ref, path, pathFromRoot, parents, $refs, options) {
108
+ function dereference$Ref ($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
102
109
  // console.log('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path);
103
110
 
104
111
  let $refPath = url.resolve(path, $ref.$ref);
112
+
113
+ if (dereferencedCache[$refPath]) {
114
+ const cache = dereferencedCache[$refPath];
115
+
116
+ const refKeys = Object.keys($ref);
117
+ if (refKeys.length > 1) {
118
+ const extraKeys = {};
119
+ for (let key of refKeys) {
120
+ if (key !== "$ref" && !(key in cache.value)) {
121
+ extraKeys[key] = $ref[key];
122
+ }
123
+ }
124
+ return {
125
+ circular: cache.circular,
126
+ value: Object.assign({}, cache.value, extraKeys),
127
+ };
128
+ }
129
+
130
+ return cache;
131
+ }
132
+
133
+
105
134
  let pointer = $refs._resolve($refPath, path, options);
106
135
 
107
136
  if (pointer === null) {
@@ -122,7 +151,7 @@ function dereference$Ref ($ref, path, pathFromRoot, parents, $refs, options) {
122
151
  // Crawl the dereferenced value (unless it's circular)
123
152
  if (!circular) {
124
153
  // Determine if the dereferenced value is circular
125
- let dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, $refs, options);
154
+ let dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
126
155
  circular = dereferenced.circular;
127
156
  dereferencedValue = dereferenced.value;
128
157
  }
@@ -138,10 +167,18 @@ function dereference$Ref ($ref, path, pathFromRoot, parents, $refs, options) {
138
167
  dereferencedValue.$ref = pathFromRoot;
139
168
  }
140
169
 
141
- return {
170
+
171
+ const dereferencedObject = {
142
172
  circular,
143
173
  value: dereferencedValue
144
174
  };
175
+
176
+ // only cache if no extra properties than $ref
177
+ if (Object.keys($ref).length === 1) {
178
+ dereferencedCache[$refPath] = dereferencedObject;
179
+ }
180
+
181
+ return dereferencedObject;
145
182
  }
146
183
 
147
184
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apidevtools/json-schema-ref-parser",
3
- "version": "9.0.6",
3
+ "version": "9.0.7",
4
4
  "description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
5
5
  "keywords": [
6
6
  "json",
@@ -51,23 +51,23 @@
51
51
  "release": "npm run upgrade && npm run clean && npm test && npm run bump"
52
52
  },
53
53
  "devDependencies": {
54
- "@babel/polyfill": "^7.10.4",
54
+ "@babel/polyfill": "^7.12.1",
55
55
  "@jsdevtools/eslint-config": "^1.0.7",
56
- "@jsdevtools/host-environment": "^2.0.4",
56
+ "@jsdevtools/host-environment": "^2.1.2",
57
57
  "@jsdevtools/karma-config": "^3.1.7",
58
- "@jsdevtools/version-bump-prompt": "^6.0.6",
59
- "@types/json-schema": "^7.0.4",
60
- "@types/node": "^14.0.25",
58
+ "@jsdevtools/version-bump-prompt": "^6.1.0",
59
+ "@types/json-schema": "^7.0.6",
60
+ "@types/node": "^14.14.21",
61
61
  "chai": "^4.2.0",
62
62
  "chai-subset": "^1.6.0",
63
- "eslint": "^7.5.0",
63
+ "eslint": "^7.18.0",
64
64
  "karma": "^5.0.2",
65
65
  "karma-cli": "^2.0.0",
66
- "mocha": "^8.0.1",
66
+ "mocha": "^8.2.1",
67
67
  "npm-check": "^5.9.0",
68
68
  "nyc": "^15.0.1",
69
69
  "shx": "^0.3.2",
70
- "typescript": "^3.9.7"
70
+ "typescript": "^4.0.5"
71
71
  },
72
72
  "dependencies": {
73
73
  "@jsdevtools/ono": "^7.1.3",