@speclynx/apidom-reference 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/apidom-reference.browser.js +167 -37
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +28 -28
- package/src/dereference/strategies/arazzo-1/index.cjs +5 -1
- package/src/dereference/strategies/arazzo-1/index.mjs +5 -1
- package/src/dereference/strategies/arazzo-1/visitor.cjs +15 -3
- package/src/dereference/strategies/arazzo-1/visitor.mjs +15 -3
- package/src/dereference/strategies/asyncapi-2/index.cjs +5 -1
- package/src/dereference/strategies/asyncapi-2/index.mjs +5 -1
- package/src/dereference/strategies/asyncapi-2/visitor.cjs +23 -5
- package/src/dereference/strategies/asyncapi-2/visitor.mjs +23 -5
- package/src/dereference/strategies/openapi-2/index.cjs +5 -1
- package/src/dereference/strategies/openapi-2/index.mjs +5 -1
- package/src/dereference/strategies/openapi-2/visitor.cjs +33 -7
- package/src/dereference/strategies/openapi-2/visitor.mjs +33 -7
- package/src/dereference/strategies/openapi-3-0/index.cjs +5 -1
- package/src/dereference/strategies/openapi-3-0/index.mjs +5 -1
- package/src/dereference/strategies/openapi-3-0/visitor.cjs +23 -5
- package/src/dereference/strategies/openapi-3-0/visitor.mjs +23 -5
- package/src/dereference/strategies/openapi-3-1/index.cjs +5 -1
- package/src/dereference/strategies/openapi-3-1/index.mjs +5 -1
- package/src/dereference/strategies/openapi-3-1/visitor.cjs +29 -7
- package/src/dereference/strategies/openapi-3-1/visitor.mjs +29 -7
- package/types/dereference/strategies/arazzo-1/visitor.d.ts +3 -1
- package/types/dereference/strategies/asyncapi-2/visitor.d.ts +3 -1
- package/types/dereference/strategies/openapi-2/visitor.d.ts +3 -1
- package/types/dereference/strategies/openapi-3-0/visitor.d.ts +3 -1
- package/types/dereference/strategies/openapi-3-1/visitor.d.ts +3 -1
|
@@ -30,6 +30,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
30
30
|
reference;
|
|
31
31
|
options;
|
|
32
32
|
refractCache;
|
|
33
|
+
visited;
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Tracks element ancestors across dive-deep traversal boundaries.
|
|
@@ -42,13 +43,15 @@ class OpenAPI2DereferenceVisitor {
|
|
|
42
43
|
options,
|
|
43
44
|
indirections = [],
|
|
44
45
|
ancestors = new _util.AncestorLineage(),
|
|
45
|
-
refractCache = new WeakMap()
|
|
46
|
+
refractCache = new WeakMap(),
|
|
47
|
+
visited = new WeakSet()
|
|
46
48
|
}) {
|
|
47
49
|
this.indirections = indirections;
|
|
48
50
|
this.reference = reference;
|
|
49
51
|
this.options = options;
|
|
50
52
|
this.refractCache = refractCache;
|
|
51
53
|
this.ancestors = new _util.AncestorLineage(...ancestors);
|
|
54
|
+
this.visited = visited;
|
|
52
55
|
}
|
|
53
56
|
toAncestorLineage(path) {
|
|
54
57
|
const ancestorNodes = path.getAncestorNodes();
|
|
@@ -281,6 +284,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
281
284
|
const replacer = this.options.dereference.strategyOpts['openapi-2']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
282
285
|
const replacement = replacer(refElement);
|
|
283
286
|
path.replaceWith(replacement);
|
|
287
|
+
path.skip();
|
|
284
288
|
return;
|
|
285
289
|
}
|
|
286
290
|
}
|
|
@@ -296,7 +300,11 @@ class OpenAPI2DereferenceVisitor {
|
|
|
296
300
|
*/
|
|
297
301
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
298
302
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
299
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isReferenceElement)(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
303
|
+
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isReferenceElement)(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
304
|
+
if (shouldDetectCircular) {
|
|
305
|
+
this.visited.add(referencedElement);
|
|
306
|
+
}
|
|
307
|
+
|
|
300
308
|
// append referencing reference to ancestors lineage
|
|
301
309
|
directAncestors.add(referencingElement);
|
|
302
310
|
const visitor = new OpenAPI2DereferenceVisitor({
|
|
@@ -304,10 +312,12 @@ class OpenAPI2DereferenceVisitor {
|
|
|
304
312
|
indirections: [...this.indirections],
|
|
305
313
|
options: this.options,
|
|
306
314
|
refractCache: this.refractCache,
|
|
315
|
+
visited: this.visited,
|
|
307
316
|
ancestors: ancestorsLineage
|
|
308
317
|
});
|
|
309
318
|
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
310
|
-
mutable: true
|
|
319
|
+
mutable: true,
|
|
320
|
+
skipVisited: true
|
|
311
321
|
});
|
|
312
322
|
directAncestors.delete(referencingElement);
|
|
313
323
|
}
|
|
@@ -328,6 +338,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
328
338
|
* Transclude referencing element with merged referenced element.
|
|
329
339
|
*/
|
|
330
340
|
path.replaceWith(mergedElement);
|
|
341
|
+
path.skip();
|
|
331
342
|
} catch (error) {
|
|
332
343
|
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
333
344
|
this.handleError(`Error while dereferencing Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
@@ -415,6 +426,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
415
426
|
const replacer = this.options.dereference.strategyOpts['openapi-2']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
416
427
|
const replacement = replacer(refElement);
|
|
417
428
|
path.replaceWith(replacement);
|
|
429
|
+
path.skip();
|
|
418
430
|
return;
|
|
419
431
|
}
|
|
420
432
|
}
|
|
@@ -430,7 +442,11 @@ class OpenAPI2DereferenceVisitor {
|
|
|
430
442
|
*/
|
|
431
443
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
432
444
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
433
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isPathItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
445
|
+
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isPathItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
446
|
+
if (shouldDetectCircular) {
|
|
447
|
+
this.visited.add(referencedElement);
|
|
448
|
+
}
|
|
449
|
+
|
|
434
450
|
// append referencing reference to ancestors lineage
|
|
435
451
|
directAncestors.add(referencingElement);
|
|
436
452
|
const visitor = new OpenAPI2DereferenceVisitor({
|
|
@@ -438,10 +454,12 @@ class OpenAPI2DereferenceVisitor {
|
|
|
438
454
|
indirections: [...this.indirections],
|
|
439
455
|
options: this.options,
|
|
440
456
|
refractCache: this.refractCache,
|
|
457
|
+
visited: this.visited,
|
|
441
458
|
ancestors: ancestorsLineage
|
|
442
459
|
});
|
|
443
460
|
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
444
|
-
mutable: true
|
|
461
|
+
mutable: true,
|
|
462
|
+
skipVisited: true
|
|
445
463
|
});
|
|
446
464
|
|
|
447
465
|
// remove referencing reference from ancestors lineage
|
|
@@ -569,6 +587,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
569
587
|
const replacer = this.options.dereference.strategyOpts['openapi-2']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
570
588
|
const replacement = replacer(refElement);
|
|
571
589
|
path.replaceWith(replacement);
|
|
590
|
+
path.skip();
|
|
572
591
|
return;
|
|
573
592
|
}
|
|
574
593
|
}
|
|
@@ -584,7 +603,11 @@ class OpenAPI2DereferenceVisitor {
|
|
|
584
603
|
*/
|
|
585
604
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
586
605
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
587
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isJSONReferenceElement)(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
606
|
+
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isJSONReferenceElement)(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
607
|
+
if (shouldDetectCircular) {
|
|
608
|
+
this.visited.add(referencedElement);
|
|
609
|
+
}
|
|
610
|
+
|
|
588
611
|
// append referencing reference to ancestors lineage
|
|
589
612
|
directAncestors.add(referencingElement);
|
|
590
613
|
const visitor = new OpenAPI2DereferenceVisitor({
|
|
@@ -592,10 +615,12 @@ class OpenAPI2DereferenceVisitor {
|
|
|
592
615
|
indirections: [...this.indirections],
|
|
593
616
|
options: this.options,
|
|
594
617
|
refractCache: this.refractCache,
|
|
618
|
+
visited: this.visited,
|
|
595
619
|
ancestors: ancestorsLineage
|
|
596
620
|
});
|
|
597
621
|
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
598
|
-
mutable: true
|
|
622
|
+
mutable: true,
|
|
623
|
+
skipVisited: true
|
|
599
624
|
});
|
|
600
625
|
|
|
601
626
|
// remove referencing reference from ancestors lineage
|
|
@@ -618,6 +643,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
618
643
|
* Transclude referencing element with merged referenced element.
|
|
619
644
|
*/
|
|
620
645
|
path.replaceWith(mergedElement);
|
|
646
|
+
path.skip();
|
|
621
647
|
} catch (error) {
|
|
622
648
|
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
623
649
|
this.handleError(`Error while dereferencing JSON Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
@@ -23,6 +23,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
23
23
|
reference;
|
|
24
24
|
options;
|
|
25
25
|
refractCache;
|
|
26
|
+
visited;
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Tracks element ancestors across dive-deep traversal boundaries.
|
|
@@ -35,13 +36,15 @@ class OpenAPI2DereferenceVisitor {
|
|
|
35
36
|
options,
|
|
36
37
|
indirections = [],
|
|
37
38
|
ancestors = new AncestorLineage(),
|
|
38
|
-
refractCache = new WeakMap()
|
|
39
|
+
refractCache = new WeakMap(),
|
|
40
|
+
visited = new WeakSet()
|
|
39
41
|
}) {
|
|
40
42
|
this.indirections = indirections;
|
|
41
43
|
this.reference = reference;
|
|
42
44
|
this.options = options;
|
|
43
45
|
this.refractCache = refractCache;
|
|
44
46
|
this.ancestors = new AncestorLineage(...ancestors);
|
|
47
|
+
this.visited = visited;
|
|
45
48
|
}
|
|
46
49
|
toAncestorLineage(path) {
|
|
47
50
|
const ancestorNodes = path.getAncestorNodes();
|
|
@@ -274,6 +277,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
274
277
|
const replacer = this.options.dereference.strategyOpts['openapi-2']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
275
278
|
const replacement = replacer(refElement);
|
|
276
279
|
path.replaceWith(replacement);
|
|
280
|
+
path.skip();
|
|
277
281
|
return;
|
|
278
282
|
}
|
|
279
283
|
}
|
|
@@ -289,7 +293,11 @@ class OpenAPI2DereferenceVisitor {
|
|
|
289
293
|
*/
|
|
290
294
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
291
295
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
292
|
-
if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
296
|
+
if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
297
|
+
if (shouldDetectCircular) {
|
|
298
|
+
this.visited.add(referencedElement);
|
|
299
|
+
}
|
|
300
|
+
|
|
293
301
|
// append referencing reference to ancestors lineage
|
|
294
302
|
directAncestors.add(referencingElement);
|
|
295
303
|
const visitor = new OpenAPI2DereferenceVisitor({
|
|
@@ -297,10 +305,12 @@ class OpenAPI2DereferenceVisitor {
|
|
|
297
305
|
indirections: [...this.indirections],
|
|
298
306
|
options: this.options,
|
|
299
307
|
refractCache: this.refractCache,
|
|
308
|
+
visited: this.visited,
|
|
300
309
|
ancestors: ancestorsLineage
|
|
301
310
|
});
|
|
302
311
|
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
303
|
-
mutable: true
|
|
312
|
+
mutable: true,
|
|
313
|
+
skipVisited: true
|
|
304
314
|
});
|
|
305
315
|
directAncestors.delete(referencingElement);
|
|
306
316
|
}
|
|
@@ -321,6 +331,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
321
331
|
* Transclude referencing element with merged referenced element.
|
|
322
332
|
*/
|
|
323
333
|
path.replaceWith(mergedElement);
|
|
334
|
+
path.skip();
|
|
324
335
|
} catch (error) {
|
|
325
336
|
const $ref = toValue(referencingElement.$ref);
|
|
326
337
|
this.handleError(`Error while dereferencing Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
@@ -408,6 +419,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
408
419
|
const replacer = this.options.dereference.strategyOpts['openapi-2']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
409
420
|
const replacement = replacer(refElement);
|
|
410
421
|
path.replaceWith(replacement);
|
|
422
|
+
path.skip();
|
|
411
423
|
return;
|
|
412
424
|
}
|
|
413
425
|
}
|
|
@@ -423,7 +435,11 @@ class OpenAPI2DereferenceVisitor {
|
|
|
423
435
|
*/
|
|
424
436
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
425
437
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
426
|
-
if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
438
|
+
if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
439
|
+
if (shouldDetectCircular) {
|
|
440
|
+
this.visited.add(referencedElement);
|
|
441
|
+
}
|
|
442
|
+
|
|
427
443
|
// append referencing reference to ancestors lineage
|
|
428
444
|
directAncestors.add(referencingElement);
|
|
429
445
|
const visitor = new OpenAPI2DereferenceVisitor({
|
|
@@ -431,10 +447,12 @@ class OpenAPI2DereferenceVisitor {
|
|
|
431
447
|
indirections: [...this.indirections],
|
|
432
448
|
options: this.options,
|
|
433
449
|
refractCache: this.refractCache,
|
|
450
|
+
visited: this.visited,
|
|
434
451
|
ancestors: ancestorsLineage
|
|
435
452
|
});
|
|
436
453
|
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
437
|
-
mutable: true
|
|
454
|
+
mutable: true,
|
|
455
|
+
skipVisited: true
|
|
438
456
|
});
|
|
439
457
|
|
|
440
458
|
// remove referencing reference from ancestors lineage
|
|
@@ -562,6 +580,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
562
580
|
const replacer = this.options.dereference.strategyOpts['openapi-2']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
563
581
|
const replacement = replacer(refElement);
|
|
564
582
|
path.replaceWith(replacement);
|
|
583
|
+
path.skip();
|
|
565
584
|
return;
|
|
566
585
|
}
|
|
567
586
|
}
|
|
@@ -577,7 +596,11 @@ class OpenAPI2DereferenceVisitor {
|
|
|
577
596
|
*/
|
|
578
597
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
579
598
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
580
|
-
if ((isExternalReference || isNonEntryDocument || isJSONReferenceElement(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
599
|
+
if ((isExternalReference || isNonEntryDocument || isJSONReferenceElement(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
600
|
+
if (shouldDetectCircular) {
|
|
601
|
+
this.visited.add(referencedElement);
|
|
602
|
+
}
|
|
603
|
+
|
|
581
604
|
// append referencing reference to ancestors lineage
|
|
582
605
|
directAncestors.add(referencingElement);
|
|
583
606
|
const visitor = new OpenAPI2DereferenceVisitor({
|
|
@@ -585,10 +608,12 @@ class OpenAPI2DereferenceVisitor {
|
|
|
585
608
|
indirections: [...this.indirections],
|
|
586
609
|
options: this.options,
|
|
587
610
|
refractCache: this.refractCache,
|
|
611
|
+
visited: this.visited,
|
|
588
612
|
ancestors: ancestorsLineage
|
|
589
613
|
});
|
|
590
614
|
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
591
|
-
mutable: true
|
|
615
|
+
mutable: true,
|
|
616
|
+
skipVisited: true
|
|
592
617
|
});
|
|
593
618
|
|
|
594
619
|
// remove referencing reference from ancestors lineage
|
|
@@ -611,6 +636,7 @@ class OpenAPI2DereferenceVisitor {
|
|
|
611
636
|
* Transclude referencing element with merged referenced element.
|
|
612
637
|
*/
|
|
613
638
|
path.replaceWith(mergedElement);
|
|
639
|
+
path.skip();
|
|
614
640
|
} catch (error) {
|
|
615
641
|
const $ref = toValue(referencingElement.$ref);
|
|
616
642
|
this.handleError(`Error while dereferencing JSON Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
@@ -64,12 +64,16 @@ class OpenAPI3_0DereferenceStrategy extends _DereferenceStrategy.default {
|
|
|
64
64
|
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
65
65
|
refSet = mutableRefSet;
|
|
66
66
|
}
|
|
67
|
+
const shouldDetectCircular = ['error', 'replace'].includes(options.dereference.circular);
|
|
67
68
|
const visitor = new _visitor.default({
|
|
68
69
|
reference: reference,
|
|
69
70
|
options
|
|
70
71
|
});
|
|
71
72
|
const dereferencedElement = await (0, _apidomTraverse.traverseAsync)(refSet.rootRef.value, visitor, {
|
|
72
|
-
mutable: true
|
|
73
|
+
mutable: true,
|
|
74
|
+
...(shouldDetectCircular && {
|
|
75
|
+
skipVisited: true
|
|
76
|
+
})
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
/**
|
|
@@ -57,12 +57,16 @@ class OpenAPI3_0DereferenceStrategy extends DereferenceStrategy {
|
|
|
57
57
|
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
58
58
|
refSet = mutableRefSet;
|
|
59
59
|
}
|
|
60
|
+
const shouldDetectCircular = ['error', 'replace'].includes(options.dereference.circular);
|
|
60
61
|
const visitor = new OpenAPI3_0DereferenceVisitor({
|
|
61
62
|
reference: reference,
|
|
62
63
|
options
|
|
63
64
|
});
|
|
64
65
|
const dereferencedElement = await traverseAsync(refSet.rootRef.value, visitor, {
|
|
65
|
-
mutable: true
|
|
66
|
+
mutable: true,
|
|
67
|
+
...(shouldDetectCircular && {
|
|
68
|
+
skipVisited: true
|
|
69
|
+
})
|
|
66
70
|
});
|
|
67
71
|
|
|
68
72
|
/**
|
|
@@ -31,6 +31,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
31
31
|
reference;
|
|
32
32
|
options;
|
|
33
33
|
refractCache;
|
|
34
|
+
visited;
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Tracks element ancestors across dive-deep traversal boundaries.
|
|
@@ -43,13 +44,15 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
43
44
|
options,
|
|
44
45
|
indirections = [],
|
|
45
46
|
ancestors = new _util.AncestorLineage(),
|
|
46
|
-
refractCache = new WeakMap()
|
|
47
|
+
refractCache = new WeakMap(),
|
|
48
|
+
visited = new WeakSet()
|
|
47
49
|
}) {
|
|
48
50
|
this.indirections = indirections;
|
|
49
51
|
this.reference = reference;
|
|
50
52
|
this.options = options;
|
|
51
53
|
this.ancestors = new _util.AncestorLineage(...ancestors);
|
|
52
54
|
this.refractCache = refractCache;
|
|
55
|
+
this.visited = visited;
|
|
53
56
|
}
|
|
54
57
|
toAncestorLineage(path) {
|
|
55
58
|
const ancestorNodes = path.getAncestorNodes();
|
|
@@ -282,6 +285,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
282
285
|
const replacer = this.options.dereference.strategyOpts['openapi-3-0']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
283
286
|
const replacement = replacer(refElement);
|
|
284
287
|
path.replaceWith(replacement);
|
|
288
|
+
path.skip();
|
|
285
289
|
return;
|
|
286
290
|
}
|
|
287
291
|
}
|
|
@@ -297,7 +301,11 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
297
301
|
*/
|
|
298
302
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
299
303
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
300
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isReferenceElement)(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
304
|
+
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isReferenceElement)(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
305
|
+
if (shouldDetectCircular) {
|
|
306
|
+
this.visited.add(referencedElement);
|
|
307
|
+
}
|
|
308
|
+
|
|
301
309
|
// append referencing reference to ancestors lineage
|
|
302
310
|
directAncestors.add(referencingElement);
|
|
303
311
|
const visitor = new OpenAPI3_0DereferenceVisitor({
|
|
@@ -305,10 +313,12 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
305
313
|
indirections: [...this.indirections],
|
|
306
314
|
options: this.options,
|
|
307
315
|
refractCache: this.refractCache,
|
|
316
|
+
visited: this.visited,
|
|
308
317
|
ancestors: ancestorsLineage
|
|
309
318
|
});
|
|
310
319
|
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
311
|
-
mutable: true
|
|
320
|
+
mutable: true,
|
|
321
|
+
skipVisited: true
|
|
312
322
|
});
|
|
313
323
|
|
|
314
324
|
// remove referencing reference from ancestors lineage
|
|
@@ -331,6 +341,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
331
341
|
* Transclude referencing element with merged referenced element.
|
|
332
342
|
*/
|
|
333
343
|
path.replaceWith(mergedElement);
|
|
344
|
+
path.skip();
|
|
334
345
|
} catch (error) {
|
|
335
346
|
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
336
347
|
this.handleError(`Error while dereferencing Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
@@ -418,6 +429,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
418
429
|
const replacer = this.options.dereference.strategyOpts['openapi-3-0']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
419
430
|
const replacement = replacer(refElement);
|
|
420
431
|
path.replaceWith(replacement);
|
|
432
|
+
path.skip();
|
|
421
433
|
return;
|
|
422
434
|
}
|
|
423
435
|
}
|
|
@@ -433,7 +445,11 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
433
445
|
*/
|
|
434
446
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
435
447
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
436
|
-
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isPathItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
448
|
+
if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isPathItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
449
|
+
if (shouldDetectCircular) {
|
|
450
|
+
this.visited.add(referencedElement);
|
|
451
|
+
}
|
|
452
|
+
|
|
437
453
|
// append referencing reference to ancestors lineage
|
|
438
454
|
directAncestors.add(referencingElement);
|
|
439
455
|
const visitor = new OpenAPI3_0DereferenceVisitor({
|
|
@@ -441,10 +457,12 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
441
457
|
indirections: [...this.indirections],
|
|
442
458
|
options: this.options,
|
|
443
459
|
refractCache: this.refractCache,
|
|
460
|
+
visited: this.visited,
|
|
444
461
|
ancestors: ancestorsLineage
|
|
445
462
|
});
|
|
446
463
|
referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
|
|
447
|
-
mutable: true
|
|
464
|
+
mutable: true,
|
|
465
|
+
skipVisited: true
|
|
448
466
|
});
|
|
449
467
|
|
|
450
468
|
// remove referencing reference from ancestors lineage
|
|
@@ -24,6 +24,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
24
24
|
reference;
|
|
25
25
|
options;
|
|
26
26
|
refractCache;
|
|
27
|
+
visited;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Tracks element ancestors across dive-deep traversal boundaries.
|
|
@@ -36,13 +37,15 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
36
37
|
options,
|
|
37
38
|
indirections = [],
|
|
38
39
|
ancestors = new AncestorLineage(),
|
|
39
|
-
refractCache = new WeakMap()
|
|
40
|
+
refractCache = new WeakMap(),
|
|
41
|
+
visited = new WeakSet()
|
|
40
42
|
}) {
|
|
41
43
|
this.indirections = indirections;
|
|
42
44
|
this.reference = reference;
|
|
43
45
|
this.options = options;
|
|
44
46
|
this.ancestors = new AncestorLineage(...ancestors);
|
|
45
47
|
this.refractCache = refractCache;
|
|
48
|
+
this.visited = visited;
|
|
46
49
|
}
|
|
47
50
|
toAncestorLineage(path) {
|
|
48
51
|
const ancestorNodes = path.getAncestorNodes();
|
|
@@ -275,6 +278,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
275
278
|
const replacer = this.options.dereference.strategyOpts['openapi-3-0']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
276
279
|
const replacement = replacer(refElement);
|
|
277
280
|
path.replaceWith(replacement);
|
|
281
|
+
path.skip();
|
|
278
282
|
return;
|
|
279
283
|
}
|
|
280
284
|
}
|
|
@@ -290,7 +294,11 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
290
294
|
*/
|
|
291
295
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
292
296
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
293
|
-
if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
297
|
+
if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
298
|
+
if (shouldDetectCircular) {
|
|
299
|
+
this.visited.add(referencedElement);
|
|
300
|
+
}
|
|
301
|
+
|
|
294
302
|
// append referencing reference to ancestors lineage
|
|
295
303
|
directAncestors.add(referencingElement);
|
|
296
304
|
const visitor = new OpenAPI3_0DereferenceVisitor({
|
|
@@ -298,10 +306,12 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
298
306
|
indirections: [...this.indirections],
|
|
299
307
|
options: this.options,
|
|
300
308
|
refractCache: this.refractCache,
|
|
309
|
+
visited: this.visited,
|
|
301
310
|
ancestors: ancestorsLineage
|
|
302
311
|
});
|
|
303
312
|
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
304
|
-
mutable: true
|
|
313
|
+
mutable: true,
|
|
314
|
+
skipVisited: true
|
|
305
315
|
});
|
|
306
316
|
|
|
307
317
|
// remove referencing reference from ancestors lineage
|
|
@@ -324,6 +334,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
324
334
|
* Transclude referencing element with merged referenced element.
|
|
325
335
|
*/
|
|
326
336
|
path.replaceWith(mergedElement);
|
|
337
|
+
path.skip();
|
|
327
338
|
} catch (error) {
|
|
328
339
|
const $ref = toValue(referencingElement.$ref);
|
|
329
340
|
this.handleError(`Error while dereferencing Reference Object. Cannot resolve $ref "${$ref}": ${error.message}`, error, referencingElement, '$ref', $ref, path);
|
|
@@ -411,6 +422,7 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
411
422
|
const replacer = this.options.dereference.strategyOpts['openapi-3-0']?.circularReplacer ?? this.options.dereference.circularReplacer;
|
|
412
423
|
const replacement = replacer(refElement);
|
|
413
424
|
path.replaceWith(replacement);
|
|
425
|
+
path.skip();
|
|
414
426
|
return;
|
|
415
427
|
}
|
|
416
428
|
}
|
|
@@ -426,7 +438,11 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
426
438
|
*/
|
|
427
439
|
const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
|
|
428
440
|
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
|
|
429
|
-
if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
441
|
+
if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
|
|
442
|
+
if (shouldDetectCircular) {
|
|
443
|
+
this.visited.add(referencedElement);
|
|
444
|
+
}
|
|
445
|
+
|
|
430
446
|
// append referencing reference to ancestors lineage
|
|
431
447
|
directAncestors.add(referencingElement);
|
|
432
448
|
const visitor = new OpenAPI3_0DereferenceVisitor({
|
|
@@ -434,10 +450,12 @@ class OpenAPI3_0DereferenceVisitor {
|
|
|
434
450
|
indirections: [...this.indirections],
|
|
435
451
|
options: this.options,
|
|
436
452
|
refractCache: this.refractCache,
|
|
453
|
+
visited: this.visited,
|
|
437
454
|
ancestors: ancestorsLineage
|
|
438
455
|
});
|
|
439
456
|
referencedElement = await traverseAsync(referencedElement, visitor, {
|
|
440
|
-
mutable: true
|
|
457
|
+
mutable: true,
|
|
458
|
+
skipVisited: true
|
|
441
459
|
});
|
|
442
460
|
|
|
443
461
|
// remove referencing reference from ancestors lineage
|
|
@@ -67,12 +67,16 @@ class OpenAPI3_1DereferenceStrategy extends _DereferenceStrategy.default {
|
|
|
67
67
|
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
68
68
|
refSet = mutableRefSet;
|
|
69
69
|
}
|
|
70
|
+
const shouldDetectCircular = ['error', 'replace'].includes(options.dereference.circular);
|
|
70
71
|
const visitor = new _visitor.default({
|
|
71
72
|
reference: reference,
|
|
72
73
|
options
|
|
73
74
|
});
|
|
74
75
|
const dereferencedElement = await (0, _apidomTraverse.traverseAsync)(refSet.rootRef.value, visitor, {
|
|
75
|
-
mutable: true
|
|
76
|
+
mutable: true,
|
|
77
|
+
...(shouldDetectCircular && {
|
|
78
|
+
skipVisited: true
|
|
79
|
+
})
|
|
76
80
|
});
|
|
77
81
|
|
|
78
82
|
/**
|
|
@@ -56,12 +56,16 @@ class OpenAPI3_1DereferenceStrategy extends DereferenceStrategy {
|
|
|
56
56
|
reference = mutableRefSet.find(ref => ref.uri === file.uri);
|
|
57
57
|
refSet = mutableRefSet;
|
|
58
58
|
}
|
|
59
|
+
const shouldDetectCircular = ['error', 'replace'].includes(options.dereference.circular);
|
|
59
60
|
const visitor = new OpenAPI3_1DereferenceVisitor({
|
|
60
61
|
reference: reference,
|
|
61
62
|
options
|
|
62
63
|
});
|
|
63
64
|
const dereferencedElement = await traverseAsync(refSet.rootRef.value, visitor, {
|
|
64
|
-
mutable: true
|
|
65
|
+
mutable: true,
|
|
66
|
+
...(shouldDetectCircular && {
|
|
67
|
+
skipVisited: true
|
|
68
|
+
})
|
|
65
69
|
});
|
|
66
70
|
|
|
67
71
|
/**
|