@speclynx/apidom-reference 4.7.1 → 4.9.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/apidom-reference.browser.js +148 -36
  3. package/dist/apidom-reference.browser.min.js +1 -1
  4. package/package.json +28 -28
  5. package/src/dereference/strategies/arazzo-1/index.cjs +5 -1
  6. package/src/dereference/strategies/arazzo-1/index.mjs +5 -1
  7. package/src/dereference/strategies/arazzo-1/visitor.cjs +12 -3
  8. package/src/dereference/strategies/arazzo-1/visitor.mjs +12 -3
  9. package/src/dereference/strategies/asyncapi-2/index.cjs +5 -1
  10. package/src/dereference/strategies/asyncapi-2/index.mjs +5 -1
  11. package/src/dereference/strategies/asyncapi-2/visitor.cjs +20 -5
  12. package/src/dereference/strategies/asyncapi-2/visitor.mjs +20 -5
  13. package/src/dereference/strategies/openapi-2/index.cjs +5 -1
  14. package/src/dereference/strategies/openapi-2/index.mjs +5 -1
  15. package/src/dereference/strategies/openapi-2/visitor.cjs +28 -7
  16. package/src/dereference/strategies/openapi-2/visitor.mjs +28 -7
  17. package/src/dereference/strategies/openapi-3-0/index.cjs +5 -1
  18. package/src/dereference/strategies/openapi-3-0/index.mjs +5 -1
  19. package/src/dereference/strategies/openapi-3-0/visitor.cjs +20 -5
  20. package/src/dereference/strategies/openapi-3-0/visitor.mjs +20 -5
  21. package/src/dereference/strategies/openapi-3-1/index.cjs +5 -1
  22. package/src/dereference/strategies/openapi-3-1/index.mjs +5 -1
  23. package/src/dereference/strategies/openapi-3-1/visitor.cjs +25 -7
  24. package/src/dereference/strategies/openapi-3-1/visitor.mjs +25 -7
  25. package/types/dereference/strategies/arazzo-1/visitor.d.ts +3 -1
  26. package/types/dereference/strategies/asyncapi-2/visitor.d.ts +3 -1
  27. package/types/dereference/strategies/openapi-2/visitor.d.ts +3 -1
  28. package/types/dereference/strategies/openapi-3-0/visitor.d.ts +3 -1
  29. package/types/dereference/strategies/openapi-3-1/visitor.d.ts +3 -1
@@ -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();
@@ -298,7 +301,11 @@ class OpenAPI3_0DereferenceVisitor {
298
301
  */
299
302
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
300
303
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
301
- 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
+
302
309
  // append referencing reference to ancestors lineage
303
310
  directAncestors.add(referencingElement);
304
311
  const visitor = new OpenAPI3_0DereferenceVisitor({
@@ -306,10 +313,12 @@ class OpenAPI3_0DereferenceVisitor {
306
313
  indirections: [...this.indirections],
307
314
  options: this.options,
308
315
  refractCache: this.refractCache,
316
+ visited: this.visited,
309
317
  ancestors: ancestorsLineage
310
318
  });
311
319
  referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
312
- mutable: true
320
+ mutable: true,
321
+ skipVisited: true
313
322
  });
314
323
 
315
324
  // remove referencing reference from ancestors lineage
@@ -436,7 +445,11 @@ class OpenAPI3_0DereferenceVisitor {
436
445
  */
437
446
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
438
447
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
439
- 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
+
440
453
  // append referencing reference to ancestors lineage
441
454
  directAncestors.add(referencingElement);
442
455
  const visitor = new OpenAPI3_0DereferenceVisitor({
@@ -444,10 +457,12 @@ class OpenAPI3_0DereferenceVisitor {
444
457
  indirections: [...this.indirections],
445
458
  options: this.options,
446
459
  refractCache: this.refractCache,
460
+ visited: this.visited,
447
461
  ancestors: ancestorsLineage
448
462
  });
449
463
  referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
450
- mutable: true
464
+ mutable: true,
465
+ skipVisited: true
451
466
  });
452
467
 
