@speclynx/apidom-reference 4.12.0 → 4.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,559 @@
1
+ import { propEq } from 'ramda';
2
+ import { isElement, isObjectElement, isStringElement, ObjectElement, AnnotationElement, cloneDeep } from '@speclynx/apidom-datamodel';
3
+ import { toValue, toYAML, fixedFields } from '@speclynx/apidom-core';
4
+ import { traverseAsync } from '@speclynx/apidom-traverse';
5
+ import { evaluate, escape, parse as parseJSONPointer, URIFragmentIdentifier } from '@speclynx/apidom-json-pointer';
6
+ import { DefinitionsElement, ParametersDefinitionsElement, ResponsesDefinitionsElement, SwaggerElement, isReferenceElement, isJSONReferenceElement, isReferenceLikeElement, isJSONReferenceLikeElement, isPathItemElement, refract, refractReference, refractJSONReference, refractPathItem } from '@speclynx/apidom-ns-openapi-2';
7
+ import BundleError from "../../../errors/BundleError.mjs";
8
+ import UnresolvableReferenceError from "../../../errors/UnresolvableReferenceError.mjs";
9
+ import MaximumBundleDepthError from "../../../errors/MaximumBundleDepthError.mjs";
10
+ import MaximumResolveDepthError from "../../../errors/MaximumResolveDepthError.mjs";
11
+ import * as url from "../../../util/url.mjs";
12
+ import parse from "../../../parse/index.mjs";
13
+ import Reference from "../../../Reference.mjs";
14
+ import { toPascalCase, sanitizeComponentName, uniqueName as resolveUniqueName } from "../../util.mjs";
15
+ /**
16
+ * Maps the `referenced-element` meta value (set during refraction) to the
17
+ * top-level Swagger Object field where the referenced element should be
18
+ * hoisted. Unlike OpenAPI 3.x, OpenAPI 2.0 has no single Components Object;
19
+ * reusable definitions live directly under the document root. Field names are
20
+ * sourced from the Swagger Object fixed fields so they cannot drift from the
21
+ * namespace definition.
22
+ */
23
+ const sf = fixedFields(SwaggerElement, {
24
+ indexed: true
25
+ });
26
+ const fieldByReferencedElement = {
27
+ schema: sf.definitions.name,
28
+ parameter: sf.parameters.name,
29
+ response: sf.responses.name
30
+ };
31
+
32
+ /**
33
+ * Maps a top-level Swagger Object field to the named-content element the
34
+ * namespace uses for it, so a bundle-created field matches a parsed/refracted
35
+ * one (e.g. carries the `definitions` class) rather than being a generic
36
+ * object.
37
+ */
38
+ const fieldElementByField = {
39
+ [sf.definitions.name]: DefinitionsElement,
40
+ [sf.parameters.name]: ParametersDefinitionsElement,
41
+ [sf.responses.name]: ResponsesDefinitionsElement
42
+ };
43
+
44
+ /**
45
+ * @public
46
+ */
47
+
48
+ /**
49
+ * @public
50
+ */
51
+ class OpenAPI2BundleVisitor {
52
+ reference;
53
+ options;
54
+
55
+ /**
56
+ * The base URI (without hash) of the entry document. A reference is
57
+ * considered internal when it resolves to this URI and external otherwise.
58
+ * Derived from the shared refSet's root reference.
59
+ */
60
+ get entryURI() {
61
+ return url.stripHash(this.reference.refSet?.rootRef?.uri ?? '');
62
+ }
63
+
64
+ /**
65
+ * The entry parse result. Derived from the shared refSet's root reference.
66
+ */
67
+ get entryParseResult() {
68
+ return this.reference.refSet.rootRef.value;
69
+ }
70
+
71
+ /**
72
+ * The entry document element. Hoisted external fragments are placed into its
73
+ * top-level definition fields. The `canBundle` guard guarantees it is a
74
+ * SwaggerElement.
75
+ */
76
+ get entryResult() {
77
+ return this.entryParseResult.result;
78
+ }
79
+
80
+ /**
81
+ * Shared across the entry document and every external document visitor.
82
+ * Guarantees each external fragment is hoisted exactly once and gives us a
83
+ * stable internal pointer to rewrite every referencing element to.
84
+ */
85
+ assignments;
86
+
87
+ /**
88
+ * Component names already reserved per definition field. Reserved before
89
+ * recursion so collision suffixing (`Pet`, `Pet-2`, ...) accounts for
90
+ * components that are still being bundled.
91
+ */
92
+ reservedNames;
93
+
94
+ /**
95
+ * Caches refracted fragments keyed by source element and target element type.
96
+ * The type is part of the key because the same source can be refracted into
97
+ * different semantic elements depending on the referencing context (e.g. a
98
+ * generic object referenced once as a Parameter and once as a Response).
99
+ */
100
+ refractCache;
101
+
102
+ /**
103
+ * Canonical URIs of Path Item Objects currently being inlined. Path Items
104
+ * are not a top-level definition field in OpenAPI 2.0, so the `assignments`
105
+ * map can't break their cycles. This stack guards against circular external
106
+ * Path Item references.
107
+ */
108
+ inlineStack;
109
+ constructor({
110
+ reference,
111
+ options,
112
+ assignments = new Map(),
113
+ reservedNames = new Map(),
114
+ refractCache = new WeakMap(),
115
+ inlineStack = new Set()
116
+ }) {
117
+ this.reference = reference;
118
+ this.options = options;
119
+ this.inlineStack = inlineStack;
120
+ this.assignments = assignments;
121
+ this.reservedNames = reservedNames;
122
+ this.refractCache = refractCache;
123
+ }
124
+ getRefracted(source, type) {
125
+ return this.refractCache.get(source)?.get(type);
126
+ }
127
+ setRefracted(source, type, refracted) {
128
+ let byType = this.refractCache.get(source);
129
+ if (byType === undefined) {
130
+ byType = new Map();
131
+ this.refractCache.set(source, byType);
132
+ }
133
+ byType.set(type, refracted);
134
+ }
135
+ toBaseURI(uri) {
136
+ return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
137
+ }
138
+ async toReference(uri) {
139
+ // detect maximum depth of resolution
140
+ if (this.reference.depth >= this.options.resolve.maxDepth) {
141
+ throw new MaximumResolveDepthError(`Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`, {
142
+ maxDepth: this.options.resolve.maxDepth,
143
+ uri: this.reference.uri
144
+ });
145
+ }
146
+ const baseURI = this.toBaseURI(uri);
147
+ const {
148
+ refSet
149
+ } = this.reference;
150
+
151
+ // we've already processed this Reference in past
152
+ if (refSet.has(baseURI)) {
153
+ return refSet.find(propEq(baseURI, 'uri'));
154
+ }
155
+ const parseResult = await parse(url.unsanitize(baseURI), {
156
+ ...this.options,
157
+ parse: {
158
+ ...this.options.parse,
159
+ mediaType: 'text/plain'
160
+ }
161
+ });
162
+ const reference = new Reference({
163
+ uri: baseURI,
164
+ value: parseResult,
165
+ depth: this.reference.depth + 1
166
+ });
167
+ refSet.add(reference);
168
+ return reference;
169
+ }
170
+
171
+ /**
172
+ * Normalizes a self-file reference (e.g. `./root.json#/definitions/Pet`)
173
+ * to a bare fragment (`#/definitions/Pet`) so the bundled document stays
174
+ * transferable. Bare fragments are returned unchanged.
175
+ */
176
+ normalizeSelfFileRef(ref) {
177
+ return ref.startsWith('#') ? ref : url.getHash(ref);
178
+ }
179
+
180
+ /**
181
+ * Handles an error according to the `bundle.continueOnError` option.
182
+ *
183
+ * For new errors: wraps in UnresolvableReferenceError with structured
184
+ * context. For errors already wrapped by a nested visitor: prepends the
185
+ * current hop to the trace.
186
+ *
187
+ * Inner/intermediate visitors always throw to let the trace accumulate. Only
188
+ * the entry document visitor respects continueOnError (callback/swallow/throw).
189
+ */
190
+ handleError(message, error, referencingElement, refFieldName, refFieldValue, visitorPath) {
191
+ // a collision reported as `error` is a deliberate hard stop with no
192
+ // resolution-failure analog, so pass it through unchanged. A maxDepth
193
+ // breach (MaximumBundleDepthError, which also extends BundleError) is a
194
+ // resolution failure and flows through below — wrapped and subject to
195
+ // continueOnError, like dereferencing.
196
+ if (error instanceof BundleError && !(error instanceof MaximumBundleDepthError)) {
197
+ throw error;
198
+ }
199
+ const {
200
+ continueOnError
201
+ } = this.options.bundle;
202
+ const isEntryDocument = url.stripHash(this.reference.refSet?.rootRef?.uri ?? '') === this.reference.uri;
203
+ const uri = this.reference.uri;
204
+ const type = referencingElement.element;
205
+ const codeFrame = toYAML(referencingElement);
206
+ const location = visitorPath.formatPath();
207
+ const hop = {
208
+ uri,
209
+ type,
210
+ refFieldName,
211
+ refFieldValue,
212
+ location,
213
+ codeFrame
214
+ };
215
+ let unresolvedError;
216
+ if (error instanceof UnresolvableReferenceError) {
217
+ // @ts-ignore
218
+ error.trace = [hop, ...error.trace];
219
+ unresolvedError = error;
220
+ } else {
221
+ unresolvedError = new UnresolvableReferenceError(message, {
222
+ cause: error,
223
+ type,
224
+ uri,
225
+ location,
226
+ codeFrame,
227
+ refFieldName,
228
+ refFieldValue,
229
+ trace: []
230
+ });
231
+ }
232
+ if (!isEntryDocument || continueOnError === false) throw unresolvedError;
233
+ if (typeof continueOnError === 'function') continueOnError(unresolvedError);
234
+ }
235
+
236
+ /**
237
+ * Lazily creates the requested top-level definition field on the entry
238
+ * document, returning the field where a fragment is hoisted.
239
+ */
240
+ ensureField(field) {
241
+ const entryResult = this.entryResult;
242
+ let fieldElement = entryResult.get(field);
243
+ if (!isObjectElement(fieldElement)) {
244
+ const FieldElement = fieldElementByField[field] ?? ObjectElement;
245
+ fieldElement = new FieldElement();
246
+ entryResult.set(field, fieldElement);
247
+ }
248
+ return fieldElement;
249
+ }
250
+
251
+ /**
252
+ * Derives a component name from the referenced JSON Pointer's last token,
253
+ * falling back to the referenced file's basename.
254
+ */
255
+ basenameOf(jsonPointer, baseURI) {
256
+ const tokens = parseJSONPointer(jsonPointer).tree;
257
+ let candidate = tokens.length > 0 ? tokens[tokens.length - 1] : '';
258
+ if (candidate === '') {
259
+ const lastSlash = baseURI.lastIndexOf('/');
260
+ const lastDot = baseURI.lastIndexOf('.');
261
+ const fileName = baseURI.slice(lastSlash + 1);
262
+ // strip the extension only when the last dot belongs to the file name
263
+ candidate = lastDot > lastSlash ? baseURI.slice(lastSlash + 1, lastDot) : fileName;
264
+ }
265
+ if (candidate === '') candidate = 'Schema';
266
+ return candidate;
267
+ }
268
+
269
+ /**
270
+ * Computes the base component name (before collision suffixing) according to
271
+ * the configured naming strategy.
272
+ */
273
+ baseName(element, field, jsonPointer, baseURI) {
274
+ // strategy specific options take precedence over the top-level bundle options
275
+ const componentNamesStrategy = this.options.bundle.strategyOpts['openapi-2']?.componentNamesStrategy ?? this.options.bundle.componentNamesStrategy;
276
+ if (typeof componentNamesStrategy === 'function') {
277
+ const resolved = componentNamesStrategy({
278
+ element,
279
+ field,
280
+ jsonPointer,
281
+ baseURI
282
+ });
283
+ if (typeof resolved === 'string' && resolved !== '') {
284
+ return resolved;
285
+ }
286
+ return this.basenameOf(jsonPointer, baseURI);
287
+ }
288
+ if (componentNamesStrategy === 'title') {
289
+ const title = isObjectElement(element) ? toValue(element.get('title')) : undefined;
290
+ if (typeof title === 'string' && title.trim() !== '') {
291
+ const name = sanitizeComponentName(toPascalCase(title));
292
+ if (name !== '') return name;
293
+ }
294
+ // fall back to basename when no usable title is present
295
+ }
296
+ return this.basenameOf(jsonPointer, baseURI);
297
+ }
298
+
299
+ /**
300
+ * Computes a collision-free component name within the target field. A name is
301
+ * taken if it's already placed in the field or reserved by a component that
302
+ * is still being bundled (reserved before recursion).
303
+ */
304
+ uniqueName(candidate, field) {
305
+ const fieldElement = this.ensureField(field);
306
+ const reserved = this.reservedNames.get(field) ?? new Set();
307
+ return resolveUniqueName(candidate, name => fieldElement.hasKey(name) || reserved.has(name));
308
+ }
309
+
310
+ /**
311
+ * Bundles a Reference Object (parameters/responses) or a JSON Reference
312
+ * Object (schemas). The two reference flavors differ only in their predicate
313
+ * and refraction helpers, so the shared logic is parameterized here.
314
+ */
315
+ async bundleReference(path, referencingElement, isSemanticReference, isReferenceLike, refractReferenceFn, label) {
316
+ const $ref = toValue(referencingElement.$ref);
317
+ const retrievalURI = this.toBaseURI($ref);
318
+ const isInternalReference = this.entryURI === retrievalURI;
319
+ const isExternalReference = !isInternalReference;
320
+ if (isInternalReference) {
321
+ // normalize self-file references to a bare fragment so the bundled
322
+ // document stays transferable; bare fragments are left untouched
323
+ referencingElement.set('$ref', this.normalizeSelfFileRef($ref));
324
+ path.skip();
325
+ return;
326
+ }
327
+
328
+ // honor the resolve.external switch
329
+ if (!this.options.resolve.external && isExternalReference) {
330
+ path.skip();
331
+ return;
332
+ }
333
+ const $refBaseURI = url.resolve(retrievalURI, $ref);
334
+ const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
335
+
336
+ // the target field depends on the referencing context, so it's part of the
337
+ // identity: the same external target referenced as e.g. both a parameter and
338
+ // a response must be hoisted into both fields. The refractor sets
339
+ // `referenced-element` for every Reference Object position; the `schema`
340
+ // fallback is a defensive default for the (unexpected) untagged case.
341
+ const referencedElementType = referencingElement.meta.get('referenced-element');
342
+ const field = fieldByReferencedElement[referencedElementType] ?? fieldByReferencedElement.schema;
343
+ const canonicalKey = `${field}\t${retrievalURI}#${jsonPointer}`;
344
+
345
+ // already hoisted (or being hoisted) — just rewrite the pointer.
346
+ //
347
+ // this is also how circular references terminate: the assignment is
348
+ // reserved BEFORE recursing into the fragment (see below), so a reference
349
+ // that cycles back (directly or indirectly) finds its pointer already
350
+ // reserved here and is rewritten without recursing. Cycles are deliberately
351
+ // preserved as internal `$ref`s pointing at each other — that is valid,
352
+ // serializable output; resolving the cycle (if desired) is dereferencing's
353
+ // job, not bundling's.
354
+ if (this.assignments.has(canonicalKey)) {
355
+ referencingElement.set('$ref', this.assignments.get(canonicalKey));
356
+ path.skip();
357
+ return;
358
+ }
359
+ try {
360
+ // detect maximum depth of bundling
361
+ if (this.reference.depth >= this.options.bundle.maxDepth) {
362
+ throw new MaximumBundleDepthError(`Maximum bundle depth of "${this.options.bundle.maxDepth}" has been exceeded in file "${this.reference.uri}"`, {
363
+ maxDepth: this.options.bundle.maxDepth,
364
+ uri: this.reference.uri
365
+ });
366
+ }
367
+ const reference = await this.toReference($ref);
368
+
369
+ // possibly non-semantic fragment
370
+ let referencedElement = evaluate(reference.value.result, jsonPointer);
371
+
372
+ // apply semantics to the fragment so nested references become Reference Objects
373
+ if (referencedElement.element !== referencedElementType && !isSemanticReference(referencedElement)) {
374
+ const cached = this.getRefracted(referencedElement, referencedElementType);
375
+ if (cached !== undefined) {
376
+ referencedElement = cached;
377
+ } else if (isReferenceLike(referencedElement)) {
378
+ const sourceElement = referencedElement;
379
+ referencedElement = refractReferenceFn(referencedElement);
380
+ referencedElement.meta.set('referenced-element', referencedElementType);
381
+ this.setRefracted(sourceElement, referencedElementType, referencedElement);
382
+ } else {
383
+ const sourceElement = referencedElement;
384
+ referencedElement = refract(referencedElement, {
385
+ element: referencedElementType
386
+ });
387
+ this.setRefracted(sourceElement, referencedElementType, referencedElement);
388
+ }
389
+ }
390
+ const preferredName = this.baseName(referencedElement, field, jsonPointer, retrievalURI);
391
+ const componentName = this.uniqueName(preferredName, field);
392
+ const internalPointer = `#/${field}/${escape(componentName)}`;
393
+
394
+ // a rename means two distinct targets resolved to the same name; each
395
+ // keeps its own component (and origin), so report the rename per severity.
396
+ // strategy specific options take precedence over the top-level bundle options
397
+ const onComponentNameCollision = this.options.bundle.strategyOpts['openapi-2']?.onComponentNameCollision ?? this.options.bundle.onComponentNameCollision;
398
+ if (componentName !== preferredName && onComponentNameCollision !== 'off') {
399
+ const message = `Component "${preferredName}" in ${field} is referenced with the same name but different content. Renamed to "${componentName}".`;
400
+ if (onComponentNameCollision === 'error') {
401
+ throw new BundleError(message);
402
+ }
403
+ const annotation = new AnnotationElement(message);
404
+ annotation.classes.push('warning');
405
+ annotation.code = 'bundle-component-name-collision';
406
+ // append (never prepend) so the result element stays ahead of annotations
407
+ this.entryParseResult.content.push(annotation);
408
+ }
409
+
410
+ // reserve the assignment and component name before recursing so cyclic
411
+ // references terminate
412
+ this.assignments.set(canonicalKey, internalPointer);
413
+ if (!this.reservedNames.has(field)) this.reservedNames.set(field, new Set());
414
+ this.reservedNames.get(field).add(componentName);
415
+
416
+ // own a copy of the fragment and bundle its own external references
417
+ const hoistedElement = cloneDeep(referencedElement);
418
+ const visitor = new OpenAPI2BundleVisitor({
419
+ reference,
420
+ options: this.options,
421
+ assignments: this.assignments,
422
+ reservedNames: this.reservedNames,
423
+ refractCache: this.refractCache,
424
+ inlineStack: this.inlineStack
425
+ });
426
+ const bundledElement = await traverseAsync(hoistedElement, visitor, {
427
+ mutable: true
428
+ });
429
+
430
+ // annotate the hoisted fragment with info about its origin
431
+ if (isElement(bundledElement)) {
432
+ bundledElement.meta.set('ref-origin', reference.uri);
433
+ }
434
+
435
+ // place the bundled fragment into the entry document's definitions
436
+ this.ensureField(field).set(componentName, bundledElement);
437
+
438
+ // rewrite the referencing element to point at the hoisted fragment
439
+ referencingElement.set('$ref', internalPointer);
440
+ path.skip();
441
+ } catch (error) {
442
+ this.handleError(`Error while bundling ${label}. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
443
+ path.skip();
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Reference Object covers reusable Parameter and Response Objects, which are
449
+ * hoisted into the top-level `parameters` and `responses` fields.
450
+ */
451
+ async ReferenceElement(path) {
452
+ await this.bundleReference(path, path.node, isReferenceElement, isReferenceLikeElement, refractReference, 'Reference Object');
453
+ }
454
+
455
+ /**
456
+ * JSON Reference Object covers reusable Schema Objects, which are hoisted
457
+ * into the top-level `definitions` field.
458
+ */
459
+ async JSONReferenceElement(path) {
460
+ await this.bundleReference(path, path.node, isJSONReferenceElement, isJSONReferenceLikeElement, refractJSONReference, 'JSON Reference Object');
461
+ }
462
+
463
+ /**
464
+ * Path Item Object is not a top-level definition field in OpenAPI 2.0, so an
465
+ * external Path Item reference cannot be hoisted; it is inlined in place
466
+ * instead, after bundling its own external references.
467
+ */
468
+ async PathItemElement(path) {
469
+ const pathItemElement = path.node;
470
+
471
+ // ignore Path Item Objects without a $ref field
472
+ if (!isStringElement(pathItemElement.$ref)) {
473
+ return;
474
+ }
475
+ const $ref = toValue(pathItemElement.$ref);
476
+ const retrievalURI = this.toBaseURI($ref);
477
+ const isInternalReference = this.entryURI === retrievalURI;
478
+ const isExternalReference = !isInternalReference;
479
+ if (isInternalReference) {
480
+ // normalize self-file references to a bare fragment so the bundled
481
+ // document stays transferable; bare fragments are left untouched
482
+ pathItemElement.set('$ref', this.normalizeSelfFileRef($ref));
483
+ return;
484
+ }
485
+
486
+ // honor the resolve.external switch
487
+ if (!this.options.resolve.external && isExternalReference) {
488
+ return;
489
+ }
490
+ const $refBaseURI = url.resolve(retrievalURI, $ref);
491
+ const jsonPointer = URIFragmentIdentifier.fromURIReference($refBaseURI);
492
+ const canonicalKey = `${retrievalURI}#${jsonPointer}`;
493
+
494
+ // a circular external Path Item reference cannot be inlined without
495
+ // recursing forever; leave the $ref in place to break the cycle
496
+ if (this.inlineStack.has(canonicalKey)) {
497
+ return;
498
+ }
499
+ try {
500
+ // detect maximum depth of bundling
501
+ if (this.reference.depth >= this.options.bundle.maxDepth) {
502
+ throw new MaximumBundleDepthError(`Maximum bundle depth of "${this.options.bundle.maxDepth}" has been exceeded in file "${this.reference.uri}"`, {
503
+ maxDepth: this.options.bundle.maxDepth,
504
+ uri: this.reference.uri
505
+ });
506
+ }
507
+ const reference = await this.toReference($ref);
508
+ let referencedElement = evaluate(reference.value.result, jsonPointer);
509
+
510
+ // apply Path Item semantics to the referenced fragment
511
+ if (!isPathItemElement(referencedElement)) {
512
+ const cached = this.getRefracted(referencedElement, 'pathItem');
513
+ if (cached !== undefined) {
514
+ referencedElement = cached;
515
+ } else {
516
+ const sourceElement = referencedElement;
517
+ referencedElement = refractPathItem(referencedElement);
518
+ this.setRefracted(sourceElement, 'pathItem', referencedElement);
519
+ }
520
+ }
521
+
522
+ // own a copy and bundle the external references it contains
523
+ const inlinedElement = cloneDeep(referencedElement);
524
+ this.inlineStack.add(canonicalKey);
525
+ const visitor = new OpenAPI2BundleVisitor({
526
+ reference,
527
+ options: this.options,
528
+ assignments: this.assignments,
529
+ reservedNames: this.reservedNames,
530
+ refractCache: this.refractCache,
531
+ inlineStack: this.inlineStack
532
+ });
533
+ let bundledElement;
534
+ try {
535
+ bundledElement = await traverseAsync(inlinedElement, visitor, {
536
+ mutable: true
537
+ });
538
+ } finally {
539
+ this.inlineStack.delete(canonicalKey);
540
+ }
541
+
542
+ // merge sibling fields from the referencing Path Item over the referenced
543
+ // one. The referencing `$ref` is being resolved away and is skipped; the
544
+ // referenced element keeps its own `$ref` if one survived (i.e. it was
545
+ // left in place to break a circular external Path Item chain).
546
+ pathItemElement.forEach((_value, keyElement, item) => {
547
+ const key = toValue(keyElement);
548
+ if (key === '$ref') return;
549
+ bundledElement.remove(key);
550
+ bundledElement.content.push(item);
551
+ });
552
+ bundledElement.meta.set('ref-origin', reference.uri);
553
+ path.replaceWith(bundledElement);
554
+ } catch (error) {
555
+ this.handleError(`Error while bundling Path Item Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, pathItemElement, '$ref', $ref, path);
556
+ }
557
+ }
558
+ }
559
+ export default OpenAPI2BundleVisitor;
@@ -36,20 +36,21 @@ var _index25 = _interopRequireDefault(require("../dereference/strategies/openapi
36
36
  var _index26 = _interopRequireDefault(require("../dereference/strategies/asyncapi-2/index.cjs"));
37
37
  var _index27 = _interopRequireDefault(require("../dereference/strategies/arazzo-1/index.cjs"));
38
38
  var _index28 = _interopRequireDefault(require("../dereference/strategies/overlay-1/index.cjs"));
39
- var _index29 = _interopRequireDefault(require("../bundle/strategies/openapi-3-0/index.cjs"));
40
- var _index30 = _interopRequireDefault(require("../bundle/strategies/openapi-3-1/index.cjs"));
41
- var _index31 = require("../index.cjs");
42
- Object.keys(_index31).forEach(function (key) {
39
+ var _index29 = _interopRequireDefault(require("../bundle/strategies/openapi-2/index.cjs"));
40
+ var _index30 = _interopRequireDefault(require("../bundle/strategies/openapi-3-0/index.cjs"));
41
+ var _index31 = _interopRequireDefault(require("../bundle/strategies/openapi-3-1/index.cjs"));
42
+ var _index32 = require("../index.cjs");
43
+ Object.keys(_index32).forEach(function (key) {
43
44
  if (key === "default" || key === "__esModule") return;
44
- if (key in exports && exports[key] === _index31[key]) return;
45
+ if (key in exports && exports[key] === _index32[key]) return;
45
46
  Object.defineProperty(exports, key, {
46
47
  enumerable: true,
47
48
  get: function () {
48
- return _index31[key];
49
+ return _index32[key];
49
50
  }
50
51
  });
51
52
  });
52
- _index31.options.parse.parsers = [new _index9.default({
53
+ _index32.options.parse.parsers = [new _index9.default({
53
54
  allowEmpty: true,
54
55
  sourceMap: false
55
56
  }), new _index0.default({
@@ -97,11 +98,11 @@ _index31.options.parse.parsers = [new _index9.default({
97
98
  }), new _indexNode2.default({
98
99
  allowEmpty: true
99
100
  })];
100
- _index31.options.resolve.resolvers = [new _indexNode.default(), new _index.default({
101
+ _index32.options.resolve.resolvers = [new _indexNode.default(), new _index.default({
101
102
  timeout: 5000,
102
103
  redirects: 5,
103
104
  withCredentials: false
104
105
  })];
105
- _index31.options.resolve.strategies = [new _index2.default(), new _index3.default(), new _index4.default(), new _index5.default(), new _index6.default(), new _index7.default(), new _index8.default()];
106
- _index31.options.dereference.strategies = [new _index23.default(), new _index24.default(), new _index25.default(), new _index26.default(), new _index27.default(), new _index28.default(), new _index22.default()];
107
- _index31.options.bundle.strategies = [new _index29.default(), new _index30.default()];
106
+ _index32.options.resolve.strategies = [new _index2.default(), new _index3.default(), new _index4.default(), new _index5.default(), new _index6.default(), new _index7.default(), new _index8.default()];
107
+ _index32.options.dereference.strategies = [new _index23.default(), new _index24.default(), new _index25.default(), new _index26.default(), new _index27.default(), new _index28.default(), new _index22.default()];
108
+ _index32.options.bundle.strategies = [new _index29.default(), new _index30.default(), new _index31.default()];
@@ -30,6 +30,7 @@ import OpenAPI3_1DereferenceStrategy from "../dereference/strategies/openapi-3-1
30
30
  import AsyncAPI2DereferenceStrategy from "../dereference/strategies/asyncapi-2/index.mjs";
31
31
  import Arazzo1DereferenceStrategy from "../dereference/strategies/arazzo-1/index.mjs";
32
32
  import Overlay1DereferenceStrategy from "../dereference/strategies/overlay-1/index.mjs";
33
+ import OpenAPI2BundleStrategy from "../bundle/strategies/openapi-2/index.mjs";
33
34
  import OpenAPI3_0BundleStrategy from "../bundle/strategies/openapi-3-0/index.mjs";
34
35
  import OpenAPI3_1BundleStrategy from "../bundle/strategies/openapi-3-1/index.mjs";
35
36
  import { options } from "../index.mjs";
@@ -88,5 +89,5 @@ options.resolve.resolvers = [new FileResolver(), new HTTPResolverAxios({
88
89
  })];
89
90
  options.resolve.strategies = [new OpenAPI2ResolveStrategy(), new OpenAPI3_0ResolveStrategy(), new OpenAPI3_1ResolveStrategy(), new AsyncAPI2ResolveStrategy(), new Arazzo1ResolveStrategy(), new Overlay1ResolveStrategy(), new ApiDOMResolveStrategy()];
90
91
  options.dereference.strategies = [new OpenAPI2DereferenceStrategy(), new OpenAPI3_0DereferenceStrategy(), new OpenAPI3_1DereferenceStrategy(), new AsyncAPI2DereferenceStrategy(), new Arazzo1DereferenceStrategy(), new Overlay1DereferenceStrategy(), new ApiDOMDereferenceStrategy()];
91
- options.bundle.strategies = [new OpenAPI3_0BundleStrategy(), new OpenAPI3_1BundleStrategy()];
92
+ options.bundle.strategies = [new OpenAPI2BundleStrategy(), new OpenAPI3_0BundleStrategy(), new OpenAPI3_1BundleStrategy()];
92
93
  export * from "../index.mjs";
@@ -0,0 +1,31 @@
1
+ import { ParseResultElement } from '@speclynx/apidom-datamodel';
2
+ import File from '../../../File.ts';
3
+ import BundleStrategy, { BundleStrategyOptions } from '../BundleStrategy.ts';
4
+ import OpenAPI2BundleVisitor from './visitor.ts';
5
+ import type { ReferenceOptions } from '../../../options/index.ts';
6
+ export type { default as DereferenceStrategy, DereferenceStrategyOptions, } from '../../../dereference/strategies/DereferenceStrategy.ts';
7
+ export type { default as File, FileOptions } from '../../../File.ts';
8
+ export type { default as Reference, ReferenceOptions } from '../../../Reference.ts';
9
+ export type { default as ReferenceSet, ReferenceSetOptions } from '../../../ReferenceSet.ts';
10
+ export type { OpenAPI2BundleVisitorOptions } from './visitor.ts';
11
+ export type { ReferenceOptions as ApiDOMReferenceOptions, ReferenceBundleOptions as ApiDOMReferenceBundleOptions, ReferenceDereferenceOptions as ApiDOMReferenceDereferenceOptions, ReferenceParseOptions as ApiDOMReferenceParseOptions, ReferenceResolveOptions as ApiDOMReferenceResolveOptions, } from '../../../options/index.ts';
12
+ export type { default as Parser, ParserOptions } from '../../../parse/parsers/Parser.ts';
13
+ export type { default as Resolver, ResolverOptions } from '../../../resolve/resolvers/Resolver.ts';
14
+ export type { default as ResolveStrategy, ResolveStrategyOptions, } from '../../../resolve/strategies/ResolveStrategy.ts';
15
+ export type { default as BundleStrategy, BundleStrategyOptions } from '../BundleStrategy.ts';
16
+ export type { ComponentNamesStrategy, ComponentNameResolver, ComponentNameResolverArgs, ComponentNameCollisionSeverity, } from '../../../options/index.ts';
17
+ /**
18
+ * @public
19
+ */
20
+ export interface OpenAPI2BundleStrategyOptions extends Omit<BundleStrategyOptions, 'name'> {
21
+ }
22
+ /**
23
+ * @public
24
+ */
25
+ declare class OpenAPI2BundleStrategy extends BundleStrategy {
26
+ constructor(options?: OpenAPI2BundleStrategyOptions);
27
+ canBundle(file: File): boolean;
28
+ bundle(file: File, options: ReferenceOptions): Promise<ParseResultElement>;
29
+ }
30
+ export { OpenAPI2BundleVisitor };
31
+ export default OpenAPI2BundleStrategy;