@texaryn/schema-json 0.7.0 → 0.8.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/CHANGELOG.md +32 -0
- package/README.md +33 -1
- package/THIRD-PARTY-NOTICES.md +7 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +479 -24
- package/dist/adapter.js.map +1 -1
- package/dist/bare-maps.d.ts +3 -0
- package/dist/bare-maps.d.ts.map +1 -0
- package/dist/bare-maps.js +44 -0
- package/dist/bare-maps.js.map +1 -0
- package/dist/identity.d.ts +11 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +103 -22
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/instance-pointer.d.ts +9 -0
- package/dist/instance-pointer.d.ts.map +1 -0
- package/dist/instance-pointer.js +115 -0
- package/dist/instance-pointer.js.map +1 -0
- package/dist/local-pointer-aliases.d.ts +4 -0
- package/dist/local-pointer-aliases.d.ts.map +1 -0
- package/dist/local-pointer-aliases.js +345 -0
- package/dist/local-pointer-aliases.js.map +1 -0
- package/dist/normalize.d.ts +1 -1
- package/dist/normalize.d.ts.map +1 -1
- package/dist/normalize.js +3 -1
- package/dist/normalize.js.map +1 -1
- package/dist/projection-shape.d.ts +25 -0
- package/dist/projection-shape.d.ts.map +1 -0
- package/dist/projection-shape.js +74 -0
- package/dist/projection-shape.js.map +1 -0
- package/dist/projection-validation-coherence.d.ts +11 -0
- package/dist/projection-validation-coherence.d.ts.map +1 -0
- package/dist/projection-validation-coherence.js +213 -0
- package/dist/projection-validation-coherence.js.map +1 -0
- package/dist/projection.d.ts +2 -2
- package/dist/projection.d.ts.map +1 -1
- package/dist/projection.js +922 -243
- package/dist/projection.js.map +1 -1
- package/dist/resources.d.ts +19 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +730 -0
- package/dist/resources.js.map +1 -0
- package/dist/root-reference.js +1 -1
- package/dist/schema-graph.d.ts +7 -0
- package/dist/schema-graph.d.ts.map +1 -1
- package/dist/schema-graph.js +79 -20
- package/dist/schema-graph.js.map +1 -1
- package/dist/submission-projection.d.ts +5 -0
- package/dist/submission-projection.d.ts.map +1 -0
- package/dist/submission-projection.js +233 -0
- package/dist/submission-projection.js.map +1 -0
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/vendor/json-schema-library/LICENSE.md +9 -0
- package/dist/vendor/json-schema-library/index.mjs +2 -0
- package/dist/vendor/json-schema-library/index.mjs.map +1 -0
- package/package.json +9 -4
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
import { detectDialect } from './dialect.js';
|
|
2
|
+
export const DEFAULT_MAX_EXTERNAL_RESOURCES = 128;
|
|
3
|
+
const SINGLE = {
|
|
4
|
+
'draft-07': new Set([
|
|
5
|
+
'additionalItems',
|
|
6
|
+
'additionalProperties',
|
|
7
|
+
'contains',
|
|
8
|
+
'else',
|
|
9
|
+
'if',
|
|
10
|
+
'items',
|
|
11
|
+
'not',
|
|
12
|
+
'propertyNames',
|
|
13
|
+
'then',
|
|
14
|
+
]),
|
|
15
|
+
'2019-09': new Set([
|
|
16
|
+
'additionalItems',
|
|
17
|
+
'additionalProperties',
|
|
18
|
+
'contains',
|
|
19
|
+
'contentSchema',
|
|
20
|
+
'else',
|
|
21
|
+
'if',
|
|
22
|
+
'items',
|
|
23
|
+
'not',
|
|
24
|
+
'propertyNames',
|
|
25
|
+
'then',
|
|
26
|
+
'unevaluatedItems',
|
|
27
|
+
'unevaluatedProperties',
|
|
28
|
+
]),
|
|
29
|
+
'2020-12': new Set([
|
|
30
|
+
'additionalProperties',
|
|
31
|
+
'contains',
|
|
32
|
+
'contentSchema',
|
|
33
|
+
'else',
|
|
34
|
+
'if',
|
|
35
|
+
'items',
|
|
36
|
+
'not',
|
|
37
|
+
'propertyNames',
|
|
38
|
+
'then',
|
|
39
|
+
'unevaluatedItems',
|
|
40
|
+
'unevaluatedProperties',
|
|
41
|
+
]),
|
|
42
|
+
};
|
|
43
|
+
const LIST = {
|
|
44
|
+
'draft-07': new Set(['allOf', 'anyOf', 'oneOf']),
|
|
45
|
+
'2019-09': new Set(['allOf', 'anyOf', 'oneOf']),
|
|
46
|
+
'2020-12': new Set(['allOf', 'anyOf', 'oneOf', 'prefixItems']),
|
|
47
|
+
};
|
|
48
|
+
const MAP = {
|
|
49
|
+
'draft-07': new Set(['$defs', 'definitions', 'dependencies', 'patternProperties', 'properties']),
|
|
50
|
+
'2019-09': new Set(['$defs', 'definitions', 'dependencies', 'dependentSchemas', 'patternProperties', 'properties']),
|
|
51
|
+
'2020-12': new Set(['$defs', 'definitions', 'dependencies', 'dependentSchemas', 'patternProperties', 'properties']),
|
|
52
|
+
};
|
|
53
|
+
const META_URIS = new Set([
|
|
54
|
+
'http://json-schema.org/draft-07/schema',
|
|
55
|
+
'https://json-schema.org/draft-07/schema',
|
|
56
|
+
'http://json-schema.org/draft/2019-09/schema',
|
|
57
|
+
'https://json-schema.org/draft/2019-09/schema',
|
|
58
|
+
'http://json-schema.org/draft/2019-09/meta/core',
|
|
59
|
+
'https://json-schema.org/draft/2019-09/meta/core',
|
|
60
|
+
'http://json-schema.org/draft/2019-09/meta/applicator',
|
|
61
|
+
'https://json-schema.org/draft/2019-09/meta/applicator',
|
|
62
|
+
'http://json-schema.org/draft/2019-09/meta/validation',
|
|
63
|
+
'https://json-schema.org/draft/2019-09/meta/validation',
|
|
64
|
+
'http://json-schema.org/draft/2019-09/meta/meta-data',
|
|
65
|
+
'https://json-schema.org/draft/2019-09/meta/meta-data',
|
|
66
|
+
'http://json-schema.org/draft/2019-09/meta/format',
|
|
67
|
+
'https://json-schema.org/draft/2019-09/meta/format',
|
|
68
|
+
'http://json-schema.org/draft/2019-09/meta/content',
|
|
69
|
+
'https://json-schema.org/draft/2019-09/meta/content',
|
|
70
|
+
'http://json-schema.org/draft/2020-12/schema',
|
|
71
|
+
'https://json-schema.org/draft/2020-12/schema',
|
|
72
|
+
'http://json-schema.org/draft/2020-12/meta/core',
|
|
73
|
+
'https://json-schema.org/draft/2020-12/meta/core',
|
|
74
|
+
'http://json-schema.org/draft/2020-12/meta/applicator',
|
|
75
|
+
'https://json-schema.org/draft/2020-12/meta/applicator',
|
|
76
|
+
'http://json-schema.org/draft/2020-12/meta/unevaluated',
|
|
77
|
+
'https://json-schema.org/draft/2020-12/meta/unevaluated',
|
|
78
|
+
'http://json-schema.org/draft/2020-12/meta/validation',
|
|
79
|
+
'https://json-schema.org/draft/2020-12/meta/validation',
|
|
80
|
+
'http://json-schema.org/draft/2020-12/meta/meta-data',
|
|
81
|
+
'https://json-schema.org/draft/2020-12/meta/meta-data',
|
|
82
|
+
'http://json-schema.org/draft/2020-12/meta/format-annotation',
|
|
83
|
+
'https://json-schema.org/draft/2020-12/meta/format-annotation',
|
|
84
|
+
'http://json-schema.org/draft/2020-12/meta/content',
|
|
85
|
+
'https://json-schema.org/draft/2020-12/meta/content',
|
|
86
|
+
]);
|
|
87
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
88
|
+
export class SchemaResourceResolutionError extends Error {
|
|
89
|
+
uri;
|
|
90
|
+
referringPosition;
|
|
91
|
+
constructor(message, uri, referringPosition) {
|
|
92
|
+
super(message);
|
|
93
|
+
this.name = 'SchemaResourceResolutionError';
|
|
94
|
+
this.uri = uri;
|
|
95
|
+
this.referringPosition = referringPosition;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function withoutFragment(uri) {
|
|
99
|
+
const hash = uri.indexOf('#');
|
|
100
|
+
return hash === -1 ? uri : uri.slice(0, hash);
|
|
101
|
+
}
|
|
102
|
+
function absoluteUri(reference, base) {
|
|
103
|
+
try {
|
|
104
|
+
return base === undefined ? new URL(reference).href : new URL(reference, base).href;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function resourceBase(identifier, parent, dialect) {
|
|
111
|
+
if (typeof identifier !== 'string')
|
|
112
|
+
return parent;
|
|
113
|
+
if (dialect === 'draft-07' && identifier.startsWith('#'))
|
|
114
|
+
return parent;
|
|
115
|
+
const resolved = absoluteUri(identifier, parent);
|
|
116
|
+
return resolved === undefined ? parent : withoutFragment(resolved);
|
|
117
|
+
}
|
|
118
|
+
const escape = (segment) => segment.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
119
|
+
function pointerTargetWithContext(document, fragment, initialBase, initialPosition, dialect, knownResources) {
|
|
120
|
+
let pointer;
|
|
121
|
+
try {
|
|
122
|
+
pointer = decodeURIComponent(fragment);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
pointer = fragment;
|
|
126
|
+
}
|
|
127
|
+
if (pointer === '')
|
|
128
|
+
return {
|
|
129
|
+
schema: document,
|
|
130
|
+
parentBase: initialBase,
|
|
131
|
+
base: initialBase,
|
|
132
|
+
resourceRoot: document,
|
|
133
|
+
resourceRootPosition: initialPosition,
|
|
134
|
+
position: initialPosition,
|
|
135
|
+
};
|
|
136
|
+
if (!pointer.startsWith('/'))
|
|
137
|
+
return undefined;
|
|
138
|
+
let current = document;
|
|
139
|
+
let base = initialBase;
|
|
140
|
+
let resourceRoot = document;
|
|
141
|
+
let resourceRootPosition = initialPosition;
|
|
142
|
+
let position = initialPosition;
|
|
143
|
+
let parentBase = base;
|
|
144
|
+
const segments = pointer.slice(1).split('/');
|
|
145
|
+
for (const rawSegment of segments) {
|
|
146
|
+
const segment = rawSegment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
147
|
+
let child;
|
|
148
|
+
if (Array.isArray(current)) {
|
|
149
|
+
const index = Number(segment);
|
|
150
|
+
if (!Number.isInteger(index) || index < 0 || index >= current.length || !Object.hasOwn(current, index))
|
|
151
|
+
return undefined;
|
|
152
|
+
child = current[index];
|
|
153
|
+
}
|
|
154
|
+
else if (isRecord(current) && Object.hasOwn(current, segment)) {
|
|
155
|
+
child = current[segment];
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
parentBase = base;
|
|
161
|
+
position = `${position}/${escape(segment)}`;
|
|
162
|
+
if (isRecord(child) && !(dialect === 'draft-07' && typeof child.$ref === 'string') && typeof child.$id === 'string') {
|
|
163
|
+
const childBase = resourceBase(child.$id, base, dialect);
|
|
164
|
+
if (childBase !== undefined) {
|
|
165
|
+
knownResources?.add(childBase);
|
|
166
|
+
const embeddedDialect = detectDialect(child, { defaultDialect: dialect });
|
|
167
|
+
if (embeddedDialect !== dialect) {
|
|
168
|
+
throw new SchemaResourceResolutionError(`The resource at "${childBase}" uses ${embeddedDialect}, but this adapter uses ${dialect}.`, childBase, position);
|
|
169
|
+
}
|
|
170
|
+
const startsResource = !(dialect === 'draft-07' && child.$id.startsWith('#'));
|
|
171
|
+
if (startsResource) {
|
|
172
|
+
base = childBase;
|
|
173
|
+
resourceRoot = child;
|
|
174
|
+
resourceRootPosition = position;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
current = child;
|
|
179
|
+
}
|
|
180
|
+
const target = current;
|
|
181
|
+
return { schema: target, parentBase, base, resourceRoot, resourceRootPosition, position };
|
|
182
|
+
}
|
|
183
|
+
function seenAtBase(seen, schema, base) {
|
|
184
|
+
const bases = seen.get(schema) ?? new Set();
|
|
185
|
+
if (bases.has(base))
|
|
186
|
+
return true;
|
|
187
|
+
bases.add(base);
|
|
188
|
+
seen.set(schema, bases);
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
function referencesIn(document, initialBase, dialect, knownResources) {
|
|
192
|
+
const references = new Map();
|
|
193
|
+
const seen = new WeakMap();
|
|
194
|
+
const localReferences = [];
|
|
195
|
+
const anchorTargets = new Map();
|
|
196
|
+
const contextsByPosition = new Map();
|
|
197
|
+
const visitedLocalReferences = new Set();
|
|
198
|
+
const referenceKeywords = dialect === 'draft-07'
|
|
199
|
+
? ['$ref']
|
|
200
|
+
: dialect === '2019-09'
|
|
201
|
+
? ['$ref', '$recursiveRef']
|
|
202
|
+
: ['$ref', '$dynamicRef'];
|
|
203
|
+
const visit = (schema, parentBase, position, resourceRoot, resourceRootPosition) => {
|
|
204
|
+
if (typeof schema !== 'object' || schema === null)
|
|
205
|
+
return;
|
|
206
|
+
if (Array.isArray(schema)) {
|
|
207
|
+
if (seenAtBase(seen, schema, parentBase))
|
|
208
|
+
return;
|
|
209
|
+
schema.forEach((child, index) => visit(child, parentBase, `${position}/${index}`, resourceRoot, resourceRootPosition));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const record = schema;
|
|
213
|
+
const ignoresSiblings = dialect === 'draft-07' && typeof record.$ref === 'string';
|
|
214
|
+
const base = ignoresSiblings ? parentBase : resourceBase(record.$id, parentBase, dialect);
|
|
215
|
+
if (!ignoresSiblings && typeof record.$id === 'string' && base !== undefined) {
|
|
216
|
+
knownResources?.add(base);
|
|
217
|
+
const embeddedDialect = detectDialect(record, { defaultDialect: dialect });
|
|
218
|
+
if (embeddedDialect !== dialect) {
|
|
219
|
+
throw new SchemaResourceResolutionError(`The resource at "${base}" uses ${embeddedDialect}, but this adapter uses ${dialect}.`, base, position);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const startsResource = !ignoresSiblings && typeof record.$id === 'string' && !(dialect === 'draft-07' && record.$id.startsWith('#'));
|
|
223
|
+
const currentRoot = startsResource ? schema : resourceRoot;
|
|
224
|
+
const currentRootPosition = startsResource ? position : resourceRootPosition;
|
|
225
|
+
contextsByPosition.set(position, { base, resourceRoot: currentRoot, resourceRootPosition: currentRootPosition });
|
|
226
|
+
if (seenAtBase(seen, schema, parentBase))
|
|
227
|
+
return;
|
|
228
|
+
if (!ignoresSiblings && dialect === 'draft-07' && typeof record.$id === 'string' && record.$id.startsWith('#')) {
|
|
229
|
+
const anchorUri = absoluteUri(record.$id, parentBase) ?? (parentBase === undefined ? record.$id : undefined);
|
|
230
|
+
if (anchorUri !== undefined)
|
|
231
|
+
anchorTargets.set(anchorUri, { schema, base, position });
|
|
232
|
+
}
|
|
233
|
+
if (dialect !== 'draft-07' && typeof record.$anchor === 'string') {
|
|
234
|
+
anchorTargets.set(`${base ?? ''}#${record.$anchor}`, { schema, base, position });
|
|
235
|
+
}
|
|
236
|
+
if (dialect === '2020-12' && typeof record.$dynamicAnchor === 'string') {
|
|
237
|
+
anchorTargets.set(`${base ?? ''}#${record.$dynamicAnchor}`, { schema, base, position });
|
|
238
|
+
}
|
|
239
|
+
for (const keyword of referenceKeywords) {
|
|
240
|
+
const reference = record[keyword];
|
|
241
|
+
if (typeof reference === 'string') {
|
|
242
|
+
references.set(JSON.stringify([base, reference]), { base, reference, position: `${position}/${keyword}` });
|
|
243
|
+
const resolved = absoluteUri(reference, base);
|
|
244
|
+
const localUri = resolved ?? (base === undefined && reference.startsWith('#') ? reference : undefined);
|
|
245
|
+
if (localUri !== undefined && (base === undefined || withoutFragment(localUri) === base)) {
|
|
246
|
+
localReferences.push({
|
|
247
|
+
uri: localUri,
|
|
248
|
+
base,
|
|
249
|
+
resourceRoot: currentRoot,
|
|
250
|
+
resourceRootPosition: currentRootPosition,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (dialect === 'draft-07' && typeof record.$ref === 'string') {
|
|
256
|
+
for (const keyword of ['definitions', '$defs']) {
|
|
257
|
+
const children = record[keyword];
|
|
258
|
+
if (isRecord(children)) {
|
|
259
|
+
for (const [key, child] of Object.entries(children)) {
|
|
260
|
+
if (isRecord(child) || typeof child === 'boolean') {
|
|
261
|
+
visit(child, base, `${position}/${keyword}/${escape(key)}`, currentRoot, currentRootPosition);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
for (const keyword of SINGLE[dialect]) {
|
|
269
|
+
const child = record[keyword];
|
|
270
|
+
if (isRecord(child) || typeof child === 'boolean') {
|
|
271
|
+
visit(child, base, `${position}/${keyword}`, currentRoot, currentRootPosition);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
for (const keyword of LIST[dialect]) {
|
|
275
|
+
const children = record[keyword];
|
|
276
|
+
if (Array.isArray(children)) {
|
|
277
|
+
children.forEach((child, index) => visit(child, base, `${position}/${keyword}/${index}`, currentRoot, currentRootPosition));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const keyword of MAP[dialect]) {
|
|
281
|
+
const children = record[keyword];
|
|
282
|
+
if (!isRecord(children))
|
|
283
|
+
continue;
|
|
284
|
+
for (const [key, child] of Object.entries(children)) {
|
|
285
|
+
if (isRecord(child) || typeof child === 'boolean') {
|
|
286
|
+
visit(child, base, `${position}/${keyword}/${escape(key)}`, currentRoot, currentRootPosition);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (dialect !== '2020-12' && Array.isArray(record.items)) {
|
|
291
|
+
record.items.forEach((child, index) => visit(child, base, `${position}/items/${index}`, currentRoot, currentRootPosition));
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
visit(document, initialBase, '#', document, '#');
|
|
295
|
+
let progressed = true;
|
|
296
|
+
while (progressed) {
|
|
297
|
+
progressed = false;
|
|
298
|
+
for (let index = 0; index < localReferences.length; index += 1) {
|
|
299
|
+
if (visitedLocalReferences.has(index))
|
|
300
|
+
continue;
|
|
301
|
+
const local = localReferences[index];
|
|
302
|
+
const hash = local.uri.indexOf('#');
|
|
303
|
+
const fragment = hash === -1 ? '' : local.uri.slice(hash + 1);
|
|
304
|
+
let target;
|
|
305
|
+
let targetBase = local.base;
|
|
306
|
+
let targetPosition = local.resourceRootPosition;
|
|
307
|
+
let targetResourceRoot = local.resourceRoot;
|
|
308
|
+
let targetResourceRootPosition = local.resourceRootPosition;
|
|
309
|
+
if (fragment === '' || fragment.startsWith('/')) {
|
|
310
|
+
const located = pointerTargetWithContext(local.resourceRoot, fragment, local.base, local.resourceRootPosition, dialect, knownResources);
|
|
311
|
+
target = located?.schema;
|
|
312
|
+
targetBase = located?.parentBase ?? local.base;
|
|
313
|
+
targetPosition = located?.position ?? local.resourceRootPosition;
|
|
314
|
+
targetResourceRoot = located?.resourceRoot ?? local.resourceRoot;
|
|
315
|
+
targetResourceRootPosition = located?.resourceRootPosition ?? local.resourceRootPosition;
|
|
316
|
+
if (fragment === '')
|
|
317
|
+
targetBase = local.base;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
const anchor = anchorTargets.get(local.uri);
|
|
321
|
+
if (anchor === undefined) {
|
|
322
|
+
visitedLocalReferences.delete(index);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
target = anchor.schema;
|
|
326
|
+
targetBase = anchor.base ?? local.base;
|
|
327
|
+
targetPosition = anchor.position;
|
|
328
|
+
}
|
|
329
|
+
visitedLocalReferences.add(index);
|
|
330
|
+
progressed = true;
|
|
331
|
+
if (isRecord(target) || typeof target === 'boolean') {
|
|
332
|
+
const knownContext = contextsByPosition.get(targetPosition);
|
|
333
|
+
if (knownContext === undefined) {
|
|
334
|
+
visit(target, targetBase, targetPosition, targetResourceRoot, targetResourceRootPosition);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return [...references.values()];
|
|
340
|
+
}
|
|
341
|
+
function declaredResourceIds(document, initialBase, dialect) {
|
|
342
|
+
const ids = new Set();
|
|
343
|
+
const seen = new WeakMap();
|
|
344
|
+
const visit = (schema, parentBase, position) => {
|
|
345
|
+
if (typeof schema !== 'object' || schema === null || seenAtBase(seen, schema, parentBase))
|
|
346
|
+
return;
|
|
347
|
+
if (Array.isArray(schema)) {
|
|
348
|
+
schema.forEach((child, index) => visit(child, parentBase, `${position}/${index}`));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const record = schema;
|
|
352
|
+
const ignoresSiblings = dialect === 'draft-07' && typeof record.$ref === 'string';
|
|
353
|
+
const base = ignoresSiblings ? parentBase : resourceBase(record.$id, parentBase, dialect);
|
|
354
|
+
if (!ignoresSiblings && typeof record.$id === 'string' && base !== undefined) {
|
|
355
|
+
ids.add(base);
|
|
356
|
+
const embeddedDialect = detectDialect(record, { defaultDialect: dialect });
|
|
357
|
+
if (embeddedDialect !== dialect) {
|
|
358
|
+
throw new SchemaResourceResolutionError(`The resource at "${base}" uses ${embeddedDialect}, but this adapter uses ${dialect}.`, base, position);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (ignoresSiblings) {
|
|
362
|
+
for (const keyword of ['definitions', '$defs']) {
|
|
363
|
+
const children = record[keyword];
|
|
364
|
+
if (isRecord(children)) {
|
|
365
|
+
for (const [key, child] of Object.entries(children)) {
|
|
366
|
+
if (isRecord(child) || typeof child === 'boolean')
|
|
367
|
+
visit(child, base, `${position}/${keyword}/${escape(key)}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
for (const keyword of SINGLE[dialect]) {
|
|
374
|
+
const child = record[keyword];
|
|
375
|
+
if (isRecord(child) || typeof child === 'boolean')
|
|
376
|
+
visit(child, base, `${position}/${keyword}`);
|
|
377
|
+
}
|
|
378
|
+
for (const keyword of LIST[dialect]) {
|
|
379
|
+
const children = record[keyword];
|
|
380
|
+
if (Array.isArray(children))
|
|
381
|
+
children.forEach((child, index) => visit(child, base, `${position}/${keyword}/${index}`));
|
|
382
|
+
}
|
|
383
|
+
for (const keyword of MAP[dialect]) {
|
|
384
|
+
const children = record[keyword];
|
|
385
|
+
if (isRecord(children)) {
|
|
386
|
+
for (const [key, child] of Object.entries(children)) {
|
|
387
|
+
if (isRecord(child) || typeof child === 'boolean')
|
|
388
|
+
visit(child, base, `${position}/${keyword}/${escape(key)}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (dialect !== '2020-12' && Array.isArray(record.items)) {
|
|
393
|
+
record.items.forEach((child, index) => visit(child, base, `${position}/items/${index}`));
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
visit(document, initialBase, '#');
|
|
397
|
+
return ids;
|
|
398
|
+
}
|
|
399
|
+
function cloneValue(value, seen = new Map()) {
|
|
400
|
+
if (typeof value !== 'object' || value === null)
|
|
401
|
+
return value;
|
|
402
|
+
const previous = seen.get(value);
|
|
403
|
+
if (previous !== undefined)
|
|
404
|
+
return previous;
|
|
405
|
+
if (Array.isArray(value)) {
|
|
406
|
+
const copy = [];
|
|
407
|
+
seen.set(value, copy);
|
|
408
|
+
for (const child of value)
|
|
409
|
+
copy.push(cloneValue(child, seen));
|
|
410
|
+
return copy;
|
|
411
|
+
}
|
|
412
|
+
const copy = {};
|
|
413
|
+
seen.set(value, copy);
|
|
414
|
+
for (const [key, child] of Object.entries(value)) {
|
|
415
|
+
Object.defineProperty(copy, key, {
|
|
416
|
+
value: cloneValue(child, seen),
|
|
417
|
+
enumerable: true,
|
|
418
|
+
configurable: true,
|
|
419
|
+
writable: true,
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return copy;
|
|
423
|
+
}
|
|
424
|
+
function structurallyEqual(left, right, seen = new WeakMap()) {
|
|
425
|
+
if (Object.is(left, right))
|
|
426
|
+
return true;
|
|
427
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
428
|
+
return Array.isArray(left) && Array.isArray(right) &&
|
|
429
|
+
left.length === right.length && left.every((value, index) => structurallyEqual(value, right[index], seen));
|
|
430
|
+
}
|
|
431
|
+
if (!isRecord(left) || !isRecord(right))
|
|
432
|
+
return false;
|
|
433
|
+
const compared = seen.get(left) ?? new WeakSet();
|
|
434
|
+
if (compared.has(right))
|
|
435
|
+
return true;
|
|
436
|
+
compared.add(right);
|
|
437
|
+
seen.set(left, compared);
|
|
438
|
+
const leftKeys = Object.keys(left).sort();
|
|
439
|
+
const rightKeys = Object.keys(right).sort();
|
|
440
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => key === rightKeys[index] && structurallyEqual(left[key], right[key], seen));
|
|
441
|
+
}
|
|
442
|
+
function draft7AnchorTargets(source, retrievalUri) {
|
|
443
|
+
const targets = new Map();
|
|
444
|
+
const seen = new WeakMap();
|
|
445
|
+
const visit = (schema, parentBase, position, resourceBase, resourcePosition) => {
|
|
446
|
+
if (!isRecord(schema))
|
|
447
|
+
return;
|
|
448
|
+
const contexts = seen.get(schema) ?? new Set();
|
|
449
|
+
const context = `${parentBase}\u0000${resourcePosition}`;
|
|
450
|
+
if (contexts.has(context))
|
|
451
|
+
return;
|
|
452
|
+
contexts.add(context);
|
|
453
|
+
seen.set(schema, contexts);
|
|
454
|
+
const ignoresSiblings = typeof schema.$ref === 'string';
|
|
455
|
+
let base = parentBase;
|
|
456
|
+
let anchorBase = resourceBase;
|
|
457
|
+
let anchorPosition = resourcePosition;
|
|
458
|
+
if (!ignoresSiblings && typeof schema.$id === 'string') {
|
|
459
|
+
const resolved = absoluteUri(schema.$id, parentBase);
|
|
460
|
+
if (resolved !== undefined && schema.$id.startsWith('#')) {
|
|
461
|
+
const pointer = position.startsWith(resourcePosition) ? position.slice(resourcePosition.length) : position.slice(1);
|
|
462
|
+
targets.set(resolved, { base: resourceBase, pointer });
|
|
463
|
+
}
|
|
464
|
+
else if (resolved !== undefined) {
|
|
465
|
+
base = withoutFragment(resolved);
|
|
466
|
+
anchorBase = base;
|
|
467
|
+
anchorPosition = position;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const visitChild = (child, childPosition) => {
|
|
471
|
+
if (isRecord(child) || typeof child === 'boolean')
|
|
472
|
+
visit(child, base, childPosition, anchorBase, anchorPosition);
|
|
473
|
+
};
|
|
474
|
+
if (ignoresSiblings) {
|
|
475
|
+
for (const keyword of ['definitions', '$defs']) {
|
|
476
|
+
const map = schema[keyword];
|
|
477
|
+
if (isRecord(map)) {
|
|
478
|
+
for (const [key, child] of Object.entries(map))
|
|
479
|
+
visitChild(child, `${position}/${keyword}/${escape(key)}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
for (const keyword of SINGLE['draft-07'])
|
|
485
|
+
visitChild(schema[keyword], `${position}/${keyword}`);
|
|
486
|
+
for (const keyword of LIST['draft-07']) {
|
|
487
|
+
const list = schema[keyword];
|
|
488
|
+
if (Array.isArray(list))
|
|
489
|
+
list.forEach((child, index) => visitChild(child, `${position}/${keyword}/${index}`));
|
|
490
|
+
}
|
|
491
|
+
for (const keyword of MAP['draft-07']) {
|
|
492
|
+
const map = schema[keyword];
|
|
493
|
+
if (isRecord(map))
|
|
494
|
+
for (const [key, child] of Object.entries(map))
|
|
495
|
+
visitChild(child, `${position}/${keyword}/${escape(key)}`);
|
|
496
|
+
}
|
|
497
|
+
if (Array.isArray(schema.items))
|
|
498
|
+
schema.items.forEach((child, index) => visitChild(child, `${position}/items/${index}`));
|
|
499
|
+
};
|
|
500
|
+
visit(source, retrievalUri, '#', retrievalUri, '#');
|
|
501
|
+
return targets;
|
|
502
|
+
}
|
|
503
|
+
function remoteSchema(source, retrievalUri, dialect, canonicalBase, rootIdentifier) {
|
|
504
|
+
const sourceDocument = typeof source === 'boolean'
|
|
505
|
+
? { allOf: [source] }
|
|
506
|
+
: source;
|
|
507
|
+
const referenceKeywords = dialect === 'draft-07'
|
|
508
|
+
? new Set(['$ref'])
|
|
509
|
+
: dialect === '2019-09'
|
|
510
|
+
? new Set(['$ref', '$recursiveRef'])
|
|
511
|
+
: new Set(['$ref', '$dynamicRef']);
|
|
512
|
+
const legacyAnchors = dialect === 'draft-07' ? draft7AnchorTargets(source, retrievalUri) : new Map();
|
|
513
|
+
const memo = new WeakMap();
|
|
514
|
+
const visit = (value, parentBase, position, root = false) => {
|
|
515
|
+
if (!isRecord(value)) {
|
|
516
|
+
if (Array.isArray(value))
|
|
517
|
+
return value.map((child, index) => visit(child, parentBase, `${position}/${index}`));
|
|
518
|
+
return cloneValue(value);
|
|
519
|
+
}
|
|
520
|
+
const keyBase = parentBase;
|
|
521
|
+
const cached = memo.get(value)?.get(keyBase);
|
|
522
|
+
if (cached !== undefined)
|
|
523
|
+
return cached;
|
|
524
|
+
const originalId = value.$id;
|
|
525
|
+
const ignoresSiblings = dialect === 'draft-07' && typeof value.$ref === 'string';
|
|
526
|
+
let base = parentBase;
|
|
527
|
+
let resolvedId;
|
|
528
|
+
if (root) {
|
|
529
|
+
base = canonicalBase;
|
|
530
|
+
resolvedId = rootIdentifier;
|
|
531
|
+
}
|
|
532
|
+
else if (!ignoresSiblings && typeof originalId === 'string') {
|
|
533
|
+
resolvedId = absoluteUri(originalId, parentBase);
|
|
534
|
+
if (resolvedId === undefined) {
|
|
535
|
+
throw new SchemaResourceResolutionError(`Cannot resolve $id "${originalId}" at "${position}" in the resource retrieved from "${retrievalUri}".`, retrievalUri, position);
|
|
536
|
+
}
|
|
537
|
+
base = dialect === 'draft-07' && originalId.startsWith('#') ? parentBase : withoutFragment(resolvedId);
|
|
538
|
+
}
|
|
539
|
+
if (resolvedId !== undefined && withoutFragment(resolvedId).startsWith('file:')) {
|
|
540
|
+
throw new SchemaResourceResolutionError(`File schema resources are not supported: "${withoutFragment(resolvedId)}" at "${position}".`, withoutFragment(resolvedId), position);
|
|
541
|
+
}
|
|
542
|
+
const output = {};
|
|
543
|
+
const values = memo.get(value) ?? new Map();
|
|
544
|
+
values.set(keyBase, output);
|
|
545
|
+
memo.set(value, values);
|
|
546
|
+
for (const [keyword, child] of Object.entries(value)) {
|
|
547
|
+
if (keyword === '$id' && resolvedId !== undefined) {
|
|
548
|
+
const normalizedId = dialect === 'draft-07' && typeof originalId === 'string' && originalId.startsWith('#')
|
|
549
|
+
? originalId
|
|
550
|
+
: resolvedId;
|
|
551
|
+
Object.defineProperty(output, keyword, { value: normalizedId, enumerable: true, configurable: true, writable: true });
|
|
552
|
+
}
|
|
553
|
+
else if (referenceKeywords.has(keyword) && typeof child === 'string') {
|
|
554
|
+
const resolved = absoluteUri(child, base);
|
|
555
|
+
if (resolved === undefined) {
|
|
556
|
+
throw new SchemaResourceResolutionError(`Cannot resolve schema reference "${child}" at "${position}/${keyword}" in the resource retrieved from "${retrievalUri}".`, retrievalUri, `${position}/${keyword}`);
|
|
557
|
+
}
|
|
558
|
+
const anchor = legacyAnchors.get(resolved);
|
|
559
|
+
const normalizedReference = anchor === undefined ? resolved : `${anchor.base}#${anchor.pointer}`;
|
|
560
|
+
Object.defineProperty(output, keyword, { value: normalizedReference, enumerable: true, configurable: true, writable: true });
|
|
561
|
+
}
|
|
562
|
+
else if (ignoresSiblings && (keyword === 'definitions' || keyword === '$defs') && isRecord(child)) {
|
|
563
|
+
Object.defineProperty(output, keyword, { value: Object.fromEntries(Object.entries(child).map(([name, member]) => [
|
|
564
|
+
name,
|
|
565
|
+
isRecord(member) || typeof member === 'boolean' ? visit(member, base, `${position}/${keyword}/${escape(name)}`) : cloneValue(member),
|
|
566
|
+
])), enumerable: true, configurable: true, writable: true });
|
|
567
|
+
}
|
|
568
|
+
else if (ignoresSiblings) {
|
|
569
|
+
Object.defineProperty(output, keyword, { value: cloneValue(child), enumerable: true, configurable: true, writable: true });
|
|
570
|
+
}
|
|
571
|
+
else if (SINGLE[dialect].has(keyword) && (isRecord(child) || typeof child === 'boolean')) {
|
|
572
|
+
Object.defineProperty(output, keyword, { value: visit(child, base, `${position}/${keyword}`), enumerable: true, configurable: true, writable: true });
|
|
573
|
+
}
|
|
574
|
+
else if (LIST[dialect].has(keyword) && Array.isArray(child)) {
|
|
575
|
+
Object.defineProperty(output, keyword, { value: child.map((member, index) => visit(member, base, `${position}/${keyword}/${index}`)), enumerable: true, configurable: true, writable: true });
|
|
576
|
+
}
|
|
577
|
+
else if (MAP[dialect].has(keyword) && isRecord(child)) {
|
|
578
|
+
Object.defineProperty(output, keyword, { value: Object.fromEntries(Object.entries(child).map(([name, member]) => [
|
|
579
|
+
name,
|
|
580
|
+
Array.isArray(member) && keyword === 'dependencies'
|
|
581
|
+
? cloneValue(member)
|
|
582
|
+
: isRecord(member) || typeof member === 'boolean'
|
|
583
|
+
? visit(member, base, `${position}/${keyword}/${escape(name)}`)
|
|
584
|
+
: cloneValue(member),
|
|
585
|
+
])), enumerable: true, configurable: true, writable: true });
|
|
586
|
+
}
|
|
587
|
+
else if (keyword === 'items' && dialect !== '2020-12' && Array.isArray(child)) {
|
|
588
|
+
Object.defineProperty(output, keyword, { value: child.map((member, index) => visit(member, base, `${position}/items/${index}`)), enumerable: true, configurable: true, writable: true });
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
Object.defineProperty(output, keyword, { value: cloneValue(child), enumerable: true, configurable: true, writable: true });
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
if (root) {
|
|
595
|
+
output.$id = rootIdentifier;
|
|
596
|
+
if (!Object.hasOwn(output, '$schema')) {
|
|
597
|
+
output.$schema = dialect === 'draft-07'
|
|
598
|
+
? 'http://json-schema.org/draft-07/schema#'
|
|
599
|
+
: `https://json-schema.org/draft/${dialect}/schema`;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return output;
|
|
603
|
+
};
|
|
604
|
+
return visit(sourceDocument, retrievalUri, '#', true);
|
|
605
|
+
}
|
|
606
|
+
function canonicalRemote(uri, schema, dialect) {
|
|
607
|
+
if (!isRecord(schema) && typeof schema !== 'boolean') {
|
|
608
|
+
throw new SchemaResourceResolutionError(`The resource resolver returned a non-schema value for "${uri}".`, uri);
|
|
609
|
+
}
|
|
610
|
+
if (isRecord(schema) && schema.$id !== undefined && typeof schema.$id !== 'string') {
|
|
611
|
+
throw new SchemaResourceResolutionError(`The resource at "${uri}" has a non-string $id.`, uri);
|
|
612
|
+
}
|
|
613
|
+
const id = isRecord(schema) && typeof schema.$id === 'string' ? schema.$id : uri;
|
|
614
|
+
const resolvedId = absoluteUri(id, uri);
|
|
615
|
+
if (resolvedId === undefined) {
|
|
616
|
+
throw new SchemaResourceResolutionError(`The resource at "${uri}" declares an unresolvable $id.`, uri);
|
|
617
|
+
}
|
|
618
|
+
const canonicalBase = withoutFragment(resolvedId);
|
|
619
|
+
if (canonicalBase.startsWith('file:')) {
|
|
620
|
+
throw new SchemaResourceResolutionError(`File schema resources are not supported: "${canonicalBase}".`, canonicalBase);
|
|
621
|
+
}
|
|
622
|
+
const primary = remoteSchema(schema, uri, dialect, canonicalBase, resolvedId);
|
|
623
|
+
const aliases = withoutFragment(resolvedId) === uri
|
|
624
|
+
? []
|
|
625
|
+
: [remoteSchema(schema, uri, dialect, canonicalBase, dialect === 'draft-07' && resolvedId.includes('#') ? `${uri}${resolvedId.slice(resolvedId.indexOf('#'))}` : uri)];
|
|
626
|
+
return { primary, aliases, canonicalBase };
|
|
627
|
+
}
|
|
628
|
+
function isMetaSchema(uri) {
|
|
629
|
+
return META_URIS.has(uri);
|
|
630
|
+
}
|
|
631
|
+
export function assertNoFileSchemaIdentifiers(schema, dialect) {
|
|
632
|
+
const rootId = isRecord(schema) && typeof schema.$id === 'string'
|
|
633
|
+
? resourceBase(schema.$id, undefined, dialect)
|
|
634
|
+
: undefined;
|
|
635
|
+
for (const uri of declaredResourceIds(schema, rootId, dialect)) {
|
|
636
|
+
if (uri.startsWith('file:')) {
|
|
637
|
+
throw new Error(`Hyperjump does not support schema identifiers with the file: scheme: "${uri}".`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
export async function loadExternalResources(schema, dialect, options) {
|
|
642
|
+
const resolver = options?.resolveResource;
|
|
643
|
+
const rootId = isRecord(schema) && typeof schema.$id === 'string'
|
|
644
|
+
? resourceBase(schema.$id, undefined, dialect)
|
|
645
|
+
: undefined;
|
|
646
|
+
const known = declaredResourceIds(schema, rootId, dialect);
|
|
647
|
+
if (rootId)
|
|
648
|
+
known.add(rootId);
|
|
649
|
+
if (!resolver) {
|
|
650
|
+
referencesIn(schema, rootId, dialect, known);
|
|
651
|
+
return [];
|
|
652
|
+
}
|
|
653
|
+
const maximum = options.maxExternalResources ?? DEFAULT_MAX_EXTERNAL_RESOURCES;
|
|
654
|
+
if (!Number.isInteger(maximum) || maximum < 1) {
|
|
655
|
+
throw new RangeError('maxExternalResources must be a positive integer.');
|
|
656
|
+
}
|
|
657
|
+
const resources = new Map();
|
|
658
|
+
const documents = new Map();
|
|
659
|
+
const scanned = new Set();
|
|
660
|
+
const queue = [{ document: schema, base: rootId }];
|
|
661
|
+
const loading = new Map();
|
|
662
|
+
const load = (uri, position) => {
|
|
663
|
+
const existing = loading.get(uri);
|
|
664
|
+
if (existing)
|
|
665
|
+
return existing;
|
|
666
|
+
if (loading.size >= maximum) {
|
|
667
|
+
throw new SchemaResourceResolutionError(`The external schema resource limit of ${maximum} was exceeded at "${position}".`, uri, position);
|
|
668
|
+
}
|
|
669
|
+
const promise = Promise.resolve(resolver(uri)).then((resolved) => {
|
|
670
|
+
if (resolved === undefined) {
|
|
671
|
+
throw new SchemaResourceResolutionError(`No schema resource was returned for "${uri}" referenced at "${position}".`, uri, position);
|
|
672
|
+
}
|
|
673
|
+
return canonicalRemote(uri, resolved, dialect);
|
|
674
|
+
});
|
|
675
|
+
loading.set(uri, promise);
|
|
676
|
+
return promise;
|
|
677
|
+
};
|
|
678
|
+
while (queue.length > 0) {
|
|
679
|
+
const current = queue.shift();
|
|
680
|
+
const key = current.base ?? `anonymous:${scanned.size}`;
|
|
681
|
+
if (scanned.has(key))
|
|
682
|
+
continue;
|
|
683
|
+
scanned.add(key);
|
|
684
|
+
const references = referencesIn(current.document, current.base, dialect, known);
|
|
685
|
+
for (const { base, reference, position } of references) {
|
|
686
|
+
if (reference.startsWith('#')) {
|
|
687
|
+
const localUri = base === undefined ? undefined : absoluteUri(reference, base);
|
|
688
|
+
if (localUri !== undefined && withoutFragment(localUri).startsWith('file:')) {
|
|
689
|
+
throw new SchemaResourceResolutionError(`File schema resources are not supported: "${withoutFragment(localUri)}" at "${position}".`, withoutFragment(localUri), position);
|
|
690
|
+
}
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const resolved = absoluteUri(reference, base);
|
|
694
|
+
if (resolved === undefined) {
|
|
695
|
+
throw new SchemaResourceResolutionError(`Cannot resolve relative schema reference "${reference}" at "${position}" without an absolute base URI.`, undefined, position);
|
|
696
|
+
}
|
|
697
|
+
const uri = withoutFragment(resolved);
|
|
698
|
+
if (uri.startsWith('file:')) {
|
|
699
|
+
throw new SchemaResourceResolutionError(`File schema resources are not supported: "${uri}" at "${position}".`, uri, position);
|
|
700
|
+
}
|
|
701
|
+
if (!uri || isMetaSchema(uri) || known.has(uri) || resources.has(uri))
|
|
702
|
+
continue;
|
|
703
|
+
const loaded = await load(uri, position);
|
|
704
|
+
const remoteDialect = detectDialect(loaded.primary, { defaultDialect: dialect });
|
|
705
|
+
if (remoteDialect !== dialect) {
|
|
706
|
+
throw new SchemaResourceResolutionError(`The resource at "${uri}" uses ${remoteDialect}, but this adapter uses ${dialect}.`, uri, position);
|
|
707
|
+
}
|
|
708
|
+
resources.set(uri, loaded.primary);
|
|
709
|
+
known.add(uri);
|
|
710
|
+
const nested = declaredResourceIds(loaded.primary, loaded.canonicalBase, dialect);
|
|
711
|
+
for (const id of nested)
|
|
712
|
+
known.add(id);
|
|
713
|
+
const uniqueDocuments = [loaded.primary, ...loaded.aliases];
|
|
714
|
+
for (const document of uniqueDocuments) {
|
|
715
|
+
const id = isRecord(document) && typeof document.$id === 'string' ? document.$id : undefined;
|
|
716
|
+
if (id === undefined)
|
|
717
|
+
throw new SchemaResourceResolutionError(`A normalized resource for "${uri}" has no $id.`, uri, position);
|
|
718
|
+
const previous = documents.get(id);
|
|
719
|
+
if (previous !== undefined && !structurallyEqual(previous, document)) {
|
|
720
|
+
throw new SchemaResourceResolutionError(`Two retrieved resources declare conflicting schemas for "$id ${id}".`, uri, position);
|
|
721
|
+
}
|
|
722
|
+
documents.set(id, document);
|
|
723
|
+
known.add(withoutFragment(id));
|
|
724
|
+
}
|
|
725
|
+
queue.push({ document: loaded.primary, base: loaded.canonicalBase });
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return [...documents.values()];
|
|
729
|
+
}
|
|
730
|
+
//# sourceMappingURL=resources.js.map
|