@apidevtools/json-schema-ref-parser 10.0.0 → 10.1.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.
Files changed (103) hide show
  1. package/dist/lib/bundle.d.ts +10 -0
  2. package/dist/lib/bundle.js +265 -0
  3. package/dist/lib/dereference.d.ts +9 -0
  4. package/dist/lib/dereference.js +206 -0
  5. package/dist/lib/index.d.ts +206 -0
  6. package/dist/lib/index.js +223 -0
  7. package/dist/lib/normalize-args.d.ts +10 -0
  8. package/dist/lib/normalize-args.js +42 -0
  9. package/dist/lib/options.d.ts +77 -0
  10. package/dist/lib/options.js +119 -0
  11. package/dist/lib/parse.d.ts +8 -0
  12. package/dist/lib/parse.js +177 -0
  13. package/dist/lib/parsers/binary.d.ts +3 -0
  14. package/dist/lib/parsers/binary.js +35 -0
  15. package/dist/lib/parsers/json.d.ts +3 -0
  16. package/dist/lib/parsers/json.js +57 -0
  17. package/dist/lib/parsers/text.d.ts +3 -0
  18. package/dist/lib/parsers/text.js +42 -0
  19. package/dist/lib/parsers/yaml.d.ts +3 -0
  20. package/dist/lib/parsers/yaml.js +65 -0
  21. package/dist/lib/pointer.d.ts +87 -0
  22. package/dist/lib/pointer.js +256 -0
  23. package/dist/lib/ref.d.ts +181 -0
  24. package/dist/lib/ref.js +239 -0
  25. package/dist/lib/refs.d.ts +127 -0
  26. package/dist/lib/refs.js +223 -0
  27. package/dist/lib/resolve-external.d.ts +14 -0
  28. package/dist/lib/resolve-external.js +148 -0
  29. package/dist/lib/resolvers/file.d.ts +3 -0
  30. package/dist/lib/resolvers/file.js +76 -0
  31. package/dist/lib/resolvers/http.d.ts +3 -0
  32. package/dist/lib/resolvers/http.js +159 -0
  33. package/dist/lib/types/index.d.ts +104 -0
  34. package/dist/lib/types/index.js +2 -0
  35. package/dist/lib/util/errors.d.ts +50 -0
  36. package/dist/lib/util/errors.js +106 -0
  37. package/dist/lib/util/maybe.d.ts +3 -0
  38. package/dist/lib/util/maybe.js +24 -0
  39. package/dist/lib/util/next.d.ts +2 -0
  40. package/dist/lib/util/next.js +16 -0
  41. package/dist/lib/util/plugins.d.ts +36 -0
  42. package/dist/lib/util/plugins.js +144 -0
  43. package/dist/lib/util/url.d.ts +93 -0
  44. package/{cjs → dist/lib}/util/url.js +134 -102
  45. package/dist/vite.config.d.ts +2 -0
  46. package/dist/vite.config.js +23 -0
  47. package/lib/{bundle.js → bundle.ts} +105 -101
  48. package/lib/{dereference.js → dereference.ts} +113 -52
  49. package/lib/index.ts +413 -0
  50. package/lib/{normalize-args.js → normalize-args.ts} +7 -14
  51. package/lib/options.ts +202 -0
  52. package/lib/parse.ts +153 -0
  53. package/lib/parsers/binary.ts +39 -0
  54. package/lib/parsers/{json.js → json.ts} +9 -22
  55. package/lib/parsers/text.ts +46 -0
  56. package/lib/parsers/{yaml.js → yaml.ts} +15 -19
  57. package/lib/pointer.ts +296 -0
  58. package/lib/ref.ts +288 -0
  59. package/lib/refs.ts +238 -0
  60. package/lib/{resolve-external.js → resolve-external.ts} +39 -36
  61. package/lib/resolvers/file.ts +40 -0
  62. package/lib/resolvers/http.ts +136 -0
  63. package/lib/tsconfig.json +103 -0
  64. package/lib/types/index.ts +135 -0
  65. package/lib/util/errors.ts +141 -0
  66. package/lib/util/maybe.ts +22 -0
  67. package/lib/util/next.ts +13 -0
  68. package/lib/util/{plugins.js → plugins.ts} +58 -57
  69. package/lib/util/{url.js → url.ts} +64 -83
  70. package/package.json +44 -45
  71. package/cjs/bundle.js +0 -304
  72. package/cjs/dereference.js +0 -258
  73. package/cjs/index.js +0 -603
  74. package/cjs/normalize-args.js +0 -64
  75. package/cjs/options.js +0 -125
  76. package/cjs/package.json +0 -3
  77. package/cjs/parse.js +0 -338
  78. package/cjs/parsers/binary.js +0 -54
  79. package/cjs/parsers/json.js +0 -199
  80. package/cjs/parsers/text.js +0 -61
  81. package/cjs/parsers/yaml.js +0 -239
  82. package/cjs/pointer.js +0 -290
  83. package/cjs/ref.js +0 -333
  84. package/cjs/refs.js +0 -214
  85. package/cjs/resolve-external.js +0 -333
  86. package/cjs/resolvers/file.js +0 -106
  87. package/cjs/resolvers/http.js +0 -184
  88. package/cjs/util/errors.js +0 -401
  89. package/cjs/util/plugins.js +0 -159
  90. package/cjs/util/projectDir.cjs +0 -6
  91. package/lib/index.d.ts +0 -496
  92. package/lib/index.js +0 -290
  93. package/lib/options.js +0 -128
  94. package/lib/parse.js +0 -162
  95. package/lib/parsers/binary.js +0 -53
  96. package/lib/parsers/text.js +0 -64
  97. package/lib/pointer.js +0 -293
  98. package/lib/ref.js +0 -292
  99. package/lib/refs.js +0 -196
  100. package/lib/resolvers/file.js +0 -63
  101. package/lib/resolvers/http.js +0 -155
  102. package/lib/util/errors.js +0 -134
  103. package/lib/util/projectDir.cjs +0 -6
