@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
|
@@ -6,520 +6,228 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
8
|
exports.default = void 0;
|
|
9
|
-
var _ramda = require("ramda");
|
|
10
9
|
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
11
10
|
var _apidomCore = require("@speclynx/apidom-core");
|
|
12
11
|
var _apidomError = require("@speclynx/apidom-error");
|
|
13
|
-
var _apidomTraverse = require("@speclynx/apidom-traverse");
|
|
14
12
|
var _apidomJsonPointer = require("@speclynx/apidom-json-pointer");
|
|
15
13
|
var _apidomNsAsyncapi = require("@speclynx/apidom-ns-asyncapi-2");
|
|
16
|
-
var
|
|
17
|
-
var _MaximumDereferenceDepthError = _interopRequireDefault(require("../../../errors/MaximumDereferenceDepthError.cjs"));
|
|
18
|
-
var _MaximumResolveDepthError = _interopRequireDefault(require("../../../errors/MaximumResolveDepthError.cjs"));
|
|
19
|
-
var _util = require("../../util.cjs");
|
|
14
|
+
var _DereferenceVisitor = _interopRequireDefault(require("../DereferenceVisitor.cjs"));
|
|
20
15
|
var url = _interopRequireWildcard(require("../../../util/url.cjs"));
|
|
21
|
-
var _index = _interopRequireDefault(require("../../../parse/index.cjs"));
|
|
22
|
-
var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
|
|
23
16
|
/**
|
|
24
17
|
* @public
|
|
25
18
|
*/
|
|
26
19
|
|
|
27
20
|
/**
|
|
21
|
+
* Dereferences an AsyncAPI 2 document. Reference Objects expect the type of their
|
|
22
|
+
* `referenced-element` meta, Channel Item `$ref`s a Channel Item Object.
|
|
23
|
+
*
|
|
28
24
|
* @public
|
|
29
25
|
*/
|
|
30
|
-
class AsyncAPI2DereferenceVisitor {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
options;
|
|
34
|
-
refractCache;
|
|
35
|
-
visited;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Tracks element ancestors across dive-deep traversal boundaries.
|
|
39
|
-
* Used for cycle detection: if a referenced element is found in
|
|
40
|
-
* the ancestor lineage, a circular reference is detected.
|
|
41
|
-
*/
|
|
42
|
-
ancestors;
|
|
43
|
-
constructor({
|
|
44
|
-
reference,
|
|
45
|
-
options,
|
|
46
|
-
indirections = [],
|
|
47
|
-
ancestors = new _util.AncestorLineage(),
|
|
48
|
-
refractCache = new WeakMap(),
|
|
49
|
-
visited = new WeakSet()
|
|
50
|
-
}) {
|
|
51
|
-
this.indirections = indirections;
|
|
52
|
-
this.reference = reference;
|
|
53
|
-
this.options = options;
|
|
54
|
-
this.ancestors = new _util.AncestorLineage(...ancestors);
|
|
55
|
-
this.refractCache = refractCache;
|
|
56
|
-
this.visited = visited;
|
|
26
|
+
class AsyncAPI2DereferenceVisitor extends _DereferenceVisitor.default {
|
|
27
|
+
get strategyName() {
|
|
28
|
+
return 'asyncapi-2';
|
|
57
29
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return [ancestorsLineage, directAncestors];
|
|
63
|
-
}
|
|
64
|
-
toBaseURI(uri) {
|
|
65
|
-
return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
|
|
66
|
-
}
|
|
67
|
-
async toReference(uri) {
|
|
68
|
-
// detect maximum depth of resolution
|
|
69
|
-
if (this.reference.depth >= this.options.resolve.maxDepth) {
|
|
70
|
-
throw new _MaximumResolveDepthError.default(`Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`, {
|
|
71
|
-
maxDepth: this.options.resolve.maxDepth,
|
|
72
|
-
uri: this.reference.uri
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
const baseURI = this.toBaseURI(uri);
|
|
76
|
-
const {
|
|
77
|
-
refSet
|
|
78
|
-
} = this.reference;
|
|
79
|
-
|
|
80
|
-
// we've already processed this Reference in past
|
|
81
|
-
if (refSet.has(baseURI)) {
|
|
82
|
-
return refSet.find((0, _ramda.propEq)(baseURI, 'uri'));
|
|
83
|
-
}
|
|
84
|
-
const parseResult = await (0, _index.default)(url.unsanitize(baseURI), {
|
|
85
|
-
...this.options,
|
|
86
|
-
parse: {
|
|
87
|
-
...this.options.parse,
|
|
88
|
-
mediaType: 'text/plain'
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// register new mutable reference with a refSet
|
|
93
|
-
//
|
|
94
|
-
// NOTE(known limitation): the mutable reference is mutated in place during traversal
|
|
95
|
-
// (via `{ mutable: true }`). When an external document evaluates a JSON pointer back
|
|
96
|
-
// into this document, it may receive an already-resolved element instead of the original
|
|
97
|
-
// $ref. That resolved element was produced using the entry document's resolution context
|
|
98
|
-
// (ancestors, indirections), which may differ from the external document's context.
|
|
99
|
-
// This can affect cycle detection in rare cross-document circular reference patterns.
|
|
100
|
-
//
|
|
101
|
-
// Remediation: evaluate JSON pointers against the immutable (original) parse tree
|
|
102
|
-
// instead of the mutable working copy. The `immutable://` reference below preserves
|
|
103
|
-
// the original tree and could be used for pointer evaluation, ensuring every resolution
|
|
104
|
-
// context always sees raw, unresolved elements and processes them with its own
|
|
105
|
-
// ancestors/indirections. The trade-off is that elements referenced by multiple
|
|
106
|
-
// documents would be resolved once per context instead of being reused.
|
|
107
|
-
const mutableReference = new _Reference.default({
|
|
108
|
-
uri: baseURI,
|
|
109
|
-
value: this.options.dereference.immutable ? (0, _apidomDatamodel.cloneDeep)(parseResult) : parseResult,
|
|
110
|
-
depth: this.reference.depth + 1
|
|
30
|
+
createVisitor(reference) {
|
|
31
|
+
return new AsyncAPI2DereferenceVisitor({
|
|
32
|
+
reference,
|
|
33
|
+
options: this.options
|
|
111
34
|
});
|
|
112
|
-
refSet.add(mutableReference);
|
|
113
|
-
if (this.options.dereference.immutable) {
|
|
114
|
-
// register new immutable reference with a refSet
|
|
115
|
-
const immutableReference = new _Reference.default({
|
|
116
|
-
uri: `immutable://${baseURI}`,
|
|
117
|
-
value: parseResult,
|
|
118
|
-
depth: this.reference.depth + 1
|
|
119
|
-
});
|
|
120
|
-
refSet.add(immutableReference);
|
|
121
|
-
}
|
|
122
|
-
return mutableReference;
|
|
123
35
|
}
|
|
124
36
|
|
|
125
37
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* For new errors: wraps in UnresolvableReferenceError with structured context
|
|
129
|
-
* (type, uri, location, codeFrame, refFieldName, refFieldValue, trace).
|
|
130
|
-
* For errors already wrapped by a nested visitor: prepends the current hop to the trace.
|
|
131
|
-
*
|
|
132
|
-
* Inner/intermediate visitors always throw to let the trace accumulate.
|
|
133
|
-
* Only the entry document visitor respects continueOnError (callback/swallow/throw).
|
|
38
|
+
* A Reference Object stands for the type its reference expects: it's dereferenced as that type.
|
|
134
39
|
*/
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const isEntryDocument = url.stripHash(this.reference.refSet?.rootRef?.uri ?? '') === this.reference.uri;
|
|
140
|
-
const uri = this.reference.uri;
|
|
141
|
-
const type = referencingElement.element;
|
|
142
|
-
const codeFrame = (0, _apidomCore.toYAML)(referencingElement);
|
|
143
|
-
|
|
144
|
-
// find element location by identity in the document tree.
|
|
145
|
-
// guarded: this.reference.value may not be a ParseResultElement or may lack a result.
|
|
146
|
-
// falls back to visitorPath which may produce an incomplete path when
|
|
147
|
-
// dereferenceApiDOM is called with a fragment (cloneShallow creates a new root identity).
|
|
148
|
-
let location;
|
|
149
|
-
const root = this.reference.value.result;
|
|
150
|
-
if ((0, _apidomDatamodel.isElement)(root)) {
|
|
151
|
-
(0, _apidomTraverse.traverse)(root, {
|
|
152
|
-
enter: p => {
|
|
153
|
-
if (p.node === referencingElement || this.refractCache.get(p.node) === referencingElement) {
|
|
154
|
-
location = p.formatPath();
|
|
155
|
-
p.stop();
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
location ??= visitorPath.formatPath();
|
|
161
|
-
const hop = {
|
|
162
|
-
uri,
|
|
163
|
-
type,
|
|
164
|
-
refFieldName,
|
|
165
|
-
refFieldValue,
|
|
166
|
-
location,
|
|
167
|
-
codeFrame
|
|
168
|
-
};
|
|
40
|
+
isOfType(element, type) {
|
|
41
|
+
if ((0, _apidomNsAsyncapi.isReferenceElement)(element)) return true;
|
|
42
|
+
return type === 'schema' ? (0, _apidomNsAsyncapi.isSchemaElement)(element) || (0, _apidomNsAsyncapi.isBooleanJSONSchemaElement)(element) : element.element === type;
|
|
43
|
+
}
|
|
169
44
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
for (const h of error.trace) {
|
|
181
|
-
if (h.uri === refBaseURI && h.location) h.location = fragment + h.location;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
// @ts-ignore
|
|
185
|
-
error.trace = [hop, ...error.trace];
|
|
186
|
-
unresolvedError = error;
|
|
187
|
-
} else {
|
|
188
|
-
unresolvedError = new _UnresolvableReferenceError.default(message, {
|
|
189
|
-
cause: error,
|
|
190
|
-
type,
|
|
191
|
-
uri,
|
|
192
|
-
location,
|
|
193
|
-
codeFrame,
|
|
194
|
-
refFieldName,
|
|
195
|
-
refFieldValue,
|
|
196
|
-
trace: []
|
|
197
|
-
});
|
|
45
|
+
/**
|
|
46
|
+
* A generic structure holding a `$ref` is a Reference Object to the expected type,
|
|
47
|
+
* unless the type has its own `$ref` field (Channel Item Object).
|
|
48
|
+
*/
|
|
49
|
+
refractTo(element, type) {
|
|
50
|
+
if (type !== 'channelItem' && (0, _apidomNsAsyncapi.isReferenceLikeElement)(element)) {
|
|
51
|
+
const referenceElement = (0, _apidomNsAsyncapi.refractReference)(element);
|
|
52
|
+
referenceElement.meta.set('referenced-element', type);
|
|
53
|
+
return referenceElement;
|
|
198
54
|
}
|
|
199
|
-
|
|
200
|
-
|
|
55
|
+
return (0, _apidomNsAsyncapi.refract)(element, {
|
|
56
|
+
element: type
|
|
57
|
+
});
|
|
201
58
|
}
|
|
202
59
|
async ReferenceElement(path) {
|
|
203
60
|
const referencingElement = path.node;
|
|
204
61
|
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
62
|
+
// the fields of a Reference Object hold no references
|
|
63
|
+
path.skip();
|
|
209
64
|
|
|
210
|
-
//
|
|
211
|
-
if (this.
|
|
212
|
-
path.skip();
|
|
65
|
+
// ignore Reference Object without a string $ref, e.g. an empty YAML value
|
|
66
|
+
if (this.isTranscluded(referencingElement) || !(0, _apidomDatamodel.isStringElement)(referencingElement.$ref)) {
|
|
213
67
|
return;
|
|
214
68
|
}
|
|
215
|
-
const
|
|
69
|
+
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
70
|
+
const retrievalURI = this.toBaseURI($ref);
|
|
216
71
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
217
72
|
const isExternalReference = !isInternalReference;
|
|
218
73
|
|
|
219
74
|
// ignore resolving internal Reference Objects
|
|
220
75
|
if (!this.options.resolve.internal && isInternalReference) {
|
|
221
|
-
// skip traversing this reference and all it's child elements
|
|
222
|
-
path.skip();
|
|
223
76
|
return;
|
|
224
77
|
}
|
|
225
78
|
// ignore resolving external Reference Objects
|
|
226
79
|
if (!this.options.resolve.external && isExternalReference) {
|
|
227
|
-
// skip traversing this reference and all it's child elements
|
|
228
|
-
path.skip();
|
|
229
80
|
return;
|
|
230
81
|
}
|
|
231
|
-
const $refBaseURI = url.resolve(retrievalURI,
|
|
232
|
-
const indirectionsSize = this.indirections.length;
|
|
82
|
+
const $refBaseURI = url.resolve(retrievalURI, $ref);
|
|
233
83
|
try {
|
|
234
|
-
const reference = await this.toReference(
|
|
235
|
-
this.indirections.push(referencingElement);
|
|
84
|
+
const reference = await this.toReference($ref);
|
|
236
85
|
const jsonPointer = _apidomJsonPointer.URIFragmentIdentifier.fromURIReference($refBaseURI);
|
|
237
|
-
|
|
238
86
|
// possibly non-semantic fragment
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// applying semantics to a fragment
|
|
242
|
-
const referencedElementType = referencingElement.meta.get('referenced-element');
|
|
243
|
-
if (referencedElement.element !== referencedElementType && !(0, _apidomNsAsyncapi.isReferenceElement)(referencedElement)) {
|
|
244
|
-
if (this.refractCache.has(referencedElement)) {
|
|
245
|
-
referencedElement = this.refractCache.get(referencedElement);
|
|
246
|
-
} else if ((0, _apidomNsAsyncapi.isReferenceLikeElement)(referencedElement)) {
|
|
247
|
-
// handling generic indirect references
|
|
248
|
-
const sourceElement = referencedElement;
|
|
249
|
-
referencedElement = (0, _apidomNsAsyncapi.refractReference)(referencedElement);
|
|
250
|
-
referencedElement.meta.set('referenced-element', referencedElementType);
|
|
251
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
252
|
-
} else {
|
|
253
|
-
// handling direct references
|
|
254
|
-
const sourceElement = referencedElement;
|
|
255
|
-
referencedElement = (0, _apidomNsAsyncapi.refract)(referencedElement, {
|
|
256
|
-
element: referencedElementType
|
|
257
|
-
});
|
|
258
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
87
|
+
const referencedElement = (0, _apidomJsonPointer.evaluate)(reference.value.result, jsonPointer);
|
|
261
88
|
|
|
262
|
-
// detect direct
|
|
89
|
+
// detect direct reference
|
|
263
90
|
if (referencingElement === referencedElement) {
|
|
264
91
|
throw new _apidomError.ApiDOMStructuredError('Recursive Reference Object detected', {
|
|
265
|
-
$ref
|
|
92
|
+
$ref
|
|
266
93
|
});
|
|
267
94
|
}
|
|
268
95
|
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
96
|
+
// a reference without an expected type reads its target as its own type
|
|
97
|
+
const type = (0, _apidomCore.toValue)(referencingElement.meta.get('referenced-element')) ?? referencedElement.element;
|
|
98
|
+
await this.addTransclusion(path, {
|
|
99
|
+
source: referencedElement,
|
|
100
|
+
type,
|
|
101
|
+
reference,
|
|
102
|
+
context: undefined
|
|
103
|
+
}, {
|
|
104
|
+
toTranscludedElement: (element, target) => {
|
|
105
|
+
// a chain of Reference Objects leading back to itself never reaches a value
|
|
106
|
+
if ((0, _apidomNsAsyncapi.isReferenceElement)(target)) return element;
|
|
107
|
+
|
|
108
|
+
// Boolean JSON Schemas
|
|
109
|
+
if ((0, _apidomNsAsyncapi.isBooleanJSONSchemaElement)(target)) {
|
|
110
|
+
const booleanJsonSchemaElement = (0, _apidomDatamodel.cloneDeep)(target);
|
|
111
|
+
// annotate referenced element with info about original referencing element
|
|
112
|
+
booleanJsonSchemaElement.meta.set('ref-fields', {
|
|
113
|
+
$ref
|
|
114
|
+
});
|
|
115
|
+
// annotate referenced element with info about origin
|
|
116
|
+
booleanJsonSchemaElement.meta.set('ref-origin', reference.uri);
|
|
117
|
+
booleanJsonSchemaElement.meta.set('ref-type', element.element);
|
|
118
|
+
return booleanJsonSchemaElement;
|
|
119
|
+
}
|
|
276
120
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
$ref
|
|
121
|
+
/**
|
|
122
|
+
* Creating a new version of referenced element to avoid modifying the original one.
|
|
123
|
+
*/
|
|
124
|
+
const mergedElement = (0, _apidomDatamodel.cloneShallow)(target);
|
|
125
|
+
// annotate referenced element with info about original referencing element
|
|
126
|
+
mergedElement.meta.set('ref-fields', {
|
|
127
|
+
$ref
|
|
284
128
|
});
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
129
|
+
// annotate fragment with info about origin
|
|
130
|
+
mergedElement.meta.set('ref-origin', reference.uri);
|
|
131
|
+
mergedElement.meta.set('ref-type', element.element);
|
|
132
|
+
return mergedElement;
|
|
133
|
+
},
|
|
134
|
+
circular: {
|
|
135
|
+
uri: $refBaseURI,
|
|
136
|
+
meta: {
|
|
288
137
|
uri: reference.uri,
|
|
289
|
-
$ref
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
path.skip();
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Dive deep into the fragment.
|
|
301
|
-
*
|
|
302
|
-
* Cases to consider:
|
|
303
|
-
* 1. We're crossing document boundary
|
|
304
|
-
* 2. Fragment is from non-entry document
|
|
305
|
-
* 3. Fragment is a Reference Object. We need to follow it to get the eventual value
|
|
306
|
-
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
|
|
307
|
-
*/
|
|
308
|
-
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
309
|
-
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
310
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsAsyncapi.isReferenceElement)(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
311
|
-
if (shouldDetectCircular) {
|
|
312
|
-
this.visited.add(referencedElement);
|
|
138
|
+
$ref
|
|
139
|
+
},
|
|
140
|
+
details: {
|
|
141
|
+
$ref
|
|
142
|
+
}
|
|
313
143
|
}
|
|
314
|
-
|
|
315
|
-
// append referencing reference to ancestors lineage
|
|
316
|
-
directAncestors.add(referencingElement);
|
|
317
|
-
const visitor = new AsyncAPI2DereferenceVisitor({
|
|
318
|
-
reference,
|
|
319
|
-
indirections: [...this.indirections],
|
|
320
|
-
options: this.options,
|
|
321
|
-
refractCache: this.refractCache,
|
|
322
|
-
visited: this.visited,
|
|
323
|
-
ancestors: ancestorsLineage
|
|
324
|
-
});
|
|
325
|
-
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
326
|
-
mutable: true,
|
|
327
|
-
skipVisited: 'skip'
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// remove referencing reference from ancestors lineage
|
|
331
|
-
directAncestors.delete(referencingElement);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Boolean JSON Schemas
|
|
335
|
-
if ((0, _apidomNsAsyncapi.isBooleanJSONSchemaElement)(referencedElement)) {
|
|
336
|
-
const booleanJsonSchemaElement = (0, _apidomDatamodel.cloneDeep)(referencedElement);
|
|
337
|
-
// annotate referenced element with info about original referencing element
|
|
338
|
-
booleanJsonSchemaElement.meta.set('ref-fields', {
|
|
339
|
-
$ref: (0, _apidomCore.toValue)(referencingElement.$ref)
|
|
340
|
-
});
|
|
341
|
-
// annotate referenced element with info about origin
|
|
342
|
-
booleanJsonSchemaElement.meta.set('ref-origin', reference.uri);
|
|
343
|
-
booleanJsonSchemaElement.meta.set('ref-type', referencingElement.element);
|
|
344
|
-
path.replaceWith(booleanJsonSchemaElement);
|
|
345
|
-
path.skip();
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Creating a new version of referenced element to avoid modifying the original one.
|
|
351
|
-
*/
|
|
352
|
-
const mergedElement = (0, _apidomDatamodel.cloneShallow)(referencedElement);
|
|
353
|
-
// annotate referenced element with info about original referencing element
|
|
354
|
-
mergedElement.meta.set('ref-fields', {
|
|
355
|
-
$ref: (0, _apidomCore.toValue)(referencingElement.$ref)
|
|
356
144
|
});
|
|
357
|
-
// annotate fragment with info about origin
|
|
358
|
-
mergedElement.meta.set('ref-origin', reference.uri);
|
|
359
|
-
mergedElement.meta.set('ref-type', referencingElement.element);
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Transclude referencing element with merged referenced element.
|
|
363
|
-
*/
|
|
364
|
-
path.replaceWith(mergedElement);
|
|
365
|
-
path.skip();
|
|
366
145
|
} catch (error) {
|
|
367
|
-
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
368
146
|
this.handleError(`Error while dereferencing Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
369
|
-
} finally {
|
|
370
|
-
if (this.indirections.length > indirectionsSize) this.indirections.pop();
|
|
371
147
|
}
|
|
372
148
|
}
|
|
373
149
|
async ChannelItemElement(path) {
|
|
374
150
|
const referencingElement = path.node;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (!(0, _apidomDatamodel.isStringElement)(referencingElement.$ref)) {
|
|
151
|
+
if (this.isTranscluded(referencingElement)) {
|
|
152
|
+
path.skip();
|
|
378
153
|
return;
|
|
379
154
|
}
|
|
380
155
|
|
|
381
|
-
//
|
|
382
|
-
if (
|
|
383
|
-
path.skip();
|
|
156
|
+
// ignore ChannelItemElement without $ref field
|
|
157
|
+
if (!(0, _apidomDatamodel.isStringElement)(referencingElement.$ref)) {
|
|
384
158
|
return;
|
|
385
159
|
}
|
|
386
|
-
const
|
|
160
|
+
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
161
|
+
const retrievalURI = this.toBaseURI($ref);
|
|
387
162
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
388
163
|
const isExternalReference = !isInternalReference;
|
|
389
164
|
|
|
390
165
|
// ignore resolving internal Channel Item Objects
|
|
391
166
|
if (!this.options.resolve.internal && isInternalReference) {
|
|
392
|
-
// skip traversing this
|
|
167
|
+
// skip traversing this Channel Item element but traverse all it's child elements
|
|
393
168
|
return;
|
|
394
169
|
}
|
|
395
170
|
// ignore resolving external Channel Item Objects
|
|
396
171
|
if (!this.options.resolve.external && isExternalReference) {
|
|
397
|
-
// skip traversing this
|
|
172
|
+
// skip traversing this Channel Item element but traverse all it's child elements
|
|
398
173
|
return;
|
|
399
174
|
}
|
|
400
|
-
const $refBaseURI = url.resolve(retrievalURI,
|
|
401
|
-
const indirectionsSize = this.indirections.length;
|
|
175
|
+
const $refBaseURI = url.resolve(retrievalURI, $ref);
|
|
402
176
|
try {
|
|
403
|
-
const reference = await this.toReference(
|
|
404
|
-
this.indirections.push(referencingElement);
|
|
177
|
+
const reference = await this.toReference($ref);
|
|
405
178
|
const jsonPointer = _apidomJsonPointer.URIFragmentIdentifier.fromURIReference($refBaseURI);
|
|
406
|
-
|
|
407
179
|
// possibly non-semantic referenced element
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
// applying semantics to a referenced element
|
|
411
|
-
if (!(0, _apidomNsAsyncapi.isChannelItemElement)(referencedElement)) {
|
|
412
|
-
if (this.refractCache.has(referencedElement)) {
|
|
413
|
-
referencedElement = this.refractCache.get(referencedElement);
|
|
414
|
-
} else {
|
|
415
|
-
const sourceElement = referencedElement;
|
|
416
|
-
referencedElement = (0, _apidomNsAsyncapi.refractChannelItem)(referencedElement);
|
|
417
|
-
this.refractCache.set(sourceElement, referencedElement);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
180
|
+
const referencedElement = (0, _apidomJsonPointer.evaluate)(reference.value.result, jsonPointer);
|
|
420
181
|
|
|
421
|
-
// detect direct
|
|
182
|
+
// detect direct reference
|
|
422
183
|
if (referencingElement === referencedElement) {
|
|
423
184
|
throw new _apidomError.ApiDOMStructuredError('Recursive Channel Item Object reference detected', {
|
|
424
|
-
$ref
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// detect maximum depth of dereferencing
|
|
429
|
-
if (this.indirections.length > this.options.dereference.maxDepth) {
|
|
430
|
-
throw new _MaximumDereferenceDepthError.default(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`, {
|
|
431
|
-
maxDepth: this.options.dereference.maxDepth,
|
|
432
|
-
uri: this.reference.uri
|
|
185
|
+
$ref
|
|
433
186
|
});
|
|
434
187
|
}
|
|
188
|
+
await this.addTransclusion(path, {
|
|
189
|
+
source: referencedElement,
|
|
190
|
+
type: 'channelItem',
|
|
191
|
+
reference,
|
|
192
|
+
context: undefined
|
|
193
|
+
}, {
|
|
194
|
+
toTranscludedElement: (element, target) => {
|
|
195
|
+
if (!(0, _apidomNsAsyncapi.isChannelItemElement)(target)) return target;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creating a new version of Channel Item by merging fields from referenced Channel Item with referencing one.
|
|
199
|
+
*/
|
|
200
|
+
const mergedElement = (0, _apidomDatamodel.cloneShallow)(target);
|
|
201
|
+
// existing keywords from referencing ChannelItemElement overrides ones from referenced element
|
|
202
|
+
element.forEach((value, keyElement, item) => {
|
|
203
|
+
mergedElement.remove((0, _apidomCore.toValue)(keyElement));
|
|
204
|
+
mergedElement.content.push(item);
|
|
205
|
+
});
|
|
206
|
+
mergedElement.remove('$ref');
|
|
435
207
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
reference.refSet.circular = true;
|
|
440
|
-
if (this.options.dereference.circular === 'error') {
|
|
441
|
-
throw new _apidomError.ApiDOMStructuredError('Circular reference detected', {
|
|
442
|
-
$ref: (0, _apidomCore.toValue)(referencingElement.$ref)
|
|
208
|
+
// annotate referenced element with info about original referencing element
|
|
209
|
+
mergedElement.meta.set('ref-fields', {
|
|
210
|
+
$ref
|
|
443
211
|
});
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
212
|
+
// annotate referenced element with info about origin and type
|
|
213
|
+
mergedElement.meta.set('ref-origin', reference.uri);
|
|
214
|
+
mergedElement.meta.set('ref-type', element.element);
|
|
215
|
+
return mergedElement;
|
|
216
|
+
},
|
|
217
|
+
aliasField: '$ref',
|
|
218
|
+
circular: {
|
|
219
|
+
uri: $refBaseURI,
|
|
220
|
+
meta: {
|
|
447
221
|
uri: reference.uri,
|
|
448
|
-
$ref
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Dive deep into the fragment.
|
|
459
|
-
*
|
|
460
|
-
* Cases to consider:
|
|
461
|
-
* 1. We're crossing document boundary
|
|
462
|
-
* 2. Fragment is from non-entry document
|
|
463
|
-
* 3. Fragment is a Channel Item Object with $ref field. We need to follow it to get the eventual value
|
|
464
|
-
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
|
|
465
|
-
*/
|
|
466
|
-
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
467
|
-
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
468
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsAsyncapi.isChannelItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
469
|
-
if (shouldDetectCircular) {
|
|
470
|
-
this.visited.add(referencedElement);
|
|
222
|
+
$ref
|
|
223
|
+
},
|
|
224
|
+
details: {
|
|
225
|
+
$ref
|
|
226
|
+
}
|
|
471
227
|
}
|
|
472
|
-
|
|
473
|
-
// append referencing reference to ancestors lineage
|
|
474
|
-
directAncestors.add(referencingElement);
|
|
475
|
-
const visitor = new AsyncAPI2DereferenceVisitor({
|
|
476
|
-
reference,
|
|
477
|
-
indirections: [...this.indirections],
|
|
478
|
-
options: this.options,
|
|
479
|
-
refractCache: this.refractCache,
|
|
480
|
-
visited: this.visited,
|
|
481
|
-
ancestors: ancestorsLineage
|
|
482
|
-
});
|
|
483
|
-
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
484
|
-
mutable: true,
|
|
485
|
-
skipVisited: 'skip'
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// remove referencing reference from ancestors lineage
|
|
489
|
-
directAncestors.delete(referencingElement);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* Creating a new version of Channel Item by merging fields from referenced Channel Item with referencing one.
|
|
494
|
-
*/
|
|
495
|
-
if ((0, _apidomNsAsyncapi.isChannelItemElement)(referencedElement)) {
|
|
496
|
-
const mergedElement = (0, _apidomDatamodel.cloneShallow)(referencedElement);
|
|
497
|
-
// existing keywords from referencing ChannelItemElement overrides ones from referenced ChannelItemElement
|
|
498
|
-
referencingElement.forEach((value, keyElement, item) => {
|
|
499
|
-
mergedElement.remove((0, _apidomCore.toValue)(keyElement));
|
|
500
|
-
mergedElement.content.push(item);
|
|
501
|
-
});
|
|
502
|
-
mergedElement.remove('$ref');
|
|
503
|
-
|
|
504
|
-
// annotate referenced element with info about original referencing element
|
|
505
|
-
mergedElement.meta.set('ref-fields', {
|
|
506
|
-
$ref: (0, _apidomCore.toValue)(referencingElement.$ref)
|
|
507
|
-
});
|
|
508
|
-
// annotate referenced with info about origin
|
|
509
|
-
mergedElement.meta.set('ref-origin', reference.uri);
|
|
510
|
-
mergedElement.meta.set('ref-type', referencingElement.element);
|
|
511
|
-
referencedElement = mergedElement;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* Transclude referencing element with merged referenced element.
|
|
516
|
-
*/
|
|
517
|
-
path.replaceWith(referencedElement);
|
|
228
|
+
});
|
|
518
229
|
} catch (error) {
|
|
519
|
-
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
520
230
|
this.handleError(`Error while dereferencing Channel Item Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
521
|
-
} finally {
|
|
522
|
-
if (this.indirections.length > indirectionsSize) this.indirections.pop();
|
|
523
231
|
}
|
|
524
232
|
}
|
|
525
233
|
}
|