@speclynx/apidom-reference 2.6.0 → 2.7.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 +13 -0
- package/README.md +60 -33
- package/dist/apidom-reference.browser.js +79395 -79177
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +25 -25
- package/src/bundle/index.cjs +1 -1
- package/src/bundle/index.mjs +1 -1
- package/src/configuration/saturated.cjs +2 -4
- package/src/configuration/saturated.mjs +3 -5
- package/src/dereference/index.cjs +1 -1
- package/src/dereference/index.mjs +1 -1
- package/src/dereference/strategies/arazzo-1/index.cjs +10 -0
- package/src/dereference/strategies/arazzo-1/index.mjs +10 -0
- package/src/dereference/strategies/arazzo-1/source-description.cjs +179 -0
- package/src/dereference/strategies/arazzo-1/source-description.mjs +172 -0
- package/src/dereference/strategies/openapi-3-0/visitor.cjs +3 -3
- package/src/dereference/strategies/openapi-3-0/visitor.mjs +3 -3
- package/src/dereference/strategies/openapi-3-1/visitor.cjs +3 -3
- package/src/dereference/strategies/openapi-3-1/visitor.mjs +3 -3
- package/src/errors/InvalidJsonSchema$anchorError.cjs +1 -1
- package/src/errors/InvalidJsonSchema$anchorError.mjs +1 -1
- package/src/errors/UnmatchedParserError.cjs +11 -0
- package/src/errors/UnmatchedParserError.mjs +6 -0
- package/src/index.cjs +3 -1
- package/src/index.mjs +1 -0
- package/src/parse/index.cjs +3 -3
- package/src/parse/index.mjs +3 -3
- package/src/parse/parsers/arazzo-json-1/index.cjs +1 -4
- package/src/parse/parsers/arazzo-json-1/index.mjs +1 -4
- package/src/parse/parsers/arazzo-json-1/source-description.cjs +14 -19
- package/src/parse/parsers/arazzo-json-1/source-description.mjs +14 -20
- package/src/parse/parsers/arazzo-yaml-1/index.cjs +1 -4
- package/src/parse/parsers/arazzo-yaml-1/index.mjs +1 -4
- package/src/resolve/index.cjs +2 -2
- package/src/resolve/index.mjs +2 -2
- package/src/resolve/resolvers/file/index-browser.cjs +1 -1
- package/src/resolve/resolvers/file/index-browser.mjs +1 -1
- package/src/resolve/strategies/apidom/index.cjs +1 -1
- package/src/resolve/strategies/apidom/index.mjs +1 -1
- package/src/resolve/strategies/asyncapi-2/index.cjs +1 -1
- package/src/resolve/strategies/asyncapi-2/index.mjs +1 -1
- package/src/resolve/strategies/openapi-2/index.cjs +1 -1
- package/src/resolve/strategies/openapi-2/index.mjs +1 -1
- package/src/resolve/strategies/openapi-3-0/index.cjs +1 -1
- package/src/resolve/strategies/openapi-3-0/index.mjs +1 -1
- package/src/resolve/strategies/openapi-3-1/index.cjs +1 -1
- package/src/resolve/strategies/openapi-3-1/index.mjs +1 -1
- package/src/resolve/util.cjs +1 -1
- package/src/resolve/util.mjs +1 -1
- package/types/apidom-reference.d.ts +6 -0
- package/types/dereference/strategies/arazzo-1/source-description.d.ts +8 -0
- package/types/errors/UnmatchedParserError.d.ts +7 -0
- package/types/index.d.ts +1 -0
- package/types/parse/parsers/arazzo-json-1/index.d.ts +0 -3
- package/types/parse/parsers/arazzo-json-1/source-description.d.ts +1 -6
- package/types/parse/parsers/arazzo-yaml-1/index.d.ts +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speclynx/apidom-reference",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Advanced algorithms for semantic ApiDOM manipulations like dereferencing or resolution.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -231,29 +231,29 @@
|
|
|
231
231
|
"license": "Apache-2.0",
|
|
232
232
|
"dependencies": {
|
|
233
233
|
"@babel/runtime-corejs3": "^7.28.4",
|
|
234
|
-
"@speclynx/apidom-core": "^2.
|
|
235
|
-
"@speclynx/apidom-datamodel": "^2.
|
|
236
|
-
"@speclynx/apidom-error": "^2.
|
|
237
|
-
"@speclynx/apidom-json-pointer": "^2.
|
|
238
|
-
"@speclynx/apidom-ns-arazzo-1": "^2.
|
|
239
|
-
"@speclynx/apidom-ns-asyncapi-2": "^2.
|
|
240
|
-
"@speclynx/apidom-ns-json-schema-2020-12": "^2.
|
|
241
|
-
"@speclynx/apidom-ns-openapi-2": "^2.
|
|
242
|
-
"@speclynx/apidom-ns-openapi-3-0": "^2.
|
|
243
|
-
"@speclynx/apidom-ns-openapi-3-1": "^2.
|
|
244
|
-
"@speclynx/apidom-parser-adapter-arazzo-json-1": "^2.
|
|
245
|
-
"@speclynx/apidom-parser-adapter-arazzo-yaml-1": "^2.
|
|
246
|
-
"@speclynx/apidom-parser-adapter-asyncapi-json-2": "^2.
|
|
247
|
-
"@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "^2.
|
|
248
|
-
"@speclynx/apidom-parser-adapter-json": "^2.
|
|
249
|
-
"@speclynx/apidom-parser-adapter-openapi-json-2": "^2.
|
|
250
|
-
"@speclynx/apidom-parser-adapter-openapi-json-3-0": "^2.
|
|
251
|
-
"@speclynx/apidom-parser-adapter-openapi-json-3-1": "^2.
|
|
252
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-2": "^2.
|
|
253
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "^2.
|
|
254
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "^2.
|
|
255
|
-
"@speclynx/apidom-parser-adapter-yaml-1-2": "^2.
|
|
256
|
-
"@speclynx/apidom-traverse": "^2.
|
|
234
|
+
"@speclynx/apidom-core": "^2.7.0",
|
|
235
|
+
"@speclynx/apidom-datamodel": "^2.7.0",
|
|
236
|
+
"@speclynx/apidom-error": "^2.7.0",
|
|
237
|
+
"@speclynx/apidom-json-pointer": "^2.7.0",
|
|
238
|
+
"@speclynx/apidom-ns-arazzo-1": "^2.7.0",
|
|
239
|
+
"@speclynx/apidom-ns-asyncapi-2": "^2.7.0",
|
|
240
|
+
"@speclynx/apidom-ns-json-schema-2020-12": "^2.7.0",
|
|
241
|
+
"@speclynx/apidom-ns-openapi-2": "^2.7.0",
|
|
242
|
+
"@speclynx/apidom-ns-openapi-3-0": "^2.7.0",
|
|
243
|
+
"@speclynx/apidom-ns-openapi-3-1": "^2.7.0",
|
|
244
|
+
"@speclynx/apidom-parser-adapter-arazzo-json-1": "^2.7.0",
|
|
245
|
+
"@speclynx/apidom-parser-adapter-arazzo-yaml-1": "^2.7.0",
|
|
246
|
+
"@speclynx/apidom-parser-adapter-asyncapi-json-2": "^2.7.0",
|
|
247
|
+
"@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "^2.7.0",
|
|
248
|
+
"@speclynx/apidom-parser-adapter-json": "^2.7.0",
|
|
249
|
+
"@speclynx/apidom-parser-adapter-openapi-json-2": "^2.7.0",
|
|
250
|
+
"@speclynx/apidom-parser-adapter-openapi-json-3-0": "^2.7.0",
|
|
251
|
+
"@speclynx/apidom-parser-adapter-openapi-json-3-1": "^2.7.0",
|
|
252
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-2": "^2.7.0",
|
|
253
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "^2.7.0",
|
|
254
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "^2.7.0",
|
|
255
|
+
"@speclynx/apidom-parser-adapter-yaml-1-2": "^2.7.0",
|
|
256
|
+
"@speclynx/apidom-traverse": "^2.7.0",
|
|
257
257
|
"@swaggerexpert/arazzo-runtime-expression": "^2.0.2",
|
|
258
258
|
"axios": "^1.13.0",
|
|
259
259
|
"minimatch": "^7.4.6",
|
|
@@ -274,5 +274,5 @@
|
|
|
274
274
|
"README.md",
|
|
275
275
|
"CHANGELOG.md"
|
|
276
276
|
],
|
|
277
|
-
"gitHead": "
|
|
277
|
+
"gitHead": "82ac9430aa882d0a5c63a17f7da8f5c0dcbca737"
|
|
278
278
|
}
|
package/src/bundle/index.cjs
CHANGED
|
@@ -45,7 +45,7 @@ const bundle = async (uri, options) => {
|
|
|
45
45
|
|
|
46
46
|
// we couldn't find any bundle strategy for this File
|
|
47
47
|
if ((0, _ramda.isEmpty)(bundleStrategies)) {
|
|
48
|
-
throw new _UnmatchedBundleStrategyError.default(file.uri);
|
|
48
|
+
throw new _UnmatchedBundleStrategyError.default(`Could not find a bundle strategy that can bundle the file "${file.uri}"`);
|
|
49
49
|
}
|
|
50
50
|
try {
|
|
51
51
|
const {
|
package/src/bundle/index.mjs
CHANGED
|
@@ -39,7 +39,7 @@ const bundle = async (uri, options) => {
|
|
|
39
39
|
|
|
40
40
|
// we couldn't find any bundle strategy for this File
|
|
41
41
|
if (isEmpty(bundleStrategies)) {
|
|
42
|
-
throw new UnmatchedBundleStrategyError(file.uri);
|
|
42
|
+
throw new UnmatchedBundleStrategyError(`Could not find a bundle strategy that can bundle the file "${file.uri}"`);
|
|
43
43
|
}
|
|
44
44
|
try {
|
|
45
45
|
const {
|
|
@@ -62,12 +62,10 @@ _index25.options.parse.parsers = [new _index7.default({
|
|
|
62
62
|
sourceMap: false
|
|
63
63
|
}), new _index13.default({
|
|
64
64
|
allowEmpty: true,
|
|
65
|
-
sourceMap: false
|
|
66
|
-
parseFn: _index25.parse
|
|
65
|
+
sourceMap: false
|
|
67
66
|
}), new _index14.default({
|
|
68
67
|
allowEmpty: true,
|
|
69
|
-
sourceMap: false
|
|
70
|
-
parseFn: _index25.parse
|
|
68
|
+
sourceMap: false
|
|
71
69
|
}), new _index15.default({
|
|
72
70
|
allowEmpty: true,
|
|
73
71
|
sourceMap: false
|
|
@@ -26,7 +26,7 @@ import OpenAPI3_1DereferenceStrategy from "../dereference/strategies/openapi-3-1
|
|
|
26
26
|
import AsyncAPI2DereferenceStrategy from "../dereference/strategies/asyncapi-2/index.mjs";
|
|
27
27
|
import Arazzo1DereferenceStrategy from "../dereference/strategies/arazzo-1/index.mjs";
|
|
28
28
|
import OpenAPI3_1BundleStrategy from "../bundle/strategies/openapi-3-1/index.mjs";
|
|
29
|
-
import { options
|
|
29
|
+
import { options } from "../index.mjs";
|
|
30
30
|
options.parse.parsers = [new OpenAPIJSON2Parser({
|
|
31
31
|
allowEmpty: true,
|
|
32
32
|
sourceMap: false
|
|
@@ -53,12 +53,10 @@ options.parse.parsers = [new OpenAPIJSON2Parser({
|
|
|
53
53
|
sourceMap: false
|
|
54
54
|
}), new ArazzoJSON1Parser({
|
|
55
55
|
allowEmpty: true,
|
|
56
|
-
sourceMap: false
|
|
57
|
-
parseFn: parse
|
|
56
|
+
sourceMap: false
|
|
58
57
|
}), new ArazzoYAML1Parser({
|
|
59
58
|
allowEmpty: true,
|
|
60
|
-
sourceMap: false
|
|
61
|
-
parseFn: parse
|
|
59
|
+
sourceMap: false
|
|
62
60
|
}), new APIDOMJSONParser({
|
|
63
61
|
allowEmpty: true,
|
|
64
62
|
sourceMap: false
|
|
@@ -37,7 +37,7 @@ const dereferenceApiDOM = async (element, options) => {
|
|
|
37
37
|
|
|
38
38
|
// we couldn't find any dereference strategy for this File
|
|
39
39
|
if ((0, _ramda.isEmpty)(dereferenceStrategies)) {
|
|
40
|
-
throw new _UnmatchedDereferenceStrategyError.default(file.uri);
|
|
40
|
+
throw new _UnmatchedDereferenceStrategyError.default(`Could not find a dereference strategy that can dereference the file "${file.uri}"`);
|
|
41
41
|
}
|
|
42
42
|
try {
|
|
43
43
|
const {
|
|
@@ -31,7 +31,7 @@ export const dereferenceApiDOM = async (element, options) => {
|
|
|
31
31
|
|
|
32
32
|
// we couldn't find any dereference strategy for this File
|
|
33
33
|
if (isEmpty(dereferenceStrategies)) {
|
|
34
|
-
throw new UnmatchedDereferenceStrategyError(file.uri);
|
|
34
|
+
throw new UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference the file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
try {
|
|
37
37
|
const {
|
|
@@ -12,6 +12,7 @@ var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
|
|
|
12
12
|
var _ReferenceSet = _interopRequireDefault(require("../../../ReferenceSet.cjs"));
|
|
13
13
|
var _visitor = _interopRequireDefault(require("./visitor.cjs"));
|
|
14
14
|
exports.Arazzo1DereferenceVisitor = _visitor.default;
|
|
15
|
+
var _sourceDescription = require("./source-description.cjs");
|
|
15
16
|
var _util = require("./util.cjs");
|
|
16
17
|
exports.resolveSchema$refField = _util.resolveSchema$refField;
|
|
17
18
|
exports.resolveSchema$idField = _util.resolveSchema$idField;
|
|
@@ -77,6 +78,15 @@ class Arazzo1DereferenceStrategy extends _DereferenceStrategy.default {
|
|
|
77
78
|
mutable: true
|
|
78
79
|
});
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Dereference source descriptions if option is enabled.
|
|
83
|
+
*/
|
|
84
|
+
const shouldDereferenceSourceDescriptions = options?.dereference?.strategyOpts?.[this.name]?.sourceDescriptions ?? options?.dereference?.strategyOpts?.sourceDescriptions;
|
|
85
|
+
if (shouldDereferenceSourceDescriptions) {
|
|
86
|
+
const sourceDescriptions = await (0, _sourceDescription.dereferenceSourceDescriptions)(dereferencedElement, reference, options);
|
|
87
|
+
dereferencedElement.push(...sourceDescriptions);
|
|
88
|
+
}
|
|
89
|
+
|
|
80
90
|
/**
|
|
81
91
|
* If immutable option is set, replay refs from the refSet.
|
|
82
92
|
*/
|
|
@@ -5,6 +5,7 @@ import DereferenceStrategy from "../DereferenceStrategy.mjs";
|
|
|
5
5
|
import Reference from "../../../Reference.mjs";
|
|
6
6
|
import ReferenceSet from "../../../ReferenceSet.mjs";
|
|
7
7
|
import Arazzo1DereferenceVisitor from "./visitor.mjs";
|
|
8
|
+
import { dereferenceSourceDescriptions } from "./source-description.mjs";
|
|
8
9
|
/**
|
|
9
10
|
* @public
|
|
10
11
|
*/
|
|
@@ -65,6 +66,15 @@ class Arazzo1DereferenceStrategy extends DereferenceStrategy {
|
|
|
65
66
|
mutable: true
|
|
66
67
|
});
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Dereference source descriptions if option is enabled.
|
|
71
|
+
*/
|
|
72
|
+
const shouldDereferenceSourceDescriptions = options?.dereference?.strategyOpts?.[this.name]?.sourceDescriptions ?? options?.dereference?.strategyOpts?.sourceDescriptions;
|
|
73
|
+
if (shouldDereferenceSourceDescriptions) {
|
|
74
|
+
const sourceDescriptions = await dereferenceSourceDescriptions(dereferencedElement, reference, options);
|
|
75
|
+
dereferencedElement.push(...sourceDescriptions);
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
/**
|
|
69
79
|
* If immutable option is set, replay refs from the refSet.
|
|
70
80
|
*/
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
|
|
5
|
+
exports.__esModule = true;
|
|
6
|
+
exports.dereferenceSourceDescriptions = dereferenceSourceDescriptions;
|
|
7
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
8
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
9
|
+
var _apidomNsOpenapi = require("@speclynx/apidom-ns-openapi-2");
|
|
10
|
+
var _apidomNsOpenapi2 = require("@speclynx/apidom-ns-openapi-3-0");
|
|
11
|
+
var _apidomNsOpenapi3 = require("@speclynx/apidom-ns-openapi-3-1");
|
|
12
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
13
|
+
var url = _interopRequireWildcard(require("../../../util/url.cjs"));
|
|
14
|
+
var _util = require("../../../options/util.cjs");
|
|
15
|
+
var _index = _interopRequireDefault(require("../../index.cjs"));
|
|
16
|
+
// shared key for recursion state (works across JSON/YAML documents)
|
|
17
|
+
const ARAZZO_DEREFERENCE_RECURSION_KEY = 'arazzo-1';
|
|
18
|
+
/**
|
|
19
|
+
* Dereferences a single source description element.
|
|
20
|
+
* Returns ParseResultElement on success, or with annotation if skipped.
|
|
21
|
+
*/
|
|
22
|
+
async function dereferenceSourceDescription(sourceDescription, ctx) {
|
|
23
|
+
const parseResult = new _apidomDatamodel.ParseResultElement();
|
|
24
|
+
if (!(0, _apidomNsArazzo.isSourceDescriptionElement)(sourceDescription)) {
|
|
25
|
+
const annotation = new _apidomDatamodel.AnnotationElement('Element is not a valid SourceDescriptionElement. Skipping');
|
|
26
|
+
annotation.classes.push('warning');
|
|
27
|
+
parseResult.push(annotation);
|
|
28
|
+
return parseResult;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// set class and metadata from source description element
|
|
32
|
+
parseResult.classes.push('source-description');
|
|
33
|
+
if ((0, _apidomDatamodel.isStringElement)(sourceDescription.name)) parseResult.setMetaProperty('name', (0, _apidomDatamodel.cloneDeep)(sourceDescription.name));
|
|
34
|
+
if ((0, _apidomDatamodel.isStringElement)(sourceDescription.type)) parseResult.setMetaProperty('type', (0, _apidomDatamodel.cloneDeep)(sourceDescription.type));
|
|
35
|
+
const sourceDescriptionURI = (0, _apidomCore.toValue)(sourceDescription.url);
|
|
36
|
+
if (typeof sourceDescriptionURI !== 'string') {
|
|
37
|
+
const annotation = new _apidomDatamodel.AnnotationElement('Source description URL is missing or not a string. Skipping');
|
|
38
|
+
annotation.classes.push('warning');
|
|
39
|
+
parseResult.push(annotation);
|
|
40
|
+
return parseResult;
|
|
41
|
+
}
|
|
42
|
+
const retrievalURI = url.resolve(ctx.baseURI, sourceDescriptionURI);
|
|
43
|
+
|
|
44
|
+
// skip if already visited (cycle detection)
|
|
45
|
+
if (ctx.visitedUrls.has(retrievalURI)) {
|
|
46
|
+
const annotation = new _apidomDatamodel.AnnotationElement(`Source description "${retrievalURI}" has already been visited. Skipping to prevent cycle`);
|
|
47
|
+
annotation.classes.push('warning');
|
|
48
|
+
parseResult.push(annotation);
|
|
49
|
+
return parseResult;
|
|
50
|
+
}
|
|
51
|
+
ctx.visitedUrls.add(retrievalURI);
|
|
52
|
+
try {
|
|
53
|
+
const sourceDescriptionDereferenced = await (0, _index.default)(retrievalURI, (0, _util.merge)(ctx.options, {
|
|
54
|
+
parse: {
|
|
55
|
+
mediaType: 'text/plain' // allow parser plugin detection
|
|
56
|
+
},
|
|
57
|
+
dereference: {
|
|
58
|
+
strategyOpts: {
|
|
59
|
+
[ARAZZO_DEREFERENCE_RECURSION_KEY]: {
|
|
60
|
+
sourceDescriptionsDepth: ctx.currentDepth + 1,
|
|
61
|
+
sourceDescriptionsVisitedUrls: ctx.visitedUrls
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
// merge dereferenced result into our parse result
|
|
67
|
+
for (const item of sourceDescriptionDereferenced) {
|
|
68
|
+
parseResult.push(item);
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// create error annotation instead of failing entire dereference
|
|
72
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
+
const annotation = new _apidomDatamodel.AnnotationElement(`Error dereferencing source description "${retrievalURI}": ${message}`);
|
|
74
|
+
annotation.classes.push('error');
|
|
75
|
+
parseResult.push(annotation);
|
|
76
|
+
return parseResult;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// only allow OpenAPI and Arazzo as source descriptions
|
|
80
|
+
const {
|
|
81
|
+
api: sourceDescriptionAPI
|
|
82
|
+
} = parseResult;
|
|
83
|
+
const isOpenApi = (0, _apidomNsOpenapi.isSwaggerElement)(sourceDescriptionAPI) || (0, _apidomNsOpenapi2.isOpenApi3_0Element)(sourceDescriptionAPI) || (0, _apidomNsOpenapi3.isOpenApi3_1Element)(sourceDescriptionAPI);
|
|
84
|
+
const isArazzo = (0, _apidomNsArazzo.isArazzoSpecification1Element)(sourceDescriptionAPI);
|
|
85
|
+
if (!isOpenApi && !isArazzo) {
|
|
86
|
+
const annotation = new _apidomDatamodel.AnnotationElement(`Source description "${retrievalURI}" is not an OpenAPI or Arazzo document`);
|
|
87
|
+
annotation.classes.push('warning');
|
|
88
|
+
parseResult.push(annotation);
|
|
89
|
+
return parseResult;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// validate declared type matches actual dereferenced type
|
|
93
|
+
const declaredType = (0, _apidomCore.toValue)(sourceDescription.type);
|
|
94
|
+
if (typeof declaredType === 'string') {
|
|
95
|
+
if (declaredType === 'openapi' && !isOpenApi) {
|
|
96
|
+
const annotation = new _apidomDatamodel.AnnotationElement(`Source description "${retrievalURI}" declared as "openapi" but dereferenced as Arazzo document`);
|
|
97
|
+
annotation.classes.push('warning');
|
|
98
|
+
parseResult.push(annotation);
|
|
99
|
+
} else if (declaredType === 'arazzo' && !isArazzo) {
|
|
100
|
+
const annotation = new _apidomDatamodel.AnnotationElement(`Source description "${retrievalURI}" declared as "arazzo" but dereferenced as OpenAPI document`);
|
|
101
|
+
annotation.classes.push('warning');
|
|
102
|
+
parseResult.push(annotation);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return parseResult;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Dereferences source descriptions from an Arazzo document.
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
async function dereferenceSourceDescriptions(parseResult, reference, options) {
|
|
113
|
+
const results = [];
|
|
114
|
+
const strategyName = 'arazzo-1';
|
|
115
|
+
|
|
116
|
+
// get API from dereferenced parse result
|
|
117
|
+
const {
|
|
118
|
+
api
|
|
119
|
+
} = parseResult;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Validate prerequisites for dereferencing source descriptions.
|
|
123
|
+
* Return warning annotations if validation fails.
|
|
124
|
+
*/
|
|
125
|
+
if (!(0, _apidomNsArazzo.isArazzoSpecification1Element)(api)) {
|
|
126
|
+
const annotation = new _apidomDatamodel.AnnotationElement('Cannot dereference source descriptions: API is not an Arazzo specification');
|
|
127
|
+
annotation.classes.push('warning');
|
|
128
|
+
return [new _apidomDatamodel.ParseResultElement([annotation])];
|
|
129
|
+
}
|
|
130
|
+
if (!(0, _apidomDatamodel.isArrayElement)(api.sourceDescriptions)) {
|
|
131
|
+
const annotation = new _apidomDatamodel.AnnotationElement('Cannot dereference source descriptions: sourceDescriptions field is missing or not an array');
|
|
132
|
+
annotation.classes.push('warning');
|
|
133
|
+
return [new _apidomDatamodel.ParseResultElement([annotation])];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// user config: strategy-specific options take precedence over global strategyOpts
|
|
137
|
+
const maxDepth = options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptionsMaxDepth ?? options?.dereference?.strategyOpts?.sourceDescriptionsMaxDepth ?? +Infinity;
|
|
138
|
+
|
|
139
|
+
// recursion state comes from shared key (works across JSON/YAML)
|
|
140
|
+
const sharedOpts = options?.dereference?.strategyOpts?.[ARAZZO_DEREFERENCE_RECURSION_KEY] ?? {};
|
|
141
|
+
const currentDepth = sharedOpts.sourceDescriptionsDepth ?? 0;
|
|
142
|
+
const visitedUrls = sharedOpts.sourceDescriptionsVisitedUrls ?? new Set();
|
|
143
|
+
|
|
144
|
+
// add current file to visited URLs to prevent cycles
|
|
145
|
+
visitedUrls.add(reference.uri);
|
|
146
|
+
if (currentDepth >= maxDepth) {
|
|
147
|
+
const annotation = new _apidomDatamodel.AnnotationElement(`Maximum dereference depth of ${maxDepth} has been exceeded by file "${reference.uri}"`);
|
|
148
|
+
annotation.classes.push('error');
|
|
149
|
+
const parseResult = new _apidomDatamodel.ParseResultElement([annotation]);
|
|
150
|
+
parseResult.classes.push('source-description');
|
|
151
|
+
return [parseResult];
|
|
152
|
+
}
|
|
153
|
+
const ctx = {
|
|
154
|
+
baseURI: reference.uri,
|
|
155
|
+
options,
|
|
156
|
+
currentDepth,
|
|
157
|
+
visitedUrls
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// determine which source descriptions to dereference
|
|
161
|
+
const sourceDescriptionsOption = options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptions ?? options?.dereference?.strategyOpts?.sourceDescriptions;
|
|
162
|
+
|
|
163
|
+
// handle false or other falsy values - no source descriptions should be dereferenced
|
|
164
|
+
if (!sourceDescriptionsOption) {
|
|
165
|
+
return results;
|
|
166
|
+
}
|
|
167
|
+
const sourceDescriptions = Array.isArray(sourceDescriptionsOption) ? api.sourceDescriptions.filter(sd => {
|
|
168
|
+
if (!(0, _apidomNsArazzo.isSourceDescriptionElement)(sd)) return false;
|
|
169
|
+
const name = (0, _apidomCore.toValue)(sd.name);
|
|
170
|
+
return typeof name === 'string' && sourceDescriptionsOption.includes(name);
|
|
171
|
+
}) : api.sourceDescriptions;
|
|
172
|
+
|
|
173
|
+
// process sequentially to ensure proper cycle detection with shared visitedUrls
|
|
174
|
+
for (const sourceDescription of sourceDescriptions) {
|
|
175
|
+
const sourceDescriptionDereferenceResult = await dereferenceSourceDescription(sourceDescription, ctx);
|
|
176
|
+
results.push(sourceDescriptionDereferenceResult);
|
|
177
|
+
}
|
|
178
|
+
return results;
|
|
179
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { ParseResultElement, AnnotationElement, isArrayElement, isStringElement, cloneDeep } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { isArazzoSpecification1Element, isSourceDescriptionElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
3
|
+
import { isSwaggerElement } from '@speclynx/apidom-ns-openapi-2';
|
|
4
|
+
import { isOpenApi3_0Element } from '@speclynx/apidom-ns-openapi-3-0';
|
|
5
|
+
import { isOpenApi3_1Element } from '@speclynx/apidom-ns-openapi-3-1';
|
|
6
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
7
|
+
import * as url from "../../../util/url.mjs";
|
|
8
|
+
import { merge as mergeOptions } from "../../../options/util.mjs";
|
|
9
|
+
import dereference from "../../index.mjs"; // shared key for recursion state (works across JSON/YAML documents)
|
|
10
|
+
const ARAZZO_DEREFERENCE_RECURSION_KEY = 'arazzo-1';
|
|
11
|
+
/**
|
|
12
|
+
* Dereferences a single source description element.
|
|
13
|
+
* Returns ParseResultElement on success, or with annotation if skipped.
|
|
14
|
+
*/
|
|
15
|
+
async function dereferenceSourceDescription(sourceDescription, ctx) {
|
|
16
|
+
const parseResult = new ParseResultElement();
|
|
17
|
+
if (!isSourceDescriptionElement(sourceDescription)) {
|
|
18
|
+
const annotation = new AnnotationElement('Element is not a valid SourceDescriptionElement. Skipping');
|
|
19
|
+
annotation.classes.push('warning');
|
|
20
|
+
parseResult.push(annotation);
|
|
21
|
+
return parseResult;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// set class and metadata from source description element
|
|
25
|
+
parseResult.classes.push('source-description');
|
|
26
|
+
if (isStringElement(sourceDescription.name)) parseResult.setMetaProperty('name', cloneDeep(sourceDescription.name));
|
|
27
|
+
if (isStringElement(sourceDescription.type)) parseResult.setMetaProperty('type', cloneDeep(sourceDescription.type));
|
|
28
|
+
const sourceDescriptionURI = toValue(sourceDescription.url);
|
|
29
|
+
if (typeof sourceDescriptionURI !== 'string') {
|
|
30
|
+
const annotation = new AnnotationElement('Source description URL is missing or not a string. Skipping');
|
|
31
|
+
annotation.classes.push('warning');
|
|
32
|
+
parseResult.push(annotation);
|
|
33
|
+
return parseResult;
|
|
34
|
+
}
|
|
35
|
+
const retrievalURI = url.resolve(ctx.baseURI, sourceDescriptionURI);
|
|
36
|
+
|
|
37
|
+
// skip if already visited (cycle detection)
|
|
38
|
+
if (ctx.visitedUrls.has(retrievalURI)) {
|
|
39
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" has already been visited. Skipping to prevent cycle`);
|
|
40
|
+
annotation.classes.push('warning');
|
|
41
|
+
parseResult.push(annotation);
|
|
42
|
+
return parseResult;
|
|
43
|
+
}
|
|
44
|
+
ctx.visitedUrls.add(retrievalURI);
|
|
45
|
+
try {
|
|
46
|
+
const sourceDescriptionDereferenced = await dereference(retrievalURI, mergeOptions(ctx.options, {
|
|
47
|
+
parse: {
|
|
48
|
+
mediaType: 'text/plain' // allow parser plugin detection
|
|
49
|
+
},
|
|
50
|
+
dereference: {
|
|
51
|
+
strategyOpts: {
|
|
52
|
+
[ARAZZO_DEREFERENCE_RECURSION_KEY]: {
|
|
53
|
+
sourceDescriptionsDepth: ctx.currentDepth + 1,
|
|
54
|
+
sourceDescriptionsVisitedUrls: ctx.visitedUrls
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}));
|
|
59
|
+
// merge dereferenced result into our parse result
|
|
60
|
+
for (const item of sourceDescriptionDereferenced) {
|
|
61
|
+
parseResult.push(item);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// create error annotation instead of failing entire dereference
|
|
65
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
66
|
+
const annotation = new AnnotationElement(`Error dereferencing source description "${retrievalURI}": ${message}`);
|
|
67
|
+
annotation.classes.push('error');
|
|
68
|
+
parseResult.push(annotation);
|
|
69
|
+
return parseResult;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// only allow OpenAPI and Arazzo as source descriptions
|
|
73
|
+
const {
|
|
74
|
+
api: sourceDescriptionAPI
|
|
75
|
+
} = parseResult;
|
|
76
|
+
const isOpenApi = isSwaggerElement(sourceDescriptionAPI) || isOpenApi3_0Element(sourceDescriptionAPI) || isOpenApi3_1Element(sourceDescriptionAPI);
|
|
77
|
+
const isArazzo = isArazzoSpecification1Element(sourceDescriptionAPI);
|
|
78
|
+
if (!isOpenApi && !isArazzo) {
|
|
79
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" is not an OpenAPI or Arazzo document`);
|
|
80
|
+
annotation.classes.push('warning');
|
|
81
|
+
parseResult.push(annotation);
|
|
82
|
+
return parseResult;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// validate declared type matches actual dereferenced type
|
|
86
|
+
const declaredType = toValue(sourceDescription.type);
|
|
87
|
+
if (typeof declaredType === 'string') {
|
|
88
|
+
if (declaredType === 'openapi' && !isOpenApi) {
|
|
89
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" declared as "openapi" but dereferenced as Arazzo document`);
|
|
90
|
+
annotation.classes.push('warning');
|
|
91
|
+
parseResult.push(annotation);
|
|
92
|
+
} else if (declaredType === 'arazzo' && !isArazzo) {
|
|
93
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" declared as "arazzo" but dereferenced as OpenAPI document`);
|
|
94
|
+
annotation.classes.push('warning');
|
|
95
|
+
parseResult.push(annotation);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return parseResult;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Dereferences source descriptions from an Arazzo document.
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
export async function dereferenceSourceDescriptions(parseResult, reference, options) {
|
|
106
|
+
const results = [];
|
|
107
|
+
const strategyName = 'arazzo-1';
|
|
108
|
+
|
|
109
|
+
// get API from dereferenced parse result
|
|
110
|
+
const {
|
|
111
|
+
api
|
|
112
|
+
} = parseResult;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validate prerequisites for dereferencing source descriptions.
|
|
116
|
+
* Return warning annotations if validation fails.
|
|
117
|
+
*/
|
|
118
|
+
if (!isArazzoSpecification1Element(api)) {
|
|
119
|
+
const annotation = new AnnotationElement('Cannot dereference source descriptions: API is not an Arazzo specification');
|
|
120
|
+
annotation.classes.push('warning');
|
|
121
|
+
return [new ParseResultElement([annotation])];
|
|
122
|
+
}
|
|
123
|
+
if (!isArrayElement(api.sourceDescriptions)) {
|
|
124
|
+
const annotation = new AnnotationElement('Cannot dereference source descriptions: sourceDescriptions field is missing or not an array');
|
|
125
|
+
annotation.classes.push('warning');
|
|
126
|
+
return [new ParseResultElement([annotation])];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// user config: strategy-specific options take precedence over global strategyOpts
|
|
130
|
+
const maxDepth = options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptionsMaxDepth ?? options?.dereference?.strategyOpts?.sourceDescriptionsMaxDepth ?? +Infinity;
|
|
131
|
+
|
|
132
|
+
// recursion state comes from shared key (works across JSON/YAML)
|
|
133
|
+
const sharedOpts = options?.dereference?.strategyOpts?.[ARAZZO_DEREFERENCE_RECURSION_KEY] ?? {};
|
|
134
|
+
const currentDepth = sharedOpts.sourceDescriptionsDepth ?? 0;
|
|
135
|
+
const visitedUrls = sharedOpts.sourceDescriptionsVisitedUrls ?? new Set();
|
|
136
|
+
|
|
137
|
+
// add current file to visited URLs to prevent cycles
|
|
138
|
+
visitedUrls.add(reference.uri);
|
|
139
|
+
if (currentDepth >= maxDepth) {
|
|
140
|
+
const annotation = new AnnotationElement(`Maximum dereference depth of ${maxDepth} has been exceeded by file "${reference.uri}"`);
|
|
141
|
+
annotation.classes.push('error');
|
|
142
|
+
const parseResult = new ParseResultElement([annotation]);
|
|
143
|
+
parseResult.classes.push('source-description');
|
|
144
|
+
return [parseResult];
|
|
145
|
+
}
|
|
146
|
+
const ctx = {
|
|
147
|
+
baseURI: reference.uri,
|
|
148
|
+
options,
|
|
149
|
+
currentDepth,
|
|
150
|
+
visitedUrls
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// determine which source descriptions to dereference
|
|
154
|
+
const sourceDescriptionsOption = options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptions ?? options?.dereference?.strategyOpts?.sourceDescriptions;
|
|
155
|
+
|
|
156
|
+
// handle false or other falsy values - no source descriptions should be dereferenced
|
|
157
|
+
if (!sourceDescriptionsOption) {
|
|
158
|
+
return results;
|
|
159
|
+
}
|
|
160
|
+
const sourceDescriptions = Array.isArray(sourceDescriptionsOption) ? api.sourceDescriptions.filter(sd => {
|
|
161
|
+
if (!isSourceDescriptionElement(sd)) return false;
|
|
162
|
+
const name = toValue(sd.name);
|
|
163
|
+
return typeof name === 'string' && sourceDescriptionsOption.includes(name);
|
|
164
|
+
}) : api.sourceDescriptions;
|
|
165
|
+
|
|
166
|
+
// process sequentially to ensure proper cycle detection with shared visitedUrls
|
|
167
|
+
for (const sourceDescription of sourceDescriptions) {
|
|
168
|
+
const sourceDescriptionDereferenceResult = await dereferenceSourceDescription(sourceDescription, ctx);
|
|
169
|
+
results.push(sourceDescriptionDereferenceResult);
|
|
170
|
+
}
|
|
171
|
+
return results;
|
|
172
|
+
}
|
|
@@ -389,7 +389,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
389
389
|
|
|
390
390
|
// operationRef and operationId fields are mutually exclusive
|
|
391
391
|
if ((0, _apidomDatamodel.isStringElement)(linkElement.operationRef) && (0, _apidomDatamodel.isStringElement)(linkElement.operationId)) {
|
|
392
|
-
throw new _apidomError.ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive
|
|
392
|
+
throw new _apidomError.ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive');
|
|
393
393
|
}
|
|
394
394
|
let operationElement;
|
|
395
395
|
if ((0, _apidomDatamodel.isStringElement)(linkElement.operationRef)) {
|
|
@@ -440,7 +440,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
440
440
|
operationElement = (0, _apidomTraverse.find)(reference.value.result, e => (0, _apidomNsOpenapi.isOperationElement)(e) && (0, _apidomDatamodel.isElement)(e.operationId) && e.operationId.equals(operationId));
|
|
441
441
|
// OperationElement not found by its operationId
|
|
442
442
|
if ((0, _ramdaAdjunct.isUndefined)(operationElement)) {
|
|
443
|
-
throw new _apidomError.ApiDOMError(`OperationElement(operationId=${operationId}) not found
|
|
443
|
+
throw new _apidomError.ApiDOMError(`OperationElement(operationId=${operationId}) not found`);
|
|
444
444
|
}
|
|
445
445
|
const linkElementCopy = (0, _apidomDatamodel.cloneShallow)(linkElement);
|
|
446
446
|
linkElementCopy.operationId?.meta.set('operation', operationElement);
|
|
@@ -462,7 +462,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
462
462
|
|
|
463
463
|
// value and externalValue fields are mutually exclusive
|
|
464
464
|
if (exampleElement.hasKey('value') && (0, _apidomDatamodel.isStringElement)(exampleElement.externalValue)) {
|
|
465
|
-
throw new _apidomError.ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive
|
|
465
|
+
throw new _apidomError.ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive');
|
|
466
466
|
}
|
|
467
467
|
const retrievalURI = this.toBaseURI((0, _apidomCore.toValue)(exampleElement.externalValue));
|
|
468
468
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
@@ -383,7 +383,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
383
383
|
|
|
384
384
|
// operationRef and operationId fields are mutually exclusive
|
|
385
385
|
if (isStringElement(linkElement.operationRef) && isStringElement(linkElement.operationId)) {
|
|
386
|
-
throw new ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive
|
|
386
|
+
throw new ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive');
|
|
387
387
|
}
|
|
388
388
|
let operationElement;
|
|
389
389
|
if (isStringElement(linkElement.operationRef)) {
|
|
@@ -434,7 +434,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
434
434
|
operationElement = find(reference.value.result, e => isOperationElement(e) && isElement(e.operationId) && e.operationId.equals(operationId));
|
|
435
435
|
// OperationElement not found by its operationId
|
|
436
436
|
if (isUndefined(operationElement)) {
|
|
437
|
-
throw new ApiDOMError(`OperationElement(operationId=${operationId}) not found
|
|
437
|
+
throw new ApiDOMError(`OperationElement(operationId=${operationId}) not found`);
|
|
438
438
|
}
|
|
439
439
|
const linkElementCopy = cloneShallow(linkElement);
|
|
440
440
|
linkElementCopy.operationId?.meta.set('operation', operationElement);
|
|
@@ -456,7 +456,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
456
456
|
|
|
457
457
|
// value and externalValue fields are mutually exclusive
|
|
458
458
|
if (exampleElement.hasKey('value') && isStringElement(exampleElement.externalValue)) {
|
|
459
|
-
throw new ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive
|
|
459
|
+
throw new ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive');
|
|
460
460
|
}
|
|
461
461
|
const retrievalURI = this.toBaseURI(toValue(exampleElement.externalValue));
|
|
462
462
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
@@ -411,7 +411,7 @@ class OpenAPI3_1DereferenceVisitor {
|
|
|
411
411
|
|
|
412
412
|
// operationRef and operationId fields are mutually exclusive
|
|
413
413
|
if ((0, _apidomDatamodel.isStringElement)(linkElement.operationRef) && (0, _apidomDatamodel.isStringElement)(linkElement.operationId)) {
|
|
414
|
-
throw new _apidomError.ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive
|
|
414
|
+
throw new _apidomError.ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive');
|
|
415
415
|
}
|
|
416
416
|
let operationElement;
|
|
417
417
|
if ((0, _apidomDatamodel.isStringElement)(linkElement.operationRef)) {
|
|
@@ -462,7 +462,7 @@ class OpenAPI3_1DereferenceVisitor {
|
|
|
462
462
|
operationElement = (0, _apidomTraverse.find)(reference.value.result, e => (0, _apidomNsOpenapi.isOperationElement)(e) && (0, _apidomDatamodel.isElement)(e.operationId) && e.operationId.equals(operationId));
|
|
463
463
|
// OperationElement not found by its operationId
|
|
464
464
|
if ((0, _ramdaAdjunct.isUndefined)(operationElement)) {
|
|
465
|
-
throw new _apidomError.ApiDOMError(`OperationElement(operationId=${operationId}) not found
|
|
465
|
+
throw new _apidomError.ApiDOMError(`OperationElement(operationId=${operationId}) not found`);
|
|
466
466
|
}
|
|
467
467
|
const linkElementCopy = (0, _apidomDatamodel.cloneShallow)(linkElement);
|
|
468
468
|
linkElementCopy.operationId?.meta.set('operation', operationElement);
|
|
@@ -483,7 +483,7 @@ class OpenAPI3_1DereferenceVisitor {
|
|
|
483
483
|
|
|
484
484
|
// value and externalValue fields are mutually exclusive
|
|
485
485
|
if (exampleElement.hasKey('value') && (0, _apidomDatamodel.isStringElement)(exampleElement.externalValue)) {
|
|
486
|
-
throw new _apidomError.ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive
|
|
486
|
+
throw new _apidomError.ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive');
|
|
487
487
|
}
|
|
488
488
|
const retrievalURI = this.toBaseURI((0, _apidomCore.toValue)(exampleElement.externalValue));
|
|
489
489
|
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|