dirvi-lib 0.11.0-beta.6 → 0.11.0-beta.7

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 (158) hide show
  1. package/dist/app/app-api.d.ts +7 -25
  2. package/dist/app/app-api.d.ts.map +1 -1
  3. package/dist/app/app-api.js +1 -11
  4. package/dist/app/index.d.ts +1 -0
  5. package/dist/app/index.d.ts.map +1 -1
  6. package/dist/app/index.js +1 -0
  7. package/dist/app/node-presentation.d.ts +13 -0
  8. package/dist/app/node-presentation.d.ts.map +1 -0
  9. package/dist/app/reducer/effect-to-action.d.ts +2 -2
  10. package/dist/app/reducer/effect-to-action.d.ts.map +1 -1
  11. package/dist/app/reducer/effect-to-action.js +87 -32
  12. package/dist/app/reducer/reducer-action.d.ts +12 -6
  13. package/dist/app/reducer/reducer-action.d.ts.map +1 -1
  14. package/dist/app/reducer/reducer.d.ts +4 -2
  15. package/dist/app/reducer/reducer.d.ts.map +1 -1
  16. package/dist/app/reducer/reducer.js +102 -68
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/input/application/intent-to-effect.d.ts +2 -2
  21. package/dist/input/application/intent-to-effect.d.ts.map +1 -1
  22. package/dist/input/application/intent-to-effect.js +8 -9
  23. package/dist/input/application/parse-ex-command.d.ts +1 -1
  24. package/dist/input/application/parse-ex-command.d.ts.map +1 -1
  25. package/dist/input/application/parse-normal-command.d.ts +1 -1
  26. package/dist/input/application/parse-normal-command.d.ts.map +1 -1
  27. package/dist/input/domain/effect.d.ts +1 -2
  28. package/dist/input/domain/effect.d.ts.map +1 -1
  29. package/dist/state-and-nav/cursor.d.ts +89 -0
  30. package/dist/state-and-nav/cursor.d.ts.map +1 -0
  31. package/dist/state-and-nav/cursor.js +84 -0
  32. package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.impl.d.ts +1 -1
  33. package/dist/state-and-nav/fold-node/deprecated/fold-node.impl.d.ts.map +1 -0
  34. package/dist/state-and-nav/fold-node/deprecated/fold-node.test.d.ts.map +1 -0
  35. package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.test.js +2 -2
  36. package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.types.d.ts +2 -2
  37. package/dist/state-and-nav/fold-node/deprecated/fold-node.types.d.ts.map +1 -0
  38. package/dist/{trees → state-and-nav}/fold-node/fold-node.impl.d.ts +3 -3
  39. package/dist/state-and-nav/fold-node/fold-node.impl.d.ts.map +1 -0
  40. package/dist/{trees → state-and-nav}/fold-node/fold-node.impl.js +1 -1
  41. package/dist/{trees → state-and-nav}/fold-node/fold-node.model.d.ts +1 -1
  42. package/dist/state-and-nav/fold-node/fold-node.model.d.ts.map +1 -0
  43. package/dist/{trees → state-and-nav}/fold-node/fold-node.types.d.ts +2 -2
  44. package/dist/state-and-nav/fold-node/fold-node.types.d.ts.map +1 -0
  45. package/dist/state-and-nav/fold-node/index.d.ts.map +1 -0
  46. package/dist/state-and-nav/index.d.ts +16 -0
  47. package/dist/state-and-nav/index.d.ts.map +1 -0
  48. package/dist/state-and-nav/index.js +6 -0
  49. package/dist/state-and-nav/nav/nav.ordered.impl.d.ts +12 -0
  50. package/dist/state-and-nav/nav/nav.ordered.impl.d.ts.map +1 -0
  51. package/dist/state-and-nav/nav/nav.ordered.impl.js +77 -0
  52. package/dist/state-and-nav/nav/nav.traversal.d.ts +11 -0
  53. package/dist/state-and-nav/nav/nav.traversal.d.ts.map +1 -0
  54. package/dist/state-and-nav/nav/nav.traversal.js +207 -0
  55. package/dist/{trees/nav-node/nav-node.types.d.ts → state-and-nav/nav/nav.types.d.ts} +32 -22
  56. package/dist/state-and-nav/nav/nav.types.d.ts.map +1 -0
  57. package/dist/state-and-nav/nav/nav.unordered.impl.d.ts +13 -0
  58. package/dist/state-and-nav/nav/nav.unordered.impl.d.ts.map +1 -0
  59. package/dist/state-and-nav/nav/nav.unordered.impl.js +77 -0
  60. package/dist/state-and-nav/state/state.impl.d.ts +9 -0
  61. package/dist/state-and-nav/state/state.impl.d.ts.map +1 -0
  62. package/dist/{trees → state-and-nav}/state/state.impl.js +62 -9
  63. package/dist/state-and-nav/state/state.schemas.d.ts +2 -0
  64. package/dist/state-and-nav/state/state.schemas.d.ts.map +1 -0
  65. package/dist/state-and-nav/state/state.schemas.js +39 -0
  66. package/dist/state-and-nav/state/state.types.d.ts +72 -0
  67. package/dist/state-and-nav/state/state.types.d.ts.map +1 -0
  68. package/dist/state-and-nav/tree/deprecated/tree-node.arb.d.ts.map +1 -0
  69. package/dist/state-and-nav/tree/deprecated/tree-node.arb.debug.test.d.ts.map +1 -0
  70. package/dist/state-and-nav/tree/deprecated/tree-node.impl.d.ts.map +1 -0
  71. package/dist/state-and-nav/tree/deprecated/tree-node.schemas.d.ts.map +1 -0
  72. package/dist/state-and-nav/tree/deprecated/tree-node.test.d.ts.map +1 -0
  73. package/dist/state-and-nav/tree/deprecated/tree-node.types.d.ts.map +1 -0
  74. package/dist/state-and-nav/tree/index.d.ts +7 -0
  75. package/dist/state-and-nav/tree/index.d.ts.map +1 -0
  76. package/dist/state-and-nav/tree/index.js +1 -0
  77. package/dist/state-and-nav/tree/tree-node.arb.d.ts +94 -0
  78. package/dist/state-and-nav/tree/tree-node.arb.d.ts.map +1 -0
  79. package/dist/state-and-nav/tree/tree-node.arb.debug.test.d.ts +2 -0
  80. package/dist/state-and-nav/tree/tree-node.arb.debug.test.d.ts.map +1 -0
  81. package/dist/state-and-nav/tree/tree-node.arb.debug.test.js +54 -0
  82. package/dist/state-and-nav/tree/tree-node.arb.js +188 -0
  83. package/dist/state-and-nav/tree/tree-node.model.d.ts +193 -0
  84. package/dist/state-and-nav/tree/tree-node.model.d.ts.map +1 -0
  85. package/dist/state-and-nav/tree/tree-node.model.js +110 -0
  86. package/dist/state-and-nav/tree/tree-node.test.d.ts +2 -0
  87. package/dist/state-and-nav/tree/tree-node.test.d.ts.map +1 -0
  88. package/dist/state-and-nav/tree/tree-node.test.js +234 -0
  89. package/dist/{trees/tree-node/tree-node.impl.d.ts → state-and-nav/tree/tree.impl.d.ts} +3 -3
  90. package/dist/state-and-nav/tree/tree.impl.d.ts.map +1 -0
  91. package/dist/{trees/tree-node/tree-node.impl.js → state-and-nav/tree/tree.impl.js} +19 -16
  92. package/dist/{trees/tree-node/tree-node.types.d.ts → state-and-nav/tree/tree.types.d.ts} +64 -44
  93. package/dist/state-and-nav/tree/tree.types.d.ts.map +1 -0
  94. package/dist/state-and-nav/tree/tree.types.js +1 -0
  95. package/package.json +1 -1
  96. package/dist/trees/cursor.d.ts +0 -59
  97. package/dist/trees/cursor.d.ts.map +0 -1
  98. package/dist/trees/cursor.js +0 -55
  99. package/dist/trees/fold-node/deprecated/fold-node.impl.d.ts.map +0 -1
  100. package/dist/trees/fold-node/deprecated/fold-node.test.d.ts.map +0 -1
  101. package/dist/trees/fold-node/deprecated/fold-node.types.d.ts.map +0 -1
  102. package/dist/trees/fold-node/fold-node.impl.d.ts.map +0 -1
  103. package/dist/trees/fold-node/fold-node.model.d.ts.map +0 -1
  104. package/dist/trees/fold-node/fold-node.types.d.ts.map +0 -1
  105. package/dist/trees/fold-node/index.d.ts.map +0 -1
  106. package/dist/trees/index.d.ts +0 -9
  107. package/dist/trees/index.d.ts.map +0 -1
  108. package/dist/trees/index.js +0 -8
  109. package/dist/trees/nav-node/nav-node.impl.d.ts +0 -29
  110. package/dist/trees/nav-node/nav-node.impl.d.ts.map +0 -1
  111. package/dist/trees/nav-node/nav-node.impl.js +0 -223
  112. package/dist/trees/nav-node/nav-node.types.d.ts.map +0 -1
  113. package/dist/trees/state/state.impl.d.ts +0 -8
  114. package/dist/trees/state/state.impl.d.ts.map +0 -1
  115. package/dist/trees/state/state.schemas.d.ts +0 -25
  116. package/dist/trees/state/state.schemas.d.ts.map +0 -1
  117. package/dist/trees/state/state.schemas.js +0 -17
  118. package/dist/trees/state/state.types.d.ts +0 -36
  119. package/dist/trees/state/state.types.d.ts.map +0 -1
  120. package/dist/trees/tree-node/deprecated/tree-node.arb.d.ts.map +0 -1
  121. package/dist/trees/tree-node/deprecated/tree-node.arb.debug.test.d.ts.map +0 -1
  122. package/dist/trees/tree-node/deprecated/tree-node.impl.d.ts.map +0 -1
  123. package/dist/trees/tree-node/deprecated/tree-node.schemas.d.ts.map +0 -1
  124. package/dist/trees/tree-node/deprecated/tree-node.test.d.ts.map +0 -1
  125. package/dist/trees/tree-node/deprecated/tree-node.types.d.ts.map +0 -1
  126. package/dist/trees/tree-node/index.d.ts +0 -5
  127. package/dist/trees/tree-node/index.d.ts.map +0 -1
  128. package/dist/trees/tree-node/index.js +0 -2
  129. package/dist/trees/tree-node/tree-node.arb.d.ts +0 -104
  130. package/dist/trees/tree-node/tree-node.arb.d.ts.map +0 -1
  131. package/dist/trees/tree-node/tree-node.arb.js +0 -188
  132. package/dist/trees/tree-node/tree-node.impl.d.ts.map +0 -1
  133. package/dist/trees/tree-node/tree-node.model.d.ts +0 -78
  134. package/dist/trees/tree-node/tree-node.model.d.ts.map +0 -1
  135. package/dist/trees/tree-node/tree-node.model.js +0 -37
  136. package/dist/trees/tree-node/tree-node.types.d.ts.map +0 -1
  137. /package/dist/{trees/fold-node/deprecated/fold-node.types.js → app/node-presentation.js} +0 -0
  138. /package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.impl.js +0 -0
  139. /package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.test.d.ts +0 -0
  140. /package/dist/{trees/fold-node → state-and-nav/fold-node/deprecated}/fold-node.types.js +0 -0
  141. /package/dist/{trees → state-and-nav}/fold-node/fold-node.model.js +0 -0
  142. /package/dist/{trees/nav-node/nav-node.types.js → state-and-nav/fold-node/fold-node.types.js} +0 -0
  143. /package/dist/{trees → state-and-nav}/fold-node/index.d.ts +0 -0
  144. /package/dist/{trees → state-and-nav}/fold-node/index.js +0 -0
  145. /package/dist/{trees/state/state.types.js → state-and-nav/nav/nav.types.js} +0 -0
  146. /package/dist/{trees/tree-node/deprecated/tree-node.types.js → state-and-nav/state/state.types.js} +0 -0
  147. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.d.ts +0 -0
  148. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.debug.test.d.ts +0 -0
  149. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.debug.test.js +0 -0
  150. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.js +0 -0
  151. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.impl.d.ts +0 -0
  152. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.impl.js +0 -0
  153. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.schemas.d.ts +0 -0
  154. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.schemas.js +0 -0
  155. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.test.d.ts +0 -0
  156. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.test.js +0 -0
  157. /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.types.d.ts +0 -0
  158. /package/dist/{trees/tree-node → state-and-nav/tree/deprecated}/tree-node.types.js +0 -0
