@apidevtools/json-schema-ref-parser 15.3.4 → 15.3.5
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/bundle.js +10 -5
- package/dist/lib/dereference.js +10 -5
- package/dist/lib/pointer.js +9 -8
- package/dist/lib/resolve-external.js +8 -3
- package/dist/lib/util/url.js +4 -1
- package/lib/bundle.ts +11 -5
- package/lib/dereference.ts +11 -5
- package/lib/pointer.ts +10 -8
- package/lib/resolve-external.ts +8 -3
- package/lib/util/url.ts +5 -1
- package/package.json +2 -2
package/dist/lib/bundle.js
CHANGED
|
@@ -12,9 +12,12 @@ import { getSchemaBasePath } from "./util/schema-resources.js";
|
|
|
12
12
|
*/
|
|
13
13
|
function bundle(parser, options) {
|
|
14
14
|
// console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
15
|
+
const rootScopeBase = parser.$refs._root$Ref.dynamicIdScope
|
|
16
|
+
? getSchemaBasePath(parser.$refs._root$Ref.path, parser.schema)
|
|
17
|
+
: parser.$refs._root$Ref.path;
|
|
15
18
|
// Build an inventory of all $ref pointers in the JSON Schema
|
|
16
19
|
const inventory = [];
|
|
17
|
-
crawl(parser, "schema", parser.$refs._root$Ref.path + "#",
|
|
20
|
+
crawl(parser, "schema", parser.$refs._root$Ref.path + "#", rootScopeBase, parser.$refs._root$Ref.dynamicIdScope, "#", 0, inventory, parser.$refs, options);
|
|
18
21
|
// Get the root schema's $id (if any) for qualifying refs inside sub-schemas with their own $id
|
|
19
22
|
const rootId = parser.schema && typeof parser.schema === "object" && "$id" in parser.schema
|
|
20
23
|
? parser.schema.$id
|
|
@@ -44,7 +47,7 @@ function crawl(parent, key, path, scopeBase, dynamicIdScope, pathFromRoot, indir
|
|
|
44
47
|
const bundleOptions = (options.bundle || {});
|
|
45
48
|
const isExcludedPath = bundleOptions.excludedPathMatcher || (() => false);
|
|
46
49
|
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
|
|
47
|
-
const currentScopeBase =
|
|
50
|
+
const currentScopeBase = scopeBase;
|
|
48
51
|
if ($Ref.isAllowed$Ref(obj)) {
|
|
49
52
|
inventory$Ref(parent, key, path, currentScopeBase, dynamicIdScope, pathFromRoot, indirections, inventory, $refs, options);
|
|
50
53
|
}
|
|
@@ -71,12 +74,14 @@ function crawl(parent, key, path, scopeBase, dynamicIdScope, pathFromRoot, indir
|
|
|
71
74
|
const keyPath = Pointer.join(path, key);
|
|
72
75
|
const keyPathFromRoot = Pointer.join(pathFromRoot, key);
|
|
73
76
|
const value = obj[key];
|
|
77
|
+
const childScopeBase = dynamicIdScope && value && typeof value === "object" && !ArrayBuffer.isView(value)
|
|
78
|
+
? getSchemaBasePath(currentScopeBase, value)
|
|
79
|
+
: currentScopeBase;
|
|
74
80
|
if ($Ref.isAllowed$Ref(value)) {
|
|
75
|
-
|
|
76
|
-
inventory$Ref(obj, key, keyPath, valueScopeBase, dynamicIdScope, keyPathFromRoot, indirections, inventory, $refs, options);
|
|
81
|
+
inventory$Ref(obj, key, keyPath, childScopeBase, dynamicIdScope, keyPathFromRoot, indirections, inventory, $refs, options);
|
|
77
82
|
}
|
|
78
83
|
else {
|
|
79
|
-
crawl(obj, key, keyPath,
|
|
84
|
+
crawl(obj, key, keyPath, childScopeBase, dynamicIdScope, keyPathFromRoot, indirections, inventory, $refs, options);
|
|
80
85
|
}
|
|
81
86
|
// We need to ensure that we have an object to work with here because we may be crawling
|
|
82
87
|
// an `examples` schema and `value` may be nullish.
|
package/dist/lib/dereference.js
CHANGED
|
@@ -13,8 +13,11 @@ export default dereference;
|
|
|
13
13
|
*/
|
|
14
14
|
function dereference(parser, options) {
|
|
15
15
|
const start = Date.now();
|
|
16
|
+
const rootScopeBase = parser.$refs._root$Ref.dynamicIdScope
|
|
17
|
+
? getSchemaBasePath(parser.$refs._root$Ref.path, parser.schema)
|
|
18
|
+
: parser.$refs._root$Ref.path;
|
|
16
19
|
// console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
17
|
-
const dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path,
|
|
20
|
+
const dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, rootScopeBase, parser.$refs._root$Ref.dynamicIdScope, "#", new Set(), new Set(), new Map(), parser.$refs, options, start, 0);
|
|
18
21
|
parser.$refs.circular = dereferenced.circular;
|
|
19
22
|
parser.schema = dereferenced.value;
|
|
20
23
|
}
|
|
@@ -52,7 +55,7 @@ function crawl(obj, path, scopeBase, dynamicIdScope, pathFromRoot, parents, proc
|
|
|
52
55
|
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
|
|
53
56
|
parents.add(obj);
|
|
54
57
|
processedObjects.add(obj);
|
|
55
|
-
const currentScopeBase =
|
|
58
|
+
const currentScopeBase = scopeBase;
|
|
56
59
|
if ($Ref.isAllowed$Ref(obj, options)) {
|
|
57
60
|
dereferenced = dereference$Ref(obj, path, currentScopeBase, dynamicIdScope, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth);
|
|
58
61
|
result.circular = dereferenced.circular;
|
|
@@ -67,10 +70,12 @@ function crawl(obj, path, scopeBase, dynamicIdScope, pathFromRoot, parents, proc
|
|
|
67
70
|
continue;
|
|
68
71
|
}
|
|
69
72
|
const value = obj[key];
|
|
73
|
+
const childScopeBase = dynamicIdScope && value && typeof value === "object" && !ArrayBuffer.isView(value)
|
|
74
|
+
? getSchemaBasePath(currentScopeBase, value)
|
|
75
|
+
: currentScopeBase;
|
|
70
76
|
let circular;
|
|
71
77
|
if ($Ref.isAllowed$Ref(value, options)) {
|
|
72
|
-
|
|
73
|
-
dereferenced = dereference$Ref(value, keyPath, valueScopeBase, dynamicIdScope, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth);
|
|
78
|
+
dereferenced = dereference$Ref(value, keyPath, childScopeBase, dynamicIdScope, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth);
|
|
74
79
|
circular = dereferenced.circular;
|
|
75
80
|
// Avoid pointless mutations; breaks frozen objects to no profit
|
|
76
81
|
if (obj[key] !== dereferenced.value) {
|
|
@@ -107,7 +112,7 @@ function crawl(obj, path, scopeBase, dynamicIdScope, pathFromRoot, parents, proc
|
|
|
107
112
|
}
|
|
108
113
|
else {
|
|
109
114
|
if (!parents.has(value)) {
|
|
110
|
-
dereferenced = crawl(value, keyPath,
|
|
115
|
+
dereferenced = crawl(value, keyPath, childScopeBase, dynamicIdScope, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime, depth + 1);
|
|
111
116
|
circular = dereferenced.circular;
|
|
112
117
|
// Avoid pointless mutations; breaks frozen objects to no profit
|
|
113
118
|
if (obj[key] !== dereferenced.value) {
|
package/dist/lib/pointer.js
CHANGED
|
@@ -74,7 +74,7 @@ class Pointer {
|
|
|
74
74
|
const found = [];
|
|
75
75
|
// Crawl the object, one token at a time
|
|
76
76
|
this.value = unwrapOrThrow(obj);
|
|
77
|
-
if (this.$ref.dynamicIdScope) {
|
|
77
|
+
if (this.$ref.dynamicIdScope && !isAliasedResource(this.$ref)) {
|
|
78
78
|
this.scopeBase = getSchemaBasePath(this.scopeBase, this.value);
|
|
79
79
|
}
|
|
80
80
|
for (let i = 0; i < tokens.length; i++) {
|
|
@@ -163,7 +163,7 @@ class Pointer {
|
|
|
163
163
|
}
|
|
164
164
|
// Crawl the object, one token at a time
|
|
165
165
|
this.value = unwrapOrThrow(obj);
|
|
166
|
-
if (this.$ref.dynamicIdScope) {
|
|
166
|
+
if (this.$ref.dynamicIdScope && !isAliasedResource(this.$ref)) {
|
|
167
167
|
this.scopeBase = getSchemaBasePath(this.scopeBase, this.value);
|
|
168
168
|
}
|
|
169
169
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
@@ -273,9 +273,6 @@ function resolveIf$Ref(pointer, options, pathFromRoot) {
|
|
|
273
273
|
// This JSON reference "extends" the resolved value, rather than simply pointing to it.
|
|
274
274
|
// So the resolved path does NOT change. Just the value does.
|
|
275
275
|
pointer.value = $Ref.dereference(pointer.value, resolved.value, options);
|
|
276
|
-
if (pointer.$ref.dynamicIdScope) {
|
|
277
|
-
pointer.scopeBase = getSchemaBasePath(pointer.scopeBase, pointer.value);
|
|
278
|
-
}
|
|
279
276
|
return false;
|
|
280
277
|
}
|
|
281
278
|
else {
|
|
@@ -283,9 +280,10 @@ function resolveIf$Ref(pointer, options, pathFromRoot) {
|
|
|
283
280
|
pointer.$ref = resolved.$ref;
|
|
284
281
|
pointer.path = resolved.path;
|
|
285
282
|
pointer.value = resolved.value;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
283
|
+
// `pointer.$ref.path` is already the canonical location of the resolved resource.
|
|
284
|
+
// Re-applying the resource's own `$id` here would duplicate nested path segments
|
|
285
|
+
// such as `nested/nested/foo.json`.
|
|
286
|
+
pointer.scopeBase = pointer.$ref.path;
|
|
289
287
|
}
|
|
290
288
|
return true;
|
|
291
289
|
}
|
|
@@ -327,3 +325,6 @@ function unwrapOrThrow(value) {
|
|
|
327
325
|
function isRootPath(pathFromRoot) {
|
|
328
326
|
return typeof pathFromRoot == "string" && Pointer.parse(pathFromRoot).length == 0;
|
|
329
327
|
}
|
|
328
|
+
function isAliasedResource($ref) {
|
|
329
|
+
return Boolean($ref.path && $ref.path in $ref.$refs._aliases);
|
|
330
|
+
}
|
|
@@ -20,8 +20,11 @@ function resolveExternal(parser, options) {
|
|
|
20
20
|
return Promise.resolve();
|
|
21
21
|
}
|
|
22
22
|
try {
|
|
23
|
+
const rootScopeBase = parser.$refs._root$Ref.dynamicIdScope
|
|
24
|
+
? getSchemaBasePath(parser.$refs._root$Ref.path, parser.schema)
|
|
25
|
+
: parser.$refs._root$Ref.path;
|
|
23
26
|
// console.log('Resolving $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
24
|
-
const promises = crawl(parser.schema, parser.$refs._root$Ref.path + "#",
|
|
27
|
+
const promises = crawl(parser.schema, parser.$refs._root$Ref.path + "#", rootScopeBase, parser.$refs._root$Ref.dynamicIdScope, parser.$refs, options);
|
|
25
28
|
return Promise.all(promises);
|
|
26
29
|
}
|
|
27
30
|
catch (e) {
|
|
@@ -49,7 +52,7 @@ function crawl(obj, path, scopeBase, dynamicIdScope, $refs, options, seen, exter
|
|
|
49
52
|
let promises = [];
|
|
50
53
|
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !seen.has(obj)) {
|
|
51
54
|
seen.add(obj); // Track previously seen objects to avoid infinite recursion
|
|
52
|
-
const currentScopeBase =
|
|
55
|
+
const currentScopeBase = scopeBase;
|
|
53
56
|
if ($Ref.isExternal$Ref(obj)) {
|
|
54
57
|
promises.push(resolve$Ref(obj, path, currentScopeBase, dynamicIdScope, $refs, options));
|
|
55
58
|
}
|
|
@@ -57,7 +60,9 @@ function crawl(obj, path, scopeBase, dynamicIdScope, $refs, options, seen, exter
|
|
|
57
60
|
for (const key of keys) {
|
|
58
61
|
const keyPath = Pointer.join(path, key);
|
|
59
62
|
const value = obj[key];
|
|
60
|
-
const childScopeBase = dynamicIdScope &&
|
|
63
|
+
const childScopeBase = dynamicIdScope && value && typeof value === "object" && !ArrayBuffer.isView(value)
|
|
64
|
+
? getSchemaBasePath(currentScopeBase, value)
|
|
65
|
+
: currentScopeBase;
|
|
61
66
|
promises = promises.concat(crawl(value, keyPath, childScopeBase, dynamicIdScope, $refs, options, seen, external));
|
|
62
67
|
}
|
|
63
68
|
}
|
package/dist/lib/util/url.js
CHANGED
|
@@ -4,7 +4,7 @@ const protocolPattern = /^(\w{2,}):\/\//i;
|
|
|
4
4
|
const jsonPointerSlash = /~1/g;
|
|
5
5
|
const jsonPointerTilde = /~0/g;
|
|
6
6
|
import { isWindows } from "./is-windows.js";
|
|
7
|
-
const isAbsoluteWin32Path = /^[a-zA-Z]
|
|
7
|
+
const isAbsoluteWin32Path = /^[a-zA-Z]:[\\/]/;
|
|
8
8
|
// RegExp patterns to URL-encode special characters in local filesystem paths
|
|
9
9
|
const urlEncodePatterns = [
|
|
10
10
|
[/\?/g, "%3F"],
|
|
@@ -381,6 +381,9 @@ export function fromFileSystemPath(path) {
|
|
|
381
381
|
* Converts a URL to a local filesystem path.
|
|
382
382
|
*/
|
|
383
383
|
export function toFileSystemPath(path, keepFileProtocol) {
|
|
384
|
+
// Bare "%" characters are valid in filesystem paths, but they make `decodeURI` throw.
|
|
385
|
+
// Escape only the non-encoded ones so percent-encoded sequences still decode normally.
|
|
386
|
+
path = path.replace(/%(?![0-9A-Fa-f]{2})/g, "%25");
|
|
384
387
|
// Step 1: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
|
|
385
388
|
path = decodeURI(path);
|
|
386
389
|
// Step 2: Manually decode characters that are not decoded by `decodeURI`.
|
package/lib/bundle.ts
CHANGED
|
@@ -35,6 +35,9 @@ function bundle<S extends object = JSONSchema, O extends ParserOptions<S> = Pars
|
|
|
35
35
|
options: O,
|
|
36
36
|
) {
|
|
37
37
|
// console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
38
|
+
const rootScopeBase = parser.$refs._root$Ref.dynamicIdScope
|
|
39
|
+
? getSchemaBasePath(parser.$refs._root$Ref.path!, parser.schema)
|
|
40
|
+
: parser.$refs._root$Ref.path!;
|
|
38
41
|
|
|
39
42
|
// Build an inventory of all $ref pointers in the JSON Schema
|
|
40
43
|
const inventory: InventoryEntry[] = [];
|
|
@@ -42,7 +45,7 @@ function bundle<S extends object = JSONSchema, O extends ParserOptions<S> = Pars
|
|
|
42
45
|
parser,
|
|
43
46
|
"schema",
|
|
44
47
|
parser.$refs._root$Ref.path + "#",
|
|
45
|
-
|
|
48
|
+
rootScopeBase,
|
|
46
49
|
parser.$refs._root$Ref.dynamicIdScope,
|
|
47
50
|
"#",
|
|
48
51
|
0,
|
|
@@ -96,7 +99,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
96
99
|
const isExcludedPath = bundleOptions.excludedPathMatcher || (() => false);
|
|
97
100
|
|
|
98
101
|
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
|
|
99
|
-
const currentScopeBase =
|
|
102
|
+
const currentScopeBase = scopeBase;
|
|
100
103
|
if ($Ref.isAllowed$Ref(obj)) {
|
|
101
104
|
inventory$Ref(parent, key, path, currentScopeBase, dynamicIdScope, pathFromRoot, indirections, inventory, $refs, options);
|
|
102
105
|
} else {
|
|
@@ -121,14 +124,17 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
121
124
|
const keyPath = Pointer.join(path, key);
|
|
122
125
|
const keyPathFromRoot = Pointer.join(pathFromRoot, key);
|
|
123
126
|
const value = obj[key];
|
|
127
|
+
const childScopeBase =
|
|
128
|
+
dynamicIdScope && value && typeof value === "object" && !ArrayBuffer.isView(value)
|
|
129
|
+
? getSchemaBasePath(currentScopeBase, value)
|
|
130
|
+
: currentScopeBase;
|
|
124
131
|
|
|
125
132
|
if ($Ref.isAllowed$Ref(value)) {
|
|
126
|
-
const valueScopeBase = dynamicIdScope ? getSchemaBasePath(currentScopeBase, value) : currentScopeBase;
|
|
127
133
|
inventory$Ref(
|
|
128
134
|
obj,
|
|
129
135
|
key,
|
|
130
136
|
keyPath,
|
|
131
|
-
|
|
137
|
+
childScopeBase,
|
|
132
138
|
dynamicIdScope,
|
|
133
139
|
keyPathFromRoot,
|
|
134
140
|
indirections,
|
|
@@ -137,7 +143,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
137
143
|
options,
|
|
138
144
|
);
|
|
139
145
|
} else {
|
|
140
|
-
crawl(obj, key, keyPath,
|
|
146
|
+
crawl(obj, key, keyPath, childScopeBase, dynamicIdScope, keyPathFromRoot, indirections, inventory, $refs, options);
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
// We need to ensure that we have an object to work with here because we may be crawling
|
package/lib/dereference.ts
CHANGED
|
@@ -21,11 +21,14 @@ function dereference<S extends object = JSONSchema, O extends ParserOptions<S> =
|
|
|
21
21
|
options: O,
|
|
22
22
|
) {
|
|
23
23
|
const start = Date.now();
|
|
24
|
+
const rootScopeBase = parser.$refs._root$Ref.dynamicIdScope
|
|
25
|
+
? getSchemaBasePath(parser.$refs._root$Ref.path!, parser.schema)
|
|
26
|
+
: parser.$refs._root$Ref.path!;
|
|
24
27
|
// console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
25
28
|
const dereferenced = crawl<S, O>(
|
|
26
29
|
parser.schema,
|
|
27
30
|
parser.$refs._root$Ref.path!,
|
|
28
|
-
|
|
31
|
+
rootScopeBase,
|
|
29
32
|
parser.$refs._root$Ref.dynamicIdScope,
|
|
30
33
|
"#",
|
|
31
34
|
new Set(),
|
|
@@ -92,7 +95,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
92
95
|
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
|
|
93
96
|
parents.add(obj);
|
|
94
97
|
processedObjects.add(obj);
|
|
95
|
-
const currentScopeBase =
|
|
98
|
+
const currentScopeBase = scopeBase;
|
|
96
99
|
|
|
97
100
|
if ($Ref.isAllowed$Ref(obj, options)) {
|
|
98
101
|
dereferenced = dereference$Ref(
|
|
@@ -123,14 +126,17 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
const value = obj[key];
|
|
129
|
+
const childScopeBase =
|
|
130
|
+
dynamicIdScope && value && typeof value === "object" && !ArrayBuffer.isView(value)
|
|
131
|
+
? getSchemaBasePath(currentScopeBase, value)
|
|
132
|
+
: currentScopeBase;
|
|
126
133
|
let circular;
|
|
127
134
|
|
|
128
135
|
if ($Ref.isAllowed$Ref(value, options)) {
|
|
129
|
-
const valueScopeBase = dynamicIdScope ? getSchemaBasePath(currentScopeBase, value) : currentScopeBase;
|
|
130
136
|
dereferenced = dereference$Ref(
|
|
131
137
|
value,
|
|
132
138
|
keyPath,
|
|
133
|
-
|
|
139
|
+
childScopeBase,
|
|
134
140
|
dynamicIdScope,
|
|
135
141
|
keyPathFromRoot,
|
|
136
142
|
parents,
|
|
@@ -183,7 +189,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
183
189
|
dereferenced = crawl(
|
|
184
190
|
value,
|
|
185
191
|
keyPath,
|
|
186
|
-
|
|
192
|
+
childScopeBase,
|
|
187
193
|
dynamicIdScope,
|
|
188
194
|
keyPathFromRoot,
|
|
189
195
|
parents,
|
package/lib/pointer.ts
CHANGED
|
@@ -95,7 +95,7 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
|
|
|
95
95
|
|
|
96
96
|
// Crawl the object, one token at a time
|
|
97
97
|
this.value = unwrapOrThrow(obj);
|
|
98
|
-
if (this.$ref.dynamicIdScope) {
|
|
98
|
+
if (this.$ref.dynamicIdScope && !isAliasedResource(this.$ref)) {
|
|
99
99
|
this.scopeBase = getSchemaBasePath(this.scopeBase, this.value);
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -196,7 +196,7 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
|
|
|
196
196
|
|
|
197
197
|
// Crawl the object, one token at a time
|
|
198
198
|
this.value = unwrapOrThrow(obj);
|
|
199
|
-
if (this.$ref.dynamicIdScope) {
|
|
199
|
+
if (this.$ref.dynamicIdScope && !isAliasedResource(this.$ref)) {
|
|
200
200
|
this.scopeBase = getSchemaBasePath(this.scopeBase, this.value);
|
|
201
201
|
}
|
|
202
202
|
|
|
@@ -327,18 +327,16 @@ function resolveIf$Ref<S extends object = JSONSchema, O extends ParserOptions<S>
|
|
|
327
327
|
// This JSON reference "extends" the resolved value, rather than simply pointing to it.
|
|
328
328
|
// So the resolved path does NOT change. Just the value does.
|
|
329
329
|
pointer.value = $Ref.dereference(pointer.value, resolved.value, options);
|
|
330
|
-
if (pointer.$ref.dynamicIdScope) {
|
|
331
|
-
pointer.scopeBase = getSchemaBasePath(pointer.scopeBase, pointer.value);
|
|
332
|
-
}
|
|
333
330
|
return false;
|
|
334
331
|
} else {
|
|
335
332
|
// Resolve the reference
|
|
336
333
|
pointer.$ref = resolved.$ref;
|
|
337
334
|
pointer.path = resolved.path;
|
|
338
335
|
pointer.value = resolved.value;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
// `pointer.$ref.path` is already the canonical location of the resolved resource.
|
|
337
|
+
// Re-applying the resource's own `$id` here would duplicate nested path segments
|
|
338
|
+
// such as `nested/nested/foo.json`.
|
|
339
|
+
pointer.scopeBase = pointer.$ref.path!;
|
|
342
340
|
}
|
|
343
341
|
|
|
344
342
|
return true;
|
|
@@ -385,3 +383,7 @@ function unwrapOrThrow(value: unknown) {
|
|
|
385
383
|
function isRootPath(pathFromRoot: string | unknown): boolean {
|
|
386
384
|
return typeof pathFromRoot == "string" && Pointer.parse(pathFromRoot).length == 0;
|
|
387
385
|
}
|
|
386
|
+
|
|
387
|
+
function isAliasedResource($ref: $Ref<any, any>) {
|
|
388
|
+
return Boolean($ref.path && $ref.path in $ref.$refs._aliases);
|
|
389
|
+
}
|
package/lib/resolve-external.ts
CHANGED
|
@@ -29,11 +29,14 @@ function resolveExternal<S extends object = JSONSchema, O extends ParserOptions<
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
try {
|
|
32
|
+
const rootScopeBase = parser.$refs._root$Ref.dynamicIdScope
|
|
33
|
+
? getSchemaBasePath(parser.$refs._root$Ref.path!, parser.schema)
|
|
34
|
+
: parser.$refs._root$Ref.path!;
|
|
32
35
|
// console.log('Resolving $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
33
36
|
const promises = crawl(
|
|
34
37
|
parser.schema,
|
|
35
38
|
parser.$refs._root$Ref.path + "#",
|
|
36
|
-
|
|
39
|
+
rootScopeBase,
|
|
37
40
|
parser.$refs._root$Ref.dynamicIdScope,
|
|
38
41
|
parser.$refs,
|
|
39
42
|
options,
|
|
@@ -75,7 +78,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
75
78
|
|
|
76
79
|
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !seen.has(obj)) {
|
|
77
80
|
seen.add(obj); // Track previously seen objects to avoid infinite recursion
|
|
78
|
-
const currentScopeBase =
|
|
81
|
+
const currentScopeBase = scopeBase;
|
|
79
82
|
if ($Ref.isExternal$Ref(obj)) {
|
|
80
83
|
promises.push(resolve$Ref<S, O>(obj, path, currentScopeBase, dynamicIdScope, $refs, options));
|
|
81
84
|
}
|
|
@@ -85,7 +88,9 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
|
|
|
85
88
|
const keyPath = Pointer.join(path, key);
|
|
86
89
|
const value = obj[key as keyof typeof obj] as string | JSONSchema | Buffer | undefined;
|
|
87
90
|
const childScopeBase =
|
|
88
|
-
dynamicIdScope &&
|
|
91
|
+
dynamicIdScope && value && typeof value === "object" && !ArrayBuffer.isView(value)
|
|
92
|
+
? getSchemaBasePath(currentScopeBase, value)
|
|
93
|
+
: currentScopeBase;
|
|
89
94
|
promises = promises.concat(crawl(value, keyPath, childScopeBase, dynamicIdScope, $refs, options, seen, external));
|
|
90
95
|
}
|
|
91
96
|
}
|
package/lib/util/url.ts
CHANGED
|
@@ -7,7 +7,7 @@ const jsonPointerTilde = /~0/g;
|
|
|
7
7
|
|
|
8
8
|
import { isWindows } from "./is-windows.js";
|
|
9
9
|
|
|
10
|
-
const isAbsoluteWin32Path = /^[a-zA-Z]
|
|
10
|
+
const isAbsoluteWin32Path = /^[a-zA-Z]:[\\/]/;
|
|
11
11
|
|
|
12
12
|
// RegExp patterns to URL-encode special characters in local filesystem paths
|
|
13
13
|
const urlEncodePatterns = [
|
|
@@ -426,6 +426,10 @@ export function fromFileSystemPath(path: string) {
|
|
|
426
426
|
* Converts a URL to a local filesystem path.
|
|
427
427
|
*/
|
|
428
428
|
export function toFileSystemPath(path: string | undefined, keepFileProtocol?: boolean): string {
|
|
429
|
+
// Bare "%" characters are valid in filesystem paths, but they make `decodeURI` throw.
|
|
430
|
+
// Escape only the non-encoded ones so percent-encoded sequences still decode normally.
|
|
431
|
+
path = path!.replace(/%(?![0-9A-Fa-f]{2})/g, "%25");
|
|
432
|
+
|
|
429
433
|
// Step 1: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
|
|
430
434
|
path = decodeURI(path!);
|
|
431
435
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apidevtools/json-schema-ref-parser",
|
|
3
|
-
"version": "15.3.
|
|
3
|
+
"version": "15.3.5",
|
|
4
4
|
"description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "dist/lib/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"test": "vitest --coverage",
|
|
16
16
|
"test:specific": "vitest invalid",
|
|
17
17
|
"test:node": "yarn test",
|
|
18
|
-
"test:browser": "
|
|
18
|
+
"test:browser": "node ./test/fixtures/run-browser-tests.mjs",
|
|
19
19
|
"test:update": "vitest -u",
|
|
20
20
|
"test:watch": "vitest -w"
|
|
21
21
|
},
|