@apidevtools/json-schema-ref-parser 11.9.3 → 12.0.1
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/dist/lib/dereference.js +58 -18
- package/lib/dereference.ts +64 -18
- package/package.json +1 -1
package/dist/lib/dereference.js
CHANGED
|
@@ -76,11 +76,7 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
|
|
|
76
76
|
value: obj,
|
|
77
77
|
circular: false,
|
|
78
78
|
};
|
|
79
|
-
|
|
80
|
-
if (Date.now() - startTime > options.timeoutMs) {
|
|
81
|
-
throw new errors_1.TimeoutError(options.timeoutMs);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
79
|
+
checkDereferenceTimeout(startTime, options);
|
|
84
80
|
const derefOptions = (options.dereference || {});
|
|
85
81
|
const isExcludedPath = derefOptions.excludedPathMatcher || (() => false);
|
|
86
82
|
if (derefOptions?.circular === "ignore" || !processedObjects.has(obj)) {
|
|
@@ -94,6 +90,7 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
|
|
|
94
90
|
}
|
|
95
91
|
else {
|
|
96
92
|
for (const key of Object.keys(obj)) {
|
|
93
|
+
checkDereferenceTimeout(startTime, options);
|
|
97
94
|
const keyPath = pointer_js_1.default.join(path, key);
|
|
98
95
|
const keyPathFromRoot = pointer_js_1.default.join(pathFromRoot, key);
|
|
99
96
|
if (isExcludedPath(keyPathFromRoot)) {
|
|
@@ -171,22 +168,52 @@ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, de
|
|
|
171
168
|
const shouldResolveOnCwd = isExternalRef && options?.dereference?.externalReferenceResolution === "root";
|
|
172
169
|
const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
|
|
173
170
|
const cache = dereferencedCache.get($refPath);
|
|
174
|
-
if (cache
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
171
|
+
if (cache) {
|
|
172
|
+
// If the object we found is circular we can immediately return it because it would have been
|
|
173
|
+
// cached with everything we need already and we don't need to re-process anything inside it.
|
|
174
|
+
//
|
|
175
|
+
// If the cached object however is _not_ circular and there are additional keys alongside our
|
|
176
|
+
// `$ref` pointer here we should merge them back in and return that.
|
|
177
|
+
if (!cache.circular) {
|
|
178
|
+
const refKeys = Object.keys($ref);
|
|
179
|
+
if (refKeys.length > 1) {
|
|
180
|
+
const extraKeys = {};
|
|
181
|
+
for (const key of refKeys) {
|
|
182
|
+
if (key !== "$ref" && !(key in cache.value)) {
|
|
183
|
+
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
184
|
+
extraKeys[key] = $ref[key];
|
|
185
|
+
}
|
|
182
186
|
}
|
|
187
|
+
return {
|
|
188
|
+
circular: cache.circular,
|
|
189
|
+
value: Object.assign({}, cache.value, extraKeys),
|
|
190
|
+
};
|
|
183
191
|
}
|
|
184
|
-
return
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
192
|
+
return cache;
|
|
193
|
+
}
|
|
194
|
+
// If both our cached value and our incoming `$ref` are the same then we can return what we
|
|
195
|
+
// got out of the cache, otherwise we should re-process this value. We need to do this because
|
|
196
|
+
// the current dereference caching mechanism doesn't take into account that `$ref` are neither
|
|
197
|
+
// unique or reference the same file.
|
|
198
|
+
//
|
|
199
|
+
// For example if `schema.yaml` references `definitions/child.yaml` and
|
|
200
|
+
// `definitions/parent.yaml` references `child.yaml` then `$ref: 'child.yaml'` may get cached
|
|
201
|
+
// for `definitions/child.yaml`, resulting in `schema.yaml` being having an invalid reference
|
|
202
|
+
// to `child.yaml`.
|
|
203
|
+
//
|
|
204
|
+
// This check is not perfect and the design of the dereference caching mechanism needs a total
|
|
205
|
+
// overhaul.
|
|
206
|
+
if (typeof cache.value === 'object' && '$ref' in cache.value && '$ref' in $ref) {
|
|
207
|
+
if (cache.value.$ref === $ref.$ref) {
|
|
208
|
+
return cache;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// no-op
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
return cache;
|
|
188
216
|
}
|
|
189
|
-
return cache;
|
|
190
217
|
}
|
|
191
218
|
const pointer = $refs._resolve($refPath, path, options);
|
|
192
219
|
if (pointer === null) {
|
|
@@ -229,6 +256,19 @@ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, de
|
|
|
229
256
|
}
|
|
230
257
|
return dereferencedObject;
|
|
231
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Check if we've run past our allowed timeout and throw an error if we have.
|
|
261
|
+
*
|
|
262
|
+
* @param startTime - The time when the dereferencing started.
|
|
263
|
+
* @param options
|
|
264
|
+
*/
|
|
265
|
+
function checkDereferenceTimeout(startTime, options) {
|
|
266
|
+
if (options && options.timeoutMs) {
|
|
267
|
+
if (Date.now() - startTime > options.timeoutMs) {
|
|
268
|
+
throw new errors_1.TimeoutError(options.timeoutMs);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
232
272
|
/**
|
|
233
273
|
* Called when a circular reference is found.
|
|
234
274
|
* It sets the {@link $Refs#circular} flag, executes the options.dereference.onCircular callback,
|
package/lib/dereference.ts
CHANGED
|
@@ -69,11 +69,8 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
69
69
|
circular: false,
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
throw new TimeoutError(options.timeoutMs);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
72
|
+
checkDereferenceTimeout<S, O>(startTime, options);
|
|
73
|
+
|
|
77
74
|
const derefOptions = (options.dereference || {}) as DereferenceOptions;
|
|
78
75
|
const isExcludedPath = derefOptions.excludedPathMatcher || (() => false);
|
|
79
76
|
|
|
@@ -98,6 +95,8 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
98
95
|
result.value = dereferenced.value;
|
|
99
96
|
} else {
|
|
100
97
|
for (const key of Object.keys(obj)) {
|
|
98
|
+
checkDereferenceTimeout<S, O>(startTime, options);
|
|
99
|
+
|
|
101
100
|
const keyPath = Pointer.join(path, key);
|
|
102
101
|
const keyPathFromRoot = Pointer.join(pathFromRoot, key);
|
|
103
102
|
|
|
@@ -214,23 +213,53 @@ function dereference$Ref<S extends object = JSONSchema, O extends ParserOptions<
|
|
|
214
213
|
const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
|
|
215
214
|
|
|
216
215
|
const cache = dereferencedCache.get($refPath);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
216
|
+
|
|
217
|
+
if (cache) {
|
|
218
|
+
// If the object we found is circular we can immediately return it because it would have been
|
|
219
|
+
// cached with everything we need already and we don't need to re-process anything inside it.
|
|
220
|
+
//
|
|
221
|
+
// If the cached object however is _not_ circular and there are additional keys alongside our
|
|
222
|
+
// `$ref` pointer here we should merge them back in and return that.
|
|
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
|
+
}
|
|
225
232
|
}
|
|
233
|
+
return {
|
|
234
|
+
circular: cache.circular,
|
|
235
|
+
value: Object.assign({}, cache.value, extraKeys),
|
|
236
|
+
};
|
|
226
237
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
value: Object.assign({}, cache.value, extraKeys),
|
|
230
|
-
};
|
|
238
|
+
|
|
239
|
+
return cache;
|
|
231
240
|
}
|
|
232
241
|
|
|
233
|
-
return
|
|
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
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
return cache;
|
|
262
|
+
}
|
|
234
263
|
}
|
|
235
264
|
|
|
236
265
|
const pointer = $refs._resolve($refPath, path, options);
|
|
@@ -294,6 +323,23 @@ function dereference$Ref<S extends object = JSONSchema, O extends ParserOptions<
|
|
|
294
323
|
return dereferencedObject;
|
|
295
324
|
}
|
|
296
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Check if we've run past our allowed timeout and throw an error if we have.
|
|
328
|
+
*
|
|
329
|
+
* @param startTime - The time when the dereferencing started.
|
|
330
|
+
* @param options
|
|
331
|
+
*/
|
|
332
|
+
function checkDereferenceTimeout<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(
|
|
333
|
+
startTime: number,
|
|
334
|
+
options: O,
|
|
335
|
+
): void {
|
|
336
|
+
if (options && options.timeoutMs) {
|
|
337
|
+
if (Date.now() - startTime > options.timeoutMs) {
|
|
338
|
+
throw new TimeoutError(options.timeoutMs);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
297
343
|
/**
|
|
298
344
|
* Called when a circular reference is found.
|
|
299
345
|
* It sets the {@link $Refs#circular} flag, executes the options.dereference.onCircular callback,
|