@speclynx/apidom-core 4.10.1 → 4.12.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 CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [4.12.0](https://github.com/speclynx/apidom/compare/v4.11.1...v4.12.0) (2026-06-23)
7
+
8
+ **Note:** Version bump only for package @speclynx/apidom-core
9
+
10
+ ## [4.11.1](https://github.com/speclynx/apidom/compare/v4.11.0...v4.11.1) (2026-06-10)
11
+
12
+ **Note:** Version bump only for package @speclynx/apidom-core
13
+
14
+ # [4.11.0](https://github.com/speclynx/apidom/compare/v4.10.1...v4.11.0) (2026-06-10)
15
+
16
+ ### Features
17
+
18
+ - **traverse:** skipVisited 'enter-only' mode and path.revisited ([#333](https://github.com/speclynx/apidom/issues/333)) ([fe944df](https://github.com/speclynx/apidom/commit/fe944df0eaab437a65d5761e6a3e14d490d2d3d6))
19
+
6
20
  ## [4.10.1](https://github.com/speclynx/apidom/compare/v4.10.0...v4.10.1) (2026-05-20)
7
21
 
8
22
  **Note:** Version bump only for package @speclynx/apidom-core
@@ -28006,6 +28006,14 @@ class Path {
28006
28006
  */
28007
28007
  inList;
28008
28008
 
28009
+ /**
28010
+ * True when this node is a non-descending revisit of an already-visited node
28011
+ * (only under skipVisited: 'enter-only'). Children are not traversed.
28012
+ * Set on both the enter and the matching leave phase, so it is meaningful
28013
+ * in either phase.
28014
+ */
28015
+ revisited = false;
28016
+
28009
28017
  /**
28010
28018
  * Internal state for traversal control.
28011
28019
  */
@@ -28590,6 +28598,10 @@ __webpack_require__.r(__webpack_exports__);
28590
28598
 
28591
28599
 
28592
28600
 
28601
+ /**
28602
+ * Controls handling of already-visited nodes during traversal.
28603
+ * @public
28604
+ */
28593
28605
  /**
28594
28606
  * Options for the traverse function.
28595
28607
  * @public
@@ -28597,6 +28609,12 @@ __webpack_require__.r(__webpack_exports__);
28597
28609
  // =============================================================================
28598
28610
  // Internal types for generator
28599
28611
  // =============================================================================
28612
+
28613
+ const normalizeSkipVisited = v => {
28614
+ if (v === true) return 'skip';
28615
+ if (v === false || v === undefined) return 'never';
28616
+ return v;
28617
+ };
28600
28618
  // =============================================================================
28601
28619
  // Core generator
28602
28620
  // =============================================================================
@@ -28614,7 +28632,7 @@ function* traverseGenerator(root, visitor, options) {
28614
28632
  mutationFn
28615
28633
  } = options;
28616
28634
  const keyMapIsFunction = typeof keyMap === 'function';
28617
- const visitedNodes = skipVisited ? new WeakSet() : null;
28635
+ const visitedNodes = skipVisited !== 'never' ? new WeakSet() : null;
28618
28636
  let stack;
28619
28637
  let inArray = Array.isArray(root);
28620
28638
  let keys = [root];
@@ -28629,6 +28647,7 @@ function* traverseGenerator(root, visitor, options) {
28629
28647
  index += 1;
28630
28648
  const isLeaving = index === keys.length;
28631
28649
  let key;
28650
+ let revisitNoDescend = false;
28632
28651
  const isEdited = isLeaving && edits.length !== 0;
28633
28652
  if (isLeaving) {
28634
28653
  key = ancestors.length === 0 ? undefined : currentPath?.key;
@@ -28670,6 +28689,7 @@ function* traverseGenerator(root, visitor, options) {
28670
28689
  edits = stack.edits;
28671
28690
  const parentInArray = stack.inArray;
28672
28691
  parentPath = stack.parentPath;
28692
+ revisitNoDescend = stack.revisitNoDescend;
28673
28693
  stack = stack.prev;
28674
28694
 
28675
28695
  // Push the edited node to parent's edits for propagation up the tree
@@ -28701,15 +28721,22 @@ function* traverseGenerator(root, visitor, options) {
28701
28721
  }
28702
28722
 
28703
28723
  // Skip already-visited nodes (handles DAG structures from cloneShallow)
28704
- if (skipVisited && !isLeaving) {
28724
+ if (skipVisited !== 'never' && !isLeaving) {
28705
28725
  if (visitedNodes.has(node)) {
28706
- continue;
28726
+ if (skipVisited === 'enter-only') {
28727
+ // fire enter/leave for this occurrence, but don't re-descend
28728
+ revisitNoDescend = true;
28729
+ } else {
28730
+ continue;
28731
+ }
28732
+ } else {
28733
+ visitedNodes.add(node);
28707
28734
  }
28708
- visitedNodes.add(node);
28709
28735
  }
28710
28736
 
28711
28737
  // Always create Path for the current node (needed for parentPath chain)
28712
28738
  currentPath = new _Path_mjs__WEBPACK_IMPORTED_MODULE_2__.Path(node, parent, parentPath, key, inArray);
28739
+ currentPath.revisited = revisitNoDescend;
28713
28740
  const visitFn = (0,_visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.getVisitFn)(visitor, nodeTypeGetter(node), isLeaving);
28714
28741
  if (visitFn) {
28715
28742
  // Assign state to visitor
@@ -28773,10 +28800,13 @@ function* traverseGenerator(root, visitor, options) {
28773
28800
  keys,
28774
28801
  edits,
28775
28802
  parentPath,
28803
+ revisitNoDescend,
28776
28804
  prev: stack
28777
28805
  };
28778
28806
  inArray = Array.isArray(node);
28779
- if (inArray) {
28807
+ if (revisitNoDescend) {
28808
+ keys = [];
28809
+ } else if (inArray) {
28780
28810
  keys = node;
28781
28811
  } else if (keyMapIsFunction) {
28782
28812
  keys = keyMap(node);
@@ -28851,7 +28881,7 @@ const traverse = (root, visitor, options = {}) => {
28851
28881
  nodePredicate: options.nodePredicate ?? _visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.isNode,
28852
28882
  nodeCloneFn: options.nodeCloneFn ?? _visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.cloneNode,
28853
28883
  detectCycles: options.detectCycles ?? true,
28854
- skipVisited: options.skipVisited ?? false,
28884
+ skipVisited: normalizeSkipVisited(options.skipVisited),
28855
28885
  mutable: options.mutable ?? false,
28856
28886
  mutationFn: options.mutationFn ?? _visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.mutateNode
28857
28887
  };
@@ -28883,7 +28913,7 @@ const traverseAsync = async (root, visitor, options = {}) => {
28883
28913
  nodePredicate: options.nodePredicate ?? _visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.isNode,
28884
28914
  nodeCloneFn: options.nodeCloneFn ?? _visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.cloneNode,
28885
28915
  detectCycles: options.detectCycles ?? true,
28886
- skipVisited: options.skipVisited ?? false,
28916
+ skipVisited: normalizeSkipVisited(options.skipVisited),
28887
28917
  mutable: options.mutable ?? false,
28888
28918
  mutationFn: options.mutationFn ?? _visitors_mjs__WEBPACK_IMPORTED_MODULE_3__.mutateNode
28889
28919
  };
@@ -29351,7 +29381,9 @@ mergeVisitors[Symbol.for('nodejs.util.promisify.custom')] = mergeVisitorsAsync;
29351
29381
  * @internal
29352
29382
  */
29353
29383
  function createPathProxy(originalPath, currentNode) {
29354
- return new _Path_mjs__WEBPACK_IMPORTED_MODULE_4__.Path(currentNode, originalPath.parent, originalPath.parentPath, originalPath.key, originalPath.inList);
29384
+ const proxy = new _Path_mjs__WEBPACK_IMPORTED_MODULE_4__.Path(currentNode, originalPath.parent, originalPath.parentPath, originalPath.key, originalPath.inList);
29385
+ proxy.revisited = originalPath.revisited;
29386
+ return proxy;
29355
29387
  }
29356
29388
 
29357
29389
  /***/ }