@apidevtools/json-schema-ref-parser 15.2.2 → 15.3.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.
@@ -16,6 +16,8 @@ function bundle(parser, options) {
16
16
  crawl(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);
17
17
  // Remap all $ref pointers
18
18
  remap(inventory, options);
19
+ // Fix any $ref paths that traverse through other $refs (which is invalid per JSON Schema spec)
20
+ fixRefsThroughRefs(inventory, parser.schema);
19
21
  }
20
22
  /**
21
23
  * Recursively crawls the given value, and inventories all JSON references.
@@ -261,4 +263,80 @@ function removeFromInventory(inventory, entry) {
261
263
  const index = inventory.indexOf(entry);
262
264
  inventory.splice(index, 1);
263
265
  }
266
+ /**
267
+ * After remapping, some $ref paths may traverse through other $ref nodes.
268
+ * JSON pointer resolution does not follow $ref indirection, so these paths are invalid.
269
+ * This function detects and fixes such paths by following any intermediate $refs
270
+ * to compute a valid direct path.
271
+ */
272
+ function fixRefsThroughRefs(inventory, schema) {
273
+ for (const entry of inventory) {
274
+ if (!entry.$ref || typeof entry.$ref !== "object" || !("$ref" in entry.$ref)) {
275
+ continue;
276
+ }
277
+ const refValue = entry.$ref.$ref;
278
+ if (typeof refValue !== "string" || !refValue.startsWith("#/")) {
279
+ continue;
280
+ }
281
+ const fixedPath = resolvePathThroughRefs(schema, refValue);
282
+ if (fixedPath !== refValue) {
283
+ entry.$ref.$ref = fixedPath;
284
+ }
285
+ }
286
+ }
287
+ /**
288
+ * Walks a JSON pointer path through the schema. If any intermediate value
289
+ * is a $ref, follows it and adjusts the path accordingly.
290
+ * Returns the corrected path that doesn't traverse through any $ref.
291
+ */
292
+ function resolvePathThroughRefs(schema, refPath) {
293
+ if (!refPath.startsWith("#/")) {
294
+ return refPath;
295
+ }
296
+ const segments = refPath.slice(2).split("/");
297
+ let current = schema;
298
+ const resolvedSegments = [];
299
+ for (const seg of segments) {
300
+ if (current === null || current === undefined || typeof current !== "object") {
301
+ // Can't walk further, return original path
302
+ return refPath;
303
+ }
304
+ // If the current value is a $ref, follow it
305
+ if ("$ref" in current && typeof current.$ref === "string" && current.$ref.startsWith("#/")) {
306
+ // Follow the $ref and restart the path from its target
307
+ const targetSegments = current.$ref.slice(2).split("/");
308
+ resolvedSegments.length = 0;
309
+ resolvedSegments.push(...targetSegments);
310
+ current = walkPath(schema, current.$ref);
311
+ if (current === null || current === undefined || typeof current !== "object") {
312
+ return refPath;
313
+ }
314
+ }
315
+ const decoded = seg.replace(/~1/g, "/").replace(/~0/g, "~");
316
+ const idx = Array.isArray(current) ? parseInt(decoded) : decoded;
317
+ current = current[idx];
318
+ resolvedSegments.push(seg);
319
+ }
320
+ const result = "#/" + resolvedSegments.join("/");
321
+ return result;
322
+ }
323
+ /**
324
+ * Walks a JSON pointer path through a schema object, returning the value at that path.
325
+ */
326
+ function walkPath(schema, path) {
327
+ if (!path.startsWith("#/")) {
328
+ return undefined;
329
+ }
330
+ const segments = path.slice(2).split("/");
331
+ let current = schema;
332
+ for (const seg of segments) {
333
+ if (current === null || current === undefined || typeof current !== "object") {
334
+ return undefined;
335
+ }
336
+ const decoded = seg.replace(/~1/g, "/").replace(/~0/g, "~");
337
+ const idx = Array.isArray(current) ? parseInt(decoded) : decoded;
338
+ current = current[idx];
339
+ }
340
+ return current;
341
+ }
264
342
  export default bundle;
