@speclynx/apidom-reference 5.2.2 → 5.2.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/CHANGELOG.md +20 -0
- package/README.md +30 -11
- package/dist/apidom-reference.browser.js +1121 -516
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +28 -28
- package/src/bundle/strategies/arazzo-1/visitor.cjs +105 -22
- package/src/bundle/strategies/arazzo-1/visitor.mjs +107 -24
- package/src/bundle/strategies/openapi-3-1/visitor.cjs +197 -47
- package/src/bundle/strategies/openapi-3-1/visitor.mjs +200 -50
- package/src/bundle/util.cjs +57 -2
- package/src/bundle/util.mjs +52 -0
- package/src/dereference/strategies/arazzo-1/index.cjs +9 -7
- package/src/dereference/strategies/arazzo-1/index.mjs +3 -1
- package/src/dereference/strategies/arazzo-1/selectors/$anchor.cjs +6 -0
- package/src/dereference/strategies/arazzo-1/selectors/$anchor.mjs +1 -1
- package/src/dereference/strategies/arazzo-1/selectors/uri.cjs +6 -0
- package/src/dereference/strategies/arazzo-1/selectors/uri.mjs +1 -1
- package/src/dereference/strategies/arazzo-1/util.cjs +6 -0
- package/src/dereference/strategies/arazzo-1/util.mjs +1 -1
- package/src/dereference/strategies/arazzo-1/visitor.cjs +67 -9
- package/src/dereference/strategies/arazzo-1/visitor.mjs +71 -13
- package/src/dereference/strategies/openapi-3-1/index.cjs +2 -1
- package/src/dereference/strategies/openapi-3-1/index.mjs +3 -1
- package/src/dereference/strategies/openapi-3-1/selectors/$anchor.cjs +16 -4
- package/src/dereference/strategies/openapi-3-1/selectors/$anchor.mjs +14 -3
- package/src/dereference/strategies/openapi-3-1/selectors/json-pointer.cjs +29 -0
- package/src/dereference/strategies/openapi-3-1/selectors/json-pointer.mjs +22 -0
- package/src/dereference/strategies/openapi-3-1/selectors/uri.cjs +54 -27
- package/src/dereference/strategies/openapi-3-1/selectors/uri.mjs +51 -27
- package/src/dereference/strategies/openapi-3-1/util.cjs +75 -14
- package/src/dereference/strategies/openapi-3-1/util.mjs +68 -14
- package/src/dereference/strategies/openapi-3-1/visitor.cjs +85 -9
- package/src/dereference/strategies/openapi-3-1/visitor.mjs +89 -13
- package/src/util/url.cjs +35 -2
- package/src/util/url.mjs +32 -0
- package/types/apidom-reference.d.ts +12 -0
- package/types/bundle/strategies/arazzo-1/index.d.ts +1 -1
- package/types/bundle/strategies/arazzo-1/visitor.d.ts +51 -6
- package/types/bundle/strategies/openapi-3-1/index.d.ts +1 -1
- package/types/bundle/strategies/openapi-3-1/visitor.d.ts +59 -3
- package/types/bundle/util.d.ts +39 -0
- package/types/dereference/strategies/arazzo-1/selectors/$anchor.d.ts +1 -1
- package/types/dereference/strategies/arazzo-1/selectors/uri.d.ts +1 -1
- package/types/dereference/strategies/arazzo-1/util.d.ts +1 -1
- package/types/dereference/strategies/arazzo-1/visitor.d.ts +17 -1
- package/types/dereference/strategies/openapi-3-1/selectors/$anchor.d.ts +8 -0
- package/types/dereference/strategies/openapi-3-1/selectors/json-pointer.d.ts +9 -0
- package/types/dereference/strategies/openapi-3-1/selectors/uri.d.ts +37 -4
- package/types/dereference/strategies/openapi-3-1/util.d.ts +53 -2
- package/types/dereference/strategies/openapi-3-1/visitor.d.ts +17 -1
- package/types/util/url.d.ts +10 -0
|
@@ -67,6 +67,12 @@ const componentFieldElementByField = {
|
|
|
67
67
|
[cf.pathItems.name]: _apidomNsOpenapi.ComponentsPathItemsElement
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* A bundled element awaiting placement into the entry document's Components
|
|
72
|
+
* Object field.
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
|
|
70
76
|
/**
|
|
71
77
|
* @public
|
|
72
78
|
*/
|
|
@@ -124,18 +130,50 @@ class OpenAPI3_1BundleVisitor {
|
|
|
124
130
|
* generic object referenced once as a Parameter and once as a Response).
|
|
125
131
|
*/
|
|
126
132
|
refractCache;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Index of `$id`-bearing schemas per document, shared across the entry document
|
|
136
|
+
* and every external document visitor of a single bundle run so it never
|
|
137
|
+
* outlives mutations of the documents (e.g. the final placement of components).
|
|
138
|
+
*/
|
|
139
|
+
schema$idIndex;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Bundled fragments waiting to be placed into the entry document's
|
|
143
|
+
* Components Object, shared across the entry document and every external
|
|
144
|
+
* document visitor. Placement is deferred until the entry document traversal
|
|
145
|
+
* completes: the traversal walks live content, so placing a fragment mid-way
|
|
146
|
+
* would make it descend into the fragment and re-bundle its `$ref`s against
|
|
147
|
+
* the entry document's base URI instead of the fragment's own.
|
|
148
|
+
*/
|
|
149
|
+
placements;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The base URI the traversed content will have once placed into the entry
|
|
153
|
+
* document, when placement changes it: content hoisted out of a non-schema
|
|
154
|
+
* document (a Response, Parameter, Path Item, ...) trades that document's
|
|
155
|
+
* base URI for the entry document's. Unset for the entry document itself and
|
|
156
|
+
* for embedded schema resources, whose `$id` carries their base along.
|
|
157
|
+
*/
|
|
158
|
+
relocationBaseURI;
|
|
127
159
|
constructor({
|
|
128
160
|
reference,
|
|
129
161
|
options,
|
|
130
162
|
assignments = new Map(),
|
|
131
163
|
reservedNames = new Map(),
|
|
132
|
-
refractCache = new WeakMap()
|
|
164
|
+
refractCache = new WeakMap(),
|
|
165
|
+
schema$idIndex = new WeakMap(),
|
|
166
|
+
placements = [],
|
|
167
|
+
relocationBaseURI
|
|
133
168
|
}) {
|
|
134
169
|
this.reference = reference;
|
|
135
170
|
this.options = options;
|
|
136
171
|
this.assignments = assignments;
|
|
137
172
|
this.reservedNames = reservedNames;
|
|
138
173
|
this.refractCache = refractCache;
|
|
174
|
+
this.schema$idIndex = schema$idIndex;
|
|
175
|
+
this.placements = placements;
|
|
176
|
+
this.relocationBaseURI = relocationBaseURI;
|
|
139
177
|
}
|
|
140
178
|
getRefracted(source, type) {
|
|
141
179
|
return this.refractCache.get(source)?.get(type);
|
|
@@ -193,6 +231,22 @@ class OpenAPI3_1BundleVisitor {
|
|
|
193
231
|
return ref.startsWith('#') ? ref : url.getHash(ref);
|
|
194
232
|
}
|
|
195
233
|
|
|
234
|
+
/**
|
|
235
|
+
* The base URI the given Schema Object's `$ref` will be resolved against once
|
|
236
|
+
* the content is placed into the entry document, or `undefined` when the
|
|
237
|
+
* `$ref` as written resolves to `$refBaseURI` from there as well: the content
|
|
238
|
+
* isn't relocated, an absolute `$id` on the schema's ancestor chain pins its
|
|
239
|
+
* base, or the hoisted document sits next to the entry document.
|
|
240
|
+
*/
|
|
241
|
+
relocatedSchemaBaseURI(path, $refBaseURI) {
|
|
242
|
+
if (this.relocationBaseURI === undefined) return undefined;
|
|
243
|
+
const relocatedBaseURI = (0, _util.resolveSchemaBaseURI)(this.relocationBaseURI, path);
|
|
244
|
+
if ((0, _util.resolveSchema$refField)(relocatedBaseURI, path.node) === $refBaseURI) {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
return relocatedBaseURI;
|
|
248
|
+
}
|
|
249
|
+
|
|
196
250
|
/**
|
|
197
251
|
* Handles an error according to the `bundle.continueOnError` option.
|
|
198
252
|
*
|
|
@@ -311,13 +365,16 @@ class OpenAPI3_1BundleVisitor {
|
|
|
311
365
|
|
|
312
366
|
/**
|
|
313
367
|
* Computes a collision-free component name within the target field. A name is
|
|
314
|
-
* taken if it's already
|
|
315
|
-
* is still being bundled (reserved before recursion).
|
|
368
|
+
* taken if it's already present in the entry document's components or reserved
|
|
369
|
+
* by a component that is still being bundled (reserved before recursion).
|
|
316
370
|
*/
|
|
317
371
|
uniqueName(candidate, field) {
|
|
318
|
-
const
|
|
372
|
+
const {
|
|
373
|
+
components
|
|
374
|
+
} = this.entryResult;
|
|
375
|
+
const fieldElement = (0, _apidomDatamodel.isObjectElement)(components) ? components.get(field) : undefined;
|
|
319
376
|
const reserved = this.reservedNames.get(field) ?? new Set();
|
|
320
|
-
return (0, _util2.uniqueName)(candidate, name => fieldElement.hasKey(name) || reserved.has(name));
|
|
377
|
+
return (0, _util2.uniqueName)(candidate, name => (0, _apidomDatamodel.isObjectElement)(fieldElement) && fieldElement.hasKey(name) || reserved.has(name));
|
|
321
378
|
}
|
|
322
379
|
|
|
323
380
|
/**
|
|
@@ -341,6 +398,28 @@ class OpenAPI3_1BundleVisitor {
|
|
|
341
398
|
// append (never prepend) so the result element stays ahead of annotations
|
|
342
399
|
this.entryParseResult.content.push(annotation);
|
|
343
400
|
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* The entry document traversal is rooted at its Parse Result (nested
|
|
404
|
+
* traversals are rooted at fragments), so leaving it marks the moment the
|
|
405
|
+
* whole entry document has been visited and the collected fragments can be
|
|
406
|
+
* placed into its Components Object without the traversal descending into them.
|
|
407
|
+
* Guarded on the node so that a traversal rooted at any other Parse Result
|
|
408
|
+
* never flushes the shared placements early.
|
|
409
|
+
*/
|
|
410
|
+
ParseResultElement = {
|
|
411
|
+
leave: path => {
|
|
412
|
+
if (path.node !== this.entryParseResult) return;
|
|
413
|
+
for (const {
|
|
414
|
+
field,
|
|
415
|
+
name,
|
|
416
|
+
element
|
|
417
|
+
} of this.placements) {
|
|
418
|
+
this.ensureComponentsField(field).set(name, element);
|
|
419
|
+
}
|
|
420
|
+
this.placements.length = 0;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
344
423
|
async ReferenceElement(path) {
|
|
345
424
|
const referencingElement = path.node;
|
|
346
425
|
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
@@ -428,14 +507,19 @@ class OpenAPI3_1BundleVisitor {
|
|
|
428
507
|
if (!this.reservedNames.has(field)) this.reservedNames.set(field, new Set());
|
|
429
508
|
this.reservedNames.get(field).add(componentName);
|
|
430
509
|
|
|
431
|
-
// own a copy of the fragment and bundle its own external references
|
|
510
|
+
// own a copy of the fragment and bundle its own external references; the
|
|
511
|
+
// fragment ends up in the entry document, so that is where its content
|
|
512
|
+
// resolves relative references from
|
|
432
513
|
const hoistedElement = (0, _apidomDatamodel.cloneDeep)(referencedElement);
|
|
433
514
|
const visitor = new OpenAPI3_1BundleVisitor({
|
|
434
515
|
reference,
|
|
435
516
|
options: this.options,
|
|
436
517
|
assignments: this.assignments,
|
|
437
518
|
reservedNames: this.reservedNames,
|
|
438
|
-
refractCache: this.refractCache
|
|
519
|
+
refractCache: this.refractCache,
|
|
520
|
+
schema$idIndex: this.schema$idIndex,
|
|
521
|
+
placements: this.placements,
|
|
522
|
+
relocationBaseURI: this.entryURI
|
|
439
523
|
});
|
|
440
524
|
const bundledElement = await (0, _apidomTraverse.traverseAsync)(hoistedElement, visitor, {
|
|
441
525
|
mutable: true
|
|
@@ -446,8 +530,12 @@ class OpenAPI3_1BundleVisitor {
|
|
|
446
530
|
bundledElement.meta.set('ref-origin', reference.uri);
|
|
447
531
|
}
|
|
448
532
|
|
|
449
|
-
//
|
|
450
|
-
this.
|
|
533
|
+
// queue the bundled fragment for placement into the entry document's components
|
|
534
|
+
this.placements.push({
|
|
535
|
+
field,
|
|
536
|
+
name: componentName,
|
|
537
|
+
element: bundledElement
|
|
538
|
+
});
|
|
451
539
|
|
|
452
540
|
// rewrite the referencing element to point at the hoisted fragment
|
|
453
541
|
referencingElement.set('$ref', internalPointer);
|
|
@@ -536,14 +624,19 @@ class OpenAPI3_1BundleVisitor {
|
|
|
536
624
|
if (!this.reservedNames.has(field)) this.reservedNames.set(field, new Set());
|
|
537
625
|
this.reservedNames.get(field).add(componentName);
|
|
538
626
|
|
|
539
|
-
// own a copy of the fragment and bundle its own external references
|
|
627
|
+
// own a copy of the fragment and bundle its own external references; the
|
|
628
|
+
// Path Item ends up in the entry document, so that is where its content
|
|
629
|
+
// resolves relative references from
|
|
540
630
|
const hoistedElement = (0, _apidomDatamodel.cloneDeep)(referencedElement);
|
|
541
631
|
const visitor = new OpenAPI3_1BundleVisitor({
|
|
542
632
|
reference,
|
|
543
633
|
options: this.options,
|
|
544
634
|
assignments: this.assignments,
|
|
545
635
|
reservedNames: this.reservedNames,
|
|
546
|
-
refractCache: this.refractCache
|
|
636
|
+
refractCache: this.refractCache,
|
|
637
|
+
schema$idIndex: this.schema$idIndex,
|
|
638
|
+
placements: this.placements,
|
|
639
|
+
relocationBaseURI: this.entryURI
|
|
547
640
|
});
|
|
548
641
|
const bundledElement = await (0, _apidomTraverse.traverseAsync)(hoistedElement, visitor, {
|
|
549
642
|
mutable: true
|
|
@@ -554,8 +647,12 @@ class OpenAPI3_1BundleVisitor {
|
|
|
554
647
|
// internal `#/components/pathItems/...` pointer by the child traversal
|
|
555
648
|
bundledElement.meta.set('ref-origin', reference.uri);
|
|
556
649
|
|
|
557
|
-
//
|
|
558
|
-
this.
|
|
650
|
+
// queue the bundled Path Item for placement into the entry document's components
|
|
651
|
+
this.placements.push({
|
|
652
|
+
field,
|
|
653
|
+
name: componentName,
|
|
654
|
+
element: bundledElement
|
|
655
|
+
});
|
|
559
656
|
|
|
560
657
|
// rewrite the referencing Path Item to point at the hoisted one, keeping
|
|
561
658
|
// any sibling fields (e.g. summary, description) next to the $ref
|
|
@@ -590,7 +687,8 @@ class OpenAPI3_1BundleVisitor {
|
|
|
590
687
|
// toReference) so an internal $ref needs no resolution and never trips the
|
|
591
688
|
// resolve.maxDepth guard, matching how ReferenceElement returns early.
|
|
592
689
|
const retrievalURI = this.reference.uri;
|
|
593
|
-
const
|
|
690
|
+
const schemaBaseURI = (0, _util.resolveSchemaBaseURI)(retrievalURI, path);
|
|
691
|
+
const $refBaseURI = (0, _util.resolveSchema$refField)(schemaBaseURI, referencingElement);
|
|
594
692
|
const $refBaseURIStrippedHash = url.stripHash($refBaseURI);
|
|
595
693
|
const file = new _File.default({
|
|
596
694
|
uri: $refBaseURIStrippedHash
|
|
@@ -626,59 +724,95 @@ class OpenAPI3_1BundleVisitor {
|
|
|
626
724
|
// as a canonical URI / URL against the current document's $id graph; if
|
|
627
725
|
// that fails, fall back to fetching the external document and resolving
|
|
628
726
|
// the fragment there as a $anchor or JSON Pointer.
|
|
727
|
+
//
|
|
728
|
+
// the fragment being traversed is searched before the whole document:
|
|
729
|
+
// content hoisted out of an external document (a Response, Parameter, Path
|
|
730
|
+
// Item, ...) is refracted with its own semantics, so the Schema Objects it
|
|
731
|
+
// contains are indexed, whereas the external document as a whole is parsed
|
|
732
|
+
// generically and refracted as a bare JSON Schema, which leaves those Schema
|
|
733
|
+
// Objects (under `content`, `schema`, ...) unrecognized and their `$id`s out
|
|
734
|
+
// of the index
|
|
735
|
+
const documentElement = this.reference.value.result;
|
|
736
|
+
const rootNode = path.getAncestorNodes().at(-1) ?? path.node;
|
|
737
|
+
const fragmentElement = (0, _apidomDatamodel.isParseResultElement)(rootNode) ? rootNode.result : rootNode;
|
|
738
|
+
const uriEvaluateOptions = {
|
|
739
|
+
baseURI: retrievalURI,
|
|
740
|
+
index: this.schema$idIndex
|
|
741
|
+
};
|
|
629
742
|
let schemaReference = this.reference;
|
|
743
|
+
let resourceRoot;
|
|
744
|
+
let resourceBaseURI;
|
|
630
745
|
try {
|
|
631
|
-
|
|
632
|
-
|
|
746
|
+
try {
|
|
747
|
+
(0, _uri.evaluate)($refBaseURI, (0, _util.maybeRefractToSchemaElement)(fragmentElement), uriEvaluateOptions);
|
|
748
|
+
// a $ref that resolves (by $id/$anchor/pointer) within the traversed
|
|
749
|
+
// content is internal even when its URI form (e.g. a URN or absolute
|
|
750
|
+
// $id) is not a bare fragment: the $id resource travels with the content
|
|
751
|
+
// wherever it is placed. Leave it untouched — it resolves against the
|
|
752
|
+
// in-content $id graph, and embedding the content into itself would be
|
|
753
|
+
// wrong.
|
|
754
|
+
return;
|
|
755
|
+
} catch (error) {
|
|
756
|
+
if (!(error instanceof _EvaluationJsonSchemaUriError.default) || fragmentElement === documentElement) {
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
const documentAsSchema = (0, _util.maybeRefractToSchemaElement)(documentElement);
|
|
760
|
+
(0, _uri.evaluate)($refBaseURI, documentAsSchema, uriEvaluateOptions);
|
|
761
|
+
// the $id resource sits in the current document but outside the
|
|
762
|
+
// traversed fragment, so it stays behind once the fragment is placed
|
|
763
|
+
// into the entry document. The resource to embed is that $id-bearing
|
|
764
|
+
// schema, addressed by its canonical URI (the $ref without fragment).
|
|
765
|
+
resourceRoot = (0, _uri.evaluate)($refBaseURIStrippedHash, documentAsSchema, uriEvaluateOptions);
|
|
766
|
+
resourceBaseURI = $refBaseURIStrippedHash;
|
|
767
|
+
}
|
|
633
768
|
} catch (error) {
|
|
634
769
|
if (isURL && error instanceof _EvaluationJsonSchemaUriError.default) {
|
|
770
|
+
schemaReference = await this.toReference(url.unsanitize($refBaseURI));
|
|
771
|
+
const referenceAsSchema = (0, _util.maybeRefractToSchemaElement)(schemaReference.value.result);
|
|
635
772
|
if ((0, _$anchor.isAnchor)((0, _$anchor.uriToAnchor)($refBaseURI))) {
|
|
636
|
-
schemaReference = await this.toReference(url.unsanitize($refBaseURI));
|
|
637
773
|
const selector = (0, _$anchor.uriToAnchor)($refBaseURI);
|
|
638
|
-
const referenceAsSchema = (0, _util.maybeRefractToSchemaElement)(schemaReference.value.result);
|
|
639
774
|
(0, _$anchor.evaluate)(selector, referenceAsSchema);
|
|
640
775
|
} else {
|
|
641
|
-
schemaReference = await this.toReference(url.unsanitize($refBaseURI));
|
|
642
776
|
const selector = _apidomJsonPointer.URIFragmentIdentifier.fromURIReference($refBaseURI);
|
|
643
|
-
const referenceAsSchema = (0, _util.maybeRefractToSchemaElement)(schemaReference.value.result);
|
|
644
777
|
(0, _apidomJsonPointer.evaluate)(referenceAsSchema, selector);
|
|
645
778
|
}
|
|
779
|
+
|
|
780
|
+
// the resource to embed is the WHOLE external document (its root
|
|
781
|
+
// schema), identified by its $id. A $ref into a fragment of the
|
|
782
|
+
// document embeds the entire document resource once; the fragment
|
|
783
|
+
// keeps resolving against the embedded $id.
|
|
784
|
+
resourceRoot = referenceAsSchema;
|
|
785
|
+
resourceBaseURI = (0, _util.resolveSchema$idField)(url.stripHash(schemaReference.uri), resourceRoot) ?? url.stripHash(schemaReference.uri);
|
|
646
786
|
} else {
|
|
647
787
|
throw error;
|
|
648
788
|
}
|
|
649
789
|
}
|
|
650
|
-
|
|
651
|
-
// a $ref that resolves (by $id/$anchor/pointer) within the current document
|
|
652
|
-
// is internal even when its URI form (e.g. a URN or absolute $id) is not a
|
|
653
|
-
// bare fragment. Leave it untouched — it resolves against the in-document
|
|
654
|
-
// $id graph, and embedding the current document into itself would be wrong.
|
|
655
|
-
if (url.stripHash(schemaReference.uri) === url.stripHash(this.reference.uri)) {
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
// the resource to embed is the WHOLE external document (its root schema),
|
|
660
|
-
// identified by its $id. A $ref into a fragment of the document embeds the
|
|
661
|
-
// entire document resource once; the fragment keeps resolving against the
|
|
662
|
-
// embedded $id.
|
|
663
|
-
const resourceRoot = (0, _util.maybeRefractToSchemaElement)(schemaReference.value.result);
|
|
664
|
-
const resourceBaseURI = (0, _util.resolveSchema$idField)(url.stripHash(schemaReference.uri), resourceRoot) ?? url.stripHash(schemaReference.uri);
|
|
665
790
|
const field = cf.schemas.name;
|
|
666
791
|
const canonicalKey = `${field}\t${resourceBaseURI}`;
|
|
667
792
|
|
|
668
|
-
//
|
|
669
|
-
// $
|
|
793
|
+
// a location-based $ref to a self-identifying resource is rebased onto the
|
|
794
|
+
// resource's $id (keeping its fragment) — once embedded, the resource is
|
|
795
|
+
// reachable only by its $id. A $ref already resolving to that $id is left
|
|
796
|
+
// as written. See rebaseSchema$ref for the spec trade-off.
|
|
797
|
+
//
|
|
798
|
+
// a $ref whose base URI changes on relocation into the entry document
|
|
799
|
+
// (inside a hoisted Response, Parameter, Path Item, ...) is instead
|
|
800
|
+
// rewritten to address the embedded resource from the base it will have
|
|
801
|
+
// there, otherwise it dangles once placed. See relocateSchema$ref.
|
|
802
|
+
const relocatedBaseURI = this.relocatedSchemaBaseURI(path, $refBaseURI);
|
|
803
|
+
const rebased$ref = relocatedBaseURI === undefined ? (0, _util2.rebaseSchema$ref)($refBaseURI, resourceBaseURI) : (0, _util2.relocateSchema$ref)($refBaseURI, resourceBaseURI, relocatedBaseURI, (0, _apidomDatamodel.isStringElement)(resourceRoot.$id));
|
|
804
|
+
|
|
805
|
+
// resource already embedded (or being embedded) — point the referencing
|
|
806
|
+
// $ref at it and stop. This also terminates circular external schema
|
|
670
807
|
// references, since the assignment is reserved BEFORE recursion.
|
|
671
808
|
if (this.assignments.has(canonicalKey)) {
|
|
809
|
+
if (rebased$ref !== undefined) referencingElement.set('$ref', rebased$ref);
|
|
672
810
|
path.skip();
|
|
673
811
|
return;
|
|
674
812
|
}
|
|
675
813
|
|
|
676
|
-
// own a copy of the resource
|
|
677
|
-
// $ref still resolves against it once embedded
|
|
814
|
+
// own a copy of the resource
|
|
678
815
|
const embeddedElement = (0, _apidomDatamodel.cloneDeep)(resourceRoot);
|
|
679
|
-
if (!(0, _apidomDatamodel.isStringElement)(embeddedElement.$id)) {
|
|
680
|
-
embeddedElement.set('$id', resourceBaseURI);
|
|
681
|
-
}
|
|
682
816
|
|
|
683
817
|
// the embedded thing is the WHOLE resource (keyed by its $id), so its name
|
|
684
818
|
// is derived from the resource URI, not the $ref fragment — passing a root
|
|
@@ -700,20 +834,36 @@ class OpenAPI3_1BundleVisitor {
|
|
|
700
834
|
options: this.options,
|
|
701
835
|
assignments: this.assignments,
|
|
702
836
|
reservedNames: this.reservedNames,
|
|
703
|
-
refractCache: this.refractCache
|
|
837
|
+
refractCache: this.refractCache,
|
|
838
|
+
schema$idIndex: this.schema$idIndex,
|
|
839
|
+
placements: this.placements
|
|
704
840
|
});
|
|
705
841
|
const bundledElement = await (0, _apidomTraverse.traverseAsync)(embeddedElement, visitor, {
|
|
706
842
|
mutable: true
|
|
707
843
|
});
|
|
708
844
|
|
|
845
|
+
// a resource without its own $id is identified by its retrieval URI; write
|
|
846
|
+
// it relative to the entry document (the base of components.schemas) so the
|
|
847
|
+
// bundle carries no absolute filesystem path and stays relocatable. Assigned
|
|
848
|
+
// after the nested traversal so a reader deriving a schema's base from live
|
|
849
|
+
// $ids (see #540) never resolves the resource's own $refs against the entry
|
|
850
|
+
// document.
|
|
851
|
+
if (!(0, _apidomDatamodel.isStringElement)(bundledElement.$id)) {
|
|
852
|
+
bundledElement.set('$id', url.relative(this.entryURI, resourceBaseURI));
|
|
853
|
+
}
|
|
854
|
+
|
|
709
855
|
// annotate the embedded resource with info about its origin
|
|
710
856
|
bundledElement.meta.set('ref-origin', schemaReference.uri);
|
|
711
857
|
|
|
712
|
-
//
|
|
713
|
-
this.
|
|
858
|
+
// queue the embedded resource for placement into the entry document's components
|
|
859
|
+
this.placements.push({
|
|
860
|
+
field,
|
|
861
|
+
name: componentName,
|
|
862
|
+
element: bundledElement
|
|
863
|
+
});
|
|
714
864
|
|
|
715
|
-
// the referencing $ref
|
|
716
|
-
|
|
865
|
+
// point the referencing $ref at the embedded resource's $id
|
|
866
|
+
if (rebased$ref !== undefined) referencingElement.set('$ref', rebased$ref);
|
|
717
867
|
path.skip();
|
|
718
868
|
} catch (error) {
|
|
719
869
|
this.handleError(`Error while bundling Schema Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|