@speclynx/apidom-reference 1.12.1
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 +86 -0
- package/LICENSE +202 -0
- package/LICENSES/AFL-3.0.txt +182 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/BSD-3-Clause.txt +26 -0
- package/LICENSES/MIT.txt +9 -0
- package/NOTICE +65 -0
- package/README.md +2107 -0
- package/dist/167.apidom-reference.browser.js +10 -0
- package/dist/167.apidom-reference.browser.min.js +1 -0
- package/dist/451.apidom-reference.browser.js +10 -0
- package/dist/451.apidom-reference.browser.min.js +1 -0
- package/dist/9786785aaddf11f37840fad896531940.wasm +0 -0
- package/dist/apidom-reference.browser.js +85376 -0
- package/dist/apidom-reference.browser.min.js +1 -0
- package/package.json +304 -0
- package/src/File.cjs +50 -0
- package/src/File.mjs +44 -0
- package/src/Reference.cjs +31 -0
- package/src/Reference.mjs +27 -0
- package/src/ReferenceSet.cjs +60 -0
- package/src/ReferenceSet.mjs +57 -0
- package/src/bundle/index.cjs +61 -0
- package/src/bundle/index.mjs +55 -0
- package/src/bundle/strategies/BundleStrategy.cjs +20 -0
- package/src/bundle/strategies/BundleStrategy.mjs +16 -0
- package/src/bundle/strategies/openapi-3-1/index.cjs +35 -0
- package/src/bundle/strategies/openapi-3-1/index.mjs +29 -0
- package/src/configuration/empty.cjs +9 -0
- package/src/configuration/empty.mjs +1 -0
- package/src/configuration/saturated.cjs +95 -0
- package/src/configuration/saturated.mjs +87 -0
- package/src/dereference/index.cjs +86 -0
- package/src/dereference/index.mjs +79 -0
- package/src/dereference/strategies/DereferenceStrategy.cjs +20 -0
- package/src/dereference/strategies/DereferenceStrategy.mjs +16 -0
- package/src/dereference/strategies/apidom/index.cjs +89 -0
- package/src/dereference/strategies/apidom/index.mjs +84 -0
- package/src/dereference/strategies/apidom/selectors/element-id.cjs +36 -0
- package/src/dereference/strategies/apidom/selectors/element-id.mjs +30 -0
- package/src/dereference/strategies/apidom/visitor.cjs +165 -0
- package/src/dereference/strategies/apidom/visitor.mjs +159 -0
- package/src/dereference/strategies/asyncapi-2/index.cjs +100 -0
- package/src/dereference/strategies/asyncapi-2/index.mjs +94 -0
- package/src/dereference/strategies/asyncapi-2/visitor.cjs +412 -0
- package/src/dereference/strategies/asyncapi-2/visitor.mjs +406 -0
- package/src/dereference/strategies/openapi-2/index.cjs +102 -0
- package/src/dereference/strategies/openapi-2/index.mjs +96 -0
- package/src/dereference/strategies/openapi-2/visitor.cjs +530 -0
- package/src/dereference/strategies/openapi-2/visitor.mjs +524 -0
- package/src/dereference/strategies/openapi-3-0/index.cjs +102 -0
- package/src/dereference/strategies/openapi-3-0/index.mjs +96 -0
- package/src/dereference/strategies/openapi-3-0/visitor.cjs +519 -0
- package/src/dereference/strategies/openapi-3-0/visitor.mjs +513 -0
- package/src/dereference/strategies/openapi-3-1/index.cjs +105 -0
- package/src/dereference/strategies/openapi-3-1/index.mjs +96 -0
- package/src/dereference/strategies/openapi-3-1/selectors/$anchor.cjs +66 -0
- package/src/dereference/strategies/openapi-3-1/selectors/$anchor.mjs +55 -0
- package/src/dereference/strategies/openapi-3-1/selectors/uri.cjs +50 -0
- package/src/dereference/strategies/openapi-3-1/selectors/uri.mjs +42 -0
- package/src/dereference/strategies/openapi-3-1/util.cjs +67 -0
- package/src/dereference/strategies/openapi-3-1/util.mjs +58 -0
- package/src/dereference/strategies/openapi-3-1/visitor.cjs +776 -0
- package/src/dereference/strategies/openapi-3-1/visitor.mjs +770 -0
- package/src/dereference/util.cjs +31 -0
- package/src/dereference/util.mjs +27 -0
- package/src/errors/BundleError.cjs +10 -0
- package/src/errors/BundleError.mjs +7 -0
- package/src/errors/DereferenceError.cjs +10 -0
- package/src/errors/DereferenceError.mjs +7 -0
- package/src/errors/EvaluationElementIdError.cjs +10 -0
- package/src/errors/EvaluationElementIdError.mjs +7 -0
- package/src/errors/EvaluationJsonSchema$anchorError.cjs +11 -0
- package/src/errors/EvaluationJsonSchema$anchorError.mjs +6 -0
- package/src/errors/EvaluationJsonSchemaUriError.cjs +11 -0
- package/src/errors/EvaluationJsonSchemaUriError.mjs +6 -0
- package/src/errors/InvalidJsonSchema$anchorError.cjs +15 -0
- package/src/errors/InvalidJsonSchema$anchorError.mjs +10 -0
- package/src/errors/JsonSchema$anchorError.cjs +10 -0
- package/src/errors/JsonSchema$anchorError.mjs +7 -0
- package/src/errors/JsonSchemaUriError.cjs +10 -0
- package/src/errors/JsonSchemaUriError.mjs +7 -0
- package/src/errors/MaximumBundleDepthError.cjs +11 -0
- package/src/errors/MaximumBundleDepthError.mjs +6 -0
- package/src/errors/MaximumDereferenceDepthError.cjs +11 -0
- package/src/errors/MaximumDereferenceDepthError.mjs +6 -0
- package/src/errors/MaximumResolveDepthError.cjs +11 -0
- package/src/errors/MaximumResolveDepthError.mjs +6 -0
- package/src/errors/ParseError.cjs +10 -0
- package/src/errors/ParseError.mjs +7 -0
- package/src/errors/ParserError.cjs +11 -0
- package/src/errors/ParserError.mjs +6 -0
- package/src/errors/PluginError.cjs +18 -0
- package/src/errors/PluginError.mjs +15 -0
- package/src/errors/ResolveError.cjs +10 -0
- package/src/errors/ResolveError.mjs +7 -0
- package/src/errors/ResolverError.cjs +11 -0
- package/src/errors/ResolverError.mjs +6 -0
- package/src/errors/UnmatchedBundleStrategyError.cjs +11 -0
- package/src/errors/UnmatchedBundleStrategyError.mjs +6 -0
- package/src/errors/UnmatchedDereferenceStrategyError.cjs +11 -0
- package/src/errors/UnmatchedDereferenceStrategyError.mjs +6 -0
- package/src/errors/UnmatchedResolveStrategyError.cjs +11 -0
- package/src/errors/UnmatchedResolveStrategyError.mjs +6 -0
- package/src/errors/UnmatchedResolverError.cjs +11 -0
- package/src/errors/UnmatchedResolverError.mjs +6 -0
- package/src/index.cjs +142 -0
- package/src/index.mjs +101 -0
- package/src/options/index.cjs +185 -0
- package/src/options/index.mjs +182 -0
- package/src/options/util.cjs +24 -0
- package/src/options/util.mjs +19 -0
- package/src/parse/index.cjs +69 -0
- package/src/parse/index.mjs +63 -0
- package/src/parse/parsers/Parser.cjs +48 -0
- package/src/parse/parsers/Parser.mjs +44 -0
- package/src/parse/parsers/api-design-systems-json/index.cjs +55 -0
- package/src/parse/parsers/api-design-systems-json/index.mjs +49 -0
- package/src/parse/parsers/api-design-systems-yaml/index.cjs +54 -0
- package/src/parse/parsers/api-design-systems-yaml/index.mjs +48 -0
- package/src/parse/parsers/apidom-json/index.cjs +70 -0
- package/src/parse/parsers/apidom-json/index.mjs +64 -0
- package/src/parse/parsers/arazzo-json-1/index.cjs +55 -0
- package/src/parse/parsers/arazzo-json-1/index.mjs +49 -0
- package/src/parse/parsers/arazzo-yaml-1/index.cjs +54 -0
- package/src/parse/parsers/arazzo-yaml-1/index.mjs +48 -0
- package/src/parse/parsers/asyncapi-json-2/index.cjs +55 -0
- package/src/parse/parsers/asyncapi-json-2/index.mjs +49 -0
- package/src/parse/parsers/asyncapi-yaml-2/index.cjs +54 -0
- package/src/parse/parsers/asyncapi-yaml-2/index.mjs +48 -0
- package/src/parse/parsers/binary/index-browser.cjs +56 -0
- package/src/parse/parsers/binary/index-browser.mjs +50 -0
- package/src/parse/parsers/binary/index-node.cjs +51 -0
- package/src/parse/parsers/binary/index-node.mjs +45 -0
- package/src/parse/parsers/json/index.cjs +54 -0
- package/src/parse/parsers/json/index.mjs +48 -0
- package/src/parse/parsers/openapi-json-2/index.cjs +55 -0
- package/src/parse/parsers/openapi-json-2/index.mjs +49 -0
- package/src/parse/parsers/openapi-json-3-0/index.cjs +55 -0
- package/src/parse/parsers/openapi-json-3-0/index.mjs +49 -0
- package/src/parse/parsers/openapi-json-3-1/index.cjs +55 -0
- package/src/parse/parsers/openapi-json-3-1/index.mjs +49 -0
- package/src/parse/parsers/openapi-yaml-2/index.cjs +54 -0
- package/src/parse/parsers/openapi-yaml-2/index.mjs +48 -0
- package/src/parse/parsers/openapi-yaml-3-0/index.cjs +54 -0
- package/src/parse/parsers/openapi-yaml-3-0/index.mjs +48 -0
- package/src/parse/parsers/openapi-yaml-3-1/index.cjs +54 -0
- package/src/parse/parsers/openapi-yaml-3-1/index.mjs +48 -0
- package/src/parse/parsers/yaml-1-2/index.cjs +54 -0
- package/src/parse/parsers/yaml-1-2/index.mjs +48 -0
- package/src/resolve/index.cjs +67 -0
- package/src/resolve/index.mjs +60 -0
- package/src/resolve/resolvers/HTTPResolver.cjs +38 -0
- package/src/resolve/resolvers/HTTPResolver.mjs +31 -0
- package/src/resolve/resolvers/Resolver.cjs +20 -0
- package/src/resolve/resolvers/Resolver.mjs +16 -0
- package/src/resolve/resolvers/file/index-browser.cjs +24 -0
- package/src/resolve/resolvers/file/index-browser.mjs +19 -0
- package/src/resolve/resolvers/file/index-node.cjs +49 -0
- package/src/resolve/resolvers/file/index-node.mjs +42 -0
- package/src/resolve/resolvers/http-axios/index.cjs +80 -0
- package/src/resolve/resolvers/http-axios/index.mjs +73 -0
- package/src/resolve/strategies/ResolveStrategy.cjs +20 -0
- package/src/resolve/strategies/ResolveStrategy.mjs +16 -0
- package/src/resolve/strategies/apidom/index.cjs +49 -0
- package/src/resolve/strategies/apidom/index.mjs +43 -0
- package/src/resolve/strategies/asyncapi-2/index.cjs +49 -0
- package/src/resolve/strategies/asyncapi-2/index.mjs +43 -0
- package/src/resolve/strategies/openapi-2/index.cjs +49 -0
- package/src/resolve/strategies/openapi-2/index.mjs +43 -0
- package/src/resolve/strategies/openapi-3-0/index.cjs +49 -0
- package/src/resolve/strategies/openapi-3-0/index.mjs +43 -0
- package/src/resolve/strategies/openapi-3-1/index.cjs +49 -0
- package/src/resolve/strategies/openapi-3-1/index.mjs +43 -0
- package/src/resolve/util.cjs +37 -0
- package/src/resolve/util.mjs +30 -0
- package/src/util/plugins.cjs +44 -0
- package/src/util/plugins.mjs +37 -0
- package/src/util/url.cjs +288 -0
- package/src/util/url.mjs +274 -0
- package/types/File.d.ts +24 -0
- package/types/Reference.d.ts +23 -0
- package/types/ReferenceSet.d.ts +25 -0
- package/types/apidom-reference.d.ts +584 -0
- package/types/bundle/index.d.ts +7 -0
- package/types/bundle/strategies/BundleStrategy.d.ts +19 -0
- package/types/bundle/strategies/openapi-3-1/index.d.ts +26 -0
- package/types/configuration/empty.d.ts +1 -0
- package/types/configuration/saturated.d.ts +1 -0
- package/types/dereference/index.d.ts +11 -0
- package/types/dereference/strategies/DereferenceStrategy.d.ts +19 -0
- package/types/dereference/strategies/apidom/index.d.ts +30 -0
- package/types/dereference/strategies/apidom/selectors/element-id.d.ts +11 -0
- package/types/dereference/strategies/apidom/visitor.d.ts +32 -0
- package/types/dereference/strategies/asyncapi-2/index.d.ts +31 -0
- package/types/dereference/strategies/asyncapi-2/visitor.d.ts +43 -0
- package/types/dereference/strategies/openapi-2/index.d.ts +32 -0
- package/types/dereference/strategies/openapi-2/visitor.d.ts +47 -0
- package/types/dereference/strategies/openapi-3-0/index.d.ts +31 -0
- package/types/dereference/strategies/openapi-3-0/visitor.d.ts +49 -0
- package/types/dereference/strategies/openapi-3-1/index.d.ts +32 -0
- package/types/dereference/strategies/openapi-3-1/selectors/$anchor.d.ts +22 -0
- package/types/dereference/strategies/openapi-3-1/selectors/uri.d.ts +12 -0
- package/types/dereference/strategies/openapi-3-1/util.d.ts +21 -0
- package/types/dereference/strategies/openapi-3-1/visitor.d.ts +52 -0
- package/types/dereference/util.d.ts +9 -0
- package/types/errors/BundleError.d.ts +7 -0
- package/types/errors/DereferenceError.d.ts +7 -0
- package/types/errors/EvaluationElementIdError.d.ts +7 -0
- package/types/errors/EvaluationJsonSchema$anchorError.d.ts +7 -0
- package/types/errors/EvaluationJsonSchemaUriError.d.ts +7 -0
- package/types/errors/InvalidJsonSchema$anchorError.d.ts +8 -0
- package/types/errors/JsonSchema$anchorError.d.ts +7 -0
- package/types/errors/JsonSchemaUriError.d.ts +7 -0
- package/types/errors/MaximumBundleDepthError.d.ts +7 -0
- package/types/errors/MaximumDereferenceDepthError.d.ts +7 -0
- package/types/errors/MaximumResolveDepthError.d.ts +7 -0
- package/types/errors/ParseError.d.ts +7 -0
- package/types/errors/ParserError.d.ts +7 -0
- package/types/errors/PluginError.d.ts +12 -0
- package/types/errors/ResolveError.d.ts +7 -0
- package/types/errors/ResolverError.d.ts +7 -0
- package/types/errors/UnmatchedBundleStrategyError.d.ts +7 -0
- package/types/errors/UnmatchedDereferenceStrategyError.d.ts +7 -0
- package/types/errors/UnmatchedResolveStrategyError.d.ts +7 -0
- package/types/errors/UnmatchedResolverError.d.ts +7 -0
- package/types/index.d.ts +75 -0
- package/types/options/index.d.ts +62 -0
- package/types/options/util.d.ts +5 -0
- package/types/parse/index.d.ts +7 -0
- package/types/parse/parsers/Parser.d.ts +38 -0
- package/types/parse/parsers/api-design-systems-json/index.d.ts +21 -0
- package/types/parse/parsers/api-design-systems-yaml/index.d.ts +20 -0
- package/types/parse/parsers/apidom-json/index.d.ts +24 -0
- package/types/parse/parsers/arazzo-json-1/index.d.ts +21 -0
- package/types/parse/parsers/arazzo-yaml-1/index.d.ts +20 -0
- package/types/parse/parsers/asyncapi-json-2/index.d.ts +21 -0
- package/types/parse/parsers/asyncapi-yaml-2/index.d.ts +20 -0
- package/types/parse/parsers/binary/index-browser.d.ts +21 -0
- package/types/parse/parsers/binary/index-node.d.ts +21 -0
- package/types/parse/parsers/json/index.d.ts +20 -0
- package/types/parse/parsers/openapi-json-2/index.d.ts +21 -0
- package/types/parse/parsers/openapi-json-3-0/index.d.ts +21 -0
- package/types/parse/parsers/openapi-json-3-1/index.d.ts +21 -0
- package/types/parse/parsers/openapi-yaml-2/index.d.ts +20 -0
- package/types/parse/parsers/openapi-yaml-3-0/index.d.ts +20 -0
- package/types/parse/parsers/openapi-yaml-3-1/index.d.ts +20 -0
- package/types/parse/parsers/yaml-1-2/index.d.ts +20 -0
- package/types/resolve/index.d.ts +12 -0
- package/types/resolve/resolvers/HTTPResolver.d.ts +22 -0
- package/types/resolve/resolvers/Resolver.d.ts +17 -0
- package/types/resolve/resolvers/file/index-browser.d.ts +12 -0
- package/types/resolve/resolvers/file/index-node.d.ts +20 -0
- package/types/resolve/resolvers/http-axios/index.d.ts +30 -0
- package/types/resolve/strategies/ResolveStrategy.d.ts +19 -0
- package/types/resolve/strategies/apidom/index.d.ts +27 -0
- package/types/resolve/strategies/asyncapi-2/index.d.ts +27 -0
- package/types/resolve/strategies/openapi-2/index.d.ts +27 -0
- package/types/resolve/strategies/openapi-3-0/index.d.ts +27 -0
- package/types/resolve/strategies/openapi-3-1/index.d.ts +27 -0
- package/types/resolve/util.d.ts +6 -0
- package/types/util/plugins.d.ts +14 -0
- package/types/util/url.d.ts +106 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { isElement, cloneDeep, visit } from '@speclynx/apidom-core';
|
|
2
|
+
import DereferenceStrategy from "../DereferenceStrategy.mjs";
|
|
3
|
+
import Reference from "../../../Reference.mjs";
|
|
4
|
+
import ReferenceSet from "../../../ReferenceSet.mjs";
|
|
5
|
+
import ApiDOMDereferenceVisitor from "./visitor.mjs";
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
class ApiDOMDereferenceStrategy extends DereferenceStrategy {
|
|
17
|
+
constructor(options) {
|
|
18
|
+
super({
|
|
19
|
+
...(options ?? {}),
|
|
20
|
+
name: 'apidom'
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
canDereference(file) {
|
|
24
|
+
return file.mediaType.startsWith('application/vnd.apidom') && isElement(file.parseResult?.result);
|
|
25
|
+
}
|
|
26
|
+
async dereference(file, options) {
|
|
27
|
+
const immutableRefSet = options.dereference.refSet ?? new ReferenceSet();
|
|
28
|
+
const mutableRefSet = new ReferenceSet();
|
|
29
|
+
let refSet = immutableRefSet;
|
|
30
|
+
let reference;
|
|
31
|
+
|
|
32
|
+
// determine the initial reference
|
|
33
|
+
if (!immutableRefSet.has(file.uri)) {
|
|
34
|
+
reference = new Reference({
|
|
35
|
+
uri: file.uri,
|
|
36
|
+
value: file.parseResult
|
|
37
|
+
});
|
|
38
|
+
immutableRefSet.add(reference);
|
|
39
|
+
} else {
|
|
40
|
+
// pre-computed refSet was provided as configuration option
|
|
41
|
+
reference = immutableRefSet.find(ref => ref.uri === file.uri);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Clone refSet due the dereferencing process being mutable.
|
|
46
|
+
* We don't want to mutate the original refSet and the references.
|
|
47
|
+
*/
|
|
48
|
+
if (options.dereference.immutable) {
|
|
49
|
+
immutableRefSet.refs.map(ref => new Reference({
|
|
50
|
+
...ref,
|
|
51
|
+
value: cloneDeep(ref.value)
|
|
52
|
+
})).forEach(ref => mutableRefSet.add(ref));
|
|
53
|
+
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
54
|
+
refSet = mutableRefSet;
|
|
55
|
+
}
|
|
56
|
+
const visitor = new ApiDOMDereferenceVisitor({
|
|
57
|
+
reference: reference,
|
|
58
|
+
options
|
|
59
|
+
});
|
|
60
|
+
const dereferencedElement = await visitAsync(refSet.rootRef.value, visitor);
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* If immutable option is set, replay refs from the refSet.
|
|
64
|
+
*/
|
|
65
|
+
if (options.dereference.immutable) {
|
|
66
|
+
mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new Reference({
|
|
67
|
+
...ref,
|
|
68
|
+
uri: ref.uri.replace(/^immutable:\/\//, '')
|
|
69
|
+
})).forEach(ref => immutableRefSet.add(ref));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Release all memory if this refSet was not provided as a configuration option.
|
|
74
|
+
* If provided as configuration option, then provider is responsible for cleanup.
|
|
75
|
+
*/
|
|
76
|
+
if (options.dereference.refSet === null) {
|
|
77
|
+
immutableRefSet.clean();
|
|
78
|
+
}
|
|
79
|
+
mutableRefSet.clean();
|
|
80
|
+
return dereferencedElement;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export { ApiDOMDereferenceVisitor };
|
|
84
|
+
export default ApiDOMDereferenceStrategy;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.evaluate = void 0;
|
|
6
|
+
var _ramdaAdjunct = require("ramda-adjunct");
|
|
7
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
8
|
+
var _EvaluationElementIdError = _interopRequireDefault(require("../../../../errors/EvaluationElementIdError.cjs"));
|
|
9
|
+
exports.EvaluationElementIdError = _EvaluationElementIdError.default;
|
|
10
|
+
const hasElementID = element => !!element.id;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Evaluates element ID against ApiDOM fragment.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
const evaluate = (elementID, element) => {
|
|
17
|
+
const {
|
|
18
|
+
cache
|
|
19
|
+
} = evaluate;
|
|
20
|
+
// warm the cache
|
|
21
|
+
if (!cache.has(element)) {
|
|
22
|
+
const elementsWithID = (0, _apidomCore.filter)(hasElementID, element);
|
|
23
|
+
cache.set(element, Array.from(elementsWithID));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// search for the matching element
|
|
27
|
+
const result = cache.get(element).find(e => {
|
|
28
|
+
return String((0, _apidomCore.toValue)(e.id)) === elementID;
|
|
29
|
+
});
|
|
30
|
+
if ((0, _ramdaAdjunct.isUndefined)(result)) {
|
|
31
|
+
throw new _EvaluationElementIdError.default(`Evaluation failed on element ID: "${elementID}"`);
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
exports.evaluate = evaluate;
|
|
36
|
+
evaluate.cache = new WeakMap();
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isUndefined } from 'ramda-adjunct';
|
|
2
|
+
import { filter, toValue } from '@speclynx/apidom-core';
|
|
3
|
+
import EvaluationElementIdError from "../../../../errors/EvaluationElementIdError.mjs";
|
|
4
|
+
const hasElementID = element => !!element.id;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Evaluates element ID against ApiDOM fragment.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export const evaluate = (elementID, element) => {
|
|
11
|
+
const {
|
|
12
|
+
cache
|
|
13
|
+
} = evaluate;
|
|
14
|
+
// warm the cache
|
|
15
|
+
if (!cache.has(element)) {
|
|
16
|
+
const elementsWithID = filter(hasElementID, element);
|
|
17
|
+
cache.set(element, Array.from(elementsWithID));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// search for the matching element
|
|
21
|
+
const result = cache.get(element).find(e => {
|
|
22
|
+
return String(toValue(e.id)) === elementID;
|
|
23
|
+
});
|
|
24
|
+
if (isUndefined(result)) {
|
|
25
|
+
throw new EvaluationElementIdError(`Evaluation failed on element ID: "${elementID}"`);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
evaluate.cache = new WeakMap();
|
|
30
|
+
export { EvaluationElementIdError };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
5
|
+
exports.__esModule = true;
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _ramda = require("ramda");
|
|
8
|
+
var _apidomError = require("@speclynx/apidom-error");
|
|
9
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
10
|
+
var _apidomJsonPointer = require("@speclynx/apidom-json-pointer");
|
|
11
|
+
var _MaximumResolveDepthError = _interopRequireDefault(require("../../../errors/MaximumResolveDepthError.cjs"));
|
|
12
|
+
var url = _interopRequireWildcard(require("../../../util/url.cjs"));
|
|
13
|
+
var _index = _interopRequireDefault(require("../../../parse/index.cjs"));
|
|
14
|
+
var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
|
|
15
|
+
var _elementId = require("./selectors/element-id.cjs");
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
const visitAsync = _apidomCore.visit[Symbol.for('nodejs.util.promisify.custom')];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The following rules apply:
|
|
21
|
+
*
|
|
22
|
+
* 1. When referencing an element in the local document, the id of the element MAY be used
|
|
23
|
+
* 2. When referencing remote elements, an absolute URL or relative URL MAY be used
|
|
24
|
+
* 3. When a URL fragment exists in the URL given, it references the element with the matching id in the given document. The URL fragment MAY need to be URL decoded before making a match.
|
|
25
|
+
* 4. When a URL fragment does not exist, the URL references the root element
|
|
26
|
+
* 5. When path is used, it references the given property of the referenced element
|
|
27
|
+
* 6. When path is used in an element that includes the data of the pointer (such as with ref), the referenced path MAY need to be converted to a refract structure in order to be valid
|
|
28
|
+
*
|
|
29
|
+
* WARNING: this implementation only supports referencing elements in the local document. Points 2-4 are not supported.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
class ApiDOMDereferenceVisitor {
|
|
37
|
+
reference;
|
|
38
|
+
options;
|
|
39
|
+
constructor({
|
|
40
|
+
reference,
|
|
41
|
+
options
|
|
42
|
+
}) {
|
|
43
|
+
this.reference = reference;
|
|
44
|
+
this.options = options;
|
|
45
|
+
}
|
|
46
|
+
toBaseURI(uri) {
|
|
47
|
+
return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
|
|
48
|
+
}
|
|
49
|
+
async toReference(uri) {
|
|
50
|
+
// detect maximum depth of resolution
|
|
51
|
+
if (this.reference.depth >= this.options.resolve.maxDepth) {
|
|
52
|
+
throw new _MaximumResolveDepthError.default(`Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`);
|
|
53
|
+
}
|
|
54
|
+
const baseURI = this.toBaseURI(uri);
|
|
55
|
+
const {
|
|
56
|
+
refSet
|
|
57
|
+
} = this.reference;
|
|
58
|
+
|
|
59
|
+
// we've already processed this Reference in past
|
|
60
|
+
if (refSet.has(baseURI)) {
|
|
61
|
+
return refSet.find((0, _ramda.propEq)(baseURI, 'uri'));
|
|
62
|
+
}
|
|
63
|
+
const parseResult = await (0, _index.default)(url.unsanitize(baseURI), {
|
|
64
|
+
...this.options,
|
|
65
|
+
parse: {
|
|
66
|
+
...this.options.parse,
|
|
67
|
+
mediaType: 'text/plain'
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// register new mutable reference with a refSet
|
|
72
|
+
const mutableReference = new _Reference.default({
|
|
73
|
+
uri: baseURI,
|
|
74
|
+
value: (0, _apidomCore.cloneDeep)(parseResult),
|
|
75
|
+
depth: this.reference.depth + 1
|
|
76
|
+
});
|
|
77
|
+
refSet.add(mutableReference);
|
|
78
|
+
if (this.options.dereference.immutable) {
|
|
79
|
+
// register new immutable reference with a refSet
|
|
80
|
+
const immutableReference = new _Reference.default({
|
|
81
|
+
uri: `immutable://${baseURI}`,
|
|
82
|
+
value: parseResult,
|
|
83
|
+
depth: this.reference.depth + 1
|
|
84
|
+
});
|
|
85
|
+
refSet.add(immutableReference);
|
|
86
|
+
}
|
|
87
|
+
return mutableReference;
|
|
88
|
+
}
|
|
89
|
+
async RefElement(refElement, key, parent, path, ancestors) {
|
|
90
|
+
const refURI = (0, _apidomCore.toValue)(refElement);
|
|
91
|
+
const refNormalizedURI = refURI.includes('#') ? refURI : `#${refURI}`;
|
|
92
|
+
const retrievalURI = this.toBaseURI(refNormalizedURI);
|
|
93
|
+
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
94
|
+
const isExternalReference = !isInternalReference;
|
|
95
|
+
|
|
96
|
+
// ignore resolving internal RefElements
|
|
97
|
+
if (!this.options.resolve.internal && isInternalReference) {
|
|
98
|
+
// skip traversing this ref element
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
// ignore resolving external RefElements
|
|
102
|
+
if (!this.options.resolve.external && isExternalReference) {
|
|
103
|
+
// skip traversing this ref element
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const reference = await this.toReference(refNormalizedURI);
|
|
107
|
+
const refBaseURI = url.resolve(retrievalURI, refNormalizedURI);
|
|
108
|
+
const elementID = _apidomJsonPointer.URIFragmentIdentifier.fromURIReference(refBaseURI);
|
|
109
|
+
let referencedElement = (0, _elementId.evaluate)(elementID, reference.value.result);
|
|
110
|
+
if (!(0, _apidomCore.isElement)(referencedElement)) {
|
|
111
|
+
throw new _apidomError.ApiDOMError(`Referenced element with id="${elementID}" was not found`);
|
|
112
|
+
}
|
|
113
|
+
if (refElement === referencedElement) {
|
|
114
|
+
throw new _apidomError.ApiDOMError('RefElement cannot reference itself');
|
|
115
|
+
}
|
|
116
|
+
if ((0, _apidomCore.isRefElement)(referencedElement)) {
|
|
117
|
+
throw new _apidomError.ApiDOMError('RefElement cannot reference another RefElement');
|
|
118
|
+
}
|
|
119
|
+
if (isExternalReference) {
|
|
120
|
+
// dive deep into the fragment
|
|
121
|
+
const visitor = new ApiDOMDereferenceVisitor({
|
|
122
|
+
reference,
|
|
123
|
+
options: this.options
|
|
124
|
+
});
|
|
125
|
+
referencedElement = await visitAsync(referencedElement, visitor);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* When path is used, it references the given property of the referenced element
|
|
130
|
+
*/
|
|
131
|
+
const referencedElementPath = (0, _apidomCore.toValue)(refElement.path);
|
|
132
|
+
if (referencedElementPath !== 'element' && (0, _apidomCore.isElement)(referencedElement)) {
|
|
133
|
+
referencedElement = (0, _apidomCore.refract)(referencedElement[referencedElementPath]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Transclusion of a Ref Element SHALL be defined in the if/else block below.
|
|
138
|
+
*/
|
|
139
|
+
if ((0, _apidomCore.isObjectElement)(referencedElement) && (0, _apidomCore.isObjectElement)(ancestors[ancestors.length - 1]) && Array.isArray(parent) && typeof key === 'number') {
|
|
140
|
+
/**
|
|
141
|
+
* If the Ref Element is held by an Object Element and references an Object Element,
|
|
142
|
+
* its content entries SHALL be inserted in place of the Ref Element.
|
|
143
|
+
*/
|
|
144
|
+
parent.splice(key, 1, ...referencedElement.content);
|
|
145
|
+
} else if ((0, _apidomCore.isArrayElement)(referencedElement) && Array.isArray(parent) && typeof key === 'number') {
|
|
146
|
+
/**
|
|
147
|
+
* If the Ref Element is held by an Array Element and references an Array Element,
|
|
148
|
+
* its content entries SHALL be inserted in place of the Ref Element.
|
|
149
|
+
*/
|
|
150
|
+
parent.splice(key, 1, ...referencedElement.content);
|
|
151
|
+
} else if ((0, _apidomCore.isMemberElement)(parent)) {
|
|
152
|
+
/**
|
|
153
|
+
* The Ref Element is substituted by the Element it references.
|
|
154
|
+
*/
|
|
155
|
+
parent.value = referencedElement;
|
|
156
|
+
} else if (Array.isArray(parent)) {
|
|
157
|
+
/**
|
|
158
|
+
* The Ref Element is substituted by the Element it references.
|
|
159
|
+
*/
|
|
160
|
+
parent[key] = referencedElement;
|
|
161
|
+
}
|
|
162
|
+
return !parent ? referencedElement : false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
var _default = exports.default = ApiDOMDereferenceVisitor;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { propEq } from 'ramda';
|
|
2
|
+
import { ApiDOMError } from '@speclynx/apidom-error';
|
|
3
|
+
import { isElement, isMemberElement, isArrayElement, isObjectElement, isRefElement, toValue, refract, visit, cloneDeep } from '@speclynx/apidom-core';
|
|
4
|
+
import { URIFragmentIdentifier } from '@speclynx/apidom-json-pointer';
|
|
5
|
+
import MaximumResolveDepthError from "../../../errors/MaximumResolveDepthError.mjs";
|
|
6
|
+
import * as url from "../../../util/url.mjs";
|
|
7
|
+
import parse from "../../../parse/index.mjs";
|
|
8
|
+
import Reference from "../../../Reference.mjs";
|
|
9
|
+
import { evaluate } from "./selectors/element-id.mjs";
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The following rules apply:
|
|
15
|
+
*
|
|
16
|
+
* 1. When referencing an element in the local document, the id of the element MAY be used
|
|
17
|
+
* 2. When referencing remote elements, an absolute URL or relative URL MAY be used
|
|
18
|
+
* 3. When a URL fragment exists in the URL given, it references the element with the matching id in the given document. The URL fragment MAY need to be URL decoded before making a match.
|
|
19
|
+
* 4. When a URL fragment does not exist, the URL references the root element
|
|
20
|
+
* 5. When path is used, it references the given property of the referenced element
|
|
21
|
+
* 6. When path is used in an element that includes the data of the pointer (such as with ref), the referenced path MAY need to be converted to a refract structure in order to be valid
|
|
22
|
+
*
|
|
23
|
+
* WARNING: this implementation only supports referencing elements in the local document. Points 2-4 are not supported.
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
class ApiDOMDereferenceVisitor {
|
|
31
|
+
reference;
|
|
32
|
+
options;
|
|
33
|
+
constructor({
|
|
34
|
+
reference,
|
|
35
|
+
options
|
|
36
|
+
}) {
|
|
37
|
+
this.reference = reference;
|
|
38
|
+
this.options = options;
|
|
39
|
+
}
|
|
40
|
+
toBaseURI(uri) {
|
|
41
|
+
return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
|
|
42
|
+
}
|
|
43
|
+
async toReference(uri) {
|
|
44
|
+
// detect maximum depth of resolution
|
|
45
|
+
if (this.reference.depth >= this.options.resolve.maxDepth) {
|
|
46
|
+
throw new MaximumResolveDepthError(`Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`);
|
|
47
|
+
}
|
|
48
|
+
const baseURI = this.toBaseURI(uri);
|
|
49
|
+
const {
|
|
50
|
+
refSet
|
|
51
|
+
} = this.reference;
|
|
52
|
+
|
|
53
|
+
// we've already processed this Reference in past
|
|
54
|
+
if (refSet.has(baseURI)) {
|
|
55
|
+
return refSet.find(propEq(baseURI, 'uri'));
|
|
56
|
+
}
|
|
57
|
+
const parseResult = await parse(url.unsanitize(baseURI), {
|
|
58
|
+
...this.options,
|
|
59
|
+
parse: {
|
|
60
|
+
...this.options.parse,
|
|
61
|
+
mediaType: 'text/plain'
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// register new mutable reference with a refSet
|
|
66
|
+
const mutableReference = new Reference({
|
|
67
|
+
uri: baseURI,
|
|
68
|
+
value: cloneDeep(parseResult),
|
|
69
|
+
depth: this.reference.depth + 1
|
|
70
|
+
});
|
|
71
|
+
refSet.add(mutableReference);
|
|
72
|
+
if (this.options.dereference.immutable) {
|
|
73
|
+
// register new immutable reference with a refSet
|
|
74
|
+
const immutableReference = new Reference({
|
|
75
|
+
uri: `immutable://${baseURI}`,
|
|
76
|
+
value: parseResult,
|
|
77
|
+
depth: this.reference.depth + 1
|
|
78
|
+
});
|
|
79
|
+
refSet.add(immutableReference);
|
|
80
|
+
}
|
|
81
|
+
return mutableReference;
|
|
82
|
+
}
|
|
83
|
+
async RefElement(refElement, key, parent, path, ancestors) {
|
|
84
|
+
const refURI = toValue(refElement);
|
|
85
|
+
const refNormalizedURI = refURI.includes('#') ? refURI : `#${refURI}`;
|
|
86
|
+
const retrievalURI = this.toBaseURI(refNormalizedURI);
|
|
87
|
+
const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
|
|
88
|
+
const isExternalReference = !isInternalReference;
|
|
89
|
+
|
|
90
|
+
// ignore resolving internal RefElements
|
|
91
|
+
if (!this.options.resolve.internal && isInternalReference) {
|
|
92
|
+
// skip traversing this ref element
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// ignore resolving external RefElements
|
|
96
|
+
if (!this.options.resolve.external && isExternalReference) {
|
|
97
|
+
// skip traversing this ref element
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
const reference = await this.toReference(refNormalizedURI);
|
|
101
|
+
const refBaseURI = url.resolve(retrievalURI, refNormalizedURI);
|
|
102
|
+
const elementID = URIFragmentIdentifier.fromURIReference(refBaseURI);
|
|
103
|
+
let referencedElement = evaluate(elementID, reference.value.result);
|
|
104
|
+
if (!isElement(referencedElement)) {
|
|
105
|
+
throw new ApiDOMError(`Referenced element with id="${elementID}" was not found`);
|
|
106
|
+
}
|
|
107
|
+
if (refElement === referencedElement) {
|
|
108
|
+
throw new ApiDOMError('RefElement cannot reference itself');
|
|
109
|
+
}
|
|
110
|
+
if (isRefElement(referencedElement)) {
|
|
111
|
+
throw new ApiDOMError('RefElement cannot reference another RefElement');
|
|
112
|
+
}
|
|
113
|
+
if (isExternalReference) {
|
|
114
|
+
// dive deep into the fragment
|
|
115
|
+
const visitor = new ApiDOMDereferenceVisitor({
|
|
116
|
+
reference,
|
|
117
|
+
options: this.options
|
|
118
|
+
});
|
|
119
|
+
referencedElement = await visitAsync(referencedElement, visitor);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* When path is used, it references the given property of the referenced element
|
|
124
|
+
*/
|
|
125
|
+
const referencedElementPath = toValue(refElement.path);
|
|
126
|
+
if (referencedElementPath !== 'element' && isElement(referencedElement)) {
|
|
127
|
+
referencedElement = refract(referencedElement[referencedElementPath]);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Transclusion of a Ref Element SHALL be defined in the if/else block below.
|
|
132
|
+
*/
|
|
133
|
+
if (isObjectElement(referencedElement) && isObjectElement(ancestors[ancestors.length - 1]) && Array.isArray(parent) && typeof key === 'number') {
|
|
134
|
+
/**
|
|
135
|
+
* If the Ref Element is held by an Object Element and references an Object Element,
|
|
136
|
+
* its content entries SHALL be inserted in place of the Ref Element.
|
|
137
|
+
*/
|
|
138
|
+
parent.splice(key, 1, ...referencedElement.content);
|
|
139
|
+
} else if (isArrayElement(referencedElement) && Array.isArray(parent) && typeof key === 'number') {
|
|
140
|
+
/**
|
|
141
|
+
* If the Ref Element is held by an Array Element and references an Array Element,
|
|
142
|
+
* its content entries SHALL be inserted in place of the Ref Element.
|
|
143
|
+
*/
|
|
144
|
+
parent.splice(key, 1, ...referencedElement.content);
|
|
145
|
+
} else if (isMemberElement(parent)) {
|
|
146
|
+
/**
|
|
147
|
+
* The Ref Element is substituted by the Element it references.
|
|
148
|
+
*/
|
|
149
|
+
parent.value = referencedElement;
|
|
150
|
+
} else if (Array.isArray(parent)) {
|
|
151
|
+
/**
|
|
152
|
+
* The Ref Element is substituted by the Element it references.
|
|
153
|
+
*/
|
|
154
|
+
parent[key] = referencedElement;
|
|
155
|
+
}
|
|
156
|
+
return !parent ? referencedElement : false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export default ApiDOMDereferenceVisitor;
|
|
@@ -0,0 +1,100 @@
|
|
|
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.default = void 0;
|
|
7
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
8
|
+
var _apidomNsAsyncapi = _interopRequireWildcard(require("@speclynx/apidom-ns-asyncapi-2"));
|
|
9
|
+
var _DereferenceStrategy = _interopRequireDefault(require("../DereferenceStrategy.cjs"));
|
|
10
|
+
var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
|
|
11
|
+
var _ReferenceSet = _interopRequireDefault(require("../../../ReferenceSet.cjs"));
|
|
12
|
+
var _visitor = _interopRequireDefault(require("./visitor.cjs"));
|
|
13
|
+
exports.AsyncAPI2DereferenceVisitor = _visitor.default;
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
const visitAsync = _apidomCore.visit[Symbol.for('nodejs.util.promisify.custom')];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
class AsyncAPI2DereferenceStrategy extends _DereferenceStrategy.default {
|
|
25
|
+
constructor(options) {
|
|
26
|
+
super({
|
|
27
|
+
...(options ?? {}),
|
|
28
|
+
name: 'asyncapi-2'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
canDereference(file) {
|
|
32
|
+
// assert by media type
|
|
33
|
+
if (file.mediaType !== 'text/plain') {
|
|
34
|
+
return _apidomNsAsyncapi.mediaTypes.includes(file.mediaType);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// assert by inspecting ApiDOM
|
|
38
|
+
return (0, _apidomNsAsyncapi.isAsyncApi2Element)(file.parseResult?.api);
|
|
39
|
+
}
|
|
40
|
+
async dereference(file, options) {
|
|
41
|
+
const namespace = (0, _apidomCore.createNamespace)(_apidomNsAsyncapi.default);
|
|
42
|
+
const immutableRefSet = options.dereference.refSet ?? new _ReferenceSet.default();
|
|
43
|
+
const mutableRefSet = new _ReferenceSet.default();
|
|
44
|
+
let refSet = immutableRefSet;
|
|
45
|
+
let reference;
|
|
46
|
+
if (!immutableRefSet.has(file.uri)) {
|
|
47
|
+
reference = new _Reference.default({
|
|
48
|
+
uri: file.uri,
|
|
49
|
+
value: file.parseResult
|
|
50
|
+
});
|
|
51
|
+
immutableRefSet.add(reference);
|
|
52
|
+
} else {
|
|
53
|
+
// pre-computed refSet was provided as configuration option
|
|
54
|
+
reference = immutableRefSet.find(ref => ref.uri === file.uri);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Clone refSet due the dereferencing process being mutable.
|
|
59
|
+
* We don't want to mutate the original refSet and the references.
|
|
60
|
+
*/
|
|
61
|
+
if (options.dereference.immutable) {
|
|
62
|
+
immutableRefSet.refs.map(ref => new _Reference.default({
|
|
63
|
+
...ref,
|
|
64
|
+
value: (0, _apidomCore.cloneDeep)(ref.value)
|
|
65
|
+
})).forEach(ref => mutableRefSet.add(ref));
|
|
66
|
+
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
67
|
+
refSet = mutableRefSet;
|
|
68
|
+
}
|
|
69
|
+
const visitor = new _visitor.default({
|
|
70
|
+
reference,
|
|
71
|
+
namespace,
|
|
72
|
+
options
|
|
73
|
+
});
|
|
74
|
+
const dereferencedElement = await visitAsync(refSet.rootRef.value, visitor, {
|
|
75
|
+
keyMap: _apidomNsAsyncapi.keyMap,
|
|
76
|
+
nodeTypeGetter: _apidomNsAsyncapi.getNodeType
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* If immutable option is set, replay refs from the refSet.
|
|
81
|
+
*/
|
|
82
|
+
if (options.dereference.immutable) {
|
|
83
|
+
mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new _Reference.default({
|
|
84
|
+
...ref,
|
|
85
|
+
uri: ref.uri.replace(/^immutable:\/\//, '')
|
|
86
|
+
})).forEach(ref => immutableRefSet.add(ref));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Release all memory if this refSet was not provided as a configuration option.
|
|
91
|
+
* If provided as configuration option, then provider is responsible for cleanup.
|
|
92
|
+
*/
|
|
93
|
+
if (options.dereference.refSet === null) {
|
|
94
|
+
immutableRefSet.clean();
|
|
95
|
+
}
|
|
96
|
+
mutableRefSet.clean();
|
|
97
|
+
return dereferencedElement;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
var _default = exports.default = AsyncAPI2DereferenceStrategy;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createNamespace, visit, cloneDeep } from '@speclynx/apidom-core';
|
|
2
|
+
import asyncApi2Namespace, { getNodeType, isAsyncApi2Element, keyMap, mediaTypes } from '@speclynx/apidom-ns-asyncapi-2';
|
|
3
|
+
import DereferenceStrategy from "../DereferenceStrategy.mjs";
|
|
4
|
+
import Reference from "../../../Reference.mjs";
|
|
5
|
+
import ReferenceSet from "../../../ReferenceSet.mjs";
|
|
6
|
+
import AsyncAPI2DereferenceVisitor from "./visitor.mjs";
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
class AsyncAPI2DereferenceStrategy extends DereferenceStrategy {
|
|
18
|
+
constructor(options) {
|
|
19
|
+
super({
|
|
20
|
+
...(options ?? {}),
|
|
21
|
+
name: 'asyncapi-2'
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
canDereference(file) {
|
|
25
|
+
// assert by media type
|
|
26
|
+
if (file.mediaType !== 'text/plain') {
|
|
27
|
+
return mediaTypes.includes(file.mediaType);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// assert by inspecting ApiDOM
|
|
31
|
+
return isAsyncApi2Element(file.parseResult?.api);
|
|
32
|
+
}
|
|
33
|
+
async dereference(file, options) {
|
|
34
|
+
const namespace = createNamespace(asyncApi2Namespace);
|
|
35
|
+
const immutableRefSet = options.dereference.refSet ?? new ReferenceSet();
|
|
36
|
+
const mutableRefSet = new ReferenceSet();
|
|
37
|
+
let refSet = immutableRefSet;
|
|
38
|
+
let reference;
|
|
39
|
+
if (!immutableRefSet.has(file.uri)) {
|
|
40
|
+
reference = new Reference({
|
|
41
|
+
uri: file.uri,
|
|
42
|
+
value: file.parseResult
|
|
43
|
+
});
|
|
44
|
+
immutableRefSet.add(reference);
|
|
45
|
+
} else {
|
|
46
|
+
// pre-computed refSet was provided as configuration option
|
|
47
|
+
reference = immutableRefSet.find(ref => ref.uri === file.uri);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Clone refSet due the dereferencing process being mutable.
|
|
52
|
+
* We don't want to mutate the original refSet and the references.
|
|
53
|
+
*/
|
|
54
|
+
if (options.dereference.immutable) {
|
|
55
|
+
immutableRefSet.refs.map(ref => new Reference({
|
|
56
|
+
...ref,
|
|
57
|
+
value: cloneDeep(ref.value)
|
|
58
|
+
})).forEach(ref => mutableRefSet.add(ref));
|
|
59
|
+
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
60
|
+
refSet = mutableRefSet;
|
|
61
|
+
}
|
|
62
|
+
const visitor = new AsyncAPI2DereferenceVisitor({
|
|
63
|
+
reference,
|
|
64
|
+
namespace,
|
|
65
|
+
options
|
|
66
|
+
});
|
|
67
|
+
const dereferencedElement = await visitAsync(refSet.rootRef.value, visitor, {
|
|
68
|
+
keyMap,
|
|
69
|
+
nodeTypeGetter: getNodeType
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* If immutable option is set, replay refs from the refSet.
|
|
74
|
+
*/
|
|
75
|
+
if (options.dereference.immutable) {
|
|
76
|
+
mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new Reference({
|
|
77
|
+
...ref,
|
|
78
|
+
uri: ref.uri.replace(/^immutable:\/\//, '')
|
|
79
|
+
})).forEach(ref => immutableRefSet.add(ref));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Release all memory if this refSet was not provided as a configuration option.
|
|
84
|
+
* If provided as configuration option, then provider is responsible for cleanup.
|
|
85
|
+
*/
|
|
86
|
+
if (options.dereference.refSet === null) {
|
|
87
|
+
immutableRefSet.clean();
|
|
88
|
+
}
|
|
89
|
+
mutableRefSet.clean();
|
|
90
|
+
return dereferencedElement;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export { AsyncAPI2DereferenceVisitor };
|
|
94
|
+
export default AsyncAPI2DereferenceStrategy;
|