453
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();
@@ -291,7 +294,11 @@ class OpenAPI3_0DereferenceVisitor {
291
294
  */
292
295
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
293
296
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
294
- 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
+
295
302
  // append referencing reference to ancestors lineage
296
303
  directAncestors.add(referencingElement);
297
304
  const visitor = new OpenAPI3_0DereferenceVisitor({
@@ -299,10 +306,12 @@ class OpenAPI3_0DereferenceVisitor {
299
306
  indirections: [...this.indirections],
300
307
  options: this.options,
301
308
  refractCache: this.refractCache,
309
+ visited: this.visited,
302
310
  ancestors: ancestorsLineage
303
311
  });
304
312
  referencedElement = await traverseAsync(referencedElement, visitor, {
305
- mutable: true
313
+ mutable: true,
314
+ skipVisited: true
306
315
  });
307
316
 
308
317
  // remove referencing reference from ancestors lineage
@@ -429,7 +438,11 @@ class OpenAPI3_0DereferenceVisitor {
429
438
  */
430
439
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
431
440
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
432
- 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
+
433
446
  // append referencing reference to ancestors lineage
434
447
  directAncestors.add(referencingElement);
435
448
  const visitor = new OpenAPI3_0DereferenceVisitor({
@@ -437,10 +450,12 @@ class OpenAPI3_0DereferenceVisitor {
437
450
  indirections: [...this.indirections],
438
451
  options: this.options,
439
452
  refractCache: this.refractCache,
453
+ visited: this.visited,
440
454
  ancestors: ancestorsLineage
441
455
  });
442
456
  referencedElement = await traverseAsync(referencedElement, visitor, {
443
- mutable: true
457
+ mutable: true,
458
+ skipVisited: true
444
459
  });
445
460
 
446
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
  /**
@@ -36,6 +36,7 @@ class OpenAPI3_1DereferenceVisitor {
36
36
  reference;
37
37
  options;
38
38
  refractCache;
39
+ visited;
39
40
 
40
41
  /**
41
42
  * Tracks element ancestors across dive-deep traversal boundaries.
@@ -48,13 +49,15 @@ class OpenAPI3_1DereferenceVisitor {
48
49
  options,
49
50
  indirections = [],
50
51
  refractCache = new WeakMap(),
51
- ancestors = new _util2.AncestorLineage()
52
+ ancestors = new _util2.AncestorLineage(),
53
+ visited = new WeakSet()
52
54
  }) {
53
55
  this.indirections = indirections;
54
56
  this.reference = reference;
55
57
  this.options = options;
56
58
  this.refractCache = refractCache;
57
59
  this.ancestors = new _util2.AncestorLineage(...ancestors);
60
+ this.visited = visited;
58
61
  }
59
62
  toAncestorLineage(path) {
60
63
  const ancestorNodes = path.getAncestorNodes();
@@ -303,17 +306,22 @@ class OpenAPI3_1DereferenceVisitor {
303
306
  */
304
307
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
305
308
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
306
- if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isReferenceElement)(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
309
+ if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isReferenceElement)(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
310
+ if (shouldDetectCircular) {
311
+ this.visited.add(referencedElement);
312
+ }
307
313
  directAncestors.add(referencingElement);
308
314
  const visitor = new OpenAPI3_1DereferenceVisitor({
309
315
  reference,
310
316
  indirections: [...this.indirections],
311
317
  options: this.options,
312
318
  refractCache: this.refractCache,
319
+ visited: this.visited,
313
320
  ancestors: ancestorsLineage
314
321
  });
315
322
  referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
316
- mutable: true
323
+ mutable: true,
324
+ skipVisited: true
317
325
  });
318
326
  directAncestors.delete(referencingElement);
319
327
  }
@@ -456,17 +464,22 @@ class OpenAPI3_1DereferenceVisitor {
456
464
  */
457
465
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
458
466
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
459
- if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isPathItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
467
+ if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isPathItemElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
468
+ if (shouldDetectCircular) {
469
+ this.visited.add(referencedElement);
470
+ }
460
471
  directAncestors.add(referencingElement);
461
472
  const visitor = new OpenAPI3_1DereferenceVisitor({
462
473
  reference,
463
474
  indirections: [...this.indirections],
464
475
  options: this.options,
465
476
  refractCache: this.refractCache,
477
+ visited: this.visited,
466
478
  ancestors: ancestorsLineage
467
479
  });
468
480
  referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
469
- mutable: true
481
+ mutable: true,
482
+ skipVisited: true
470
483
  });
471
484
  directAncestors.delete(referencingElement);
472
485
  }
