@speclynx/apidom-reference 6.1.2 → 7.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/CHANGELOG.md +63 -0
- package/README.md +57 -0
- package/dist/apidom-reference.browser.js +5783 -3741
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +31 -30
- package/src/File.cjs +5 -2
- package/src/File.mjs +5 -2
- package/src/bundle/index.cjs +6 -4
- package/src/bundle/index.mjs +6 -4
- package/src/bundle/strategies/arazzo-1/index.cjs +3 -2
- package/src/bundle/strategies/arazzo-1/index.mjs +3 -2
- package/src/bundle/strategies/asyncapi-2/index.cjs +3 -2
- package/src/bundle/strategies/asyncapi-2/index.mjs +3 -2
- package/src/bundle/strategies/openapi-2/index.cjs +3 -2
- package/src/bundle/strategies/openapi-2/index.mjs +3 -2
- package/src/bundle/strategies/openapi-3-0/index.cjs +3 -2
- package/src/bundle/strategies/openapi-3-0/index.mjs +3 -2
- package/src/bundle/strategies/openapi-3-1/index.cjs +3 -2
- package/src/bundle/strategies/openapi-3-1/index.mjs +3 -2
- package/src/dereference/index.cjs +8 -5
- package/src/dereference/index.mjs +8 -5
- package/src/dereference/strategies/DereferenceVisitor.cjs +588 -0
- package/src/dereference/strategies/DereferenceVisitor.mjs +580 -0
- package/src/dereference/strategies/arazzo-1/index.cjs +14 -39
- package/src/dereference/strategies/arazzo-1/index.mjs +15 -40
- package/src/dereference/strategies/arazzo-1/visitor.cjs +207 -331
- package/src/dereference/strategies/arazzo-1/visitor.mjs +215 -338
- package/src/dereference/strategies/asyncapi-2/index.cjs +11 -39
- package/src/dereference/strategies/asyncapi-2/index.mjs +11 -39
- package/src/dereference/strategies/asyncapi-2/visitor.cjs +133 -425
- package/src/dereference/strategies/asyncapi-2/visitor.mjs +137 -429
- package/src/dereference/strategies/openapi-2/index.cjs +12 -42
- package/src/dereference/strategies/openapi-2/index.mjs +12 -42
- package/src/dereference/strategies/openapi-2/visitor.cjs +168 -532
- package/src/dereference/strategies/openapi-2/visitor.mjs +172 -536
- package/src/dereference/strategies/openapi-3-0/index.cjs +12 -42
- package/src/dereference/strategies/openapi-3-0/index.mjs +12 -42
- package/src/dereference/strategies/openapi-3-0/visitor.cjs +194 -468
- package/src/dereference/strategies/openapi-3-0/visitor.mjs +199 -473
- package/src/dereference/strategies/openapi-3-1/index.cjs +16 -42
- package/src/dereference/strategies/openapi-3-1/index.mjs +16 -42
- package/src/dereference/strategies/openapi-3-1/visitor.cjs +350 -602
- package/src/dereference/strategies/openapi-3-1/visitor.mjs +357 -608
- package/src/dereference/strategies/overlay-1/index.cjs +3 -2
- package/src/dereference/strategies/overlay-1/index.mjs +3 -2
- package/src/index.cjs +0 -7
- package/src/index.mjs +0 -1
- package/src/options/index.cjs +4 -0
- package/src/options/index.mjs +4 -0
- package/src/options/util.cjs +7 -1
- package/src/options/util.mjs +8 -2
- package/src/parse/index.cjs +9 -1
- package/src/parse/index.mjs +9 -1
- package/src/parse/parsers/apidom-json/index.cjs +2 -1
- package/src/parse/parsers/apidom-json/index.mjs +2 -1
- package/src/parse/parsers/arazzo-json-1/index.cjs +2 -1
- package/src/parse/parsers/arazzo-json-1/index.mjs +2 -1
- package/src/parse/parsers/arazzo-yaml-1/index.cjs +2 -1
- package/src/parse/parsers/arazzo-yaml-1/index.mjs +2 -1
- package/src/parse/parsers/asyncapi-json-2/index.cjs +2 -1
- package/src/parse/parsers/asyncapi-json-2/index.mjs +2 -1
- package/src/parse/parsers/asyncapi-yaml-2/index.cjs +2 -1
- package/src/parse/parsers/asyncapi-yaml-2/index.mjs +2 -1
- package/src/parse/parsers/json/index.cjs +2 -1
- package/src/parse/parsers/json/index.mjs +2 -1
- package/src/parse/parsers/openapi-json-2/index.cjs +2 -1
- package/src/parse/parsers/openapi-json-2/index.mjs +2 -1
- package/src/parse/parsers/openapi-json-3-0/index.cjs +2 -1
- package/src/parse/parsers/openapi-json-3-0/index.mjs +2 -1
- package/src/parse/parsers/openapi-json-3-1/index.cjs +2 -1
- package/src/parse/parsers/openapi-json-3-1/index.mjs +2 -1
- package/src/parse/parsers/openapi-yaml-2/index.cjs +2 -1
- package/src/parse/parsers/openapi-yaml-2/index.mjs +2 -1
- package/src/parse/parsers/openapi-yaml-3-0/index.cjs +2 -1
- package/src/parse/parsers/openapi-yaml-3-0/index.mjs +2 -1
- package/src/parse/parsers/openapi-yaml-3-1/index.cjs +2 -1
- package/src/parse/parsers/openapi-yaml-3-1/index.mjs +2 -1
- package/src/parse/parsers/overlay-json-1/index.cjs +2 -1
- package/src/parse/parsers/overlay-json-1/index.mjs +2 -1
- package/src/parse/parsers/overlay-yaml-1/index.cjs +2 -1
- package/src/parse/parsers/overlay-yaml-1/index.mjs +2 -1
- package/src/parse/parsers/yaml-1-2/index.cjs +2 -1
- package/src/parse/parsers/yaml-1-2/index.mjs +2 -1
- package/src/resolve/index.cjs +6 -3
- package/src/resolve/index.mjs +6 -3
- package/src/util/url.cjs +38 -8
- package/src/util/url.mjs +35 -6
- package/types/apidom-reference.d.ts +13 -9
- package/types/dereference/strategies/DereferenceVisitor.d.ts +224 -0
- package/types/dereference/strategies/arazzo-1/index.d.ts +0 -1
- package/types/dereference/strategies/arazzo-1/visitor.d.ts +38 -38
- package/types/dereference/strategies/asyncapi-2/index.d.ts +0 -1
- package/types/dereference/strategies/asyncapi-2/visitor.d.ts +13 -29
- package/types/dereference/strategies/openapi-2/index.d.ts +0 -1
- package/types/dereference/strategies/openapi-2/visitor.d.ts +14 -29
- package/types/dereference/strategies/openapi-3-0/index.d.ts +0 -1
- package/types/dereference/strategies/openapi-3-0/visitor.d.ts +13 -28
- package/types/dereference/strategies/openapi-3-1/index.d.ts +0 -1
- package/types/dereference/strategies/openapi-3-1/visitor.d.ts +37 -33
- package/types/index.d.ts +0 -1
- package/types/util/url.d.ts +11 -0
- package/LICENSES/AFL-3.0.txt +0 -182
- package/LICENSES/BSD-3-Clause.txt +0 -26
- package/src/dereference/util.cjs +0 -33
- package/src/dereference/util.mjs +0 -27
- package/types/dereference/util.d.ts +0 -9
|
@@ -1,363 +1,147 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { toValue, toYAML } from '@speclynx/apidom-core';
|
|
1
|
+
import { isStringElement, cloneShallow } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
4
3
|
import { ApiDOMStructuredError } from '@speclynx/apidom-error';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import UnresolvableReferenceError from "../../../errors/UnresolvableReferenceError.mjs";
|
|
9
|
-
import MaximumDereferenceDepthError from "../../../errors/MaximumDereferenceDepthError.mjs";
|
|
10
|
-
import MaximumResolveDepthError from "../../../errors/MaximumResolveDepthError.mjs";
|
|
11
|
-
import { AncestorLineage } from "../../util.mjs";
|
|
4
|
+
import { evaluate as jsonPointerEvaluate, URIFragmentIdentifier } from '@speclynx/apidom-json-pointer';
|
|
5
|
+
import { isReferenceLikeElement, isJSONReferenceLikeElement, isPathItemElement, isReferenceElement, isJSONReferenceElement, refract, refractReference, refractJSONReference } from '@speclynx/apidom-ns-openapi-2';
|
|
6
|
+
import DereferenceVisitor from "../DereferenceVisitor.mjs";
|
|
12
7
|
import * as url from "../../../util/url.mjs";
|
|
13
|
-
import parse from "../../../parse/index.mjs";
|
|
14
|
-
import Reference from "../../../Reference.mjs";
|
|
15
8
|
/**
|
|
16
9
|
* @public
|
|
17
10
|
*/
|
|
18
11
|
/**
|
|
12
|
+
* Dereferences an OpenAPI 2.0 document. Reference Objects and JSON Reference Objects expect
|
|
13
|
+
* the type of their `referenced-element` meta, Path Item `$ref`s a Path Item Object.
|
|
14
|
+
*
|
|
19
15
|
* @public
|
|
20
16
|
*/
|
|
21
|
-
class OpenAPI2DereferenceVisitor {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
options;
|
|
25
|
-
refractCache;
|
|
26
|
-
visited;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Tracks element ancestors across dive-deep traversal boundaries.
|
|
30
|
-
* Used for cycle detection: if a referenced element is found in
|
|
31
|
-
* the ancestor lineage, a circular reference is detected.
|
|
32
|
-
*/
|
|
33
|
-
ancestors;
|
|
34
|
-
constructor({
|
|
35
|
-
reference,
|
|
36
|
-
options,
|
|
37
|
-
indirections = [],
|
|
38
|
-
ancestors = new AncestorLineage(),
|
|
39
|
-
refractCache = new WeakMap(),
|
|
40
|
-
visited = new WeakSet()
|
|
41
|
-
}) {
|
|
42
|
-
this.indirections = indirections;
|
|
43
|
-
this.reference = reference;
|
|
44
|
-
this.options = options;
|
|
45
|
-
this.refractCache = refractCache;
|
|
46
|
-
this.ancestors = new AncestorLineage(...ancestors);
|
|
47
|
-
this.visited = visited;
|
|
48
|
-
}
|
|
49
|
-
toAncestorLineage(path) {
|
|
50
|
-
const ancestorNodes = path.getAncestorNodes();
|
|
51
|
-
const directAncestors = new Set(ancestorNodes.filter(isElement));
|
|
52
|
-
const ancestorsLineage = new AncestorLineage(...this.ancestors, directAncestors);
|
|
53
|
-
return [ancestorsLineage, directAncestors];
|
|
17
|
+
class OpenAPI2DereferenceVisitor extends DereferenceVisitor {
|
|
18
|
+
get strategyName() {
|
|
19
|
+
return 'openapi-2';
|
|
54
20
|
}
|
|
55
|
-
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// detect maximum depth of resolution
|
|
60
|
-
if (this.reference.depth >= this.options.resolve.maxDepth) {
|
|
61
|
-
throw new MaximumResolveDepthError(`Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`, {
|
|
62
|
-
maxDepth: this.options.resolve.maxDepth,
|
|
63
|
-
uri: this.reference.uri
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
const baseURI = this.toBaseURI(uri);
|
|
67
|
-
const {
|
|
68
|
-
refSet
|
|
69
|
-
} = this.reference;
|
|
70
|
-
|
|
71
|
-
// we've already processed this Reference in past
|
|
72
|
-
if (refSet.has(baseURI)) {
|
|
73
|
-
return refSet.find(propEq(baseURI, 'uri'));
|
|
74
|
-
}
|
|
75
|
-
const parseResult = await parse(url.unsanitize(baseURI), {
|
|
76
|
-
...this.options,
|
|
77
|
-
parse: {
|
|
78
|
-
...this.options.parse,
|
|
79
|
-
mediaType: 'text/plain'
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// register new mutable reference with a refSet
|
|
84
|
-
//
|
|
85
|
-
// NOTE(known limitation): the mutable reference is mutated in place during traversal
|
|
86
|
-
// (via `{ mutable: true }`). When an external document evaluates a JSON pointer back
|
|
87
|
-
// into this document, it may receive an already-resolved element instead of the original
|
|
88
|
-
// $ref. That resolved element was produced using the entry document's resolution context
|
|
89
|
-
// (ancestors, indirections), which may differ from the external document's context.
|
|
90
|
-
// This can affect cycle detection in rare cross-document circular reference patterns.
|
|
91
|
-
//
|
|
92
|
-
// Remediation: evaluate JSON pointers against the immutable (original) parse tree
|
|
93
|
-
// instead of the mutable working copy. The `immutable://` reference below preserves
|
|
94
|
-
// the original tree and could be used for pointer evaluation, ensuring every resolution
|
|
95
|
-
// context always sees raw, unresolved elements and processes them with its own
|
|
96
|
-
// ancestors/indirections. The trade-off is that elements referenced by multiple
|
|
97
|
-
// documents would be resolved once per context instead of being reused.
|
|
98
|
-
const mutableReference = new Reference({
|
|
99
|
-
uri: baseURI,
|
|
100
|
-
value: this.options.dereference.immutable ? cloneDeep(parseResult) : parseResult,
|
|
101
|
-
depth: this.reference.depth + 1
|
|
21
|
+
createVisitor(reference) {
|
|
22
|
+
return new OpenAPI2DereferenceVisitor({
|
|
23
|
+
reference,
|
|
24
|
+
options: this.options
|
|
102
25
|
});
|
|
103
|
-
refSet.add(mutableReference);
|
|
104
|
-
if (this.options.dereference.immutable) {
|
|
105
|
-
// register new immutable reference with a refSet
|
|
106
|
-
const immutableReference = new Reference({
|
|
107
|
-
uri: `immutable://${baseURI}`,
|
|
108
|
-
value: parseResult,
|
|
109
|
-
depth: this.reference.depth + 1
|
|
110
|
-
});
|
|
111
|
-
refSet.add(immutableReference);
|
|
112
|
-
}
|
|
113
|
-
return mutableReference;
|
|
114
26
|
}
|
|
115
27
|
|
|
116
28
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* For new errors: wraps in UnresolvableReferenceError with structured context
|
|
120
|
-
* (type, uri, location, codeFrame, refFieldName, refFieldValue, trace).
|
|
121
|
-
* For errors already wrapped by a nested visitor: prepends the current hop to the trace.
|
|
122
|
-
*
|
|
123
|
-
* Inner/intermediate visitors always throw to let the trace accumulate.
|
|
124
|
-
* Only the entry document visitor respects continueOnError (callback/swallow/throw).
|
|
29
|
+
* A (JSON) Reference Object stands for the type its reference expects: it's dereferenced as that type.
|
|
125
30
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} = this.options.dereference;
|
|
130
|
-
const isEntryDocument = url.stripHash(this.reference.refSet?.rootRef?.uri ?? '') === this.reference.uri;
|
|
131
|
-
const uri = this.reference.uri;
|
|
132
|
-
const type = referencingElement.element;
|
|
133
|
-
const codeFrame = toYAML(referencingElement);
|
|
31
|
+
isOfType(element, type) {
|
|
32
|
+
return isReferenceElement(element) || isJSONReferenceElement(element) || element.element === type;
|
|
33
|
+
}
|
|
134
34
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
location = p.formatPath();
|
|
146
|
-
p.stop();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
});
|
|
35
|
+
/**
|
|
36
|
+
* A generic structure holding a `$ref` is a reference to the expected type: a JSON Reference
|
|
37
|
+
* Object for a Schema Object, a Reference Object otherwise, unless the type has its own `$ref`
|
|
38
|
+
* field (Path Item Object).
|
|
39
|
+
*/
|
|
40
|
+
refractTo(element, type) {
|
|
41
|
+
if (type === 'schema' && isJSONReferenceLikeElement(element)) {
|
|
42
|
+
const referenceElement = refractJSONReference(element);
|
|
43
|
+
referenceElement.meta.set('referenced-element', type);
|
|
44
|
+
return referenceElement;
|
|
150
45
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
refFieldName,
|
|
156
|
-
refFieldValue,
|
|
157
|
-
location,
|
|
158
|
-
codeFrame
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// enrich existing error from nested visitor or create new one
|
|
162
|
-
let unresolvedError;
|
|
163
|
-
if (error instanceof UnresolvableReferenceError) {
|
|
164
|
-
// prefix relative locations for entries belonging to the referenced document
|
|
165
|
-
const refBaseURI = this.toBaseURI(refFieldValue);
|
|
166
|
-
const fragment = URIFragmentIdentifier.fromURIReference(refFieldValue);
|
|
167
|
-
if (fragment) {
|
|
168
|
-
if (refBaseURI === error.uri && error.location) {
|
|
169
|
-
error.location = fragment + error.location;
|
|
170
|
-
}
|
|
171
|
-
for (const h of error.trace) {
|
|
172
|
-
if (h.uri === refBaseURI && h.location) h.location = fragment + h.location;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
// @ts-ignore
|
|
176
|
-
error.trace = [hop, ...error.trace];
|
|
177
|
-
unresolvedError = error;
|
|
178
|
-
} else {
|
|
179
|
-
unresolvedError = new UnresolvableReferenceError(message, {
|
|
180
|
-
cause: error,
|
|
181
|
-
type,
|
|
182
|
-
uri,
|
|
183
|
-
location,
|
|
184
|
-
codeFrame,
|
|
185
|
-
refFieldName,
|
|
186
|
-
refFieldValue,
|
|
187
|
-
trace: []
|
|
188
|
-
});
|
|
46
|
+
if (type !== 'schema' && type !== 'pathItem' && isReferenceLikeElement(element)) {
|
|
47
|
+
const referenceElement = refractReference(element);
|
|
48
|
+
referenceElement.meta.set('referenced-element', type);
|
|
49
|
+
return referenceElement;
|
|
189
50
|
}
|
|
190
|
-
|
|
191
|
-
|
|
51
|
+
return refract(element, {
|
|
52
|
+
element: type
|
|
53
|
+
});
|
|
192
54
|
}
|
|
193
55
|
async ReferenceElement(path) {
|
|
194
56
|
const referencingElement = path.node;
|
|
195
57
|
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
58
|
+
// the fields of a Reference Object hold no references
|
|
59
|
+
path.skip();
|
|
200
60
|
|
|
201
|
-
//
|
|
202
|
-
if (this.
|
|
203
|
-
path.skip();
|
|
61
|
+
// ignore Reference Object without a string $ref, e.g. an empty YAML value
|
|
62
|
+
if (this.isTranscluded(referencingElement) || !isStringElement(referencingElement.$ref)) {
|
|
204
63
|
return;
|
|
205
64
|
}
|
|
206
|
-
const
|
|
65
|
+
const $ref = toValue(referencingElement.$ref);
|
|
66
|
+
const retrievalURI = this.toBaseURI($ref);
|
|
207
67
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
208
68
|
const isExternalReference = !isInternalReference;
|
|
209
69
|
|
|
210
70
|
// ignore resolving internal Reference Objects
|
|
211
71
|
if (!this.options.resolve.internal && isInternalReference) {
|
|
212
|
-
// skip traversing this reference element and all it's child elements
|
|
213
|
-
path.skip();
|
|
214
72
|
return;
|
|
215
73
|
}
|
|
216
74
|
// ignore resolving external Reference Objects
|
|
217
75
|
if (!this.options.resolve.external && isExternalReference) {
|
|
218
|
-
// skip traversing this reference element and all it's child elements
|
|
219
|
-
path.skip();
|
|
220
76
|
return;
|
|
221
77
|
}
|
|
222
|
-
const $refBaseURI = url.resolve(retrievalURI,
|
|
223
|
-
const indirectionsSize = this.indirections.length;
|
|
78
|
+
const $refBaseURI = url.resolve(retrievalURI, $ref);
|
|
224
79
|
try {
|
|
225
|
-
const reference = await this.toReference(
|
|
226
|
-
this.indirections.push(referencingElement);
|
|
80
|
+
const reference = await this.toReference($ref);
|
|
227
81
|
const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
|
|
228
|
-
|
|
229
82
|
// possibly non-semantic fragment
|
|
230
|
-
|
|
83
|
+
const referencedElement = jsonPointerEvaluate(reference.value.result, jsonPointer);
|
|
231
84
|
|
|
232
|
-
//
|
|
233
|
-
const referencedElementType = referencingElement.meta.get('referenced-element');
|
|
234
|
-
if (referencedElement.element !== referencedElementType && !isReferenceElement(referencedElement)) {
|
|
235
|
-
if (this.refractCache.has(referencedElement)) {
|
|
236
|
-
referencedElement = this.refractCache.get(referencedElement);
|
|
237
|
-
} else if (isReferenceLikeElement(referencedElement)) {
|
|
238
|
-
// handling generic indirect references
|
|
239
|
-
const sourceElement = referencedElement;
|
|
240
|
-
referencedElement = refractReference(referencedElement);
|
|
241
|
-
referencedElement.meta.set('referenced-element', referencedElementType);
|
|
242
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
243
|
-
} else {
|
|
244
|
-
// handling direct references
|
|
245
|
-
const sourceElement = referencedElement;
|
|
246
|
-
referencedElement = refract(referencedElement, {
|
|
247
|
-
element: referencedElementType
|
|
248
|
-
});
|
|
249
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// detect direct or indirect reference
|
|
85
|
+
// detect direct reference
|
|
254
86
|
if (referencingElement === referencedElement) {
|
|
255
87
|
throw new ApiDOMStructuredError('Recursive Reference Object detected', {
|
|
256
|
-
$ref
|
|
88
|
+
$ref
|
|
257
89
|
});
|
|
258
90
|
}
|
|
259
91
|
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
92
|
+
// a reference without an expected type reads its target as its own type
|
|
93
|
+
const type = toValue(referencingElement.meta.get('referenced-element')) ?? referencedElement.element;
|
|
94
|
+
await this.addTransclusion(path, {
|
|
95
|
+
source: referencedElement,
|
|
96
|
+
type,
|
|
97
|
+
reference,
|
|
98
|
+
context: undefined
|
|
99
|
+
}, {
|
|
100
|
+
toTranscludedElement: (element, target) => {
|
|
101
|
+
// a chain of Reference Objects leading back to itself never reaches a value
|
|
102
|
+
if (isReferenceElement(target)) return element;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Creating a new version of referenced element to avoid modifying the original one.
|
|
106
|
+
*/
|
|
107
|
+
const mergedElement = cloneShallow(target);
|
|
108
|
+
// annotate referenced element with info about original referencing element
|
|
109
|
+
mergedElement.meta.set('ref-fields', {
|
|
110
|
+
$ref
|
|
275
111
|
});
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
112
|
+
// annotate fragment with info about origin
|
|
113
|
+
mergedElement.meta.set('ref-origin', reference.uri);
|
|
114
|
+
mergedElement.meta.set('ref-type', element.element);
|
|
115
|
+
return mergedElement;
|
|
116
|
+
},
|
|
117
|
+
circular: {
|
|
118
|
+
uri: $refBaseURI,
|
|
119
|
+
meta: {
|
|
279
120
|
uri: reference.uri,
|
|
280
|
-
$ref
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
path.skip();
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Dive deep into the fragment.
|
|
292
|
-
*
|
|
293
|
-
* Cases to consider:
|
|
294
|
-
* 1. We're crossing document boundary
|
|
295
|
-
* 2. Fragment is from non-entry document
|
|
296
|
-
* 3. Fragment is a Reference Object. We need to follow it to get the eventual value
|
|
297
|
-
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
|
|
298
|
-
*/
|
|
299
|
-
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
300
|
-
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
301
|
-
if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
302
|
-
if (shouldDetectCircular) {
|
|
303
|
-
this.visited.add(referencedElement);
|
|
121
|
+
$ref
|
|
122
|
+
},
|
|
123
|
+
details: {
|
|
124
|
+
$ref
|
|
125
|
+
}
|
|
304
126
|
}
|
|
305
|
-
|
|
306
|
-
// append referencing reference to ancestors lineage
|
|
307
|
-
directAncestors.add(referencingElement);
|
|
308
|
-
const visitor = new OpenAPI2DereferenceVisitor({
|
|
309
|
-
reference,
|
|
310
|
-
indirections: [...this.indirections],
|
|
311
|
-
options: this.options,
|
|
312
|
-
refractCache: this.refractCache,
|
|
313
|
-
visited: this.visited,
|
|
314
|
-
ancestors: ancestorsLineage
|
|
315
|
-
});
|
|
316
|
-
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
317
|
-
mutable: true,
|
|
318
|
-
skipVisited: 'skip'
|
|
319
|
-
});
|
|
320
|
-
directAncestors.delete(referencingElement);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Creating a new version of referenced element to avoid modifying the original one.
|
|
325
|
-
*/
|
|
326
|
-
const mergedElement = cloneShallow(referencedElement);
|
|
327
|
-
// annotate referenced element with info about original referencing element
|
|
328
|
-
mergedElement.meta.set('ref-fields', {
|
|
329
|
-
$ref: toValue(referencingElement.$ref)
|
|
330
127
|
});
|
|
331
|
-
// annotate fragment with info about origin
|
|
332
|
-
mergedElement.meta.set('ref-origin', reference.uri);
|
|
333
|
-
mergedElement.meta.set('ref-type', referencingElement.element);
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Transclude referencing element with merged referenced element.
|
|
337
|
-
*/
|
|
338
|
-
path.replaceWith(mergedElement);
|
|
339
|
-
path.skip();
|
|
340
128
|
} catch (error) {
|
|
341
|
-
const $ref = toValue(referencingElement.$ref);
|
|
342
129
|
this.handleError(`Error while dereferencing Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
343
|
-
} finally {
|
|
344
|
-
if (this.indirections.length > indirectionsSize) this.indirections.pop();
|
|
345
130
|
}
|
|
346
131
|
}
|
|
347
132
|
async PathItemElement(path) {
|
|
348
133
|
const referencingElement = path.node;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (!isStringElement(referencingElement.$ref)) {
|
|
134
|
+
if (this.isTranscluded(referencingElement)) {
|
|
135
|
+
path.skip();
|
|
352
136
|
return;
|
|
353
137
|
}
|
|
354
138
|
|
|
355
|
-
//
|
|
356
|
-
if (
|
|
357
|
-
path.skip();
|
|
139
|
+
// ignore PathItemElement without $ref field
|
|
140
|
+
if (!isStringElement(referencingElement.$ref)) {
|
|
358
141
|
return;
|
|
359
142
|
}
|
|
360
|
-
const
|
|
143
|
+
const $ref = toValue(referencingElement.$ref);
|
|
144
|
+
const retrievalURI = this.toBaseURI($ref);
|
|
361
145
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
362
146
|
const isExternalReference = !isInternalReference;
|
|
363
147
|
|
|
@@ -371,287 +155,139 @@ class OpenAPI2DereferenceVisitor {
|
|
|
371
155
|
// skip traversing this Path Item element but traverse all it's child elements
|
|
372
156
|
return;
|
|
373
157
|
}
|
|
374
|
-
const $refBaseURI = url.resolve(retrievalURI,
|
|
375
|
-
const indirectionsSize = this.indirections.length;
|
|
158
|
+
const $refBaseURI = url.resolve(retrievalURI, $ref);
|
|
376
159
|
try {
|
|
377
|
-
const reference = await this.toReference(
|
|
378
|
-
this.indirections.push(referencingElement);
|
|
160
|
+
const reference = await this.toReference($ref);
|
|
379
161
|
const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
|
|
380
|
-
|
|
381
162
|
// possibly non-semantic referenced element
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
// applying semantics to a referenced element
|
|
385
|
-
if (!isPathItemElement(referencedElement)) {
|
|
386
|
-
if (this.refractCache.has(referencedElement)) {
|
|
387
|
-
referencedElement = this.refractCache.get(referencedElement);
|
|
388
|
-
} else {
|
|
389
|
-
const sourceElement = referencedElement;
|
|
390
|
-
referencedElement = refractPathItem(referencedElement);
|
|
391
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
163
|
+
const referencedElement = jsonPointerEvaluate(reference.value.result, jsonPointer);
|
|
394
164
|
|
|
395
|
-
// detect direct
|
|
165
|
+
// detect direct reference
|
|
396
166
|
if (referencingElement === referencedElement) {
|
|
397
167
|
throw new ApiDOMStructuredError('Recursive Path Item Object reference detected', {
|
|
398
|
-
$ref
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// detect maximum depth of dereferencing
|
|
403
|
-
if (this.indirections.length > this.options.dereference.maxDepth) {
|
|
404
|
-
throw new MaximumDereferenceDepthError(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`, {
|
|
405
|
-
maxDepth: this.options.dereference.maxDepth,
|
|
406
|
-
uri: this.reference.uri
|
|
168
|
+
$ref
|
|
407
169
|
});
|
|
408
170
|
}
|
|
171
|
+
await this.addTransclusion(path, {
|
|
172
|
+
source: referencedElement,
|
|
173
|
+
type: 'pathItem',
|
|
174
|
+
reference,
|
|
175
|
+
context: undefined
|
|
176
|
+
}, {
|
|
177
|
+
toTranscludedElement: (element, target) => {
|
|
178
|
+
if (!isPathItemElement(target)) return target;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creating a new version of Path Item by merging fields from referenced Path Item with referencing one.
|
|
182
|
+
*/
|
|
183
|
+
const mergedElement = cloneShallow(target);
|
|
184
|
+
// existing keywords from referencing PathItemElement overrides ones from referenced element
|
|
185
|
+
element.forEach((value, keyElement, item) => {
|
|
186
|
+
mergedElement.remove(toValue(keyElement));
|
|
187
|
+
mergedElement.content.push(item);
|
|
188
|
+
});
|
|
189
|
+
mergedElement.remove('$ref');
|
|
409
190
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
reference.refSet.circular = true;
|
|
414
|
-
if (this.options.dereference.circular === 'error') {
|
|
415
|
-
throw new ApiDOMStructuredError('Circular reference detected', {
|
|
416
|
-
$ref: toValue(referencingElement.$ref)
|
|
191
|
+
// annotate referenced element with info about original referencing element
|
|
192
|
+
mergedElement.meta.set('ref-fields', {
|
|
193
|
+
$ref
|
|
417
194
|
});
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
195
|
+
// annotate referenced element with info about origin and type
|
|
196
|
+
mergedElement.meta.set('ref-origin', reference.uri);
|
|
197
|
+
mergedElement.meta.set('ref-type', element.element);
|
|
198
|
+
return mergedElement;
|
|
199
|
+
},
|
|
200
|
+
aliasField: '$ref',
|
|
201
|
+
circular: {
|
|
202
|
+
uri: $refBaseURI,
|
|
203
|
+
meta: {
|
|
421
204
|
uri: reference.uri,
|
|
422
|
-
$ref
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
path.skip();
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Dive deep into the fragment.
|
|
434
|
-
*
|
|
435
|
-
* Cases to consider:
|
|
436
|
-
* 1. We're crossing document boundary
|
|
437
|
-
* 2. Fragment is from non-entry document
|
|
438
|
-
* 3. Fragment is a Path Item Object with $ref field. We need to follow it to get the eventual value
|
|
439
|
-
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
|
|
440
|
-
*/
|
|
441
|
-
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
442
|
-
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
443
|
-
if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
444
|
-
if (shouldDetectCircular) {
|
|
445
|
-
this.visited.add(referencedElement);
|
|
205
|
+
$ref
|
|
206
|
+
},
|
|
207
|
+
details: {
|
|
208
|
+
$ref
|
|
209
|
+
}
|
|
446
210
|
}
|
|
447
|
-
|
|
448
|
-
// append referencing reference to ancestors lineage
|
|
449
|
-
directAncestors.add(referencingElement);
|
|
450
|
-
const visitor = new OpenAPI2DereferenceVisitor({
|
|
451
|
-
reference,
|
|
452
|
-
indirections: [...this.indirections],
|
|
453
|
-
options: this.options,
|
|
454
|
-
refractCache: this.refractCache,
|
|
455
|
-
visited: this.visited,
|
|
456
|
-
ancestors: ancestorsLineage
|
|
457
|
-
});
|
|
458
|
-
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
459
|
-
mutable: true,
|
|
460
|
-
skipVisited: 'skip'
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
// remove referencing reference from ancestors lineage
|
|
464
|
-
directAncestors.delete(referencingElement);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Creating a new version of Path Item by merging fields from referenced Path Item with referencing one.
|
|
469
|
-
*/
|
|
470
|
-
if (isPathItemElement(referencedElement)) {
|
|
471
|
-
const mergedElement = cloneShallow(referencedElement);
|
|
472
|
-
// existing keywords from referencing PathItemElement overrides ones from referenced element
|
|
473
|
-
referencingElement.forEach((value, keyElement, item) => {
|
|
474
|
-
mergedElement.remove(toValue(keyElement));
|
|
475
|
-
mergedElement.content.push(item);
|
|
476
|
-
});
|
|
477
|
-
mergedElement.remove('$ref');
|
|
478
|
-
|
|
479
|
-
// annotate referenced element with info about original referencing element
|
|
480
|
-
mergedElement.meta.set('ref-fields', {
|
|
481
|
-
$ref: toValue(referencingElement.$ref)
|
|
482
|
-
});
|
|
483
|
-
// annotate referenced element with info about origin and type
|
|
484
|
-
mergedElement.meta.set('ref-origin', reference.uri);
|
|
485
|
-
mergedElement.meta.set('ref-type', referencingElement.element);
|
|
486
|
-
referencedElement = mergedElement;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Transclude referencing element with merged referenced element.
|
|
491
|
-
*/
|
|
492
|
-
path.replaceWith(referencedElement);
|
|
493
|
-
return;
|
|
211
|
+
});
|
|
494
212
|
} catch (error) {
|
|
495
|
-
const $ref = toValue(referencingElement.$ref);
|
|
496
213
|
this.handleError(`Error while dereferencing Path Item Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
497
|
-
} finally {
|
|
498
|
-
if (this.indirections.length > indirectionsSize) this.indirections.pop();
|
|
499
214
|
}
|
|
500
215
|
}
|
|
501
216
|
async JSONReferenceElement(path) {
|
|
502
217
|
const referencingElement = path.node;
|
|
503
218
|
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
219
|
+
// the fields of a JSON Reference Object hold no references
|
|
220
|
+
path.skip();
|
|
508
221
|
|
|
509
|
-
//
|
|
510
|
-
if (this.
|
|
511
|
-
path.skip();
|
|
222
|
+
// ignore JSON Reference Object without a string $ref, e.g. an empty YAML value
|
|
223
|
+
if (this.isTranscluded(referencingElement) || !isStringElement(referencingElement.$ref)) {
|
|
512
224
|
return;
|
|
513
225
|
}
|
|
514
|
-
const
|
|
226
|
+
const $ref = toValue(referencingElement.$ref);
|
|
227
|
+
const retrievalURI = this.toBaseURI($ref);
|
|
515
228
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
516
229
|
const isExternalReference = !isInternalReference;
|
|
517
230
|
|
|
518
|
-
// ignore resolving internal
|
|
231
|
+
// ignore resolving internal JSON Reference Objects
|
|
519
232
|
if (!this.options.resolve.internal && isInternalReference) {
|
|
520
|
-
// skip traversing this JSONReference element and all it's child elements
|
|
521
|
-
path.skip();
|
|
522
233
|
return;
|
|
523
234
|
}
|
|
524
|
-
// ignore resolving external
|
|
235
|
+
// ignore resolving external JSON Reference Objects
|
|
525
236
|
if (!this.options.resolve.external && isExternalReference) {
|
|
526
|
-
// skip traversing this JSONReference element and all it's child elements
|
|
527
|
-
path.skip();
|
|
528
237
|
return;
|
|
529
238
|
}
|
|
530
|
-
const $refBaseURI = url.resolve(retrievalURI,
|
|
531
|
-
const indirectionsSize = this.indirections.length;
|
|
239
|
+
const $refBaseURI = url.resolve(retrievalURI, $ref);
|
|
532
240
|
try {
|
|
533
|
-
const reference = await this.toReference(
|
|
534
|
-
this.indirections.push(referencingElement);
|
|
241
|
+
const reference = await this.toReference($ref);
|
|
535
242
|
const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
|
|
536
|
-
|
|
537
243
|
// possibly non-semantic fragment
|
|
538
|
-
|
|
244
|
+
const referencedElement = jsonPointerEvaluate(reference.value.result, jsonPointer);
|
|
539
245
|
|
|
540
|
-
//
|
|
541
|
-
const referencedElementType = referencingElement.meta.get('referenced-element');
|
|
542
|
-
if (referencedElement.element !== referencedElementType && !isJSONReferenceElement(referencedElement)) {
|
|
543
|
-
if (this.refractCache.has(referencedElement)) {
|
|
544
|
-
referencedElement = this.refractCache.get(referencedElement);
|
|
545
|
-
} else if (isJSONReferenceLikeElement(referencedElement)) {
|
|
546
|
-
// handling generic indirect references
|
|
547
|
-
const sourceElement = referencedElement;
|
|
548
|
-
referencedElement = refractJSONReference(referencedElement);
|
|
549
|
-
referencedElement.meta.set('referenced-element', referencedElementType);
|
|
550
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
551
|
-
} else {
|
|
552
|
-
// handling direct references
|
|
553
|
-
const sourceElement = referencedElement;
|
|
554
|
-
referencedElement = refract(referencedElement, {
|
|
555
|
-
element: referencedElementType
|
|
556
|
-
});
|
|
557
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// detect direct or indirect reference
|
|
246
|
+
// detect direct reference
|
|
562
247
|
if (referencingElement === referencedElement) {
|
|
563
248
|
throw new ApiDOMStructuredError('Recursive JSON Reference Object detected', {
|
|
564
|
-
$ref
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// detect maximum depth of dereferencing
|
|
569
|
-
if (this.indirections.length > this.options.dereference.maxDepth) {
|
|
570
|
-
throw new MaximumDereferenceDepthError(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`, {
|
|
571
|
-
maxDepth: this.options.dereference.maxDepth,
|
|
572
|
-
uri: this.reference.uri
|
|
249
|
+
$ref
|
|
573
250
|
});
|
|
574
251
|
}
|
|
575
252
|
|
|
576
|
-
//
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
253
|
+
// a reference without an expected type reads its target as its own type
|
|
254
|
+
const type = toValue(referencingElement.meta.get('referenced-element')) ?? referencedElement.element;
|
|
255
|
+
await this.addTransclusion(path, {
|
|
256
|
+
source: referencedElement,
|
|
257
|
+
type,
|
|
258
|
+
reference,
|
|
259
|
+
context: undefined
|
|
260
|
+
}, {
|
|
261
|
+
toTranscludedElement: (element, target) => {
|
|
262
|
+
// a chain of JSON Reference Objects leading back to itself never reaches a value
|
|
263
|
+
if (isJSONReferenceElement(target)) return element;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Creating a new version of referenced element to avoid modifying the original one.
|
|
267
|
+
*/
|
|
268
|
+
const mergedElement = cloneShallow(target);
|
|
269
|
+
// annotate referenced element with info about original referencing element
|
|
270
|
+
mergedElement.meta.set('ref-fields', {
|
|
271
|
+
$ref
|
|
583
272
|
});
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
273
|
+
// annotate fragment with info about origin
|
|
274
|
+
mergedElement.meta.set('ref-origin', reference.uri);
|
|
275
|
+
mergedElement.meta.set('ref-type', element.element);
|
|
276
|
+
return mergedElement;
|
|
277
|
+
},
|
|
278
|
+
circular: {
|
|
279
|
+
uri: $refBaseURI,
|
|
280
|
+
meta: {
|
|
587
281
|
uri: reference.uri,
|
|
588
|
-
$ref
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
path.skip();
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Dive deep into the fragment.
|
|
600
|
-
*
|
|
601
|
-
* Cases to consider:
|
|
602
|
-
* 1. We're crossing document boundary
|
|
603
|
-
2. Fragment is from non-entry document
|
|
604
|
-
* 3. Fragment is a JSON Reference Object. We need to follow it to get the eventual value
|
|
605
|
-
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
|
|
606
|
-
*/
|
|
607
|
-
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
608
|
-
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
609
|
-
if ((isExternalReference || isNonEntryDocument || isJSONReferenceElement(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
610
|
-
if (shouldDetectCircular) {
|
|
611
|
-
this.visited.add(referencedElement);
|
|
282
|
+
$ref
|
|
283
|
+
},
|
|
284
|
+
details: {
|
|
285
|
+
$ref
|
|
286
|
+
}
|
|
612
287
|
}
|
|
613
|
-
|
|
614
|
-
// append referencing reference to ancestors lineage
|
|
615
|
-
directAncestors.add(referencingElement);
|
|
616
|
-
const visitor = new OpenAPI2DereferenceVisitor({
|
|
617
|
-
reference,
|
|
618
|
-
indirections: [...this.indirections],
|
|
619
|
-
options: this.options,
|
|
620
|
-
refractCache: this.refractCache,
|
|
621
|
-
visited: this.visited,
|
|
622
|
-
ancestors: ancestorsLineage
|
|
623
|
-
});
|
|
624
|
-
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
625
|
-
mutable: true,
|
|
626
|
-
skipVisited: 'skip'
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
// remove referencing reference from ancestors lineage
|
|
630
|
-
directAncestors.delete(referencingElement);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Creating a new version of referenced element to avoid modifying the original one.
|
|
635
|
-
*/
|
|
636
|
-
const mergedElement = cloneShallow(referencedElement);
|
|
637
|
-
// annotate referenced element with info about original referencing element
|
|
638
|
-
mergedElement.meta.set('ref-fields', {
|
|
639
|
-
$ref: toValue(referencingElement.$ref)
|
|
640
288
|
});
|
|
641
|
-
// annotate fragment with info about origin
|
|
642
|
-
mergedElement.meta.set('ref-origin', reference.uri);
|
|
643
|
-
mergedElement.meta.set('ref-type', referencingElement.element);
|
|
644
|
-
|
|
645
|
-
/**
|
|
646
|
-
* Transclude referencing element with merged referenced element.
|
|
647
|
-
*/
|
|
648
|
-
path.replaceWith(mergedElement);
|
|
649
|
-
path.skip();
|
|
650
289
|
} catch (error) {
|
|
651
|
-
const $ref = toValue(referencingElement.$ref);
|
|
652
290
|
this.handleError(`Error while dereferencing JSON Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
653
|
-
} finally {
|
|
654
|
-
if (this.indirections.length > indirectionsSize) this.indirections.pop();
|
|
655
291
|
}
|
|
656
292
|
}
|
|
657
293
|
}
|