@@ -1,24 +1,76 @@
1
- function firstAvailableAdditionalFoldIndex(foldsApi, state) {
1
+ function firstAvailableAdditionalFoldIndex(foldsApi, folds) {
2
2
  let index = 1;
3
- while (foldsApi.hasAtIndex(state.folds, index)) {
3
+ while (foldsApi.hasAtIndex(folds, index)) {
4
4
  index += 1;
5
5
  }
6
6
  return index;
7
7
  }
8
- export function createReducer(treeNodeApi, foldsApi) {
8
+ export function createReducer(stateApi, navNodeApi) {
9
+ const { treeNodeApi, foldsApi, cursorApi } = stateApi;
10
+ /**
11
+ * Preserve the cursor if its position remains navigable. Otherwise, move it
12
+ * to a fold marker containing its representative entry, or to the nearest
13
+ * visible ancestor.
14
+ */
15
+ function reconcileCursor(state) {
16
+ const navigation = navNodeApi.from(stateApi.getRoot(state), stateApi.getFolds(state));
17
+ if (navigation === undefined || navigation.children === null) {
18
+ // StateApi guarantees that the root is a loaded branch.
19
+ throw new Error('Cannot navigate state: root is not a loaded branch.');
20
+ }
21
+ const cursor = stateApi.getCursor(state);
22
+ const positions = [
23
+ { path: [] },
24
+ ...navNodeApi.cursors(navigation.children),
25
+ ];
26
+ if (positions.some((position) => cursorApi.equal(position, cursor))) {
27
+ return state;
28
+ }
29
+ const path = cursorApi.getPath(cursor);
30
+ while (path.length > 0) {
31
+ const entryId = path.at(-1);
32
+ if (entryId !== undefined) {
33
+ const parentPath = path.slice(0, -1);
34
+ const parent = navNodeApi.getNodeAtPath(navigation.children, parentPath);
35
+ const foldEntry = parent?.entries.find((entry) => navNodeApi.entryIsFold(entry) &&
36
+ entry.folded.some((foldedEntry) => !navNodeApi.entryIsFold(foldedEntry) &&
37
+ foldedEntry.id === entryId));
38
+ if (foldEntry !== undefined && navNodeApi.entryIsFold(foldEntry)) {
39
+ const firstEntry = foldEntry.folded.find((entry) => !navNodeApi.entryIsFold(entry));
40
+ if (firstEntry !== undefined && !navNodeApi.entryIsFold(firstEntry)) {
41
+ const foldCursor = {
42
+ parentPath,
43
+ firstId: firstEntry.id,
44
+ };
45
+ if (positions.some((position) => cursorApi.equal(position, foldCursor))) {
46
+ return stateApi.update(state, { cursor: foldCursor }) ?? state;
47
+ }
48
+ }
49
+ }
50
+ const nodeCursor = { path: [...path] };
51
+ if (positions.some((position) => cursorApi.equal(position, nodeCursor))) {
52
+ return stateApi.update(state, { cursor: nodeCursor }) ?? state;
53
+ }
54
+ }
55
+ path.pop();
56
+ }
57
+ // The root cursor is always included in `positions`.
58
+ return stateApi.update(state, { cursor: { path: [] } }) ?? state;
59
+ }
60
+ function update(state, changes) {
61
+ const nextState = stateApi.update(state, changes);
62
+ return nextState === undefined ? state : reconcileCursor(nextState);
63
+ }
9
64
  return (state, action) => {
10
65
  switch (action.kind) {
11
66
  case 'changeCursor':
12
- return {
13
- ...state,
14
- cursor: action.cursor,
15
- };
67
+ return update(state, { cursor: action.cursor });
16
68
  case 'updateBranch': {
17
- const root = treeNodeApi.updateAtPath(state.root, action.path, (node) => {
69
+ const root = treeNodeApi.updateAtPath(stateApi.getRoot(state), action.path, (node) => {
18
70
  /*
19
- * Loading/unloading is a branch-only operation. TreeNodeApi can
20
- * structurally convert any node, but the application reducer must
21
- * not turn a leaf into a branch.
71
+ * Loading/unloading is a branch-only operation. TreeMethods can
72
+ * structurally convert any node, but the reducer must not turn a
73
+ * leaf into a branch.
22
74
  */
23
75
  if (treeNodeApi.kind(node) === 'leaf') {
24
76
  return undefined;
@@ -35,19 +87,14 @@ export function createReducer(treeNodeApi, foldsApi) {
35
87
  if (root === undefined || treeNodeApi.kind(root) !== 'loaded-branch') {
36
88
  return state;
37
89
  }
38
- return {
39
- ...state,
40
- root,
41
- };
90
+ return update(state, { root });
42
91
  }
43
92
  case 'setState': {
44
93
  // A newer update has already been applied.
45
94
  if (state !== action.oldState) {
46
95
  return state;
47
96
  }
48
- return {
49
- ...action.newState,
50
- };
97
+ return reconcileCursor(action.newState);
51
98
  }
52
99
  case 'addToFoldTree': {
53
100
  const entryId = action.path.at(-1);
@@ -55,82 +102,69 @@ export function createReducer(treeNodeApi, foldsApi) {
55
102
  return state;
56
103
  }
57
104
  const parentPath = action.path.slice(0, -1);
58
- const folds = foldsApi.hideEntryAtPath(state.folds, action.foldTreeIndex, parentPath, entryId);
105
+ const folds = foldsApi.hideEntryAtPath(stateApi.getFolds(state), action.foldTreeIndex, parentPath, entryId);
59
106
  if (folds === undefined) {
60
107
  return state;
61
108
  }
62
- return {
63
- ...state,
109
+ return update(state, {
64
110
  folds,
65
111
  cursor: action.cursor,
66
- };
112
+ });
67
113
  }
68
114
  case 'removeFromFoldTree': {
69
- // TODO: Change to show only entry at cursor. mirroring addToFoldTree
70
- const folds = foldsApi.showAllHiddenEntriesAtPath(state.folds, action.foldTreeIndex, action.path);
71
- if (folds === undefined) {
72
- return state;
115
+ let folds = stateApi.getFolds(state);
116
+ if (action.entryIds === null) {
117
+ const nextFolds = foldsApi.showAllHiddenEntriesAtPath(folds, action.foldTreeIndex, action.path);
118
+ if (nextFolds === undefined) {
119
+ return state;
120
+ }
121
+ folds = nextFolds;
122
+ }
123
+ else {
124
+ for (const entryId of action.entryIds) {
125
+ const nextFolds = foldsApi.showEntryAtPath(folds, action.foldTreeIndex, action.path, entryId);
126
+ if (nextFolds === undefined) {
127
+ return state;
128
+ }
129
+ folds = nextFolds;
130
+ }
73
131
  }
74
- return {
75
- ...state,
132
+ return update(state, {
76
133
  folds,
77
134
  cursor: action.cursor,
78
- };
135
+ });
79
136
  }
80
137
  case 'fold': {
81
- const folds = foldsApi.activateAtIndex(state.folds, action.foldTreeIndex);
82
- return folds === undefined
83
- ? state
84
- : {
85
- ...state,
86
- folds,
87
- };
138
+ const folds = foldsApi.activateAtIndex(stateApi.getFolds(state), action.foldTreeIndex);
139
+ return folds === undefined ? state : update(state, { folds });
88
140
  }
89
141
  case 'unfold': {
90
- const folds = foldsApi.deactivateAtIndex(state.folds, action.foldTreeIndex);
91
- return folds === undefined
92
- ? state
93
- : {
94
- ...state,
95
- folds,
96
- };
142
+ const folds = foldsApi.deactivateAtIndex(stateApi.getFolds(state), action.foldTreeIndex);
143
+ return folds === undefined ? state : update(state, { folds });
97
144
  }
98
145
  case 'toggleFold': {
99
- const folds = foldsApi.toggleActiveAtIndex(state.folds, action.foldTreeIndex);
100
- return folds === undefined
101
- ? state
102
- : {
103
- ...state,
104
- folds,
105
- };
146
+ const folds = foldsApi.toggleActiveAtIndex(stateApi.getFolds(state), action.foldTreeIndex);
147
+ return folds === undefined ? state : update(state, { folds });
106
148
  }
107
149
  case 'createFoldTree': {
108
- const index = firstAvailableAdditionalFoldIndex(foldsApi, state);
109
- const folds = foldsApi.setAdditionalFoldAtIndex(state.folds, index,
110
- // Obtain this through the actual TreeNodeApi root-ID operation.
111
- treeNodeApi.id(state.root), {
150
+ const currentFolds = stateApi.getFolds(state);
151
+ const index = firstAvailableAdditionalFoldIndex(foldsApi, currentFolds);
152
+ const folds = foldsApi.setAdditionalFoldAtIndex(currentFolds, index,
153
+ // Obtain this through the actual TreeMethods root-ID operation.
154
+ treeNodeApi.id(stateApi.getRoot(state)), {
112
155
  name: action.name,
113
156
  description: null,
114
157
  });
115
- return folds === undefined
116
- ? state
117
- : {
118
- ...state,
119
- folds,
120
- };
158
+ return folds === undefined ? state : update(state, { folds });
121
159
  }
122
160
  case 'deleteFoldTree': {
123
- const index = foldsApi.getIndexByName(state.folds, action.name);
161
+ const currentFolds = stateApi.getFolds(state);
162
+ const index = foldsApi.getIndexByName(currentFolds, action.name);
124
163
  if (index === undefined || index === 0) {
125
164
  return state;
126
165
  }
127
- const folds = foldsApi.removeAdditionalFoldAtIndex(state.folds, index);
128
- return folds === undefined
129
- ? state
130
- : {
131
- ...state,
132
- folds,
133
- };
166
+ const folds = foldsApi.removeAdditionalFoldAtIndex(currentFolds, index);
167
+ return folds === undefined ? state : update(state, { folds });
134
168
  }
135
169
  default: {
136
170
  const _exhaustive = action;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './trees/index.js';
1
+ export * from './state-and-nav/index.js';
2
2
  export * from './feedback/index.js';
3
3
  export * from './app/index.js';
4
4
  export * from './input/application/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,gBAAgB,CAAC;AAE/B,cAAc,8BAA8B,CAAC;AAE7C,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AAEzC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,gBAAgB,CAAC;AAE/B,cAAc,8BAA8B,CAAC;AAE7C,cAAc,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export * from './trees/index.js';
1
+ export * from './state-and-nav/index.js';
2
2
  export * from './feedback/index.js';
3
3
  export * from './app/index.js';
4
4
  export * from './input/application/index.js';
@@ -1,4 +1,4 @@
1
- import type { CursorApi, SerializableKey, State, StateApi, TreeNodeApi } from '../../trees/index.js';
1
+ import type { SerializableKey, State, StateApi } from '../../state-and-nav/index.js';
2
2
  import type { Effect, Intent } from '../domain/index.js';
3
3
  /**
4
4
  * Converts a user intent and the current tree state into an effect.
@@ -10,5 +10,5 @@ import type { Effect, Intent } from '../domain/index.js';
10
10
  * @typeParam Value - Application-owned data stored in each tree node.
11
11
  */
12
12
  export type IntentToEffect<Id extends SerializableKey, Value> = (intent: Intent, state: State<Id, Value>) => Effect<Id, Value> | undefined;
13
- export declare function createIntentToEffect<Id extends SerializableKey, Value>(registeredCommands: ReadonlySet<string>, stateApi: StateApi<Id, Value>, cursorApi: CursorApi<Id>, treeNodeApi: TreeNodeApi<Id, Value>): IntentToEffect<Id, Value>;
13
+ export declare function createIntentToEffect<Id extends SerializableKey, Value>(registeredCommands: ReadonlySet<string>, stateApi: StateApi<Id, Value>): IntentToEffect<Id, Value>;
14
14
  //# sourceMappingURL=intent-to-effect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"intent-to-effect.d.ts","sourceRoot":"","sources":["../../../src/input/application/intent-to-effect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,KAAK,EACL,QAAQ,EACR,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKvE;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAAI,CAC9D,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KACpB,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;AAEnC,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EACpE,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,EACvC,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,EAC7B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,GAClC,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAkE3B"}
1
+ {"version":3,"file":"intent-to-effect.d.ts","sourceRoot":"","sources":["../../../src/input/application/intent-to-effect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,KAAK,EACL,QAAQ,EACT,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKvE;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAAI,CAC9D,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KACpB,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;AAEnC,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EACpE,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,EACvC,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAC5B,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAgE3B"}
@@ -1,14 +1,14 @@
1
1
  import { parseExCommand } from './parse-ex-command.js';
2
2
  import { parseNormalCommand } from './parse-normal-command.js';
3
- export function createIntentToEffect(registeredCommands, stateApi, cursorApi, treeNodeApi) {
3
+ export function createIntentToEffect(registeredCommands, stateApi) {
4
4
  return (intent, state) => {
5
5
  switch (intent.intentType) {
6
6
  case 'setNormalBuffer':
7
7
  return normalBufferToEffectResult(intent.normalBuffer);
8
8
  case 'normalRight':
9
- return normalInteractRightToEffect(state, stateApi, cursorApi, treeNodeApi);
9
+ return normalInteractRightToEffect(state, stateApi);
10
10
  case 'normalLeft':
11
- return normalInteractLeftToEffect(state, cursorApi);
11
+ return normalInteractLeftToEffect(state, stateApi);
12
12
  case 'normalDown':
13
13
  return dispatchAction({
14
14
  effectActionType: 'nextEntry',
@@ -106,16 +106,16 @@ function normalBufferToEffectResult(updatedNormalBuffer) {
106
106
  * - An open branch dispatches an action that closes/unloads its children.
107
107
  * - A leaf has no right-interaction effect.
108
108
  */
109
- function normalInteractRightToEffect(state, stateApi, cursorApi, treeNodeApi) {
109
+ function normalInteractRightToEffect(state, stateApi) {
110
110
  const currentEntry = stateApi.getNodeAtCursor(state);
111
111
  if (currentEntry === undefined) {
112
112
  return undefined;
113
113
  }
114
- const path = cursorApi.getPath(state.cursor);
114
+ const path = stateApi.cursorPath(state);
115
115
  if (path === undefined) {
116
116
  return undefined;
117
117
  }
118
- switch (treeNodeApi.kind(currentEntry)) {
118
+ switch (stateApi.treeNodeApi.kind(currentEntry)) {
119
119
  case 'unloaded-branch':
120
120
  return {
121
121
  effectType: 'loadBranchEntries',
@@ -137,9 +137,8 @@ function normalInteractRightToEffect(state, stateApi, cursorApi, treeNodeApi) {
137
137
  * Left from the root has no effect. Otherwise dispatch navigation to the
138
138
  * parent entry.
139
139
  */
140
- function normalInteractLeftToEffect(state, cursorApi) {
141
- const path = cursorApi.getPath(state.cursor);
142
- if (path === undefined || path.length === 0) {
140
+ function normalInteractLeftToEffect(state, stateApi) {
141
+ if (stateApi.isCursorRoot(state)) {
143
142
  return undefined;
144
143
  }
145
144
  return dispatchAction({
@@ -1,4 +1,4 @@
1
- import type { SerializableKey } from '../../trees/index.js';
1
+ import type { SerializableKey } from '../../state-and-nav/index.js';
2
2
  import type { Effect } from '../domain/index.js';
3
3
  /**
4
4
  * Parses a Vim-style Ex command line into an application effect.
@@ -1 +1 @@
1
- {"version":3,"file":"parse-ex-command.d.ts","sourceRoot":"","sources":["../../../src/input/application/parse-ex-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AA6IjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,cAAc,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAC9D,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,GACtC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAoE/B"}
1
+ {"version":3,"file":"parse-ex-command.d.ts","sourceRoot":"","sources":["../../../src/input/application/parse-ex-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AA6IjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,cAAc,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAC9D,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,GACtC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAoE/B"}
@@ -1,4 +1,4 @@
1
- import type { SerializableKey } from '../../trees/index.js';
1
+ import type { SerializableKey } from '../../state-and-nav/index.js';
2
2
  import type { EffectAction } from '../domain/index.js';
3
3
  export type ParseNormalCommandResult<Id extends SerializableKey, Value> = {
4
4
  kind: 'incomplete';
@@ -1 +1 @@
1
- {"version":3,"file":"parse-normal-command.d.ts","sourceRoot":"","sources":["../../../src/input/application/parse-normal-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOvD,MAAM,MAAM,wBAAwB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAClE;IACE,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;CACjC,GACD;IACE,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEN,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAClE,YAAY,EAAE,MAAM,GACnB,wBAAwB,CAAC,EAAE,EAAE,KAAK,CAAC,CAwCrC"}
1
+ {"version":3,"file":"parse-normal-command.d.ts","sourceRoot":"","sources":["../../../src/input/application/parse-normal-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOvD,MAAM,MAAM,wBAAwB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAClE;IACE,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;CACjC,GACD;IACE,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEN,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAClE,YAAY,EAAE,MAAM,GACnB,wBAAwB,CAAC,EAAE,EAAE,KAAK,CAAC,CAwCrC"}
@@ -1,6 +1,5 @@
1
1
  import type { InputModeState } from './input-mode-state.js';
2
- import type { SerializableKey, TreeNode } from '../../trees/index.js';
3
- export type EffectClosure = () => void | Promise<void>;
2
+ import type { SerializableKey, TreeNode } from '../../state-and-nav/index.js';
4
3
  /**
5
4
  * An effect is some execution to be done in `App`, that could affect the shell
6
5
  * or current app of dirvi.
@@ -1 +1 @@
1
- {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../../src/input/domain/effect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../../src/input/domain/effect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * A root-relative path identifying the current tree position.
4
+ *
5
+ * The empty path identifies the tree root. A non-empty path identifies a
6
+ * descendant by following child IDs from the root.
7
+ *
8
+ * For example, given:
9
+ *
10
+ * ```
11
+ * root
12
+ * └── src
13
+ * └── main.ts
14
+ * ```
15
+ *
16
+ * the cursors are:
17
+ *
18
+ * ```ts
19
+ * { path: [] } // root
20
+ * { path: ['src'] } // src
21
+ * { path: ['src', 'main.ts'] } // main.ts
22
+ * ```
23
+ *
24
+ * @typeParam Id - The type of node IDs.
25
+ */
26
+ export type NodeCursor<Id> = Readonly<{
27
+ path: readonly Id[];
28
+ }>;
29
+ /**
30
+ * Fold cursors identify a contiguous fold run by its parent path and the ID of
31
+ * its first hidden child.
32
+ */
33
+ export type FoldCursor<Id> = Readonly<{
34
+ parentPath: readonly Id[];
35
+ firstId: Id;
36
+ }>;
37
+ /**
38
+ * A position in navigation.
39
+ *
40
+ * Unordered navigation uses node cursors only. Ordered navigation may also
41
+ * use fold cursors to identify inline fold blocks.
42
+ */
43
+ export type Cursor<Id> = NodeCursor<Id> | FoldCursor<Id>;
44
+ /**
45
+ * Creates a schema for cursors.
46
+ *
47
+ * The schema validates the IDs in the path using the param, but does not verify
48
+ * that the path exists in a particular tree.
49
+ *
50
+ * @typeParam IdSchema - type passed on so the parsed output can include `Id`
51
+ * type.
52
+ * @param idSchema - schema for the `Id` type.
53
+ */
54
+ export declare function createCursorSchema<IdSchema extends z.ZodTypeAny>(idSchema: IdSchema): z.ZodUnion<readonly [z.ZodObject<{
55
+ path: z.ZodArray<IdSchema>;
56
+ }, z.core.$strict>, z.ZodObject<{
57
+ parentPath: z.ZodArray<IdSchema>;
58
+ firstId: IdSchema;
59
+ }, z.core.$strict>]>;
60
+ /**
61
+ * Operations for comparing and inspecting cursors.
62
+ *
63
+ * @typeParam Id - The type of node IDs.
64
+ */
65
+ export type CursorMethods<Id> = {
66
+ isNodeCursor(cursor: Cursor<Id>): cursor is NodeCursor<Id>;
67
+ isFoldCursor(cursor: Cursor<Id>): cursor is FoldCursor<Id>;
68
+ /**
69
+ * Tests whether two cursors identify the same tree position.
70
+ */
71
+ equal(left: Cursor<Id>, right: Cursor<Id>): boolean;
72
+ /**
73
+ * Returns a mutable copy of the path to the cursor, returning the path of the
74
+ * first hidden child represented by a fold cursor.
75
+ *
76
+ * The empty path identifies the tree root.
77
+ */
78
+ getPath(cursor: Cursor<Id>): Id[];
79
+ /**
80
+ * Tests whether the cursor's path is within the subtree at `path`.
81
+ * A fold cursor uses its first hidden child's path as its representative path.
82
+ *
83
+ * The subtree includes the node at `path` itself. Therefore, equal
84
+ * paths return `true`, and an empty `path` contains every cursor.
85
+ */
86
+ cursorBelongsToSubtree(cursor: Cursor<Id>, path: readonly Id[]): boolean;
87
+ };
88
+ export declare function createCursorMethods<Id>(): CursorMethods<Id>;
89
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/state-and-nav/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,UAAU,CAAC,EAAE,IAAI,QAAQ,CAAC;IACpC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;CACrB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,EAAE,IAAI,QAAQ,CAAC;IACpC,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;IAC1B,OAAO,EAAE,EAAE,CAAC;CACb,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,MAAM,MAAM,CAAC,EAAE,IAAI,UAAU,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,CAAC,CAAC,UAAU,EAC9D,QAAQ,EAAE,QAAQ;;;;;qBAanB;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,EAAE,IAAI;IAC9B,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAC3D,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAE3D;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IAEpD;;;;;OAKG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC;IAElC;;;;;;OAMG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,OAAO,CAAC;CAC1E,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,aAAa,CAAC,EAAE,CAAC,CAqC3D"}
@@ -0,0 +1,84 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Creates a schema for cursors.
4
+ *
5
+ * The schema validates the IDs in the path using the param, but does not verify
6
+ * that the path exists in a particular tree.
7
+ *
8
+ * @typeParam IdSchema - type passed on so the parsed output can include `Id`
9
+ * type.
10
+ * @param idSchema - schema for the `Id` type.
11
+ */
12
+ export function createCursorSchema(idSchema) {
13
+ const pathSchema = z.array(idSchema);
14
+ return z.union([
15
+ z.object({
16
+ path: pathSchema,
17
+ }).strict(),
18
+ z.object({
19
+ parentPath: pathSchema,
20
+ firstId: idSchema,
21
+ }).strict(),
22
+ ]);
23
+ }
24
+ export function createCursorMethods() {
25
+ function isNodeCursor(cursor) {
26
+ return 'path' in cursor;
27
+ }
28
+ function isFoldCursor(cursor) {
29
+ return !isNodeCursor(cursor);
30
+ }
31
+ function getPath(cursor) {
32
+ return isNodeCursor(cursor)
33
+ ? [...cursor.path]
34
+ : [...cursor.parentPath, cursor.firstId];
35
+ }
36
+ return {
37
+ isNodeCursor,
38
+ isFoldCursor,
39
+ equal(left, right) {
40
+ if (isNodeCursor(left)) {
41
+ return isNodeCursor(right) && idPathEqual(left.path, right.path);
42
+ }
43
+ return (isFoldCursor(right) &&
44
+ left.firstId === right.firstId &&
45
+ idPathEqual(left.parentPath, right.parentPath));
46
+ },
47
+ getPath,
48
+ cursorBelongsToSubtree(cursor, path) {
49
+ return isPathPrefix(path, getPath(cursor));
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * Returns true when both root-relative paths contain the same IDs in the same
55
+ * order.
56
+ */
57
+ function idPathEqual(left, right) {
58
+ if (left.length !== right.length) {
59
+ return false;
60
+ }
61
+ for (let index = 0; index < left.length; index += 1) {
62
+ if (left[index] !== right[index]) {
63
+ return false;
64
+ }
65
+ }
66
+ return true;
67
+ }
68
+ /**
69
+ * Returns true when `prefix` is a prefix of `path`.
70
+ *
71
+ * Equal paths are included. An empty prefix is therefore a prefix of every
72
+ * path.
73
+ */
74
+ function isPathPrefix(prefix, path) {
75
+ if (prefix.length > path.length) {
76
+ return false;
77
+ }
78
+ for (let index = 0; index < prefix.length; index += 1) {
79
+ if (prefix[index] !== path[index]) {
80
+ return false;
81
+ }
82
+ }
83
+ return true;
84
+ }
@@ -1,5 +1,5 @@
1
1
  import type { FoldNodeApi, FoldNodeService } from './fold-node.types.js';
2
- import type { SerializableKey } from '../../tree-node/index.js';
2
+ import type { SerializableKey } from '../../tree/index.js';
3
3
  /**
4
4
  * Creates semantic operations for a fold-state tree.
5
5
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.impl.d.ts","sourceRoot":"","sources":["../../../../src/state-and-nav/fold-node/deprecated/fold-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACX,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,eAAe,EAC9D,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,GAC3B,eAAe,CAAC,EAAE,CAAC,CA0WrB"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.test.d.ts","sourceRoot":"","sources":["../../../../src/state-and-nav/fold-node/deprecated/fold-node.test.ts"],"names":[],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { createTreeNodeApi } from '../../tree-node/tree-node.impl.js';
2
+ import { createTreeMethods } from '../../tree/index.js';
3
3
  import { createFoldNodeService } from './fold-node.impl.js';
4
- const foldNodeApi = createTreeNodeApi();
4
+ const foldNodeApi = createTreeMethods();
5
5
  const service = createFoldNodeService(foldNodeApi);
6
6
  function createFoldNode(id, options = {}) {
7
7
  const node = foldNodeApi.createLoadedBranch(id, {
@@ -1,4 +1,4 @@
1
- import type { TreeNode, TreeNodeApi, SerializableKey } from '../../tree-node/index.js';
1
+ import type { TreeNode, TreeMethods, SerializableKey } from '../../tree/index.js';
2
2
  /**
3
3
  * Application-specific state stored in each fold-tree node.
4
4
  *
@@ -18,7 +18,7 @@ export type FoldNode<Id extends SerializableKey> = TreeNode<Id, FoldNodeValue<Id
18
18
  /**
19
19
  * Generic structural operations specialized to a fold-state tree.
20
20
  */
21
- export type FoldNodeApi<Id extends SerializableKey> = TreeNodeApi<Id, FoldNodeValue<Id>>;
21
+ export type FoldNodeApi<Id extends SerializableKey> = TreeMethods<Id, FoldNodeValue<Id>>;
22
22
  /**
23
23
  * Semantic operations for managing fold state.
24
24
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.types.d.ts","sourceRoot":"","sources":["../../../../src/state-and-nav/fold-node/deprecated/fold-node.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,WAAW,EACX,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,EAAE,SAAS,eAAe,IAAI,QAAQ,CAAC;IAC/D,cAAc,EAAE,SAAS,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;CACzC,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,CAAC,EAAE,SAAS,eAAe,IAAI,QAAQ,CACzD,EAAE,EACF,aAAa,CAAC,EAAE,CAAC,CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,EAAE,SAAS,eAAe,IAAI,WAAW,CAC/D,EAAE,EACF,aAAa,CAAC,EAAE,CAAC,CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,eAAe,CAAC,EAAE,SAAS,eAAe,IAAI;IACxD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEtC;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,CACpB,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EACtB,IAAI,EAAE,SAAS,EAAE,EAAE,EACnB,OAAO,EAAE,EAAE,GACV,OAAO,CAAC;IAEX;;;;OAIG;IACH,mBAAmB,CACjB,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EACtB,IAAI,EAAE,SAAS,EAAE,EAAE,GAClB,EAAE,EAAE,GAAG,SAAS,CAAC;IAEpB;;;;;;;;;;;;;;;;;OAiBG;IACH,oBAAoB,CAClB,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EACtB,IAAI,EAAE,SAAS,EAAE,EAAE,EACnB,OAAO,EAAE,EAAE,GACV,QAAQ,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAE5B;;;;;;;;;;;;;;;;;OAiBG;IACH,uBAAuB,CACrB,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EACtB,IAAI,EAAE,SAAS,EAAE,EAAE,EACnB,OAAO,EAAE,EAAE,GACV,QAAQ,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAE5B;;;;;;;;;;;;;;;;;;OAkBG;IACH,wBAAwB,CACtB,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EACtB,IAAI,EAAE,SAAS,EAAE,EAAE,GAClB,QAAQ,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CAC7B,CAAC"}
@@ -1,5 +1,5 @@
1
- import type { SerializableKey, TreeNodeApi } from '../tree-node/index.js';
2
- import type { FoldsApi } from './fold-node.types.js';
1
+ import type { SerializableKey, TreeMethods } from '../tree/index.js';
2
+ import type { FoldMethods } from './fold-node.types.js';
3
3
  /**
4
4
  * IDs of direct source-tree entries hidden at one source-tree branch.
5
5
  */
@@ -11,6 +11,6 @@ type HiddenEntryIds<Id extends SerializableKey> = readonly Id[];
11
11
  * Each fold tree preserves its own hidden-entry definition. An entry is hidden
12
12
  * by the aggregate when at least one active fold tree hides it.
13
13
  */
14
- export declare function createFoldsApi<Id extends SerializableKey>(foldTreeApi: TreeNodeApi<Id, HiddenEntryIds<Id>>): FoldsApi<Id>;
14
+ export declare function createFoldMethods<Id extends SerializableKey>(foldTreeApi: TreeMethods<Id, HiddenEntryIds<Id>>): FoldMethods<Id>;
15
15
  export {};
16
16
  //# sourceMappingURL=fold-node.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.impl.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/fold-node/fold-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAM1B,OAAO,KAAK,EAIV,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,KAAK,cAAc,CAAC,EAAE,SAAS,eAAe,IAAI,SAAS,EAAE,EAAE,CAAC;AA0ChE;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,eAAe,EAC1D,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,GAC/C,WAAW,CAAC,EAAE,CAAC,CA8nBjB"}
@@ -17,7 +17,7 @@ function hasUniqueValues(values) {
17
17
  * Each fold tree preserves its own hidden-entry definition. An entry is hidden
18
18
  * by the aggregate when at least one active fold tree hides it.
19
19
  */
20
- export function createFoldsApi(foldTreeApi) {
20
+ export function createFoldMethods(foldTreeApi) {
21
21
  function createEmptyFoldTree(rootId) {
22
22
  const tree = foldTreeApi.createLoadedBranch(rootId, [], []);
23
23
  /*
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import type { SerializableKey } from '../tree-node/index.js';
2
+ import type { SerializableKey } from '../tree/index.js';
3
3
  /**
4
4
  * Serializable semantic representation of one fold-state tree node.
5
5
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.model.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/fold-node/fold-node.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAYxD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,aAAa,CAAC,EAAE,SAAS,eAAe,IAAI,QAAQ,CAAC;IAC/D;;OAEG;IACH,EAAE,EAAE,EAAE,CAAC;IAEP;;;;;OAKG;IACH,cAAc,EAAE,SAAS,EAAE,EAAE,CAAC;IAE9B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC;CACxC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,SAAS,eAAe,EAClE,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GACtB,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CA0B9B;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,EAAE,SAAS,eAAe,IAAI,QAAQ,CAAC;IAC/D;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B;;;;;OAKG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;CACzB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,EAAE,SAAS,eAAe,IAAI,QAAQ,CAAC;IAC5D,KAAK,EAAE,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;CACtE,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,SAAS,eAAe,EAC/D,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GACtB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAmB3B"}