@apidevtools/json-schema-ref-parser 9.1.1 → 10.0.0

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # JSON Schema $Ref Parser
2
2
 
3
- _**This package needs [a new maintainer](https://github.com/APIDevTools/json-schema-ref-parser/issues/285) or at least some contributors, or a decent number of sponsors so I can hire contractors to do the work. For more information [please read this article](https://phil.tech/2022/bundling-openapi-with-javascript/). I'll mark the repo as read-only and unmaintained on January 15th 2023 along with a bunch of other @apidevtools packages like swagger-parser, so I can focus on scaling up my [reforestation charity](https://protect.earth/) instead of burning myself out trying to maintain a whole load of OSS projects I don't use in my vanishingly small spare time.** - [Phil Sturgeon](https://github.com/philsturgeon)_
3
+ _**This package needs [a new maintainer](https://github.com/APIDevTools/json-schema-ref-parser/issues/285) or at least some contributors. For more information [please read this article](https://phil.tech/2022/bundling-openapi-with-javascript/). As of v10.0.0 I am no longer spending any time working on this tool, so I can focus on scaling up my [reforestation charity](https://protect.earth/) instead of burning myself out trying to maintain a whole load of OSS projects I don't use in my vanishingly small spare time. Get in touch if you'd like to take over.** - [Phil Sturgeon](https://github.com/philsturgeon)_
4
4
 
5
5
  #### Parse, Resolve, and Dereference JSON Schema $ref pointers
6
6
 
@@ -8,14 +8,9 @@ _**This package needs [a new maintainer](https://github.com/APIDevTools/json-sch
8
8
  [![Coverage Status](https://coveralls.io/repos/github/APIDevTools/json-schema-ref-parser/badge.svg?branch=master)](https://coveralls.io/github/APIDevTools/json-schema-ref-parser)
9
9
 
10
10
  [![npm](https://img.shields.io/npm/v/@apidevtools/json-schema-ref-parser.svg)](https://www.npmjs.com/package/@apidevtools/json-schema-ref-parser)
11
- [![Dependencies](https://david-dm.org/APIDevTools/json-schema-ref-parser.svg)](https://david-dm.org/APIDevTools/json-schema-ref-parser)
12
11
  [![License](https://img.shields.io/npm/l/@apidevtools/json-schema-ref-parser.svg)](LICENSE)
13
12
  [![Buy us a tree](https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-lightgreen)](https://plant.treeware.earth/APIDevTools/json-schema-ref-parser)
14
13
 
15
-
16
- [![OS and Browser Compatibility](https://apitools.dev/img/badges/ci-badges-with-ie.svg)](https://github.com/APIDevTools/json-schema-ref-parser/actions)
17
-
18
-
19
14
  The Problem:
20
15
  --------------------------
21
16
  You've got a JSON Schema with `$ref` pointers to other files and/or URLs. Maybe you know all the referenced files ahead of time. Maybe you don't. Maybe some are local files, and others are remote URLs. Maybe they are a mix of JSON and YAML format. Maybe some of the files contain cross-references to each other.
package/cjs/bundle.js ADDED
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return _default;
9
+ }
10
+ });
11
+ var _refJs = /*#__PURE__*/ _interopRequireDefault(require("./ref.js"));
12
+ var _pointerJs = /*#__PURE__*/ _interopRequireDefault(require("./pointer.js"));
13
+ var _urlJs = /*#__PURE__*/ _interopRequireWildcard(require("./util/url.js"));
14
+ function _interopRequireDefault(obj) {
15
+ return obj && obj.__esModule ? obj : {
16
+ default: obj
17
+ };
18
+ }
19
+ function _getRequireWildcardCache(nodeInterop) {
20
+ if (typeof WeakMap !== "function") return null;
21
+ var cacheBabelInterop = new WeakMap();
22
+ var cacheNodeInterop = new WeakMap();
23
+ return (_getRequireWildcardCache = function(nodeInterop) {
24
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
25
+ })(nodeInterop);
26
+ }
27
+ function _interopRequireWildcard(obj, nodeInterop) {
28
+ if (!nodeInterop && obj && obj.__esModule) {
29
+ return obj;
30
+ }
31
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
32
+ return {
33
+ default: obj
34
+ };
35
+ }
36
+ var cache = _getRequireWildcardCache(nodeInterop);
37
+ if (cache && cache.has(obj)) {
38
+ return cache.get(obj);
39
+ }
40
+ var newObj = {};
41
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
42
+ for(var key in obj){
43
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
44
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
45
+ if (desc && (desc.get || desc.set)) {
46
+ Object.defineProperty(newObj, key, desc);
47
+ } else {
48
+ newObj[key] = obj[key];
49
+ }
50
+ }
51
+ }
52
+ newObj.default = obj;
53
+ if (cache) {
54
+ cache.set(obj, newObj);
55
+ }
56
+ return newObj;
57
+ }
58
+ var _default = bundle;
59
+ /**
60
+ * Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
61
+ * only has *internal* references, not any *external* references.
62
+ * This method mutates the JSON schema object, adding new references and re-mapping existing ones.
63
+ *
64
+ * @param {$RefParser} parser
65
+ * @param {$RefParserOptions} options
66
+ */ function bundle(parser, options) {
67
+ // console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
68
+ // Build an inventory of all $ref pointers in the JSON Schema
69
+ var inventory = [];
70
+ crawl(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);
71
+ // Remap all $ref pointers
72
+ remap(inventory);
73
+ }
74
+ /**
75
+ * Recursively crawls the given value, and inventories all JSON references.
76
+ *
77
+ * @param {object} parent - The object containing the value to crawl. If the value is not an object or array, it will be ignored.
78
+ * @param {string} key - The property key of `parent` to be crawled
79
+ * @param {string} path - The full path of the property being crawled, possibly with a JSON Pointer in the hash
80
+ * @param {string} pathFromRoot - The path of the property being crawled, from the schema root
81
+ * @param {object[]} inventory - An array of already-inventoried $ref pointers
82
+ * @param {$Refs} $refs
83
+ * @param {$RefParserOptions} options
84
+ */ function crawl(parent, key, path, pathFromRoot, indirections, inventory, $refs, options) {
85
+ var obj = key === null ? parent : parent[key];
86
+ if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
87
+ if (_refJs.default.isAllowed$Ref(obj)) {
88
+ inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options);
89
+ } else {
90
+ // Crawl the object in a specific order that's optimized for bundling.
91
+ // This is important because it determines how `pathFromRoot` gets built,
92
+ // which later determines which keys get dereferenced and which ones get remapped
93
+ var keys = Object.keys(obj).sort(function(a, b) {
94
+ // Most people will expect references to be bundled into the the "definitions" property,
95
+ // so we always crawl that property first, if it exists.
96
+ if (a === "definitions") {
97
+ return -1;
98
+ } else if (b === "definitions") {
99
+ return 1;
100
+ } else {
101
+ // Otherwise, crawl the keys based on their length.
102
+ // This produces the shortest possible bundled references
103
+ return a.length - b.length;
104
+ }
105
+ });
106
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
107
+ try {
108
+ // eslint-disable-next-line no-shadow
109
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
110
+ var _$key = _step.value;
111
+ var keyPath = _pointerJs.default.join(path, _$key);
112
+ var keyPathFromRoot = _pointerJs.default.join(pathFromRoot, _$key);
113
+ var value = obj[_$key];
114
+ if (_refJs.default.isAllowed$Ref(value)) {
115
+ inventory$Ref(obj, _$key, path, keyPathFromRoot, indirections, inventory, $refs, options);
116
+ } else {
117
+ crawl(obj, _$key, keyPath, keyPathFromRoot, indirections, inventory, $refs, options);
118
+ }
119
+ }
120
+ } catch (err) {
121
+ _didIteratorError = true;
122
+ _iteratorError = err;
123
+ } finally{
124
+ try {
125
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
126
+ _iterator.return();
127
+ }
128
+ } finally{
129
+ if (_didIteratorError) {
130
+ throw _iteratorError;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ /**
138
+ * Inventories the given JSON Reference (i.e. records detailed information about it so we can
139
+ * optimize all $refs in the schema), and then crawls the resolved value.
140
+ *
141
+ * @param {object} $refParent - The object that contains a JSON Reference as one of its keys
142
+ * @param {string} $refKey - The key in `$refParent` that is a JSON Reference
143
+ * @param {string} path - The full path of the JSON Reference at `$refKey`, possibly with a JSON Pointer in the hash
144
+ * @param {string} pathFromRoot - The path of the JSON Reference at `$refKey`, from the schema root
145
+ * @param {object[]} inventory - An array of already-inventoried $ref pointers
146
+ * @param {$Refs} $refs
147
+ * @param {$RefParserOptions} options
148
+ */ function inventory$Ref($refParent, $refKey, path, pathFromRoot, indirections, inventory, $refs, options) {
149
+ var $ref = $refKey === null ? $refParent : $refParent[$refKey];
150
+ var $refPath = _urlJs.resolve(path, $ref.$ref);
151
+ var pointer = $refs._resolve($refPath, pathFromRoot, options);
152
+ if (pointer === null) {
153
+ return;
154
+ }
155
+ var depth = _pointerJs.default.parse(pathFromRoot).length;
156
+ var file = _urlJs.stripHash(pointer.path);
157
+ var hash = _urlJs.getHash(pointer.path);
158
+ var external = file !== $refs._root$Ref.path;
159
+ var extended = _refJs.default.isExtended$Ref($ref);
160
+ indirections += pointer.indirections;
161
+ var existingEntry = findInInventory(inventory, $refParent, $refKey);
162
+ if (existingEntry) {
163
+ // This $Ref has already been inventoried, so we don't need to process it again
164
+ if (depth < existingEntry.depth || indirections < existingEntry.indirections) {
165
+ removeFromInventory(inventory, existingEntry);
166
+ } else {
167
+ return;
168
+ }
169
+ }
170
+ inventory.push({
171
+ $ref: $ref,
172
+ parent: $refParent,
173
+ key: $refKey,
174
+ pathFromRoot: pathFromRoot,
175
+ depth: depth,
176
+ file: file,
177
+ hash: hash,
178
+ value: pointer.value,
179
+ circular: pointer.circular,
180
+ extended: extended,
181
+ external: external,
182
+ indirections: indirections
183
+ });
184
+ // Recursively crawl the resolved value
185
+ if (!existingEntry || external) {
186
+ crawl(pointer.value, null, pointer.path, pathFromRoot, indirections + 1, inventory, $refs, options);
187
+ }
188
+ }
189
+ /**
190
+ * Re-maps every $ref pointer, so that they're all relative to the root of the JSON Schema.
191
+ * Each referenced value is dereferenced EXACTLY ONCE. All subsequent references to the same
192
+ * value are re-mapped to point to the first reference.
193
+ *
194
+ * @example:
195
+ * {
196
+ * first: { $ref: somefile.json#/some/part },
197
+ * second: { $ref: somefile.json#/another/part },
198
+ * third: { $ref: somefile.json },
199
+ * fourth: { $ref: somefile.json#/some/part/sub/part }
200
+ * }
201
+ *
202
+ * In this example, there are four references to the same file, but since the third reference points
203
+ * to the ENTIRE file, that's the only one we need to dereference. The other three can just be
204
+ * remapped to point inside the third one.
205
+ *
206
+ * On the other hand, if the third reference DIDN'T exist, then the first and second would both need
207
+ * to be dereferenced, since they point to different parts of the file. The fourth reference does NOT
208
+ * need to be dereferenced, because it can be remapped to point inside the first one.
209
+ *
210
+ * @param {object[]} inventory
211
+ */ function remap(inventory) {
212
+ // Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
213
+ inventory.sort(function(a, b) {
214
+ if (a.file !== b.file) {
215
+ // Group all the $refs that point to the same file
216
+ return a.file < b.file ? -1 : +1;
217
+ } else if (a.hash !== b.hash) {
218
+ // Group all the $refs that point to the same part of the file
219
+ return a.hash < b.hash ? -1 : +1;
220
+ } else if (a.circular !== b.circular) {
221
+ // If the $ref points to itself, then sort it higher than other $refs that point to this $ref
222
+ return a.circular ? -1 : +1;
223
+ } else if (a.extended !== b.extended) {
224
+ // If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
225
+ return a.extended ? +1 : -1;
226
+ } else if (a.indirections !== b.indirections) {
227
+ // Sort direct references higher than indirect references
228
+ return a.indirections - b.indirections;
229
+ } else if (a.depth !== b.depth) {
230
+ // Sort $refs by how close they are to the JSON Schema root
231
+ return a.depth - b.depth;
232
+ } else {
233
+ // Determine how far each $ref is from the "definitions" property.
234
+ // Most people will expect references to be bundled into the the "definitions" property if possible.
235
+ var aDefinitionsIndex = a.pathFromRoot.lastIndexOf("/definitions");
236
+ var bDefinitionsIndex = b.pathFromRoot.lastIndexOf("/definitions");
237
+ if (aDefinitionsIndex !== bDefinitionsIndex) {
238
+ // Give higher priority to the $ref that's closer to the "definitions" property
239
+ return bDefinitionsIndex - aDefinitionsIndex;
240
+ } else {
241
+ // All else is equal, so use the shorter path, which will produce the shortest possible reference
242
+ return a.pathFromRoot.length - b.pathFromRoot.length;
243
+ }
244
+ }
245
+ });
246
+ var file, hash, pathFromRoot;
247
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
248
+ try {
249
+ for(var _iterator = inventory[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
250
+ var entry = _step.value;
251
+ // console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
252
+ if (!entry.external) {
253
+ // This $ref already resolves to the main JSON Schema file
254
+ entry.$ref.$ref = entry.hash;
255
+ } else if (entry.file === file && entry.hash === hash) {
256
+ // This $ref points to the same value as the prevous $ref, so remap it to the same path
257
+ entry.$ref.$ref = pathFromRoot;
258
+ } else if (entry.file === file && entry.hash.indexOf(hash + "/") === 0) {
259
+ // This $ref points to a sub-value of the prevous $ref, so remap it beneath that path
260
+ entry.$ref.$ref = _pointerJs.default.join(pathFromRoot, _pointerJs.default.parse(entry.hash.replace(hash, "#")));
261
+ } else {
262
+ // We've moved to a new file or new hash
263
+ file = entry.file;
264
+ hash = entry.hash;
265
+ pathFromRoot = entry.pathFromRoot;
266
+ // This is the first $ref to point to this value, so dereference the value.
267
+ // Any other $refs that point to the same value will point to this $ref instead
268
+ entry.$ref = entry.parent[entry.key] = _refJs.default.dereference(entry.$ref, entry.value);
269
+ if (entry.circular) {
270
+ // This $ref points to itself
271
+ entry.$ref.$ref = entry.pathFromRoot;
272
+ }
273
+ }
274
+ // console.log(' new value: %s', (entry.$ref && entry.$ref.$ref) ? entry.$ref.$ref : '[object Object]');
275
+ }
276
+ } catch (err) {
277
+ _didIteratorError = true;
278
+ _iteratorError = err;
279
+ } finally{
280
+ try {
281
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
282
+ _iterator.return();
283
+ }
284
+ } finally{
285
+ if (_didIteratorError) {
286
+ throw _iteratorError;
287
+ }
288
+ }
289
+ }
290
+ }
291
+ /**
292
+ * TODO
293
+ */ function findInInventory(inventory, $refParent, $refKey) {
294
+ for(var i = 0; i < inventory.length; i++){
295
+ var existingEntry = inventory[i];
296
+ if (existingEntry.parent === $refParent && existingEntry.key === $refKey) {
297
+ return existingEntry;
298
+ }
299
+ }
300
+ }
301
+ function removeFromInventory(inventory, entry) {
302
+ var index = inventory.indexOf(entry);
303
+ inventory.splice(index, 1);
304
+ }
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return _default;
9
+ }
10
+ });
11
+ var _refJs = /*#__PURE__*/ _interopRequireDefault(require("./ref.js"));
12
+ var _pointerJs = /*#__PURE__*/ _interopRequireDefault(require("./pointer.js"));
13
+ var _ono = require("@jsdevtools/ono");
14
+ var _urlJs = /*#__PURE__*/ _interopRequireWildcard(require("./util/url.js"));
15
+ function _interopRequireDefault(obj) {
16
+ return obj && obj.__esModule ? obj : {
17
+ default: obj
18
+ };
19
+ }
20
+ function _getRequireWildcardCache(nodeInterop) {
21
+ if (typeof WeakMap !== "function") return null;
22
+ var cacheBabelInterop = new WeakMap();
23
+ var cacheNodeInterop = new WeakMap();
24
+ return (_getRequireWildcardCache = function(nodeInterop) {
25
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
26
+ })(nodeInterop);
27
+ }
28
+ function _interopRequireWildcard(obj, nodeInterop) {
29
+ if (!nodeInterop && obj && obj.__esModule) {
30
+ return obj;
31
+ }
32
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
33
+ return {
34
+ default: obj
35
+ };
36
+ }
37
+ var cache = _getRequireWildcardCache(nodeInterop);
38
+ if (cache && cache.has(obj)) {
39
+ return cache.get(obj);
40
+ }
41
+ var newObj = {};
42
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
43
+ for(var key in obj){
44
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
45
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
46
+ if (desc && (desc.get || desc.set)) {
47
+ Object.defineProperty(newObj, key, desc);
48
+ } else {
49
+ newObj[key] = obj[key];
50
+ }
51
+ }
52
+ }
53
+ newObj.default = obj;
54
+ if (cache) {
55
+ cache.set(obj, newObj);
56
+ }
57
+ return newObj;
58
+ }
59
+ var _default = dereference;
60
+ /**
61
+ * Crawls the JSON schema, finds all JSON references, and dereferences them.
62
+ * This method mutates the JSON schema object, replacing JSON references with their resolved value.
63
+ *
64
+ * @param {$RefParser} parser
65
+ * @param {$RefParserOptions} options
66
+ */ function dereference(parser, options) {
67
+ // console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
68
+ var dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", new Set(), new Set(), new Map(), parser.$refs, options);
69
+ parser.$refs.circular = dereferenced.circular;
70
+ parser.schema = dereferenced.value;
71
+ }
72
+ /**
73
+ * Recursively crawls the given value, and dereferences any JSON references.
74
+ *
75
+ * @param {*} obj - The value to crawl. If it's not an object or array, it will be ignored.
76
+ * @param {string} path - The full path of `obj`, possibly with a JSON Pointer in the hash
77
+ * @param {string} pathFromRoot - The path of `obj` from the schema root
78
+ * @param {Set<object>} parents - An array of the parent objects that have already been dereferenced
79
+ * @param {Set<object>} processedObjects - An array of all the objects that have already been processed
80
+ * @param {Map<string,object>} dereferencedCache - An map of all the dereferenced objects
81
+ * @param {$Refs} $refs
82
+ * @param {$RefParserOptions} options
83
+ * @returns {{value: object, circular: boolean}}
84
+ */ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
85
+ var dereferenced;
86
+ var result = {
87
+ value: obj,
88
+ circular: false
89
+ };
90
+ var isExcludedPath = options.dereference.excludedPathMatcher;
91
+ if (options.dereference.circular === "ignore" || !processedObjects.has(obj)) {
92
+ if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
93
+ parents.add(obj);
94
+ processedObjects.add(obj);
95
+ if (_refJs.default.isAllowed$Ref(obj, options)) {
96
+ dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
97
+ result.circular = dereferenced.circular;
98
+ result.value = dereferenced.value;
99
+ } else {
100
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
101
+ try {
102
+ for(var _iterator = Object.keys(obj)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
103
+ var key = _step.value;
104
+ var keyPath = _pointerJs.default.join(path, key);
105
+ var keyPathFromRoot = _pointerJs.default.join(pathFromRoot, key);
106
+ if (isExcludedPath(keyPathFromRoot)) {
107
+ continue;
108
+ }
109
+ var value = obj[key];
110
+ var circular = false;
111
+ if (_refJs.default.isAllowed$Ref(value, options)) {
112
+ dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
113
+ circular = dereferenced.circular;
114
+ // Avoid pointless mutations; breaks frozen objects to no profit
115
+ if (obj[key] !== dereferenced.value) {
116
+ obj[key] = dereferenced.value;
117
+ if (options.dereference.onDereference) {
118
+ options.dereference.onDereference(value.$ref, obj[key]);
119
+ }
120
+ }
121
+ } else {
122
+ if (!parents.has(value)) {
123
+ dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
124
+ circular = dereferenced.circular;
125
+ // Avoid pointless mutations; breaks frozen objects to no profit
126
+ if (obj[key] !== dereferenced.value) {
127
+ obj[key] = dereferenced.value;
128
+ }
129
+ } else {
130
+ circular = foundCircularReference(keyPath, $refs, options);
131
+ }
132
+ }
133
+ // Set the "isCircular" flag if this or any other property is circular
134
+ result.circular = result.circular || circular;
135
+ }
136
+ } catch (err) {
137
+ _didIteratorError = true;
138
+ _iteratorError = err;
139
+ } finally{
140
+ try {
141
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
142
+ _iterator.return();
143
+ }
144
+ } finally{
145
+ if (_didIteratorError) {
146
+ throw _iteratorError;
147
+ }
148
+ }
149
+ }
150
+ }
151
+ parents.delete(obj);
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ /**
157
+ * Dereferences the given JSON Reference, and then crawls the resulting value.
158
+ *
159
+ * @param {{$ref: string}} $ref - The JSON Reference to resolve
160
+ * @param {string} path - The full path of `$ref`, possibly with a JSON Pointer in the hash
161
+ * @param {string} pathFromRoot - The path of `$ref` from the schema root
162
+ * @param {Set<object>} parents - An array of the parent objects that have already been dereferenced
163
+ * @param {Set<object>} processedObjects - An array of all the objects that have already been dereferenced
164
+ * @param {Map<string,object>} dereferencedCache - An map of all the dereferenced objects
165
+ * @param {$Refs} $refs
166
+ * @param {$RefParserOptions} options
167
+ * @returns {{value: object, circular: boolean}}
168
+ */ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
169
+ // console.log('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path);
170
+ var $refPath = _urlJs.resolve(path, $ref.$ref);
171
+ var cache = dereferencedCache.get($refPath);
172
+ if (cache) {
173
+ var refKeys = Object.keys($ref);
174
+ if (refKeys.length > 1) {
175
+ var extraKeys = {};
176
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
177
+ try {
178
+ for(var _iterator = refKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
179
+ var key = _step.value;
180
+ if (key !== "$ref" && !(key in cache.value)) {
181
+ extraKeys[key] = $ref[key];
182
+ }
183
+ }
184
+ } catch (err) {
185
+ _didIteratorError = true;
186
+ _iteratorError = err;
187
+ } finally{
188
+ try {
189
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
190
+ _iterator.return();
191
+ }
192
+ } finally{
193
+ if (_didIteratorError) {
194
+ throw _iteratorError;
195
+ }
196
+ }
197
+ }
198
+ return {
199
+ circular: cache.circular,
200
+ value: Object.assign({}, cache.value, extraKeys)
201
+ };
202
+ }
203
+ return cache;
204
+ }
205
+ var pointer = $refs._resolve($refPath, path, options);
206
+ if (pointer === null) {
207
+ return {
208
+ circular: false,
209
+ value: null
210
+ };
211
+ }
212
+ // Check for circular references
213
+ var directCircular = pointer.circular;
214
+ var circular = directCircular || parents.has(pointer.value);
215
+ circular && foundCircularReference(path, $refs, options);
216
+ // Dereference the JSON reference
217
+ var dereferencedValue = _refJs.default.dereference($ref, pointer.value);
218
+ // Crawl the dereferenced value (unless it's circular)
219
+ if (!circular) {
220
+ // Determine if the dereferenced value is circular
221
+ var dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
222
+ circular = dereferenced.circular;
223
+ dereferencedValue = dereferenced.value;
224
+ }
225
+ if (circular && !directCircular && options.dereference.circular === "ignore") {
226
+ // The user has chosen to "ignore" circular references, so don't change the value
227
+ dereferencedValue = $ref;
228
+ }
229
+ if (directCircular) {
230
+ // The pointer is a DIRECT circular reference (i.e. it references itself).
231
+ // So replace the $ref path with the absolute path from the JSON Schema root
232
+ dereferencedValue.$ref = pathFromRoot;
233
+ }
234
+ var dereferencedObject = {
235
+ circular: circular,
236
+ value: dereferencedValue
237
+ };
238
+ // only cache if no extra properties than $ref
239
+ if (Object.keys($ref).length === 1) {
240
+ dereferencedCache.set($refPath, dereferencedObject);
241
+ }
242
+ return dereferencedObject;
243
+ }
244
+ /**
245
+ * Called when a circular reference is found.
246
+ * It sets the {@link $Refs#circular} flag, and throws an error if options.dereference.circular is false.
247
+ *
248
+ * @param {string} keyPath - The JSON Reference path of the circular reference
249
+ * @param {$Refs} $refs
250
+ * @param {$RefParserOptions} options
251
+ * @returns {boolean} - always returns true, to indicate that a circular reference was found
252
+ */ function foundCircularReference(keyPath, $refs, options) {
253
+ $refs.circular = true;
254
+ if (!options.dereference.circular) {
255
+ throw _ono.ono.reference("Circular $ref pointer found at ".concat(keyPath));
256
+ }
257
+ return true;
258
+ }