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