@@ -0,0 +1,10 @@
1
+ export default bundle;
2
+ /**
3
+ * Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
4
+ * only has *internal* references, not any *external* references.
5
+ * This method mutates the JSON schema object, adding new references and re-mapping existing ones.
6
+ *
7
+ * @param parser
8
+ * @param options
9
+ */
10
+ declare function bundle(parser: any, options: any): void;
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const ref_js_1 = __importDefault(require("./ref.js"));
30
+ const pointer_js_1 = __importDefault(require("./pointer.js"));
31
+ const url = __importStar(require("./util/url.js"));
32
+ exports.default = bundle;
33
+ /**
34
+ * Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
35
+ * only has *internal* references, not any *external* references.
36
+ * This method mutates the JSON schema object, adding new references and re-mapping existing ones.
37
+ *
38
+ * @param parser
39
+ * @param options
40
+ */
41
+ function bundle(parser, options) {
42
+ // console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
43
+ // Build an inventory of all $ref pointers in the JSON Schema
44
+ const inventory = [];
45
+ crawl(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);
46
+ // Remap all $ref pointers
47
+ remap(inventory);
48
+ }
49
+ /**
50
+ * Recursively crawls the given value, and inventories all JSON references.
51
+ *
52
+ * @param parent - The object containing the value to crawl. If the value is not an object or array, it will be ignored.
53
+ * @param key - The property key of `parent` to be crawled
54
+ * @param path - The full path of the property being crawled, possibly with a JSON Pointer in the hash
55
+ * @param pathFromRoot - The path of the property being crawled, from the schema root
56
+ * @param inventory - An array of already-inventoried $ref pointers
57
+ * @param $refs
58
+ * @param options
59
+ */
60
+ function crawl(parent, key, path, pathFromRoot, indirections, inventory, $refs, options) {
61
+ const obj = key === null ? parent : parent[key];
62
+ if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
63
+ // @ts-expect-error TS(2554): Expected 2 arguments, but got 1.
64
+ if (ref_js_1.default.isAllowed$Ref(obj)) {
65
+ inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options);
66
+ }
67
+ else {
68
+ // Crawl the object in a specific order that's optimized for bundling.
69
+ // This is important because it determines how `pathFromRoot` gets built,
70
+ // which later determines which keys get dereferenced and which ones get remapped
71
+ const keys = Object.keys(obj).sort((a, b) => {
72
+ // Most people will expect references to be bundled into the the "definitions" property,
73
+ // so we always crawl that property first, if it exists.
74
+ if (a === "definitions") {
75
+ return -1;
76
+ }
77
+ else if (b === "definitions") {
78
+ return 1;
79
+ }
80
+ else {
81
+ // Otherwise, crawl the keys based on their length.
82
+ // This produces the shortest possible bundled references
83
+ return a.length - b.length;
84
+ }
85
+ });
86
+ // eslint-disable-next-line no-shadow
87
+ for (const key of keys) {
88
+ const keyPath = pointer_js_1.default.join(path, key);
89
+ const keyPathFromRoot = pointer_js_1.default.join(pathFromRoot, key);
90
+ const value = obj[key];
91
+ // @ts-expect-error TS(2554): Expected 2 arguments, but got 1.
92
+ if (ref_js_1.default.isAllowed$Ref(value)) {
93
+ inventory$Ref(obj, key, path, keyPathFromRoot, indirections, inventory, $refs, options);
94
+ }
95
+ else {
96
+ crawl(obj, key, keyPath, keyPathFromRoot, indirections, inventory, $refs, options);
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ /**
103
+ * Inventories the given JSON Reference (i.e. records detailed information about it so we can
104
+ * optimize all $refs in the schema), and then crawls the resolved value.
105
+ *
106
+ * @param $refParent - The object that contains a JSON Reference as one of its keys
107
+ * @param $refKey - The key in `$refParent` that is a JSON Reference
108
+ * @param path - The full path of the JSON Reference at `$refKey`, possibly with a JSON Pointer in the hash
109
+ * @param pathFromRoot - The path of the JSON Reference at `$refKey`, from the schema root
110
+ * @param inventory - An array of already-inventoried $ref pointers
111
+ * @param $refs
112
+ * @param options
113
+ */
114
+ function inventory$Ref($refParent, $refKey, path, pathFromRoot, indirections, inventory, $refs, options) {
115
+ const $ref = $refKey === null ? $refParent : $refParent[$refKey];
116
+ const $refPath = url.resolve(path, $ref.$ref);
117
+ const pointer = $refs._resolve($refPath, pathFromRoot, options);
118
+ if (pointer === null) {
119
+ return;
120
+ }
121
+ const depth = pointer_js_1.default.parse(pathFromRoot).length;
122
+ const file = url.stripHash(pointer.path);
123
+ const hash = url.getHash(pointer.path);
124
+ const external = file !== $refs._root$Ref.path;
125
+ const extended = ref_js_1.default.isExtended$Ref($ref);
126
+ indirections += pointer.indirections;
127
+ const existingEntry = findInInventory(inventory, $refParent, $refKey);
128
+ if (existingEntry) {
129
+ // This $Ref has already been inventoried, so we don't need to process it again
130
+ if (depth < existingEntry.depth || indirections < existingEntry.indirections) {
131
+ removeFromInventory(inventory, existingEntry);
132
+ }
133
+ else {
134
+ return;
135
+ }
136
+ }
137
+ inventory.push({
138
+ $ref,
139
+ parent: $refParent,
140
+ key: $refKey,
141
+ pathFromRoot,
142
+ depth,
143
+ file,
144
+ hash,
145
+ value: pointer.value,
146
+ circular: pointer.circular,
147
+ extended,
148
+ external,
149
+ indirections, // The number of indirect references that were traversed to resolve the value
150
+ });
151
+ // Recursively crawl the resolved value
152
+ if (!existingEntry || external) {
153
+ crawl(pointer.value, null, pointer.path, pathFromRoot, indirections + 1, inventory, $refs, options);
154
+ }
155
+ }
156
+ /**
157
+ * Re-maps every $ref pointer, so that they're all relative to the root of the JSON Schema.
158
+ * Each referenced value is dereferenced EXACTLY ONCE. All subsequent references to the same
159
+ * value are re-mapped to point to the first reference.
160
+ *
161
+ * @example: {
162
+ * first: { $ref: somefile.json#/some/part },
163
+ * second: { $ref: somefile.json#/another/part },
164
+ * third: { $ref: somefile.json },
165
+ * fourth: { $ref: somefile.json#/some/part/sub/part }
166
+ * }
167
+ *
168
+ * In this example, there are four references to the same file, but since the third reference points
169
+ * to the ENTIRE file, that's the only one we need to dereference. The other three can just be
170
+ * remapped to point inside the third one.
171
+ *
172
+ * On the other hand, if the third reference DIDN'T exist, then the first and second would both need
173
+ * to be dereferenced, since they point to different parts of the file. The fourth reference does NOT
174
+ * need to be dereferenced, because it can be remapped to point inside the first one.
175
+ *
176
+ * @param inventory
177
+ */
178
+ function remap(inventory) {
179
+ // Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
180
+ inventory.sort((a, b) => {
181
+ if (a.file !== b.file) {
182
+ // Group all the $refs that point to the same file
183
+ return a.file < b.file ? -1 : +1;
184
+ }
185
+ else if (a.hash !== b.hash) {
186
+ // Group all the $refs that point to the same part of the file
187
+ return a.hash < b.hash ? -1 : +1;
188
+ }
189
+ else if (a.circular !== b.circular) {
190
+ // If the $ref points to itself, then sort it higher than other $refs that point to this $ref
191
+ return a.circular ? -1 : +1;
192
+ }
193
+ else if (a.extended !== b.extended) {
194
+ // If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
195
+ return a.extended ? +1 : -1;
196
+ }
197
+ else if (a.indirections !== b.indirections) {
198
+ // Sort direct references higher than indirect references
199
+ return a.indirections - b.indirections;
200
+ }
201
+ else if (a.depth !== b.depth) {
202
+ // Sort $refs by how close they are to the JSON Schema root
203
+ return a.depth - b.depth;
204
+ }
205
+ else {
206
+ // Determine how far each $ref is from the "definitions" property.
207
+ // Most people will expect references to be bundled into the the "definitions" property if possible.
208
+ const aDefinitionsIndex = a.pathFromRoot.lastIndexOf("/definitions");
209
+ const bDefinitionsIndex = b.pathFromRoot.lastIndexOf("/definitions");
210
+ if (aDefinitionsIndex !== bDefinitionsIndex) {
211
+ // Give higher priority to the $ref that's closer to the "definitions" property
212
+ return bDefinitionsIndex - aDefinitionsIndex;
213
+ }
214
+ else {
215
+ // All else is equal, so use the shorter path, which will produce the shortest possible reference
216
+ return a.pathFromRoot.length - b.pathFromRoot.length;
217
+ }
218
+ }
219
+ });
220
+ let file, hash, pathFromRoot;
221
+ for (const entry of inventory) {
222
+ // console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
223
+ if (!entry.external) {
224
+ // This $ref already resolves to the main JSON Schema file
225
+ entry.$ref.$ref = entry.hash;
226
+ }
227
+ else if (entry.file === file && entry.hash === hash) {
228
+ // This $ref points to the same value as the prevous $ref, so remap it to the same path
229
+ entry.$ref.$ref = pathFromRoot;
230
+ }
231
+ else if (entry.file === file && entry.hash.indexOf(hash + "/") === 0) {
232
+ // This $ref points to a sub-value of the prevous $ref, so remap it beneath that path
233
+ entry.$ref.$ref = pointer_js_1.default.join(pathFromRoot, pointer_js_1.default.parse(entry.hash.replace(hash, "#")));
234
+ }
235
+ else {
236
+ // We've moved to a new file or new hash
237
+ file = entry.file;
238
+ hash = entry.hash;
239
+ pathFromRoot = entry.pathFromRoot;
240
+ // This is the first $ref to point to this value, so dereference the value.
241
+ // Any other $refs that point to the same value will point to this $ref instead
242
+ entry.$ref = entry.parent[entry.key] = ref_js_1.default.dereference(entry.$ref, entry.value);
243
+ if (entry.circular) {
244
+ // This $ref points to itself
245
+ entry.$ref.$ref = entry.pathFromRoot;
246
+ }
247
+ }
248
+ // console.log(' new value: %s', (entry.$ref && entry.$ref.$ref) ? entry.$ref.$ref : '[object Object]');
249
+ }
250
+ }
251
+ /**
252
+ * TODO
253
+ */
254
+ function findInInventory(inventory, $refParent, $refKey) {
255
+ for (let i = 0; i < inventory.length; i++) {
256
+ const existingEntry = inventory[i];
257
+ if (existingEntry.parent === $refParent && existingEntry.key === $refKey) {
258
+ return existingEntry;
259
+ }
260
+ }
261
+ }
262
+ function removeFromInventory(inventory, entry) {
263
+ const index = inventory.indexOf(entry);
264
+ inventory.splice(index, 1);
265
+ }
@@ -0,0 +1,9 @@
1
+ export default dereference;
2
+ /**
3
+ * Crawls the JSON schema, finds all JSON references, and dereferences them.
4
+ * This method mutates the JSON schema object, replacing JSON references with their resolved value.
5
+ *
6
+ * @param parser
7
+ * @param options
8
+ */
9
+ declare function dereference(parser: any, options: any): void;
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const ref_js_1 = __importDefault(require("./ref.js"));
30
+ const pointer_js_1 = __importDefault(require("./pointer.js"));
31
+ const ono_1 = require("@jsdevtools/ono");
32
+ const url = __importStar(require("./util/url.js"));
33
+ exports.default = dereference;
34
+ /**
35
+ * Crawls the JSON schema, finds all JSON references, and dereferences them.
36
+ * This method mutates the JSON schema object, replacing JSON references with their resolved value.
37
+ *
38
+ * @param parser
39
+ * @param options
40
+ */
41
+ function dereference(parser, options) {
42
+ // console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
43
+ const dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", new Set(), new Set(), new Map(), parser.$refs, options);
44
+ parser.$refs.circular = dereferenced.circular;
45
+ parser.schema = dereferenced.value;
46
+ }
47
+ /**
48
+ * Recursively crawls the given value, and dereferences any JSON references.
49
+ *
50
+ * @param obj - The value to crawl. If it's not an object or array, it will be ignored.
51
+ * @param path - The full path of `obj`, possibly with a JSON Pointer in the hash
52
+ * @param pathFromRoot - The path of `obj` from the schema root
53
+ * @param parents - An array of the parent objects that have already been dereferenced
54
+ * @param processedObjects - An array of all the objects that have already been processed
55
+ * @param dereferencedCache - An map of all the dereferenced objects
56
+ * @param $refs
57
+ * @param options
58
+ * @returns
59
+ */
60
+ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
61
+ let dereferenced;
62
+ const result = {
63
+ value: obj,
64
+ circular: false,
65
+ };
66
+ const isExcludedPath = options.dereference.excludedPathMatcher || (() => false);
67
+ if (options.dereference.circular === "ignore" || !processedObjects.has(obj)) {
68
+ if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
69
+ parents.add(obj);
70
+ processedObjects.add(obj);
71
+ if (ref_js_1.default.isAllowed$Ref(obj, options)) {
72
+ dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
73
+ result.circular = dereferenced.circular;
74
+ result.value = dereferenced.value;
75
+ }
76
+ else {
77
+ for (const key of Object.keys(obj)) {
78
+ const keyPath = pointer_js_1.default.join(path, key);
79
+ const keyPathFromRoot = pointer_js_1.default.join(pathFromRoot, key);
80
+ if (isExcludedPath(keyPathFromRoot)) {
81
+ continue;
82
+ }
83
+ const value = obj[key];
84
+ let circular = false;
85
+ if (ref_js_1.default.isAllowed$Ref(value, options)) {
86
+ dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
87
+ circular = dereferenced.circular;
88
+ // Avoid pointless mutations; breaks frozen objects to no profit
89
+ if (obj[key] !== dereferenced.value) {
90
+ obj[key] = dereferenced.value;
91
+ if (options.dereference.onDereference) {
92
+ options.dereference.onDereference(value.$ref, obj[key]);
93
+ }
94
+ }
95
+ }
96
+ else {
97
+ if (!parents.has(value)) {
98
+ dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
99
+ circular = dereferenced.circular;
100
+ // Avoid pointless mutations; breaks frozen objects to no profit
101
+ if (obj[key] !== dereferenced.value) {
102
+ obj[key] = dereferenced.value;
103
+ }
104
+ }
105
+ else {
106
+ circular = foundCircularReference(keyPath, $refs, options);
107
+ }
108
+ }
109
+ // Set the "isCircular" flag if this or any other property is circular
110
+ result.circular = result.circular || circular;
111
+ }
112
+ }
113
+ parents.delete(obj);
114
+ }
115
+ }
116
+ return result;
117
+ }
118
+ /**
119
+ * Dereferences the given JSON Reference, and then crawls the resulting value.
120
+ *
121
+ * @param $ref - The JSON Reference to resolve
122
+ * @param path - The full path of `$ref`, possibly with a JSON Pointer in the hash
123
+ * @param pathFromRoot - The path of `$ref` from the schema root
124
+ * @param parents - An array of the parent objects that have already been dereferenced
125
+ * @param processedObjects - An array of all the objects that have already been dereferenced
126
+ * @param dereferencedCache - An map of all the dereferenced objects
127
+ * @param $refs
128
+ * @param options
129
+ * @returns
130
+ */
131
+ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
132
+ // console.log('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path);
133
+ const $refPath = url.resolve(path, $ref.$ref);
134
+ const cache = dereferencedCache.get($refPath);
135
+ if (cache) {
136
+ const refKeys = Object.keys($ref);
137
+ if (refKeys.length > 1) {
138
+ const extraKeys = {};
139
+ for (const key of refKeys) {
140
+ if (key !== "$ref" && !(key in cache.value)) {
141
+ // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
142
+ extraKeys[key] = $ref[key];
143
+ }
144
+ }
145
+ return {
146
+ circular: cache.circular,
147
+ value: Object.assign({}, cache.value, extraKeys),
148
+ };
149
+ }
150
+ return cache;
151
+ }
152
+ const pointer = $refs._resolve($refPath, path, options);
153
+ if (pointer === null) {
154
+ return {
155
+ circular: false,
156
+ value: null,
157
+ };
158
+ }
159
+ // Check for circular references
160
+ const directCircular = pointer.circular;
161
+ let circular = directCircular || parents.has(pointer.value);
162
+ circular && foundCircularReference(path, $refs, options);
163
+ // Dereference the JSON reference
164
+ let dereferencedValue = ref_js_1.default.dereference($ref, pointer.value);
165
+ // Crawl the dereferenced value (unless it's circular)
166
+ if (!circular) {
167
+ // Determine if the dereferenced value is circular
168
+ const dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options);
169
+ circular = dereferenced.circular;
170
+ dereferencedValue = dereferenced.value;
171
+ }
172
+ if (circular && !directCircular && options.dereference.circular === "ignore") {
173
+ // The user has chosen to "ignore" circular references, so don't change the value
174
+ dereferencedValue = $ref;
175
+ }
176
+ if (directCircular) {
177
+ // The pointer is a DIRECT circular reference (i.e. it references itself).
178
+ // So replace the $ref path with the absolute path from the JSON Schema root
179
+ dereferencedValue.$ref = pathFromRoot;
180
+ }
181
+ const dereferencedObject = {
182
+ circular,
183
+ value: dereferencedValue,
184
+ };
185
+ // only cache if no extra properties than $ref
186
+ if (Object.keys($ref).length === 1) {
187
+ dereferencedCache.set($refPath, dereferencedObject);
188
+ }
189
+ return dereferencedObject;
190
+ }
191
+ /**
192
+ * Called when a circular reference is found.
193
+ * It sets the {@link $Refs#circular} flag, and throws an error if options.dereference.circular is false.
194
+ *
195
+ * @param keyPath - The JSON Reference path of the circular reference
196
+ * @param $refs
197
+ * @param options
198
+ * @returns - always returns true, to indicate that a circular reference was found
199
+ */
200
+ function foundCircularReference(keyPath, $refs, options) {
201
+ $refs.circular = true;
202
+ if (!options.dereference.circular) {
203
+ throw ono_1.ono.reference(`Circular $ref pointer found at ${keyPath}`);
204
+ }
205
+ return true;
206
+ }