@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.
Files changed (263) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/LICENSE +202 -0
  3. package/LICENSES/AFL-3.0.txt +182 -0
  4. package/LICENSES/Apache-2.0.txt +202 -0
  5. package/LICENSES/BSD-3-Clause.txt +26 -0
  6. package/LICENSES/MIT.txt +9 -0
  7. package/NOTICE +65 -0
  8. package/README.md +2107 -0
  9. package/dist/167.apidom-reference.browser.js +10 -0
  10. package/dist/167.apidom-reference.browser.min.js +1 -0
  11. package/dist/451.apidom-reference.browser.js +10 -0
  12. package/dist/451.apidom-reference.browser.min.js +1 -0
  13. package/dist/9786785aaddf11f37840fad896531940.wasm +0 -0
  14. package/dist/apidom-reference.browser.js +85376 -0
  15. package/dist/apidom-reference.browser.min.js +1 -0
  16. package/package.json +304 -0
  17. package/src/File.cjs +50 -0
  18. package/src/File.mjs +44 -0
  19. package/src/Reference.cjs +31 -0
  20. package/src/Reference.mjs +27 -0
  21. package/src/ReferenceSet.cjs +60 -0
  22. package/src/ReferenceSet.mjs +57 -0
  23. package/src/bundle/index.cjs +61 -0
  24. package/src/bundle/index.mjs +55 -0
  25. package/src/bundle/strategies/BundleStrategy.cjs +20 -0
  26. package/src/bundle/strategies/BundleStrategy.mjs +16 -0
  27. package/src/bundle/strategies/openapi-3-1/index.cjs +35 -0
  28. package/src/bundle/strategies/openapi-3-1/index.mjs +29 -0
  29. package/src/configuration/empty.cjs +9 -0
  30. package/src/configuration/empty.mjs +1 -0
  31. package/src/configuration/saturated.cjs +95 -0
  32. package/src/configuration/saturated.mjs +87 -0
  33. package/src/dereference/index.cjs +86 -0
  34. package/src/dereference/index.mjs +79 -0
  35. package/src/dereference/strategies/DereferenceStrategy.cjs +20 -0
  36. package/src/dereference/strategies/DereferenceStrategy.mjs +16 -0
  37. package/src/dereference/strategies/apidom/index.cjs +89 -0
  38. package/src/dereference/strategies/apidom/index.mjs +84 -0
  39. package/src/dereference/strategies/apidom/selectors/element-id.cjs +36 -0
  40. package/src/dereference/strategies/apidom/selectors/element-id.mjs +30 -0
  41. package/src/dereference/strategies/apidom/visitor.cjs +165 -0
  42. package/src/dereference/strategies/apidom/visitor.mjs +159 -0
  43. package/src/dereference/strategies/asyncapi-2/index.cjs +100 -0
  44. package/src/dereference/strategies/asyncapi-2/index.mjs +94 -0
  45. package/src/dereference/strategies/asyncapi-2/visitor.cjs +412 -0
  46. package/src/dereference/strategies/asyncapi-2/visitor.mjs +406 -0
  47. package/src/dereference/strategies/openapi-2/index.cjs +102 -0
  48. package/src/dereference/strategies/openapi-2/index.mjs +96 -0
  49. package/src/dereference/strategies/openapi-2/visitor.cjs +530 -0
  50. package/src/dereference/strategies/openapi-2/visitor.mjs +524 -0
  51. package/src/dereference/strategies/openapi-3-0/index.cjs +102 -0
  52. package/src/dereference/strategies/openapi-3-0/index.mjs +96 -0
  53. package/src/dereference/strategies/openapi-3-0/visitor.cjs +519 -0
  54. package/src/dereference/strategies/openapi-3-0/visitor.mjs +513 -0
  55. package/src/dereference/strategies/openapi-3-1/index.cjs +105 -0
  56. package/src/dereference/strategies/openapi-3-1/index.mjs +96 -0
  57. package/src/dereference/strategies/openapi-3-1/selectors/$anchor.cjs +66 -0
  58. package/src/dereference/strategies/openapi-3-1/selectors/$anchor.mjs +55 -0
  59. package/src/dereference/strategies/openapi-3-1/selectors/uri.cjs +50 -0
  60. package/src/dereference/strategies/openapi-3-1/selectors/uri.mjs +42 -0
  61. package/src/dereference/strategies/openapi-3-1/util.cjs +67 -0
  62. package/src/dereference/strategies/openapi-3-1/util.mjs +58 -0
  63. package/src/dereference/strategies/openapi-3-1/visitor.cjs +776 -0
  64. package/src/dereference/strategies/openapi-3-1/visitor.mjs +770 -0
  65. package/src/dereference/util.cjs +31 -0
  66. package/src/dereference/util.mjs +27 -0
  67. package/src/errors/BundleError.cjs +10 -0
  68. package/src/errors/BundleError.mjs +7 -0
  69. package/src/errors/DereferenceError.cjs +10 -0
  70. package/src/errors/DereferenceError.mjs +7 -0
  71. package/src/errors/EvaluationElementIdError.cjs +10 -0
  72. package/src/errors/EvaluationElementIdError.mjs +7 -0
  73. package/src/errors/EvaluationJsonSchema$anchorError.cjs +11 -0
  74. package/src/errors/EvaluationJsonSchema$anchorError.mjs +6 -0
  75. package/src/errors/EvaluationJsonSchemaUriError.cjs +11 -0
  76. package/src/errors/EvaluationJsonSchemaUriError.mjs +6 -0
  77. package/src/errors/InvalidJsonSchema$anchorError.cjs +15 -0
  78. package/src/errors/InvalidJsonSchema$anchorError.mjs +10 -0
  79. package/src/errors/JsonSchema$anchorError.cjs +10 -0
  80. package/src/errors/JsonSchema$anchorError.mjs +7 -0
  81. package/src/errors/JsonSchemaUriError.cjs +10 -0
  82. package/src/errors/JsonSchemaUriError.mjs +7 -0
  83. package/src/errors/MaximumBundleDepthError.cjs +11 -0
  84. package/src/errors/MaximumBundleDepthError.mjs +6 -0
  85. package/src/errors/MaximumDereferenceDepthError.cjs +11 -0
  86. package/src/errors/MaximumDereferenceDepthError.mjs +6 -0
  87. package/src/errors/MaximumResolveDepthError.cjs +11 -0
  88. package/src/errors/MaximumResolveDepthError.mjs +6 -0
  89. package/src/errors/ParseError.cjs +10 -0
  90. package/src/errors/ParseError.mjs +7 -0
  91. package/src/errors/ParserError.cjs +11 -0
  92. package/src/errors/ParserError.mjs +6 -0
  93. package/src/errors/PluginError.cjs +18 -0
  94. package/src/errors/PluginError.mjs +15 -0
  95. package/src/errors/ResolveError.cjs +10 -0
  96. package/src/errors/ResolveError.mjs +7 -0
  97. package/src/errors/ResolverError.cjs +11 -0
  98. package/src/errors/ResolverError.mjs +6 -0
  99. package/src/errors/UnmatchedBundleStrategyError.cjs +11 -0
  100. package/src/errors/UnmatchedBundleStrategyError.mjs +6 -0
  101. package/src/errors/UnmatchedDereferenceStrategyError.cjs +11 -0
  102. package/src/errors/UnmatchedDereferenceStrategyError.mjs +6 -0
  103. package/src/errors/UnmatchedResolveStrategyError.cjs +11 -0
  104. package/src/errors/UnmatchedResolveStrategyError.mjs +6 -0
  105. package/src/errors/UnmatchedResolverError.cjs +11 -0
  106. package/src/errors/UnmatchedResolverError.mjs +6 -0
  107. package/src/index.cjs +142 -0
  108. package/src/index.mjs +101 -0
  109. package/src/options/index.cjs +185 -0
  110. package/src/options/index.mjs +182 -0
  111. package/src/options/util.cjs +24 -0
  112. package/src/options/util.mjs +19 -0
  113. package/src/parse/index.cjs +69 -0
  114. package/src/parse/index.mjs +63 -0
  115. package/src/parse/parsers/Parser.cjs +48 -0
  116. package/src/parse/parsers/Parser.mjs +44 -0
  117. package/src/parse/parsers/api-design-systems-json/index.cjs +55 -0
  118. package/src/parse/parsers/api-design-systems-json/index.mjs +49 -0
  119. package/src/parse/parsers/api-design-systems-yaml/index.cjs +54 -0
  120. package/src/parse/parsers/api-design-systems-yaml/index.mjs +48 -0
  121. package/src/parse/parsers/apidom-json/index.cjs +70 -0
  122. package/src/parse/parsers/apidom-json/index.mjs +64 -0
  123. package/src/parse/parsers/arazzo-json-1/index.cjs +55 -0
  124. package/src/parse/parsers/arazzo-json-1/index.mjs +49 -0
  125. package/src/parse/parsers/arazzo-yaml-1/index.cjs +54 -0
  126. package/src/parse/parsers/arazzo-yaml-1/index.mjs +48 -0
  127. package/src/parse/parsers/asyncapi-json-2/index.cjs +55 -0
  128. package/src/parse/parsers/asyncapi-json-2/index.mjs +49 -0
  129. package/src/parse/parsers/asyncapi-yaml-2/index.cjs +54 -0
  130. package/src/parse/parsers/asyncapi-yaml-2/index.mjs +48 -0
  131. package/src/parse/parsers/binary/index-browser.cjs +56 -0
  132. package/src/parse/parsers/binary/index-browser.mjs +50 -0
  133. package/src/parse/parsers/binary/index-node.cjs +51 -0
  134. package/src/parse/parsers/binary/index-node.mjs +45 -0
  135. package/src/parse/parsers/json/index.cjs +54 -0
  136. package/src/parse/parsers/json/index.mjs +48 -0
  137. package/src/parse/parsers/openapi-json-2/index.cjs +55 -0
  138. package/src/parse/parsers/openapi-json-2/index.mjs +49 -0
  139. package/src/parse/parsers/openapi-json-3-0/index.cjs +55 -0
  140. package/src/parse/parsers/openapi-json-3-0/index.mjs +49 -0
  141. package/src/parse/parsers/openapi-json-3-1/index.cjs +55 -0
  142. package/src/parse/parsers/openapi-json-3-1/index.mjs +49 -0
  143. package/src/parse/parsers/openapi-yaml-2/index.cjs +54 -0
  144. package/src/parse/parsers/openapi-yaml-2/index.mjs +48 -0
  145. package/src/parse/parsers/openapi-yaml-3-0/index.cjs +54 -0
  146. package/src/parse/parsers/openapi-yaml-3-0/index.mjs +48 -0
  147. package/src/parse/parsers/openapi-yaml-3-1/index.cjs +54 -0
  148. package/src/parse/parsers/openapi-yaml-3-1/index.mjs +48 -0
  149. package/src/parse/parsers/yaml-1-2/index.cjs +54 -0
  150. package/src/parse/parsers/yaml-1-2/index.mjs +48 -0
  151. package/src/resolve/index.cjs +67 -0
  152. package/src/resolve/index.mjs +60 -0
  153. package/src/resolve/resolvers/HTTPResolver.cjs +38 -0
  154. package/src/resolve/resolvers/HTTPResolver.mjs +31 -0
  155. package/src/resolve/resolvers/Resolver.cjs +20 -0
  156. package/src/resolve/resolvers/Resolver.mjs +16 -0
  157. package/src/resolve/resolvers/file/index-browser.cjs +24 -0
  158. package/src/resolve/resolvers/file/index-browser.mjs +19 -0
  159. package/src/resolve/resolvers/file/index-node.cjs +49 -0
  160. package/src/resolve/resolvers/file/index-node.mjs +42 -0
  161. package/src/resolve/resolvers/http-axios/index.cjs +80 -0
  162. package/src/resolve/resolvers/http-axios/index.mjs +73 -0
  163. package/src/resolve/strategies/ResolveStrategy.cjs +20 -0
  164. package/src/resolve/strategies/ResolveStrategy.mjs +16 -0
  165. package/src/resolve/strategies/apidom/index.cjs +49 -0
  166. package/src/resolve/strategies/apidom/index.mjs +43 -0
  167. package/src/resolve/strategies/asyncapi-2/index.cjs +49 -0
  168. package/src/resolve/strategies/asyncapi-2/index.mjs +43 -0
  169. package/src/resolve/strategies/openapi-2/index.cjs +49 -0
  170. package/src/resolve/strategies/openapi-2/index.mjs +43 -0
  171. package/src/resolve/strategies/openapi-3-0/index.cjs +49 -0
  172. package/src/resolve/strategies/openapi-3-0/index.mjs +43 -0
  173. package/src/resolve/strategies/openapi-3-1/index.cjs +49 -0
  174. package/src/resolve/strategies/openapi-3-1/index.mjs +43 -0
  175. package/src/resolve/util.cjs +37 -0
  176. package/src/resolve/util.mjs +30 -0
  177. package/src/util/plugins.cjs +44 -0
  178. package/src/util/plugins.mjs +37 -0
  179. package/src/util/url.cjs +288 -0
  180. package/src/util/url.mjs +274 -0
  181. package/types/File.d.ts +24 -0
  182. package/types/Reference.d.ts +23 -0
  183. package/types/ReferenceSet.d.ts +25 -0
  184. package/types/apidom-reference.d.ts +584 -0
  185. package/types/bundle/index.d.ts +7 -0
  186. package/types/bundle/strategies/BundleStrategy.d.ts +19 -0
  187. package/types/bundle/strategies/openapi-3-1/index.d.ts +26 -0
  188. package/types/configuration/empty.d.ts +1 -0
  189. package/types/configuration/saturated.d.ts +1 -0
  190. package/types/dereference/index.d.ts +11 -0
  191. package/types/dereference/strategies/DereferenceStrategy.d.ts +19 -0
  192. package/types/dereference/strategies/apidom/index.d.ts +30 -0
  193. package/types/dereference/strategies/apidom/selectors/element-id.d.ts +11 -0
  194. package/types/dereference/strategies/apidom/visitor.d.ts +32 -0
  195. package/types/dereference/strategies/asyncapi-2/index.d.ts +31 -0
  196. package/types/dereference/strategies/asyncapi-2/visitor.d.ts +43 -0
  197. package/types/dereference/strategies/openapi-2/index.d.ts +32 -0
  198. package/types/dereference/strategies/openapi-2/visitor.d.ts +47 -0
  199. package/types/dereference/strategies/openapi-3-0/index.d.ts +31 -0
  200. package/types/dereference/strategies/openapi-3-0/visitor.d.ts +49 -0
  201. package/types/dereference/strategies/openapi-3-1/index.d.ts +32 -0
  202. package/types/dereference/strategies/openapi-3-1/selectors/$anchor.d.ts +22 -0
  203. package/types/dereference/strategies/openapi-3-1/selectors/uri.d.ts +12 -0
  204. package/types/dereference/strategies/openapi-3-1/util.d.ts +21 -0
  205. package/types/dereference/strategies/openapi-3-1/visitor.d.ts +52 -0
  206. package/types/dereference/util.d.ts +9 -0
  207. package/types/errors/BundleError.d.ts +7 -0
  208. package/types/errors/DereferenceError.d.ts +7 -0
  209. package/types/errors/EvaluationElementIdError.d.ts +7 -0
  210. package/types/errors/EvaluationJsonSchema$anchorError.d.ts +7 -0
  211. package/types/errors/EvaluationJsonSchemaUriError.d.ts +7 -0
  212. package/types/errors/InvalidJsonSchema$anchorError.d.ts +8 -0
  213. package/types/errors/JsonSchema$anchorError.d.ts +7 -0
  214. package/types/errors/JsonSchemaUriError.d.ts +7 -0
  215. package/types/errors/MaximumBundleDepthError.d.ts +7 -0
  216. package/types/errors/MaximumDereferenceDepthError.d.ts +7 -0
  217. package/types/errors/MaximumResolveDepthError.d.ts +7 -0
  218. package/types/errors/ParseError.d.ts +7 -0
  219. package/types/errors/ParserError.d.ts +7 -0
  220. package/types/errors/PluginError.d.ts +12 -0
  221. package/types/errors/ResolveError.d.ts +7 -0
  222. package/types/errors/ResolverError.d.ts +7 -0
  223. package/types/errors/UnmatchedBundleStrategyError.d.ts +7 -0
  224. package/types/errors/UnmatchedDereferenceStrategyError.d.ts +7 -0
  225. package/types/errors/UnmatchedResolveStrategyError.d.ts +7 -0
  226. package/types/errors/UnmatchedResolverError.d.ts +7 -0
  227. package/types/index.d.ts +75 -0
  228. package/types/options/index.d.ts +62 -0
  229. package/types/options/util.d.ts +5 -0
  230. package/types/parse/index.d.ts +7 -0
  231. package/types/parse/parsers/Parser.d.ts +38 -0
  232. package/types/parse/parsers/api-design-systems-json/index.d.ts +21 -0
  233. package/types/parse/parsers/api-design-systems-yaml/index.d.ts +20 -0
  234. package/types/parse/parsers/apidom-json/index.d.ts +24 -0
  235. package/types/parse/parsers/arazzo-json-1/index.d.ts +21 -0
  236. package/types/parse/parsers/arazzo-yaml-1/index.d.ts +20 -0
  237. package/types/parse/parsers/asyncapi-json-2/index.d.ts +21 -0
  238. package/types/parse/parsers/asyncapi-yaml-2/index.d.ts +20 -0
  239. package/types/parse/parsers/binary/index-browser.d.ts +21 -0
  240. package/types/parse/parsers/binary/index-node.d.ts +21 -0
  241. package/types/parse/parsers/json/index.d.ts +20 -0
  242. package/types/parse/parsers/openapi-json-2/index.d.ts +21 -0
  243. package/types/parse/parsers/openapi-json-3-0/index.d.ts +21 -0
  244. package/types/parse/parsers/openapi-json-3-1/index.d.ts +21 -0
  245. package/types/parse/parsers/openapi-yaml-2/index.d.ts +20 -0
  246. package/types/parse/parsers/openapi-yaml-3-0/index.d.ts +20 -0
  247. package/types/parse/parsers/openapi-yaml-3-1/index.d.ts +20 -0
  248. package/types/parse/parsers/yaml-1-2/index.d.ts +20 -0
  249. package/types/resolve/index.d.ts +12 -0
  250. package/types/resolve/resolvers/HTTPResolver.d.ts +22 -0
  251. package/types/resolve/resolvers/Resolver.d.ts +17 -0
  252. package/types/resolve/resolvers/file/index-browser.d.ts +12 -0
  253. package/types/resolve/resolvers/file/index-node.d.ts +20 -0
  254. package/types/resolve/resolvers/http-axios/index.d.ts +30 -0
  255. package/types/resolve/strategies/ResolveStrategy.d.ts +19 -0
  256. package/types/resolve/strategies/apidom/index.d.ts +27 -0
  257. package/types/resolve/strategies/asyncapi-2/index.d.ts +27 -0
  258. package/types/resolve/strategies/openapi-2/index.d.ts +27 -0
  259. package/types/resolve/strategies/openapi-3-0/index.d.ts +27 -0
  260. package/types/resolve/strategies/openapi-3-1/index.d.ts +27 -0
  261. package/types/resolve/util.d.ts +6 -0
  262. package/types/util/plugins.d.ts +14 -0
  263. package/types/util/url.d.ts +106 -0
