source: node_modules/@swagger-api/apidom-reference/cjs/resolve/strategies/openapi-3-0/visitor.cjs

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 16 months ago

Initial commit

  • Property mode set to 100644
File size: 10.6 KB
Line 
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
4var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
5exports.__esModule = true;
6exports.default = void 0;
7var _stampit = _interopRequireDefault(require("stampit"));
8var _ramda = require("ramda");
9var _ramdaAdjunct = require("ramda-adjunct");
10var _apidomCore = require("@swagger-api/apidom-core");
11var _apidomError = require("@swagger-api/apidom-error");
12var _apidomJsonPointer = require("@swagger-api/apidom-json-pointer");
13var _apidomNsOpenapi = require("@swagger-api/apidom-ns-openapi-3-0");
14var _MaximumDereferenceDepthError = _interopRequireDefault(require("../../../errors/MaximumDereferenceDepthError.cjs"));
15var _MaximumResolveDepthError = _interopRequireDefault(require("../../../errors/MaximumResolveDepthError.cjs"));
16var url = _interopRequireWildcard(require("../../../util/url.cjs"));
17var _index = _interopRequireDefault(require("../../../parse/index.cjs"));
18var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
19// @ts-ignore
20const visitAsync = _apidomCore.visit[Symbol.for('nodejs.util.promisify.custom')];
21
22// eslint-disable-next-line @typescript-eslint/naming-convention
23const OpenApi3_0ResolveVisitor = (0, _stampit.default)({
24 props: {
25 indirections: [],
26 namespace: null,
27 reference: null,
28 crawledElements: null,
29 crawlingMap: null,
30 options: null
31 },
32 init({
33 reference,
34 namespace,
35 indirections = [],
36 options
37 }) {
38 this.indirections = indirections;
39 this.namespace = namespace;
40 this.reference = reference;
41 this.crawledElements = [];
42 this.crawlingMap = {};
43 this.options = options;
44 },
45 methods: {
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 Reference with ReferenceSet
72 const reference = (0, _Reference.default)({
73 uri: baseURI,
74 value: parseResult,
75 depth: this.reference.depth + 1
76 });
77 refSet.add(reference);
78 return reference;
79 },
80 ReferenceElement(referenceElement) {
81 const uri = (0, _apidomCore.toValue)(referenceElement.$ref);
82 const retrievalURI = this.toBaseURI(uri);
83
84 // ignore resolving external Reference Objects
85 if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
86 return false;
87 }
88 if (!(0, _ramda.has)(retrievalURI, this.crawlingMap)) {
89 this.crawlingMap[retrievalURI] = this.toReference(uri);
90 }
91 this.crawledElements.push(referenceElement);
92 return undefined;
93 },
94 PathItemElement(pathItemElement) {
95 // ignore PathItemElement without $ref field
96 if (!(0, _apidomCore.isStringElement)(pathItemElement.$ref)) {
97 return undefined;
98 }
99 const uri = (0, _apidomCore.toValue)(pathItemElement.$ref);
100 const retrievalURI = this.toBaseURI(uri);
101
102 // ignore resolving external Path Item Objects
103 if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
104 return undefined;
105 }
106 if (!(0, _ramda.has)(retrievalURI, this.crawlingMap)) {
107 this.crawlingMap[retrievalURI] = this.toReference(uri);
108 }
109 this.crawledElements.push(pathItemElement);
110 return undefined;
111 },
112 LinkElement(linkElement) {
113 // ignore LinkElement without operationRef or operationId field
114 if (!(0, _apidomCore.isStringElement)(linkElement.operationRef) && !(0, _apidomCore.isStringElement)(linkElement.operationId)) {
115 return undefined;
116 }
117
118 // operationRef and operationId are mutually exclusive
119 if ((0, _apidomCore.isStringElement)(linkElement.operationRef) && (0, _apidomCore.isStringElement)(linkElement.operationId)) {
120 throw new _apidomError.ApiDOMError('LinkElement operationRef and operationId are mutually exclusive.');
121 }
122 if ((0, _apidomCore.isStringElement)(linkElement.operationRef)) {
123 const uri = (0, _apidomCore.toValue)(linkElement.operationRef);
124 const retrievalURI = this.toBaseURI(uri);
125
126 // ignore resolving LinkElement.operationRef
127 if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
128 return undefined;
129 }
130 if (!(0, _ramda.has)(retrievalURI, this.crawlingMap)) {
131 this.crawlingMap[retrievalURI] = this.toReference(uri);
132 }
133 }
134 return undefined;
135 },
136 ExampleElement(exampleElement) {
137 // ignore ExampleElement without externalValue field
138 if (!(0, _apidomCore.isStringElement)(exampleElement.externalValue)) {
139 return undefined;
140 }
141
142 // value and externalValue fields are mutually exclusive
143 if (exampleElement.hasKey('value') && (0, _apidomCore.isStringElement)(exampleElement.externalValue)) {
144 throw new _apidomError.ApiDOMError('ExampleElement value and externalValue fields are mutually exclusive.');
145 }
146 const uri = (0, _apidomCore.toValue)(exampleElement.externalValue);
147 const retrievalURI = this.toBaseURI(uri);
148
149 // ignore resolving ExampleElement externalValue
150 if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
151 return undefined;
152 }
153 if (!(0, _ramda.has)(retrievalURI, this.crawlingMap)) {
154 this.crawlingMap[retrievalURI] = this.toReference(uri);
155 }
156 return undefined;
157 },
158 async crawlReferenceElement(referenceElement) {
159 // @ts-ignore
160 const reference = await this.toReference((0, _apidomCore.toValue)(referenceElement.$ref));
161 this.indirections.push(referenceElement);
162 const jsonPointer = (0, _apidomJsonPointer.uriToPointer)((0, _apidomCore.toValue)(referenceElement.$ref));
163
164 // possibly non-semantic fragment
165 let fragment = (0, _apidomJsonPointer.evaluate)(jsonPointer, reference.value.result);
166
167 // applying semantics to a fragment
168 if ((0, _apidomCore.isPrimitiveElement)(fragment)) {
169 const referencedElementType = (0, _apidomCore.toValue)(referenceElement.meta.get('referenced-element'));
170 if ((0, _apidomNsOpenapi.isReferenceLikeElement)(fragment)) {
171 // handling indirect references
172 fragment = _apidomNsOpenapi.ReferenceElement.refract(fragment);
173 fragment.setMetaProperty('referenced-element', referencedElementType);
174 } else {
175 // handling direct references
176 const ElementClass = this.namespace.getElementClass(referencedElementType);
177 fragment = ElementClass.refract(fragment);
178 }
179 }
180
181 // detect direct or circular reference
182 if (this.indirections.includes(fragment)) {
183 throw new _apidomError.ApiDOMError('Recursive Reference Object detected');
184 }
185
186 // detect maximum depth of dereferencing
187 if (this.indirections.length > this.options.dereference.maxDepth) {
188 throw new _MaximumDereferenceDepthError.default(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`);
189 }
190
191 // dive deep into the fragment
192 const visitor = OpenApi3_0ResolveVisitor({
193 reference,
194 namespace: this.namespace,
195 indirections: [...this.indirections],
196 options: this.options
197 });
198 await visitAsync(fragment, visitor, {
199 keyMap: _apidomNsOpenapi.keyMap,
200 nodeTypeGetter: _apidomNsOpenapi.getNodeType
201 });
202 await visitor.crawl();
203 this.indirections.pop();
204 },
205 async crawlPathItemElement(pathItemElement) {
206 // @ts-ignore
207 const reference = await this.toReference((0, _apidomCore.toValue)(pathItemElement.$ref));
208 this.indirections.push(pathItemElement);
209 const jsonPointer = (0, _apidomJsonPointer.uriToPointer)((0, _apidomCore.toValue)(pathItemElement.$ref));
210
211 // possibly non-semantic fragment
212 let referencedElement = (0, _apidomJsonPointer.evaluate)(jsonPointer, reference.value.result);
213
214 // applying semantics to a fragment
215 if ((0, _apidomCore.isPrimitiveElement)(referencedElement)) {
216 referencedElement = _apidomNsOpenapi.PathItemElement.refract(referencedElement);
217 }
218
219 // detect direct or indirect reference
220 if (this.indirections.includes(referencedElement)) {
221 throw new _apidomError.ApiDOMError('Recursive Path Item Object reference detected');
222 }
223
224 // detect maximum depth of dereferencing
225 if (this.indirections.length > this.options.dereference.maxDepth) {
226 throw new _MaximumDereferenceDepthError.default(`Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`);
227 }
228
229 // dive deep into the fragment
230 const visitor = OpenApi3_0ResolveVisitor({
231 reference,
232 namespace: this.namespace,
233 indirections: [...this.indirections],
234 options: this.options
235 });
236 await visitAsync(referencedElement, visitor, {
237 keyMap: _apidomNsOpenapi.keyMap,
238 nodeTypeGetter: _apidomNsOpenapi.getNodeType
239 });
240 await visitor.crawl();
241 this.indirections.pop();
242 },
243 async crawl() {
244 /**
245 * Synchronize all parallel resolutions in this place.
246 * After synchronization happened we can be sure that refSet
247 * contains resolved Reference objects.
248 */
249 await (0, _ramda.pipe)(_ramda.values, _ramdaAdjunct.allP)(this.crawlingMap);
250 this.crawlingMap = null;
251
252 /* eslint-disable no-await-in-loop */
253 for (const element of this.crawledElements) {
254 if ((0, _apidomNsOpenapi.isReferenceElement)(element)) {
255 await this.crawlReferenceElement(element);
256 } else if ((0, _apidomNsOpenapi.isPathItemElement)(element)) {
257 await this.crawlPathItemElement(element);
258 }
259 }
260 /* eslint-enabled */
261 }
262 }
263});
264var _default = exports.default = OpenApi3_0ResolveVisitor;
Note: See TracBrowser for help on using the repository browser.