@apidevtools/json-schema-ref-parser 11.9.2 → 12.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.
@@ -76,11 +76,7 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
76
76
  value: obj,
77
77
  circular: false,
78
78
  };
79
- if (options && options.timeoutMs) {
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,7 +168,15 @@ 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 && !cache.circular) {
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
+ return cache;
179
+ }
175
180
  const refKeys = Object.keys($ref);
176
181
  if (refKeys.length > 1) {
177
182
  const extraKeys = {};
@@ -229,6 +234,19 @@ function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, de
229
234
  }
230
235
  return dereferencedObject;
231
236
  }
237
+ /**
238
+ * Check if we've run past our allowed timeout and throw an error if we have.
239
+ *
240
+ * @param startTime - The time when the dereferencing started.
241
+ * @param options
242
+ */
243
+ function checkDereferenceTimeout(startTime, options) {
244
+ if (options && options.timeoutMs) {
245
+ if (Date.now() - startTime > options.timeoutMs) {
246
+ throw new errors_1.TimeoutError(options.timeoutMs);
247
+ }
248
+ }
249
+ }
232
250
  /**
233
251
  * Called when a circular reference is found.
234
252
  * It sets the {@link $Refs#circular} flag, executes the options.dereference.onCircular callback,
@@ -1,6 +1,7 @@
1
1
  import type { ParserOptions } from "./options.js";
2
2
  import $Ref from "./ref.js";
3
3
  import type { JSONSchema } from "./types";
4
+ export declare const nullSymbol: unique symbol;
4
5
  /**
5
6
  * This class represents a single JSON pointer and its resolved value.
6
7
  *
@@ -36,9 +36,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.nullSymbol = void 0;
39
40
  const ref_js_1 = __importDefault(require("./ref.js"));
40
41
  const url = __importStar(require("./util/url.js"));
41
42
  const errors_js_1 = require("./util/errors.js");
43
+ exports.nullSymbol = Symbol('null');
42
44
  const slashes = /\//g;
43
45
  const tildes = /~/g;
44
46
  const escapedSlash = /~1/g;
@@ -110,6 +112,15 @@ class Pointer {
110
112
  if (didFindSubstringSlashMatch) {
111
113
  continue;
112
114
  }
115
+ // If the token we're looking for ended up not containing any slashes but is
116
+ // actually instead pointing to an existing `null` value then we should use that
117
+ // `null` value.
118
+ if (token in this.value && this.value[token] === null) {
119
+ // We use a `null` symbol for internal tracking to differntiate between a general `null`
120
+ // value and our expected `null` value.
121
+ this.value = exports.nullSymbol;
122
+ continue;
123
+ }
113
124
  this.value = null;
114
125
  const path = this.$ref.path || "";
115
126
  const targetRef = this.path.replace(path, "");
package/dist/lib/ref.js CHANGED
@@ -1,9 +1,39 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
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 () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
5
35
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const pointer_js_1 = __importDefault(require("./pointer.js"));
36
+ const pointer_js_1 = __importStar(require("./pointer.js"));
7
37
  const errors_js_1 = require("./util/errors.js");
8
38
  const url_js_1 = require("./util/url.js");
9
39
  /**
@@ -78,7 +108,11 @@ class $Ref {
78
108
  resolve(path, options, friendlyPath, pathFromRoot) {
79
109
  const pointer = new pointer_js_1.default(this, path, friendlyPath);
80
110
  try {
81
- return pointer.resolve(this.value, options, pathFromRoot);
111
+ const resolved = pointer.resolve(this.value, options, pathFromRoot);
112
+ if (resolved.value === pointer_js_1.nullSymbol) {
113
+ resolved.value = null;
114
+ }
115
+ return resolved;
82
116
  }
83
117
  catch (err) {
84
118
  if (!options || !options.continueOnError || !(0, errors_js_1.isHandledError)(err)) {
@@ -104,6 +138,9 @@ class $Ref {
104
138
  set(path, value) {
105
139
  const pointer = new pointer_js_1.default(this, path);
106
140
  this.value = pointer.set(this.value, value);
141
+ if (this.value === pointer_js_1.nullSymbol) {
142
+ this.value = null;
143
+ }
107
144
  }
108
145
  /**
109
146
  * Determines whether the given value is a JSON reference.
@@ -69,11 +69,8 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
69
69
  circular: false,
70
70
  };
71
71
 
72
- if (options && options.timeoutMs) {
73
- if (Date.now() - startTime > options.timeoutMs) {
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,7 +213,17 @@ 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
- if (cache && !cache.circular) {
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
+ return cache;
225
+ }
226
+
218
227
  const refKeys = Object.keys($ref);
219
228
  if (refKeys.length > 1) {
220
229
  const extraKeys = {};
@@ -294,6 +303,23 @@ function dereference$Ref<S extends object = JSONSchema, O extends ParserOptions<
294
303
  return dereferencedObject;
295
304
  }
296
305
 
306
+ /**
307
+ * Check if we've run past our allowed timeout and throw an error if we have.
308
+ *
309
+ * @param startTime - The time when the dereferencing started.
310
+ * @param options
311
+ */
312
+ function checkDereferenceTimeout<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(
313
+ startTime: number,
314
+ options: O,
315
+ ): void {
316
+ if (options && options.timeoutMs) {
317
+ if (Date.now() - startTime > options.timeoutMs) {
318
+ throw new TimeoutError(options.timeoutMs);
319
+ }
320
+ }
321
+ }
322
+
297
323
  /**
298
324
  * Called when a circular reference is found.
299
325
  * It sets the {@link $Refs#circular} flag, executes the options.dereference.onCircular callback,
package/lib/pointer.ts CHANGED
@@ -5,6 +5,8 @@ import * as url from "./util/url.js";
5
5
  import { JSONParserError, InvalidPointerError, MissingPointerError, isHandledError } from "./util/errors.js";
6
6
  import type { JSONSchema } from "./types";
7
7
 
8
+ export const nullSymbol = Symbol('null');
9
+
8
10
  const slashes = /\//g;
9
11
  const tildes = /~/g;
10
12
  const escapedSlash = /~1/g;
@@ -121,6 +123,16 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
121
123
  continue;
122
124
  }
123
125
 
126
+ // If the token we're looking for ended up not containing any slashes but is
127
+ // actually instead pointing to an existing `null` value then we should use that
128
+ // `null` value.
129
+ if (token in this.value && this.value[token] === null) {
130
+ // We use a `null` symbol for internal tracking to differntiate between a general `null`
131
+ // value and our expected `null` value.
132
+ this.value = nullSymbol;
133
+ continue;
134
+ }
135
+
124
136
  this.value = null;
125
137
 
126
138
  const path = this.$ref.path || "";
package/lib/ref.ts CHANGED
@@ -1,4 +1,4 @@
1
- import Pointer from "./pointer.js";
1
+ import Pointer, { nullSymbol } from "./pointer.js";
2
2
  import type { JSONParserError, MissingPointerError, ParserError, ResolverError } from "./util/errors.js";
3
3
  import { InvalidPointerError, isHandledError, normalizeError } from "./util/errors.js";
4
4
  import { safePointerToPath, stripHash, getHash } from "./util/url.js";
@@ -119,7 +119,12 @@ class $Ref<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOpt
119
119
  resolve(path: string, options?: O, friendlyPath?: string, pathFromRoot?: string) {
120
120
  const pointer = new Pointer<S, O>(this, path, friendlyPath);
121
121
  try {
122
- return pointer.resolve(this.value, options, pathFromRoot);
122
+ const resolved = pointer.resolve(this.value, options, pathFromRoot);
123
+ if (resolved.value === nullSymbol) {
124
+ resolved.value = null;
125
+ }
126
+
127
+ return resolved;
123
128
  } catch (err: any) {
124
129
  if (!options || !options.continueOnError || !isHandledError(err)) {
125
130
  throw err;
@@ -148,6 +153,9 @@ class $Ref<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOpt
148
153
  set(path: string, value: any) {
149
154
  const pointer = new Pointer(this, path);
150
155
  this.value = pointer.set(this.value, value);
156
+ if (this.value === nullSymbol) {
157
+ this.value = null;
158
+ }
151
159
  }
152
160
 
153
161
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apidevtools/json-schema-ref-parser",
3
- "version": "11.9.2",
3
+ "version": "12.0.0",
4
4
  "description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
5
5
  "scripts": {
6
6
  "prepublishOnly": "yarn build",