@@ -0,0 +1,513 @@
1
+ import { propEq } from 'ramda';
2
+ import { isUndefined } from 'ramda-adjunct';
3
+ import { isPrimitiveElement, isStringElement, isMemberElement, isElement, IdentityManager, visit, find, cloneShallow, cloneDeep, toValue, RefElement } from '@speclynx/apidom-core';
4
+ import { ApiDOMError } from '@speclynx/apidom-error';
5
+ import { evaluate, URIFragmentIdentifier } from '@speclynx/apidom-json-pointer';
6
+ import { getNodeType, keyMap, ReferenceElement, OperationElement, PathItemElement, isReferenceElement, isOperationElement, isPathItemElement, isReferenceLikeElement } from '@speclynx/apidom-ns-openapi-3-0';
7
+ import MaximumDereferenceDepthError from "../../../errors/MaximumDereferenceDepthError.mjs";
8
+ import MaximumResolveDepthError from "../../../errors/MaximumResolveDepthError.mjs";
9
+ import * as url from "../../../util/url.mjs";
10
+ import parse from "../../../parse/index.mjs";
11
+ import Reference from "../../../Reference.mjs";
12
+ import { AncestorLineage } from "../../util.mjs";
13
+ // @ts-ignore
14
+ const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];
15
+
16
+ // initialize element identity manager
17
+ const identityManager = new IdentityManager();
18
+
19
+ /**
20
+ * Custom mutation replacer.
21
+ * @public
22
+ */
23
+ export const mutationReplacer = (newElement, oldElement, key, parent) => {
24
+ if (isMemberElement(parent)) {
25
+ parent.value = newElement;
26
+ } else if (Array.isArray(parent)) {
27
+ parent[key] = newElement;
28
+ }
29
+ };
30
+
31
+ /**
32
+ * @public
33
+ */
34
+
35
+ /**
36
+ * @public
37
+ */
38
+ class OpenAPI3_0DereferenceVisitor {
39
+ indirections;
40
+ namespace;
41
+ reference;
42
+ options;
43
+ ancestors;
44
+ refractCache;
45
+ constructor({
46
+ reference,
47
+ namespace,
48
+ options,
49
+ indirections = [],
50
+ ancestors = new AncestorLineage(),
51
+ refractCache = new Map()
52
+ }) {
53
+ this.indirections = indirections;
54
+ this.namespace = namespace;
55
+ this.reference = reference;
56
+ this.options = options;
57
+ this.ancestors = new AncestorLineage(...ancestors);
58
+ this.refractCache = refractCache;
59
+ }
60
+ toBaseURI(uri) {
61
+ return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
62
+ }
63
+ async toReference(uri) {
64
+ // detect maximum depth of resolution
65
+ if (this.reference.depth >= this.options.resolve.maxDepth) {
66
+ throw new MaximumResolveDepthError(`Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`);
67
+ }
68
+ const baseURI = this.toBaseURI(uri);
69
+ const {
70
+ refSet
71
+ } = this.reference;
72
+
73
+ // we've already processed this Reference in past
74
+ if (refSet.has(baseURI)) {
75
+ return refSet.find(propEq(baseURI, 'uri'));
76
+ }
77
+ const parseResult = await parse(url.unsanitize(baseURI), {
78
+ ...this.options,
79
+ parse: {
80
+ ...this.options.parse,
81
+ mediaType: 'text/plain'
82
+ }
83
+ });
84
+
85
+ // register new mutable reference with a refSet
86
+ const mutableReference = new Reference({
87
+ uri: baseURI,
88
+ value: cloneDeep(parseResult),
89
+ depth: this.reference.depth + 1
90
+ });
91
+ refSet.add(mutableReference);
92
+ if (this.options.dereference.immutable) {
93
+ // register new immutable reference with a refSet
94
+ const immutableReference = new Reference({
95
+ uri: `immutable://${baseURI}`,
96
+ value: parseResult,
97
+ depth: this.reference.depth + 1
98
+ });
99
+ refSet.add(immutableReference);
100
+ }
101
+ return mutableReference;
102
+ }
103
+ toAncestorLineage(ancestors) {
104
+ /**
105
+ * Compute full ancestors lineage.
106
+ * Ancestors are flatten to unwrap all Element instances.
107
+ */
108
+ const directAncestors = new Set(ancestors.filter(isElement));
109
+ const ancestorsLineage = new AncestorLineage(...this.ancestors, directAncestors);
110
+ return [ancestorsLineage, directAncestors];
111
+ }
112
+ async ReferenceElement(referencingElement, key, parent, path, ancestors, link) {
113
+ // skip current referencing element as it's already been access
114
+ if (this.indirections.includes(referencingElement)) {
115
+ return false;
116
+ }
117
+ const [ancestorsLineage, directAncestors] = this.toAncestorLineage([...ancestors, parent]);
118
+ const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
119
+ const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
120
+ const isExternalReference = !isInternalReference;
121
+
122
+ // ignore resolving internal Reference Objects
123
+ if (!this.options.resolve.internal && isInternalReference) {
124
+ // skip traversing this reference element
125
+ return false;
126
+ }
127
+ // ignore resolving external Reference Objects
128
+ if (!this.options.resolve.external && isExternalReference) {
129
+ // skip traversing this reference element
130
+ return false;
131
+ }
132
+ const reference = await this.toReference(toValue(referencingElement.$ref));
133
+ const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
134
+ this.indirections.push(referencingElement);
135
+ const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
136
+
137
+ // possibly non-semantic fragment
138
+ let referencedElement = evaluate(reference.value.result, jsonPointer);
139
+ referencedElement.id = identityManager.identify(referencedElement);
140
+
141
+ /**
142
+ * Applying semantics to a referenced element if semantics are missing.
143
+ */
144
+ if (isPrimitiveElement(referencedElement)) {
145
+ const referencedElementType = toValue(referencingElement.meta.get('referenced-element'));
146
+ const cacheKey = `${referencedElementType}-${toValue(identityManager.identify(referencedElement))}`;
147
+ if (this.refractCache.has(cacheKey)) {
148
+ referencedElement = this.refractCache.get(cacheKey);
149
+ } else if (isReferenceLikeElement(referencedElement)) {
150
+ // handling indirect references
151
+ referencedElement = ReferenceElement.refract(referencedElement);
152
+ referencedElement.setMetaProperty('referenced-element', referencedElementType);
153
+ this.refractCache.set(cacheKey, referencedElement);
154
+ } else {
155
+ // handling direct references
156
+ const ElementClass = this.namespace.getElementClass(referencedElementType);
157
+ referencedElement = ElementClass.refract(referencedElement);
158
+ this.refractCache.set(cacheKey, referencedElement);
159
+ }
160
+ }
161
+
162
+ // detect direct or circular reference
163
+ if (referencingElement === referencedElement) {
164
+ throw new ApiDOMError('Recursive Reference Object detected');
165
+ }
166
+
167
+ // detect maximum depth of dereferencing
168
+ if (this.indirections.length > this.options.dereference.maxDepth) {
169
+ throw new MaximumDereferenceDepthError(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`);
170
+ }
171
+
172
+ // detect second deep dive into the same fragment and avoid it
173
+ if (ancestorsLineage.includes(referencedElement)) {
174
+ reference.refSet.circular = true;
175
+ if (this.options.dereference.circular === 'error') {
176
+ throw new ApiDOMError('Circular reference detected');
177
+ } else if (this.options.dereference.circular === 'replace') {
178
+ const refElement = new RefElement(referencedElement.id, {
179
+ type: 'reference',
180
+ uri: reference.uri,
181
+ $ref: toValue(referencingElement.$ref)
182
+ });
183
+ const replacer = this.options.dereference.strategyOpts['openapi-3-0']?.circularReplacer ?? this.options.dereference.circularReplacer;
184
+ const replacement = replacer(refElement);
185
+ link.replaceWith(replacement, mutationReplacer);
186
+ return !parent ? replacement : false;
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Dive deep into the fragment.
192
+ *
193
+ * Cases to consider:
194
+ * 1. We're crossing document boundary
195
+ * 2. Fragment is from non-entry document
196
+ * 3. Fragment is a Reference Object. We need to follow it to get the eventual value
197
+ * 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
198
+ */
199
+ const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
200
+ const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
201
+ if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
202
+ // append referencing reference to ancestors lineage
203
+ directAncestors.add(referencingElement);
204
+ const visitor = new OpenAPI3_0DereferenceVisitor({
205
+ reference,
206
+ namespace: this.namespace,
207
+ indirections: [...this.indirections],
208
+ options: this.options,
209
+ refractCache: this.refractCache,
210
+ ancestors: ancestorsLineage
211
+ });
212
+ referencedElement = await visitAsync(referencedElement, visitor, {
213
+ keyMap,
214
+ nodeTypeGetter: getNodeType
215
+ });
216
+
217
+ // remove referencing reference from ancestors lineage
218
+ directAncestors.delete(referencingElement);
219
+ }
220
+ this.indirections.pop();
221
+
222
+ /**
223
+ * Creating a new version of referenced element to avoid modifying the original one.
224
+ */
225
+ const mergedElement = cloneShallow(referencedElement);
226
+ // assign unique id to merged element
227
+ mergedElement.setMetaProperty('id', identityManager.generateId());
228
+ // annotate referenced element with info about original referencing element
229
+ mergedElement.setMetaProperty('ref-fields', {
230
+ $ref: toValue(referencingElement.$ref)
231
+ });
232
+ // annotate fragment with info about origin
233
+ mergedElement.setMetaProperty('ref-origin', reference.uri);
234
+ // annotate fragment with info about referencing element
235
+ mergedElement.setMetaProperty('ref-referencing-element-id', cloneDeep(identityManager.identify(referencingElement)));
236
+
237
+ /**
238
+ * Transclude referencing element with merged referenced element.
239
+ */
240
+ link.replaceWith(mergedElement, mutationReplacer);
241
+
242
+ /**
243
+ * We're at the root of the tree, so we're just replacing the entire tree.
244
+ */
245
+ return !parent ? mergedElement : false;
246
+ }
247
+ async PathItemElement(referencingElement, key, parent, path, ancestors, link) {
248
+ // ignore PathItemElement without $ref field
249
+ if (!isStringElement(referencingElement.$ref)) {
250
+ return undefined;
251
+ }
252
+
253
+ // skip current referencing element as it's already been access
254
+ if (this.indirections.includes(referencingElement)) {
255
+ return false;
256
+ }
257
+ const [ancestorsLineage, directAncestors] = this.toAncestorLineage([...ancestors, parent]);
258
+ const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
259
+ const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
260
+ const isExternalReference = !isInternalReference;
261
+
262
+ // ignore resolving internal Path Item Objects
263
+ if (!this.options.resolve.internal && isInternalReference) {
264
+ // skip traversing this Path Item element but traverse all it's child elements
265
+ return undefined;
266
+ }
267
+ // ignore resolving external Path Item Objects
268
+ if (!this.options.resolve.external && isExternalReference) {
269
+ // skip traversing this Path Item element but traverse all it's child elements
270
+ return undefined;
271
+ }
272
+ const reference = await this.toReference(toValue(referencingElement.$ref));
273
+ const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
274
+ this.indirections.push(referencingElement);
275
+ const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
276
+
277
+ // possibly non-semantic referenced element
278
+ let referencedElement = evaluate(reference.value.result, jsonPointer);
279
+ referencedElement.id = identityManager.identify(referencedElement);
280
+
281
+ /**
282
+ * Applying semantics to a referenced element if semantics are missing.
283
+ */
284
+ if (!isPathItemElement(referencedElement)) {
285
+ const cacheKey = `path-item-${toValue(identityManager.identify(referencedElement))}`;
286
+ if (this.refractCache.has(cacheKey)) {
287
+ referencedElement = this.refractCache.get(cacheKey);
288
+ } else {
289
+ referencedElement = PathItemElement.refract(referencedElement);
290
+ this.refractCache.set(cacheKey, referencedElement);
291
+ }
292
+ }
293
+
294
+ // detect direct or circular reference
295
+ if (referencingElement === referencedElement) {
296
+ throw new ApiDOMError('Recursive Path Item Object reference detected');
297
+ }
298
+
299
+ // detect maximum depth of dereferencing
300
+ if (this.indirections.length > this.options.dereference.maxDepth) {
301
+ throw new MaximumDereferenceDepthError(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`);
302
+ }
303
+
304
+ // detect second deep dive into the same fragment and avoid it
305
+ if (ancestorsLineage.includes(referencedElement)) {
306
+ reference.refSet.circular = true;
307
+ if (this.options.dereference.circular === 'error') {
308
+ throw new ApiDOMError('Circular reference detected');
309
+ } else if (this.options.dereference.circular === 'replace') {
310
+ const refElement = new RefElement(referencedElement.id, {
311
+ type: 'path-item',
312
+ uri: reference.uri,
313
+ $ref: toValue(referencingElement.$ref)
314
+ });
315
+ const replacer = this.options.dereference.strategyOpts['openapi-3-0']?.circularReplacer ?? this.options.dereference.circularReplacer;
316
+ const replacement = replacer(refElement);
317
+ link.replaceWith(replacement, mutationReplacer);
318
+ return !parent ? replacement : undefined;
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Dive deep into the fragment.
324
+ *
325
+ * Cases to consider:
326
+ * 1. We're crossing document boundary
327
+ * 2. Fragment is from non-entry document
328
+ * 3. Fragment is a Path Item Object with $ref field. We need to follow it to get the eventual value
329
+ * 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
330
+ */
331
+ const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
332
+ const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
333
+ if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
334
+ // append referencing reference to ancestors lineage
335
+ directAncestors.add(referencingElement);
336
+ const visitor = new OpenAPI3_0DereferenceVisitor({
337
+ reference,
338
+ namespace: this.namespace,
339
+ indirections: [...this.indirections],
340
+ options: this.options,
341
+ refractCache: this.refractCache,
342
+ ancestors: ancestorsLineage
343
+ });
344
+ referencedElement = await visitAsync(referencedElement, visitor, {
345
+ keyMap,
346
+ nodeTypeGetter: getNodeType
347
+ });
348
+
349
+ // remove referencing reference from ancestors lineage
350
+ directAncestors.delete(referencingElement);
351
+ }
352
+ this.indirections.pop();
353
+
354
+ /**
355
+ * Creating a new version of Path Item by merging fields from referenced Path Item with referencing one.
356
+ */
357
+ if (isPathItemElement(referencedElement)) {
358
+ const mergedElement = new PathItemElement([...referencedElement.content], cloneDeep(referencedElement.meta), cloneDeep(referencedElement.attributes));
359
+ // assign unique id to merged element
360
+ mergedElement.setMetaProperty('id', identityManager.generateId());
361
+ // existing keywords from referencing PathItemElement overrides ones from referenced element
362
+ referencingElement.forEach((value, keyElement, item) => {
363
+ mergedElement.remove(toValue(keyElement));
364
+ mergedElement.content.push(item);
365
+ });
366
+ mergedElement.remove('$ref');
367
+
368
+ // annotate referenced element with info about original referencing element
369
+ mergedElement.setMetaProperty('ref-fields', {
370
+ $ref: toValue(referencingElement.$ref)
371
+ });
372
+ // annotate referenced element with info about origin
373
+ mergedElement.setMetaProperty('ref-origin', reference.uri);
374
+ // annotate fragment with info about referencing element
375
+ mergedElement.setMetaProperty('ref-referencing-element-id', cloneDeep(identityManager.identify(referencingElement)));
376
+ referencedElement = mergedElement;
377
+ }
378
+
379
+ /**
380
+ * Transclude referencing element with merged referenced element.
381
+ */
382
+ link.replaceWith(referencedElement, mutationReplacer);
383
+
384
+ /**
385
+ * We're at the root of the tree, so we're just replacing the entire tree.
386
+ */
387
+ return !parent ? referencedElement : undefined;
388
+ }
389
+ async LinkElement(linkElement, key, parent, path, ancestors, link) {
390
+ // ignore LinkElement without operationRef or operationId field
391
+ if (!isStringElement(linkElement.operationRef) && !isStringElement(linkElement.operationId)) {
392
+ return undefined;
393
+ }
394
+
395
+ // operationRef and operationId fields are mutually exclusive
396
+ if (isStringElement(linkElement.operationRef) && isStringElement(linkElement.operationId)) {
397
+ throw new ApiDOMError('LinkElement operationRef and operationId fields are mutually exclusive.');
398
+ }
399
+ let operationElement;
400
+ if (isStringElement(linkElement.operationRef)) {
401
+ // possibly non-semantic referenced element
402
+ const jsonPointer = URIFragmentIdentifier.fromURIReference(toValue(linkElement.operationRef));
403
+ const retrievalURI = this.toBaseURI(toValue(linkElement.operationRef));
404
+ const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
405
+ const isExternalReference = !isInternalReference;
406
+
407
+ // ignore resolving internal Operation Object reference
408
+ if (!this.options.resolve.internal && isInternalReference) {
409
+ // skip traversing this Link element but traverse all it's child elements
410
+ return undefined;
411
+ }
412
+ // ignore resolving external Operation Object reference
413
+ if (!this.options.resolve.external && isExternalReference) {
414
+ // skip traversing this Link element but traverse all it's child elements
415
+ return undefined;
416
+ }
417
+ const reference = await this.toReference(toValue(linkElement.operationRef));
418
+ operationElement = evaluate(reference.value.result, jsonPointer);
419
+ // applying semantics to a referenced element
420
+ if (isPrimitiveElement(operationElement)) {
421
+ const cacheKey = `operation-${toValue(identityManager.identify(operationElement))}`;
422
+ if (this.refractCache.has(cacheKey)) {
423
+ operationElement = this.refractCache.get(cacheKey);
424
+ } else {
425
+ operationElement = OperationElement.refract(operationElement);
426
+ this.refractCache.set(cacheKey, operationElement);
427
+ }
428
+ }
429
+ // create shallow clone to be able to annotate with metadata
430
+ operationElement = cloneShallow(operationElement);
431
+ // annotate operation element with info about origin
432
+ operationElement.setMetaProperty('ref-origin', reference.uri);
433
+ const linkElementCopy = cloneShallow(linkElement);
434
+ linkElementCopy.operationRef?.meta.set('operation', operationElement);
435
+
436
+ /**
437
+ * Transclude Link Object containing Operation Object in its meta.
438
+ */
439
+ link.replaceWith(linkElementCopy, mutationReplacer);
440
+
441
+ /**
442
+ * We're at the root of the tree, so we're just replacing the entire tree.
443
+ */
444
+ return !parent ? linkElementCopy : undefined;
445
+ }
446
+ if (isStringElement(linkElement.operationId)) {
447
+ const operationId = toValue(linkElement.operationId);
448
+ const reference = await this.toReference(url.unsanitize(this.reference.uri));
449
+ operationElement = find(e => isOperationElement(e) && isElement(e.operationId) && e.operationId.equals(operationId), reference.value.result);
450
+ // OperationElement not found by its operationId
451
+ if (isUndefined(operationElement)) {
452
+ throw new ApiDOMError(`OperationElement(operationId=${operationId}) not found.`);
453
+ }
454
+ const linkElementCopy = cloneShallow(linkElement);
455
+ linkElementCopy.operationId?.meta.set('operation', operationElement);
456
+
457
+ /**
458
+ * Transclude Link Object containing Operation Object in its meta.
459
+ */
460
+ link.replaceWith(linkElementCopy, mutationReplacer);
461
+
462
+ /**
463
+ * We're at the root of the tree, so we're just replacing the entire tree.
464
+ */
465
+ return !parent ? linkElementCopy : undefined;
466
+ }
467
+ return undefined;
468
+ }
469
+ async ExampleElement(exampleElement, key, parent, path, ancestors, link) {
470
+ // ignore ExampleElement without externalValue field
471
+ if (!isStringElement(exampleElement.externalValue)) {
472
+ return undefined;
473
+ }
474
+
475
+ // value and externalValue fields are mutually exclusive
476
+ if (exampleElement.hasKey('value') && isStringElement(exampleElement.externalValue)) {
477
+ throw new ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive.');
478
+ }
479
+ const retrievalURI = this.toBaseURI(toValue(exampleElement.externalValue));
480
+ const isInternalReference = url.stripHash(this.reference.uri) === retrievalURI;
481
+ const isExternalReference = !isInternalReference;
482
+
483
+ // ignore resolving external Example Objects
484
+ if (!this.options.resolve.internal && isInternalReference) {
485
+ // skip traversing this Example element but traverse all it's child elements
486
+ return undefined;
487
+ }
488
+ // ignore resolving external Example Objects
489
+ if (!this.options.resolve.external && isExternalReference) {
490
+ // skip traversing this Example element but traverse all it's child elements
491
+ return undefined;
492
+ }
493
+ const reference = await this.toReference(toValue(exampleElement.externalValue));
494
+
495
+ // shallow clone of the referenced element
496
+ const valueElement = cloneShallow(reference.value.result);
497
+ // annotate operation element with info about origin
498
+ valueElement.setMetaProperty('ref-origin', reference.uri);
499
+ const exampleElementCopy = cloneShallow(exampleElement);
500
+ exampleElementCopy.value = valueElement;
501
+
502
+ /**
503
+ * Transclude Example Object containing external value.
504
+ */
505
+ link.replaceWith(exampleElementCopy, mutationReplacer);
506
+
507
+ /**
508
+ * We're at the root of the tree, so we're just replacing the entire tree.
509
+ */
510
+ return !parent ? exampleElementCopy : undefined;
511
+ }
512
+ }
513
+ export default OpenAPI3_0DereferenceVisitor;
@@ -0,0 +1,105 @@
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.resolveSchema$refField = exports.resolveSchema$idField = exports.maybeRefractToSchemaElement = exports.default = void 0;
7
+ var _ramda = require("ramda");
8
+ var _apidomCore = require("@speclynx/apidom-core");
9
+ var _apidomNsOpenapi = _interopRequireWildcard(require("@speclynx/apidom-ns-openapi-3-1"));
10
+ var _DereferenceStrategy = _interopRequireDefault(require("../DereferenceStrategy.cjs"));
11
+ var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
12
+ var _ReferenceSet = _interopRequireDefault(require("../../../ReferenceSet.cjs"));
13
+ var _visitor = _interopRequireDefault(require("./visitor.cjs"));
14
+ exports.OpenAPI3_1DereferenceVisitor = _visitor.default;
15
+ var _util = require("./util.cjs");
16
+ exports.resolveSchema$refField = _util.resolveSchema$refField;
17
+ exports.resolveSchema$idField = _util.resolveSchema$idField;
18
+ exports.maybeRefractToSchemaElement = _util.maybeRefractToSchemaElement;
19
+ // @ts-ignore
20
+ const visitAsync = _apidomCore.visit[Symbol.for('nodejs.util.promisify.custom')];
21
+
22
+ /**
23
+ * @public
24
+ */
25
+
26
+ /**
27
+ * @public
28
+ */
29
+ class OpenAPI3_1DereferenceStrategy extends _DereferenceStrategy.default {
30
+ constructor(options) {
31
+ super({
32
+ ...(options ?? {}),
33
+ name: 'openapi-3-1'
34
+ });
35
+ }
36
+ canDereference(file) {
37
+ // assert by media type
38
+ if (file.mediaType !== 'text/plain') {
39
+ return _apidomNsOpenapi.mediaTypes.includes(file.mediaType);
40
+ }
41
+
42
+ // assert by inspecting ApiDOM
43
+ return (0, _apidomNsOpenapi.isOpenApi3_1Element)(file.parseResult?.result);
44
+ }
45
+ async dereference(file, options) {
46
+ const namespace = (0, _apidomCore.createNamespace)(_apidomNsOpenapi.default);
47
+ const immutableRefSet = options.dereference.refSet ?? new _ReferenceSet.default();
48
+ const mutableRefSet = new _ReferenceSet.default();
49
+ let refSet = immutableRefSet;
50
+ let reference;
51
+ if (!immutableRefSet.has(file.uri)) {
52
+ reference = new _Reference.default({
53
+ uri: file.uri,
54
+ value: file.parseResult
55
+ });
56
+ immutableRefSet.add(reference);
57
+ } else {
58
+ // pre-computed refSet was provided as configuration option
59
+ reference = immutableRefSet.find((0, _ramda.propEq)(file.uri, 'uri'));
60
+ }
61
+
62
+ /**
63
+ * Clone refSet due the dereferencing process being mutable.
64
+ * We don't want to mutate the original refSet and the references.
65
+ */
66
+ if (options.dereference.immutable) {
67
+ immutableRefSet.refs.map(ref => new _Reference.default({
68
+ ...ref,
69
+ value: (0, _apidomCore.cloneDeep)(ref.value)
70
+ })).forEach(ref => mutableRefSet.add(ref));
71
+ reference = mutableRefSet.find(ref => ref.uri === file.uri);
72
+ refSet = mutableRefSet;
73
+ }
74
+ const visitor = new _visitor.default({
75
+ reference: reference,
76
+ namespace,
77
+ options
78
+ });
79
+ const dereferencedElement = await visitAsync(refSet.rootRef.value, visitor, {
80
+ keyMap: _apidomNsOpenapi.keyMap,
81
+ nodeTypeGetter: _apidomNsOpenapi.getNodeType
82
+ });
83
+
84
+ /**
85
+ * If immutable option is set, replay refs from the refSet.
86
+ */
87
+ if (options.dereference.immutable) {
88
+ mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new _Reference.default({
89
+ ...ref,
90
+ uri: ref.uri.replace(/^immutable:\/\//, '')
91
+ })).forEach(ref => immutableRefSet.add(ref));
92
+ }
93
+
94
+ /**
95
+ * Release all memory if this refSet was not provided as an configuration option.
96
+ * If provided as configuration option, then provider is responsible for cleanup.
97
+ */
98
+ if (options.dereference.refSet === null) {
99
+ immutableRefSet.clean();
100
+ }
101
+ mutableRefSet.clean();
102
+ return dereferencedElement;
103
+ }
104
+ }
105
+ var _default = exports.default = OpenAPI3_1DereferenceStrategy;