@@ -813,17 +826,22 @@ class OpenAPI3_1DereferenceVisitor {
813
826
  */
814
827
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
815
828
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
816
- if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isSchemaElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
829
+ if ((isExternalReference || isNonEntryDocument || (0, _apidomNsOpenapi.isSchemaElement)(referencedElement) && (0, _apidomDatamodel.isStringElement)(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
830
+ if (shouldDetectCircular) {
831
+ this.visited.add(referencedElement);
832
+ }
817
833
  directAncestors.add(referencingElement);
818
834
  const visitor = new OpenAPI3_1DereferenceVisitor({
819
835
  reference,
820
836
  indirections: [...this.indirections],
821
837
  options: this.options,
822
838
  refractCache: this.refractCache,
839
+ visited: this.visited,
823
840
  ancestors: ancestorsLineage
824
841
  });
825
842
  referencedElement = await (0, _apidomTraverse.traverseAsync)(referencedElement, visitor, {
826
- mutable: true
843
+ mutable: true,
844
+ skipVisited: true
827
845
  });
828
846
  directAncestors.delete(referencingElement);
829
847
  }
@@ -29,6 +29,7 @@ class OpenAPI3_1DereferenceVisitor {
29
29
  reference;
30
30
  options;
31
31
  refractCache;
32
+ visited;
32
33
 
33
34
  /**
34
35
  * Tracks element ancestors across dive-deep traversal boundaries.
@@ -41,13 +42,15 @@ class OpenAPI3_1DereferenceVisitor {
41
42
  options,
42
43
  indirections = [],
43
44
  refractCache = new WeakMap(),
44
- ancestors = new AncestorLineage()
45
+ ancestors = new AncestorLineage(),
46
+ visited = new WeakSet()
45
47
  }) {
46
48
  this.indirections = indirections;
47
49
  this.reference = reference;
48
50
  this.options = options;
49
51
  this.refractCache = refractCache;
50
52
  this.ancestors = new AncestorLineage(...ancestors);
53
+ this.visited = visited;
51
54
  }
52
55
  toAncestorLineage(path) {
53
56
  const ancestorNodes = path.getAncestorNodes();
@@ -296,17 +299,22 @@ class OpenAPI3_1DereferenceVisitor {
296
299
  */
297
300
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
298
301
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
299
- if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
302
+ if ((isExternalReference || isNonEntryDocument || isReferenceElement(referencedElement) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
303
+ if (shouldDetectCircular) {
304
+ this.visited.add(referencedElement);
305
+ }
300
306
  directAncestors.add(referencingElement);
301
307
  const visitor = new OpenAPI3_1DereferenceVisitor({
302
308
  reference,
303
309
  indirections: [...this.indirections],
304
310
  options: this.options,
305
311
  refractCache: this.refractCache,
312
+ visited: this.visited,
306
313
  ancestors: ancestorsLineage
307
314
  });
308
315
  referencedElement = await traverseAsync(referencedElement, visitor, {
309
- mutable: true
316
+ mutable: true,
317
+ skipVisited: true
310
318
  });
311
319
  directAncestors.delete(referencingElement);
312
320
  }
@@ -449,17 +457,22 @@ class OpenAPI3_1DereferenceVisitor {
449
457
  */
450
458
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
451
459
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
452
- if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
460
+ if ((isExternalReference || isNonEntryDocument || isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
461
+ if (shouldDetectCircular) {
462
+ this.visited.add(referencedElement);
463
+ }
453
464
  directAncestors.add(referencingElement);
454
465
  const visitor = new OpenAPI3_1DereferenceVisitor({
455
466
  reference,
456
467
  indirections: [...this.indirections],
457
468
  options: this.options,
458
469
  refractCache: this.refractCache,
470
+ visited: this.visited,
459
471
  ancestors: ancestorsLineage
460
472
  });
461
473
  referencedElement = await traverseAsync(referencedElement, visitor, {
462
- mutable: true
474
+ mutable: true,
475
+ skipVisited: true
463
476
  });
464
477
  directAncestors.delete(referencingElement);
465
478
  }
@@ -806,17 +819,22 @@ class OpenAPI3_1DereferenceVisitor {
806
819
  */
807
820
  const isNonEntryDocument = url.stripHash(reference.refSet.rootRef.uri) !== reference.uri;
808
821
  const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
809
- if ((isExternalReference || isNonEntryDocument || isSchemaElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular) && !ancestorsLineage.includesCycle(referencedElement)) {
822
+ if ((isExternalReference || isNonEntryDocument || isSchemaElement(referencedElement) && isStringElement(referencedElement.$ref) || shouldDetectCircular && !this.visited.has(referencedElement)) && !ancestorsLineage.includesCycle(referencedElement)) {
823
+ if (shouldDetectCircular) {
824
+ this.visited.add(referencedElement);
825
+ }
810
826
  directAncestors.add(referencingElement);
811
827
  const visitor = new OpenAPI3_1DereferenceVisitor({
812
828
  reference,
813
829
  indirections: [...this.indirections],
814
830
  options: this.options,
815
831
  refractCache: this.refractCache,
832
+ visited: this.visited,
816
833
  ancestors: ancestorsLineage
817
834
  });
818
835
  referencedElement = await traverseAsync(referencedElement, visitor, {
819
- mutable: true
836
+ mutable: true,
837
+ skipVisited: true
820
838
  });
821
839
  directAncestors.delete(referencingElement);
822
840
  }
@@ -11,6 +11,7 @@ export interface Arazzo1DereferenceVisitorOptions {
11
11
  readonly options: ReferenceOptions;
12
12
  readonly indirections?: Element[];
13
13
  readonly ancestors?: AncestorLineage<Element>;
14
+ readonly visited?: WeakSet<Element>;
14
15
  }
15
16
  /**
16
17
  * @public
@@ -19,13 +20,14 @@ declare class Arazzo1DereferenceVisitor {
19
20
  protected readonly indirections: Element[];
20
21
  protected readonly reference: Reference;
21
22
  protected readonly options: ReferenceOptions;
23
+ protected readonly visited: WeakSet<Element>;
22
24
  /**
23
25
  * Tracks element ancestors across dive-deep traversal boundaries.
24
26
  * Used for cycle detection: if a referenced element is found in
25
27
  * the ancestor lineage, a circular reference is detected.
26
28
  */
27
29
  protected readonly ancestors: AncestorLineage<Element>;
28
- constructor({ reference, options, indirections, ancestors, }: Arazzo1DereferenceVisitorOptions);
30
+ constructor({ reference, options, indirections, ancestors, visited, }: Arazzo1DereferenceVisitorOptions);
29
31
  protected toAncestorLineage(path: Path<Element>): [AncestorLineage<Element>, Set<Element>];
30
32
  protected toBaseURI(uri: string): string;
31
33
  protected toReference(uri: string): Promise<Reference>;
@@ -12,6 +12,7 @@ export interface AsyncAPI2DereferenceVisitorOptions {
12
12
  readonly indirections?: Element[];
13
13
  readonly refractCache?: WeakMap<Element, Element>;
14
14
  readonly ancestors?: AncestorLineage<Element>;
15
+ readonly visited?: WeakSet<Element>;
15
16
  }
16
17
  /**
17
18
  * @public
@@ -21,13 +22,14 @@ declare class AsyncAPI2DereferenceVisitor {
21
22
  protected readonly reference: Reference;
22
23
  protected readonly options: ReferenceOptions;
23
24
  protected readonly refractCache: WeakMap<Element, Element>;
25
+ protected readonly visited: WeakSet<Element>;
24
26
  /**
25
27
  * Tracks element ancestors across dive-deep traversal boundaries.
26
28
  * Used for cycle detection: if a referenced element is found in
27
29
  * the ancestor lineage, a circular reference is detected.
28
30
  */
29
31
  protected readonly ancestors: AncestorLineage<Element>;
30
- constructor({ reference, options, indirections, ancestors, refractCache, }: AsyncAPI2DereferenceVisitorOptions);
32
+ constructor({ reference, options, indirections, ancestors, refractCache, visited, }: AsyncAPI2DereferenceVisitorOptions);
31
33
  protected toAncestorLineage(path: Path<Element>): [AncestorLineage<Element>, Set<Element>];
32
34
  protected toBaseURI(uri: string): string;
33
35
  protected toReference(uri: string): Promise<Reference>;
@@ -12,6 +12,7 @@ export interface OpenAPI2DereferenceVisitorOptions {
12
12
  readonly indirections?: Element[];
13
13
  readonly refractCache?: WeakMap<Element, Element>;
14
14
  readonly ancestors?: AncestorLineage<Element>;
15
+ readonly visited?: WeakSet<Element>;
15
16
  }
16
17
  /**
17
18
  * @public
@@ -21,13 +22,14 @@ declare class OpenAPI2DereferenceVisitor {
21
22
  protected readonly reference: Reference;
22
23
  protected readonly options: ReferenceOptions;
23
24
  protected readonly refractCache: WeakMap<Element, Element>;
25
+ protected readonly visited: WeakSet<Element>;
24
26
  /**
25
27
  * Tracks element ancestors across dive-deep traversal boundaries.
26
28
  * Used for cycle detection: if a referenced element is found in
27
29
  * the ancestor lineage, a circular reference is detected.
28
30
  */
29
31
  protected readonly ancestors: AncestorLineage<Element>;
30
- constructor({ reference, options, indirections, ancestors, refractCache, }: OpenAPI2DereferenceVisitorOptions);
32
+ constructor({ reference, options, indirections, ancestors, refractCache, visited, }: OpenAPI2DereferenceVisitorOptions);
31
33
  protected toAncestorLineage(path: Path<Element>): [AncestorLineage<Element>, Set<Element>];
32
34
  protected toBaseURI(uri: string): string;
33
35
  protected toReference(uri: string): Promise<Reference>;
@@ -12,6 +12,7 @@ export interface OpenAPI3_0DereferenceVisitorOptions {
12
12
  readonly indirections?: Element[];
13
13
  readonly refractCache?: WeakMap<Element, Element>;
14
14
  readonly ancestors?: AncestorLineage<Element>;
15
+ readonly visited?: WeakSet<Element>;
15
16
  }
16
17
  /**
17
18
  * @public
@@ -21,13 +22,14 @@ declare class OpenAPI3_0DereferenceVisitor {
21
22
  protected readonly reference: Reference;
22
23
  protected readonly options: ReferenceOptions;
23
24
  protected readonly refractCache: WeakMap<Element, Element>;
25
+ protected readonly visited: WeakSet<Element>;
24
26
  /**
25
27
  * Tracks element ancestors across dive-deep traversal boundaries.
26
28
  * Used for cycle detection: if a referenced element is found in
27
29
  * the ancestor lineage, a circular reference is detected.
28
30
  */
29
31
  protected readonly ancestors: AncestorLineage<Element>;
30
- constructor({ reference, options, indirections, ancestors, refractCache, }: OpenAPI3_0DereferenceVisitorOptions);
32
+ constructor({ reference, options, indirections, ancestors, refractCache, visited, }: OpenAPI3_0DereferenceVisitorOptions);
31
33
  protected toAncestorLineage(path: Path<Element>): [AncestorLineage<Element>, Set<Element>];
32
34
  protected toBaseURI(uri: string): string;
33
35
  protected toReference(uri: string): Promise<Reference>;
@@ -12,6 +12,7 @@ export interface OpenAPI3_1DereferenceVisitorOptions {
12
12
  readonly indirections?: Element[];
13
13
  readonly refractCache?: WeakMap<Element, Element>;
14
14
  readonly ancestors?: AncestorLineage<Element>;
15
+ readonly visited?: WeakSet<Element>;
15
16
  }
16
17
  /**
17
18
  * @public
@@ -21,13 +22,14 @@ declare class OpenAPI3_1DereferenceVisitor {
21
22
  protected readonly reference: Reference;
22
23
  protected readonly options: ReferenceOptions;
23
24
  protected readonly refractCache: WeakMap<Element, Element>;
25
+ protected readonly visited: WeakSet<Element>;
24
26
  /**
25
27
  * Tracks element ancestors across dive-deep traversal boundaries.
26
28
  * Used for cycle detection: if a referenced element is found in
27
29
  * the ancestor lineage, a circular reference is detected.
28
30
  */
29
31
  protected readonly ancestors: AncestorLineage<Element>;
30
- constructor({ reference, options, indirections, refractCache, ancestors, }: OpenAPI3_1DereferenceVisitorOptions);
32
+ constructor({ reference, options, indirections, refractCache, ancestors, visited, }: OpenAPI3_1DereferenceVisitorOptions);
31
33
  protected toAncestorLineage(path: Path<Element>): [AncestorLineage<Element>, Set<Element>];
32
34
  protected toBaseURI(uri: string): string;
33
35
  protected toReference(uri: string): Promise<Reference>;