@@ -13,7 +13,7 @@ export default dereference;
13
13
  function dereference(parser, options) {
14
14
  const start = Date.now();
15
15
  // console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
16
- const dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", new Set(), new Set(), new Map(), parser.$refs, options, start);
16
+ const dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", new Set(), new Set(), new Map(), parser.$refs, options, start, 0);
17
17
  parser.$refs.circular = dereferenced.circular;
18
18
  parser.schema = dereferenced.value;
19
19
  }
@@ -29,9 +29,10 @@ function dereference(parser, options) {
29
29
  * @param $refs
30
30
  * @param options
31
31
  * @param startTime - The time when the dereferencing started
32
+ * @param depth - The current recursion depth
32
33
  * @returns
33
34
  */
34
- function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime) {
35
+ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth) {
35
36
  let dereferenced;
36
37
  const result = {
37
38
  value: obj,
@@ -39,13 +40,19 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
39
40
  };
40
41
  checkDereferenceTimeout(startTime, options);
41
42
  const derefOptions = (options.dereference || {});
43
+ const maxDepth = derefOptions.maxDepth ?? 500;
44
+ if (depth > maxDepth) {
45
+ throw new RangeError(`Maximum dereference depth (${maxDepth}) exceeded at ${pathFromRoot}. ` +
46
+ `This likely indicates an extremely deep or recursive schema. ` +
47
+ `You can increase this limit with the dereference.maxDepth option.`);
48
+ }
42
49
  const isExcludedPath = derefOptions.excludedPathMatcher || (() => false);
43
50
  if (derefOptions?.circular === "ignore" || !processedObjects.has(obj)) {
44
51
  if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
45
52
  parents.add(obj);
46
53
  processedObjects.add(obj);
47
54
  if ($Ref.isAllowed$Ref(obj, options)) {
48
- dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
55
+ dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth);
49
56
  result.circular = dereferenced.circular;
50
57
  result.value = dereferenced.value;
51
58
  }
@@ -58,9 +65,9 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
58
65
  continue;
59
66
  }
60
67
  const value = obj[key];
61
- let circular = false;
68
+ let circular;
62
69
  if ($Ref.isAllowed$Ref(value, options)) {
63
- dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
70
+ dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth);
64
71
  circular = dereferenced.circular;
65
72
  // Avoid pointless mutations; breaks frozen objects to no profit
66
73
  if (obj[key] !== dereferenced.value) {
@@ -91,7 +98,7 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
91
98
  }
92
99
  else {
93
100
  if (!parents.has(value)) {
94
- dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
101
+ dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth + 1);
95
102
  circular = dereferenced.circular;
96
103
  // Avoid pointless mutations; breaks frozen objects to no profit
97
104
  if (obj[key] !== dereferenced.value) {
@@ -124,7 +131,7 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
124
131
  * @param options
125
132
  * @returns
126
133
  */
127
- function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime) {
134
+ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth) {
128
135
  const isExternalRef = $Ref.isExternal$Ref($ref);
129
136
  const shouldResolveOnCwd = isExternalRef && options?.dereference?.externalReferenceResolution === "root";
130
137
  const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
@@ -197,7 +204,7 @@ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, de
197
204
  // Crawl the dereferenced value (unless it's circular)
198
205
  if (!circular) {
199
206
  // Determine if the dereferenced value is circular
200
- const dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
207
+ const dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth + 1);
201
208
  circular = dereferenced.circular;
202
209
  dereferencedValue = dereferenced.value;
203
210
  }
@@ -70,6 +70,14 @@ export interface DereferenceOptions {
70
70
  * Default: `true`
71
71
  */
72
72
  mergeKeys?: boolean;
73
+ /**
74
+ * The maximum recursion depth for dereferencing nested schemas.
75
+ * If the schema nesting exceeds this depth, a RangeError will be thrown
76
+ * with a descriptive message instead of crashing with a stack overflow.
77
+ *
78
+ * Default: 500
79
+ */
80
+ maxDepth?: number;
73
81
  }
74
82
  /**
75
83
  * Options that determine how JSON schemas are parsed, resolved, and dereferenced.
package/dist/lib/parse.js CHANGED
@@ -67,7 +67,7 @@ async function readFile(file, options, $refs) {
67
67
  }
68
68
  else if (!err || !("error" in err)) {
69
69
  // Throw a generic, friendly error.
70
- throw new SyntaxError(`Unable to resolve $ref pointer "${file.url}"`);
70
+ throw new SyntaxError(`Unable to resolve $ref pointer "${file.url}"`, { cause: err });
71
71
  }
72
72
  // Throw the original error, if it's one of our own (user-friendly) errors.
73
73
  else if (err.error instanceof ResolverError) {
@@ -118,7 +118,7 @@ async function parseFile(file, options, $refs) {
118
118
  throw err;
119
119
  }
120
120
  else if (!err || !("error" in err)) {
121
- throw new SyntaxError(`Unable to parse ${file.url}`);
121
+ throw new SyntaxError(`Unable to parse ${file.url}`, { cause: err });
122
122
  }
123
123
  else if (err.error instanceof ParserError) {
124
124
  throw err.error;
@@ -69,10 +69,24 @@ class Pointer {
69
69
  // Crawl the object, one token at a time
70
70
  this.value = unwrapOrThrow(obj);
71
71
  for (let i = 0; i < tokens.length; i++) {
72
+ // During token walking, if the current value is an extended $ref (has sibling keys
73
+ // alongside $ref, as allowed by JSON Schema 2019-09+), and resolveIf$Ref marks it
74
+ // as circular because the $ref resolves to the same path we're walking, we should
75
+ // reset the circular flag and continue walking the object's own properties.
76
+ // This prevents false circular detection when e.g. a root schema has both
77
+ // $ref: "#/$defs/Foo" and $defs: { Foo: {...} } as siblings.
78
+ const wasCircular = this.circular;
79
+ const isExtendedRef = $Ref.isExtended$Ref(this.value);
72
80
  if (resolveIf$Ref(this, options, pathFromRoot)) {
73
81
  // The $ref path has changed, so append the remaining tokens to the path
74
82
  this.path = Pointer.join(this.path, tokens.slice(i));
75
83
  }
84
+ else if (!wasCircular && this.circular && isExtendedRef) {
85
+ // resolveIf$Ref set circular=true on an extended $ref during token walking.
86
+ // Since we still have tokens to process, the object should be walked by its
87
+ // properties, not treated as a circular self-reference.
88
+ this.circular = false;
89
+ }
76
90
  const token = tokens[i];
77
91
  if (this.value[token] === undefined || (this.value[token] === null && i === tokens.length - 1)) {
78
92
  // one final case is if the entry itself includes slashes, and was parsed out as a token - we can join the remaining tokens and try again
package/lib/bundle.ts CHANGED
@@ -41,6 +41,9 @@ function bundle<S extends object = JSONSchema, O extends ParserOptions<S> = Pars
41
41
 
42
42
  // Remap all $ref pointers
43
43
  remap<S, O>(inventory, options);
44
+
45
+ // Fix any $ref paths that traverse through other $refs (which is invalid per JSON Schema spec)
46
+ fixRefsThroughRefs(inventory, parser.schema as any);
44
47
  }
45
48
 
46
49
  /**
@@ -316,4 +319,94 @@ function removeFromInventory(inventory: InventoryEntry[], entry: any) {
316
319
  const index = inventory.indexOf(entry);
317
320
  inventory.splice(index, 1);
318
321
  }
322
+
323
+ /**
324
+ * After remapping, some $ref paths may traverse through other $ref nodes.
325
+ * JSON pointer resolution does not follow $ref indirection, so these paths are invalid.
326
+ * This function detects and fixes such paths by following any intermediate $refs
327
+ * to compute a valid direct path.
328
+ */
329
+ function fixRefsThroughRefs(inventory: InventoryEntry[], schema: any) {
330
+ for (const entry of inventory) {
331
+ if (!entry.$ref || typeof entry.$ref !== "object" || !("$ref" in entry.$ref)) {
332
+ continue;
333
+ }
334
+
335
+ const refValue = entry.$ref.$ref;
336
+ if (typeof refValue !== "string" || !refValue.startsWith("#/")) {
337
+ continue;
338
+ }
339
+
340
+ const fixedPath = resolvePathThroughRefs(schema, refValue);
341
+ if (fixedPath !== refValue) {
342
+ entry.$ref.$ref = fixedPath;
343
+ }
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Walks a JSON pointer path through the schema. If any intermediate value
349
+ * is a $ref, follows it and adjusts the path accordingly.
350
+ * Returns the corrected path that doesn't traverse through any $ref.
351
+ */
352
+ function resolvePathThroughRefs(schema: any, refPath: string): string {
353
+ if (!refPath.startsWith("#/")) {
354
+ return refPath;
355
+ }
356
+
357
+ const segments = refPath.slice(2).split("/");
358
+ let current = schema;
359
+ const resolvedSegments: string[] = [];
360
+
361
+ for (const seg of segments) {
362
+ if (current === null || current === undefined || typeof current !== "object") {
363
+ // Can't walk further, return original path
364
+ return refPath;
365
+ }
366
+
367
+ // If the current value is a $ref, follow it
368
+ if ("$ref" in current && typeof current.$ref === "string" && current.$ref.startsWith("#/")) {
369
+ // Follow the $ref and restart the path from its target
370
+ const targetSegments = current.$ref.slice(2).split("/");
371
+ resolvedSegments.length = 0;
372
+ resolvedSegments.push(...targetSegments);
373
+ current = walkPath(schema, current.$ref);
374
+ if (current === null || current === undefined || typeof current !== "object") {
375
+ return refPath;
376
+ }
377
+ }
378
+
379
+ const decoded = seg.replace(/~1/g, "/").replace(/~0/g, "~");
380
+ const idx = Array.isArray(current) ? parseInt(decoded) : decoded;
381
+ current = current[idx];
382
+ resolvedSegments.push(seg);
383
+ }
384
+
385
+ const result = "#/" + resolvedSegments.join("/");
386
+ return result;
387
+ }
388
+
389
+ /**
390
+ * Walks a JSON pointer path through a schema object, returning the value at that path.
391
+ */
392
+ function walkPath(schema: any, path: string): any {
393
+ if (!path.startsWith("#/")) {
394
+ return undefined;
395
+ }
396
+
397
+ const segments = path.slice(2).split("/");
398
+ let current = schema;
399
+
400
+ for (const seg of segments) {
401
+ if (current === null || current === undefined || typeof current !== "object") {
402
+ return undefined;
403
+ }
404
+ const decoded = seg.replace(/~1/g, "/").replace(/~0/g, "~");
405
+ const idx = Array.isArray(current) ? parseInt(decoded) : decoded;
406
+ current = current[idx];
407
+ }
408
+
409
+ return current;
410
+ }
411
+
319
412
  export default bundle;
@@ -31,6 +31,7 @@ function dereference<S extends object = JSONSchema, O extends ParserOptions<S> =
31
31
  parser.$refs,
32
32
  options,
33
33
  start,
34
+ 0,
34
35
  );
35
36
  parser.$refs.circular = dereferenced.circular;
36
37
  parser.schema = dereferenced.value;
@@ -48,6 +49,7 @@ function dereference<S extends object = JSONSchema, O extends ParserOptions<S> =
48
49
  * @param $refs
49
50
  * @param options
50
51
  * @param startTime - The time when the dereferencing started
52
+ * @param depth - The current recursion depth
51
53
  * @returns
52
54
  */
53
55
  function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(
@@ -60,6 +62,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
60
62
  $refs: $Refs<S, O>,
61
63
  options: O,
62
64
  startTime: number,
65
+ depth: number,
63
66
  ) {
64
67
  let dereferenced;
65
68
  const result = {
@@ -70,6 +73,14 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
70
73
  checkDereferenceTimeout<S, O>(startTime, options);
71
74
 
72
75
  const derefOptions = (options.dereference || {}) as DereferenceOptions;
76
+ const maxDepth = derefOptions.maxDepth ?? 500;
77
+ if (depth > maxDepth) {
78
+ throw new RangeError(
79
+ `Maximum dereference depth (${maxDepth}) exceeded at ${pathFromRoot}. ` +
80
+ `This likely indicates an extremely deep or recursive schema. ` +
81
+ `You can increase this limit with the dereference.maxDepth option.`,
82
+ );
83
+ }
73
84
  const isExcludedPath = derefOptions.excludedPathMatcher || (() => false);
74
85
 
75
86
  if (derefOptions?.circular === "ignore" || !processedObjects.has(obj)) {
@@ -88,6 +99,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
88
99
  $refs,
89
100
  options,
90
101
  startTime,
102
+ depth,
91
103
  );
92
104
  result.circular = dereferenced.circular;
93
105
  result.value = dereferenced.value;
@@ -103,7 +115,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
103
115
  }
104
116
 
105
117
  const value = obj[key];
106
- let circular = false;
118
+ let circular;
107
119
 
108
120
  if ($Ref.isAllowed$Ref(value, options)) {
109
121
  dereferenced = dereference$Ref(
@@ -116,6 +128,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
116
128
  $refs,
117
129
  options,
118
130
  startTime,
131
+ depth,
119
132
  );
120
133
  circular = dereferenced.circular;
121
134
  // Avoid pointless mutations; breaks frozen objects to no profit
@@ -159,6 +172,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
159
172
  $refs,
160
173
  options,
161
174
  startTime,
175
+ depth + 1,
162
176
  );
163
177
  circular = dereferenced.circular;
164
178
  // Avoid pointless mutations; breaks frozen objects to no profit
@@ -205,6 +219,7 @@ function dereference$Ref<S extends object = JSONSchema, O extends ParserOptions<
205
219
  $refs: $Refs<S, O>,
206
220
  options: O,
207
221
  startTime: number,
222
+ depth: number,
208
223
  ) {
209
224
  const isExternalRef = $Ref.isExternal$Ref($ref);
210
225
  const shouldResolveOnCwd = isExternalRef && options?.dereference?.externalReferenceResolution === "root";
@@ -295,6 +310,7 @@ function dereference$Ref<S extends object = JSONSchema, O extends ParserOptions<
295
310
  $refs,
296
311
  options,
297
312
  startTime,
313
+ depth + 1,
298
314
  );
299
315
  circular = dereferenced.circular;
300
316
  dereferencedValue = dereferenced.value;
package/lib/options.ts CHANGED
@@ -89,6 +89,15 @@ export interface DereferenceOptions {
89
89
  * Default: `true`
90
90
  */
91
91
  mergeKeys?: boolean;
92
+
93
+ /**
94
+ * The maximum recursion depth for dereferencing nested schemas.
95
+ * If the schema nesting exceeds this depth, a RangeError will be thrown
96
+ * with a descriptive message instead of crashing with a stack overflow.
97
+ *
98
+ * Default: 500
99
+ */
100
+ maxDepth?: number;
92
101
  }
93
102
 
94
103
  /**
package/lib/parse.ts CHANGED
@@ -91,7 +91,7 @@ async function readFile<S extends object = JSONSchema, O extends ParserOptions<S
91
91
  throw new UnmatchedResolverError(file.url);
92
92
  } else if (!err || !("error" in err)) {
93
93
  // Throw a generic, friendly error.
94
- throw new SyntaxError(`Unable to resolve $ref pointer "${file.url}"`);
94
+ throw new SyntaxError(`Unable to resolve $ref pointer "${file.url}"`, { cause: err });
95
95
  }
96
96
  // Throw the original error, if it's one of our own (user-friendly) errors.
97
97
  else if (err.error instanceof ResolverError) {
@@ -143,7 +143,7 @@ async function parseFile<S extends object = JSONSchema, O extends ParserOptions<
143
143
  } else if (err && err.message && err.message.startsWith("Error parsing")) {
144
144
  throw err;
145
145
  } else if (!err || !("error" in err)) {
146
- throw new SyntaxError(`Unable to parse ${file.url}`);
146
+ throw new SyntaxError(`Unable to parse ${file.url}`, { cause: err });
147
147
  } else if (err.error instanceof ParserError) {
148
148
  throw err.error;
149
149
  } else {
package/lib/pointer.ts CHANGED
@@ -89,9 +89,22 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
89
89
  this.value = unwrapOrThrow(obj);
90
90
 
91
91
  for (let i = 0; i < tokens.length; i++) {
92
+ // During token walking, if the current value is an extended $ref (has sibling keys
93
+ // alongside $ref, as allowed by JSON Schema 2019-09+), and resolveIf$Ref marks it
94
+ // as circular because the $ref resolves to the same path we're walking, we should
95
+ // reset the circular flag and continue walking the object's own properties.
96
+ // This prevents false circular detection when e.g. a root schema has both
97
+ // $ref: "#/$defs/Foo" and $defs: { Foo: {...} } as siblings.
98
+ const wasCircular = this.circular;
99
+ const isExtendedRef = $Ref.isExtended$Ref(this.value);
92
100
  if (resolveIf$Ref(this, options, pathFromRoot)) {
93
101
  // The $ref path has changed, so append the remaining tokens to the path
94
102
  this.path = Pointer.join(this.path, tokens.slice(i));
103
+ } else if (!wasCircular && this.circular && isExtendedRef) {
104
+ // resolveIf$Ref set circular=true on an extended $ref during token walking.
105
+ // Since we still have tokens to process, the object should be walked by its
106
+ // properties, not treated as a circular self-reference.
107
+ this.circular = false;
95
108
  }
96
109
 
97
110
  const token = tokens[i];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apidevtools/json-schema-ref-parser",
3
- "version": "15.2.2",
3
+ "version": "15.3.0",
4
4
  "description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
5
5
  "type": "module",
6
6
  "types": "dist/lib/index.d.ts",
@@ -75,28 +75,28 @@
75
75
  "js-yaml": "^4.1.1"
76
76
  },
77
77
  "devDependencies": {
78
- "@eslint/compat": "^2.0.1",
79
- "@eslint/js": "^9.39.2",
78
+ "@eslint/compat": "^2.0.2",
79
+ "@eslint/js": "^10.0.1",
80
80
  "@types/eslint": "^9.6.1",
81
81
  "@types/js-yaml": "^4.0.9",
82
82
  "@types/json-schema": "^7.0.15",
83
83
  "@types/node": "^25",
84
- "@typescript-eslint/eslint-plugin": "^8.53.1",
85
- "@typescript-eslint/parser": "^8.53.1",
84
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
85
+ "@typescript-eslint/parser": "^8.56.1",
86
86
  "@vitest/coverage-v8": "^4.0.18",
87
87
  "cross-env": "^10.1.0",
88
- "eslint": "^9.39.2",
88
+ "eslint": "^10.0.2",
89
89
  "eslint-config-prettier": "^10.1.8",
90
90
  "eslint-plugin-import": "^2.32.0",
91
91
  "eslint-plugin-prettier": "^5.5.5",
92
92
  "eslint-plugin-promise": "^7.2.1",
93
- "eslint-plugin-unused-imports": "^4.3.0",
94
- "globals": "^17.1.0",
95
- "jsdom": "^27.4.0",
93
+ "eslint-plugin-unused-imports": "^4.4.1",
94
+ "globals": "^17.3.0",
95
+ "jsdom": "^28.1.0",
96
96
  "prettier": "^3.8.1",
97
- "rimraf": "^6.1.2",
97
+ "rimraf": "^6.1.3",
98
98
  "typescript": "^5.9.3",
99
- "typescript-eslint": "^8.53.1",
99
+ "typescript-eslint": "^8.56.1",
100
100
  "vitest": "^4.0.18"
101
101
  },
102
102
  "release": {