dirvi-lib 0.7.1 → 0.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.
Files changed (66) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/tree-surfer/cursor.d.ts +52 -26
  5. package/dist/tree-surfer/cursor.d.ts.map +1 -1
  6. package/dist/tree-surfer/cursor.js +19 -44
  7. package/dist/tree-surfer/fold-node/fold-node.arb.d.ts +2 -0
  8. package/dist/tree-surfer/fold-node/fold-node.arb.d.ts.map +1 -0
  9. package/dist/tree-surfer/fold-node/fold-node.arb.js +1 -0
  10. package/dist/tree-surfer/fold-node/fold-node.impl.d.ts +3 -4
  11. package/dist/tree-surfer/fold-node/fold-node.impl.d.ts.map +1 -1
  12. package/dist/tree-surfer/fold-node/fold-node.impl.js +73 -67
  13. package/dist/tree-surfer/fold-node/fold-node.schema.d.ts +2 -5
  14. package/dist/tree-surfer/fold-node/fold-node.schema.d.ts.map +1 -1
  15. package/dist/tree-surfer/fold-node/fold-node.schema.js +2 -9
  16. package/dist/tree-surfer/fold-node/fold-node.types.d.ts +169 -46
  17. package/dist/tree-surfer/fold-node/fold-node.types.d.ts.map +1 -1
  18. package/dist/tree-surfer/fold-node/tree-node.test.d.ts +2 -0
  19. package/dist/tree-surfer/fold-node/tree-node.test.d.ts.map +1 -0
  20. package/dist/tree-surfer/fold-node/tree-node.test.js +90 -0
  21. package/dist/tree-surfer/nav-node/nav-node.impl.d.ts +5 -5
  22. package/dist/tree-surfer/nav-node/nav-node.impl.d.ts.map +1 -1
  23. package/dist/tree-surfer/nav-node/nav-node.impl.js +84 -99
  24. package/dist/tree-surfer/nav-node/nav-node.types.d.ts +62 -34
  25. package/dist/tree-surfer/nav-node/nav-node.types.d.ts.map +1 -1
  26. package/dist/tree-surfer/nav-node/nav-node.types.js +1 -3
  27. package/dist/tree-surfer/state/state.impl.d.ts.map +1 -1
  28. package/dist/tree-surfer/state/state.impl.js +34 -36
  29. package/dist/tree-surfer/state/state.schemas.d.ts +3 -3
  30. package/dist/tree-surfer/state/state.schemas.d.ts.map +1 -1
  31. package/dist/tree-surfer/state/state.schemas.js +3 -3
  32. package/dist/tree-surfer/state/state.types.d.ts +11 -7
  33. package/dist/tree-surfer/state/state.types.d.ts.map +1 -1
  34. package/dist/tree-surfer/tree-node/tree-node.arb.d.ts +7 -9
  35. package/dist/tree-surfer/tree-node/tree-node.arb.d.ts.map +1 -1
  36. package/dist/tree-surfer/tree-node/tree-node.arb.debug.test.d.ts +2 -0
  37. package/dist/tree-surfer/tree-node/tree-node.arb.debug.test.d.ts.map +1 -0
  38. package/dist/tree-surfer/tree-node/tree-node.arb.js +18 -23
  39. package/dist/tree-surfer/tree-node/tree-node.impl.d.ts +1 -1
  40. package/dist/tree-surfer/tree-node/tree-node.impl.d.ts.map +1 -1
  41. package/dist/tree-surfer/tree-node/tree-node.impl.js +41 -48
  42. package/dist/tree-surfer/tree-node/tree-node.schemas.d.ts +2 -2
  43. package/dist/tree-surfer/tree-node/tree-node.schemas.d.ts.map +1 -1
  44. package/dist/tree-surfer/tree-node/tree-node.schemas.js +2 -2
  45. package/dist/tree-surfer/tree-node/tree-node.test.js +76 -81
  46. package/dist/tree-surfer/tree-node/tree-node.types.d.ts +14 -17
  47. package/dist/tree-surfer/tree-node/tree-node.types.d.ts.map +1 -1
  48. package/dist/tree-surfer-ui/application/intent-to-effect.d.ts +6 -2
  49. package/dist/tree-surfer-ui/application/intent-to-effect.d.ts.map +1 -1
  50. package/dist/tree-surfer-ui/application/intent-to-effect.js +1 -12
  51. package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts +10 -2
  52. package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts.map +1 -1
  53. package/dist/tree-surfer-ui/application/user-input-to-intent.js +12 -5
  54. package/dist/tree-surfer-ui/domain/effect.d.ts +6 -8
  55. package/dist/tree-surfer-ui/domain/effect.d.ts.map +1 -1
  56. package/dist/tree-surfer-ui/domain/index.d.ts +1 -1
  57. package/dist/tree-surfer-ui/domain/index.d.ts.map +1 -1
  58. package/dist/tree-surfer-ui/domain/index.js +1 -1
  59. package/dist/tree-surfer-ui/domain/{input-state.d.ts → input-mode-state.d.ts} +2 -2
  60. package/dist/tree-surfer-ui/domain/input-mode-state.d.ts.map +1 -0
  61. package/package.json +1 -1
  62. package/dist/tree-surfer/tree-node/tree-node.arb.debug.d.ts +0 -2
  63. package/dist/tree-surfer/tree-node/tree-node.arb.debug.d.ts.map +0 -1
  64. package/dist/tree-surfer-ui/domain/input-state.d.ts.map +0 -1
  65. /package/dist/tree-surfer/tree-node/{tree-node.arb.debug.js → tree-node.arb.debug.test.js} +0 -0
  66. /package/dist/tree-surfer-ui/domain/{input-state.js → input-mode-state.js} +0 -0
@@ -1,42 +1,70 @@
1
- import { LeafTreeNode, SerializableKey, TreeNode } from '../tree-node/tree-node.types.js';
2
- import { FoldNodeRoot } from '../fold-node/fold-node.types.js';
1
+ import { BranchTreeNode, SerializableKey, TreeNode } from '../tree-node/tree-node.types.js';
3
2
  import { Cursor } from '../cursor.js';
4
- /**
5
- * A navigation entry preserves the original buffer-node properties, but
6
- * replaces a branch's buffer children with a NavNode.
7
- */
8
- export type NavEntry<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = NavLeaf<Id, BufferNode> | NavBranch<Id, BufferNode>;
9
- export type NavLeaf<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = BufferNode & LeafTreeNode<Id>;
10
- type ReplaceChildren<Node, Children> = Node extends {
11
- children: unknown;
12
- } ? Omit<Node, 'children'> & {
13
- children: Children;
14
- } : never;
15
- export type NavBranch<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = ReplaceChildren<BufferNode, NavNode<Id, BufferNode> | null>;
16
- export declare function isNavBranch<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(entry: NavEntry<Id, BufferNode>): entry is NavBranch<Id, BufferNode>;
17
- /**
18
- * The derived tree as navigated: list of visible entries and folded entries.
19
- */
20
- export type NavNode<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = {
3
+ import { FoldNode } from '../fold-node/fold-node.types.js';
4
+ export type NavNode<Id extends SerializableKey> = {
21
5
  /**
22
- * Currently visible entries.
6
+ * Synthetic UI entry representing folded children.
7
+ *
8
+ * It is absent when this directory has no folded children.
23
9
  */
24
- entries: NavEntry<Id, BufferNode>[];
10
+ folded: NavFoldEntry<Id> | null;
25
11
  /**
26
- * Currently loaded entries hidden by this directory's fold.
12
+ * Loaded entries that are not folded at this directory, corresponding to
13
+ * navigable rows. Entries retain the order from the TreeNode.
27
14
  */
28
- foldedEntries: NavEntry<Id, BufferNode>[];
15
+ entries: NavEntry<Id>[];
29
16
  };
30
- export type NavNodeApi<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = {
31
- from(entries: BufferNode[], foldNode: FoldNodeRoot<Id>): NavNode<Id, BufferNode>;
32
- getNodeAtPath(navigation: NavNode<Id, BufferNode>, path: Id[]): NavNode<Id, BufferNode> | undefined;
33
- getEntryAtPath(navigation: NavNode<Id, BufferNode>, path: Id[]): NavEntry<Id, BufferNode> | undefined;
34
- nextCursor(rootNode: NavNode<Id, BufferNode>, cursor: Cursor<Id>): Cursor<Id> | undefined;
35
- previousCursor(rootNode: NavNode<Id, BufferNode>, cursor: Cursor<Id>): Cursor<Id> | undefined;
36
- cursorAfterFold(rootNode: NavNode<Id, BufferNode>, cursor: Cursor<Id>): Cursor<Id> | undefined;
37
- parentCursor(navigation: NavNode<Id, BufferNode>, cursor: Cursor<Id>): Cursor<Id> | undefined;
38
- cursors(navigation: NavNode<Id, BufferNode>, parentPath?: Id[]): Cursor<Id>[];
39
- visibleLeavesPaths(navigation: NavNode<Id, BufferNode>, parentPath?: Id[]): Id[][];
17
+ export type NavFoldEntry<Id extends SerializableKey> = {
18
+ /**
19
+ * Folded entries that are present in the loaded TreeNode.
20
+ *
21
+ * This is information for rendering the folded row.
22
+ */
23
+ entries: NavEntry<Id>[];
24
+ };
25
+ export type NavEntry<Id extends SerializableKey> = NavLeaf<Id> | NavBranch<Id>;
26
+ export type NavLeaf<Id extends SerializableKey> = {
27
+ id: Id;
28
+ };
29
+ export type NavBranch<Id extends SerializableKey> = {
30
+ id: Id;
31
+ children: NavNode<Id> | null;
32
+ };
33
+ export type NavNodeApi<Id extends SerializableKey, Node extends TreeNode<Id, Node>> = {
34
+ /**
35
+ * Tests whether a navigation entry represents a branch.
36
+ *
37
+ * A branch is an entry with a `children` property. Its `children` value is
38
+ * `null` when the corresponding tree branch has not been loaded or opened.
39
+ */
40
+ entryIsBranch(entry: NavEntry<Id>): entry is NavBranch<Id>;
41
+ /**
42
+ * Creates a navigation projection of the tree node root.
43
+ *
44
+ * The root must be a branch node because navigation is rooted at a
45
+ * directory-like node. The returned navigation entry is always a `NavBranch`.
46
+ *
47
+ * The TreeNode is authoritative for:
48
+ *
49
+ * - entry identity and order;
50
+ * - whether the entry is a leaf or branch;
51
+ * - whether branch children are loaded; and
52
+ * - the loaded child entries.
53
+ *
54
+ * The optional FoldNode is authoritative for folding. When `foldRoot` is
55
+ * undefined, the projection contains no folded entries.
56
+ *
57
+ * A folded entry is omitted from its parent's navigable entries and is
58
+ * represented by that parent's synthetic `folded` entry instead.
59
+ */
60
+ from(root: Node & BranchTreeNode<Id, Node>, foldRoot: FoldNode<Id> | undefined): NavBranch<Id>;
61
+ getNodeAtPath(navigation: NavNode<Id>, path: readonly Id[]): NavNode<Id> | undefined;
62
+ getEntryAtPath(navigation: NavNode<Id>, path: readonly Id[]): NavEntry<Id> | undefined;
63
+ nextCursor(rootNode: NavBranch<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
64
+ previousCursor(rootNode: NavBranch<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
65
+ cursorAfterFold(rootNode: NavBranch<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
66
+ parentCursor(navigation: NavNode<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
67
+ cursors(navigation: NavNode<Id>, parentPath?: Id[]): Cursor<Id>[];
68
+ visibleLeavesPaths(navigation: NavNode<Id>, parentPath?: readonly Id[]): Id[][];
40
69
  };
41
- export {};
42
70
  //# sourceMappingURL=nav-node.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nav-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/nav-node/nav-node.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nav-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/nav-node/nav-node.types.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1 @@
1
- export function isNavBranch(entry) {
2
- return 'children' in entry;
3
- }
1
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"state.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAY,WAAW,EAAgB,MAAM,iCAAiC,CAAC;AACtF,OAAO,EAAU,SAAS,EAAc,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAS,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,cAAc,CAC5B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAE/B,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,EAClC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,GAC/B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,CA6IpB"}
1
+ {"version":3,"file":"state.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzG,OAAO,EAAY,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAU,SAAS,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAS,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,cAAc,CAC5B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAE/B,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,EAClC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,GAC/B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,CAoIpB"}
@@ -1,50 +1,55 @@
1
- import { CursorKind } from '../cursor.js';
2
1
  export function createStateApi(treeNodeApi, foldNodeApi, cursorApi, navNodeApi) {
3
2
  /**
4
- * Create a new buffer and fold node at a level.
3
+ * Create a new root and fold root.
5
4
  *
6
5
  * Works on fold root and descendant fold nodes using the generic.
6
+ *
7
+ * TODO: Later: Filter the fold node
7
8
  */
8
- async function reload(oldBuffer, oldFoldNode, parentPath, loadBranches) {
9
- let newBuffer = await loadBranches(parentPath);
9
+ async function reload(oldRoot, oldFoldNode, parentPath, loadBranches) {
10
+ // Do not load a branch that was already closed.
11
+ if (!treeNodeApi.isOpenBranch(oldRoot)) {
12
+ return {
13
+ root: oldRoot,
14
+ foldRoot: oldFoldNode,
15
+ };
16
+ }
17
+ const newChildren = await loadBranches(parentPath);
18
+ let newRoot = {
19
+ ...oldRoot,
20
+ children: newChildren,
21
+ };
10
22
  let newFoldNode = oldFoldNode; // Start with assumption of no changes
11
- for (const oldEntry of oldBuffer) {
23
+ for (const oldEntry of oldRoot.children) {
12
24
  if (!treeNodeApi.isBranch(oldEntry) ||
13
25
  !treeNodeApi.isOpenBranch(oldEntry)) {
14
26
  continue;
15
27
  }
16
- const newEntry = treeNodeApi.getAtPath(newBuffer, [oldEntry.id], (entry) => entry);
17
- if (newEntry === undefined || !treeNodeApi.isBranch(newEntry)) {
18
- continue;
19
- }
20
28
  const oldChildFoldNode = oldFoldNode === undefined
21
29
  ? undefined
22
30
  : foldNodeApi.getChildById(oldFoldNode, oldEntry.id);
23
31
  const entryPath = [...parentPath, oldEntry.id];
24
- const reloadedChild = await reload([...treeNodeApi.getChildren(oldEntry)], oldChildFoldNode, entryPath, loadBranches);
25
- const updatedBuffer = treeNodeApi.modifyAtPath(newBuffer, [oldEntry.id], (entry) => {
26
- // The entry may be closed: loadBranches normally returns branches
27
- // with `branches: null`. We are turning it back into an open branch.
32
+ const reloadedChild = await reload(oldEntry, oldChildFoldNode, entryPath, loadBranches);
33
+ const updatedRoot = treeNodeApi.modifyAtPath(newRoot, [oldEntry.id], (entry) => {
28
34
  if (!treeNodeApi.isBranch(entry)) {
29
35
  return undefined;
30
36
  }
31
37
  return {
32
38
  ...entry,
33
- children: reloadedChild.buffer,
39
+ children: reloadedChild.root.children,
34
40
  };
35
41
  });
36
- if (updatedBuffer !== undefined) {
37
- newBuffer = updatedBuffer;
42
+ if (updatedRoot !== undefined && treeNodeApi.isOpenBranch(updatedRoot)) {
43
+ newRoot = updatedRoot;
38
44
  }
39
45
  }
40
46
  return {
41
- buffer: newBuffer,
42
- foldNode: newFoldNode,
47
+ root: newRoot,
48
+ foldRoot: newFoldNode,
43
49
  };
44
50
  }
45
51
  /**
46
- * Currently the cursor just goes to the first entry at root if
47
- * not all root entries are folded, otherwise the fold.
52
+ * Currently the cursor just goes to root.
48
53
  *
49
54
  * TODO: Cursor policy:
50
55
  * 1. Keep the exact cursor if it survives,
@@ -53,21 +58,16 @@ export function createStateApi(treeNodeApi, foldNodeApi, cursorApi, navNodeApi)
53
58
  * 4. Otherwise, choose the first new cursor.
54
59
  * 5. If no cursor exists, use the root fold cursor.
55
60
  */
56
- function resyncCursor(oldState, newBuffer, newFoldNode) {
57
- const navigation = navNodeApi.from(newBuffer, newFoldNode);
58
- return navNodeApi.cursors(navigation)[0];
61
+ function resyncCursor(oldState, newRoot, newFoldNode) {
62
+ return [];
59
63
  }
60
64
  return {
61
65
  getNodeAtCursor(state) {
62
66
  const path = cursorApi.getPath(state.cursor);
63
- if (path === undefined) {
64
- // The cursor is positioned on a fold rather than an entry.
65
- return undefined;
66
- }
67
- return treeNodeApi.getAtPath(state.buffer, path, (node) => node);
67
+ return treeNodeApi.getAtPath(state.root, path, (node) => node);
68
68
  },
69
69
  async resync(oldState, loadChildren) {
70
- const reloaded = await reload(oldState.buffer, oldState.foldNode, [], loadChildren);
70
+ const reloaded = await reload(oldState.root, oldState.foldRoot, [], loadChildren);
71
71
  /*
72
72
  * `oldState.foldNode` is always present. At the root reload starts with
73
73
  * that node, so `reloaded.foldNode` should also always be present.
@@ -75,15 +75,13 @@ export function createStateApi(treeNodeApi, foldNodeApi, cursorApi, navNodeApi)
75
75
  * The fallback expresses the State invariant while satisfying the
76
76
  * optional return type needed by recursive child reloads.
77
77
  */
78
- const foldNode = reloaded.foldNode ?? oldState.foldNode;
79
- const cursor = resyncCursor(oldState, reloaded.buffer, foldNode) ?? {
80
- kind: CursorKind.Fold,
81
- parentPath: [],
82
- };
78
+ const foldRoot = reloaded.foldRoot ?? oldState.foldRoot;
79
+ const cursor = resyncCursor(oldState, reloaded.root, foldRoot) ?? [];
80
+ const root = reloaded.root;
83
81
  return {
84
82
  ...oldState,
85
- buffer: reloaded.buffer,
86
- foldNode,
83
+ root,
84
+ foldRoot,
87
85
  cursor,
88
86
  };
89
87
  },
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { SerializableKey, TreeNode } from '../tree-node/tree-node.types.js';
3
3
  import { State } from './state.types.js';
4
- export declare function createStateSchema<Id extends SerializableKey, Node extends TreeNode<Id, Node>>(bufferNodeSchema: z.ZodType<Node>, foldNodeRootSchema: z.ZodType<State<Id, Node>['foldNode']>, cursorSchema: z.ZodType<State<Id, Node>['cursor']>): z.ZodObject<{
5
- buffer: z.ZodArray<z.ZodType<Node, unknown, z.core.$ZodTypeInternals<Node, unknown>>>;
6
- foldNode: z.ZodType<import("../index.js").FoldNodeRoot<Id>, unknown, z.core.$ZodTypeInternals<import("../index.js").FoldNodeRoot<Id>, unknown>>;
4
+ export declare function createStateSchema<Id extends SerializableKey, Node extends TreeNode<Id, Node>>(rootSchema: z.ZodType<State<Id, Node>['root']>, foldNodeRootSchema: z.ZodType<State<Id, Node>['foldRoot']>, cursorSchema: z.ZodType<State<Id, Node>['cursor']>): z.ZodObject<{
5
+ root: z.ZodType<Node & import("../tree-node/tree-node.types.js").BranchTreeNode<Id, Node>, unknown, z.core.$ZodTypeInternals<Node & import("../tree-node/tree-node.types.js").BranchTreeNode<Id, Node>, unknown>>;
6
+ foldRoot: z.ZodType<import("../index.js").FoldNode<Id>, unknown, z.core.$ZodTypeInternals<import("../index.js").FoldNode<Id>, unknown>>;
7
7
  cursor: z.ZodType<import("../cursor.js").Cursor<Id>, unknown, z.core.$ZodTypeInternals<import("../cursor.js").Cursor<Id>, unknown>>;
8
8
  }, z.core.$strip>;
9
9
  //# sourceMappingURL=state.schemas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.schemas.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,wBAAgB,iBAAiB,CAC/B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAE/B,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EACjC,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,EAC1D,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;;;;kBAOnD"}
1
+ {"version":3,"file":"state.schemas.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,wBAAgB,iBAAiB,CAC/B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAE/B,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,EAC9C,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,EAC1D,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;;;;kBAOnD"}
@@ -1,8 +1,8 @@
1
1
  import { z } from 'zod';
2
- export function createStateSchema(bufferNodeSchema, foldNodeRootSchema, cursorSchema) {
2
+ export function createStateSchema(rootSchema, foldNodeRootSchema, cursorSchema) {
3
3
  return z.object({
4
- buffer: z.array(bufferNodeSchema),
5
- foldNode: foldNodeRootSchema,
4
+ root: rootSchema,
5
+ foldRoot: foldNodeRootSchema,
6
6
  cursor: cursorSchema,
7
7
  });
8
8
  }
@@ -1,16 +1,20 @@
1
- import { Cursor } from '../cursor.js';
2
- import { SerializableKey, TreeNode } from '../tree-node/tree-node.types.js';
3
- import { FoldNodeRoot } from '../fold-node/fold-node.types.js';
1
+ import type { Cursor } from '../cursor.js';
2
+ import { BranchTreeNode, SerializableKey, TreeNode } from '../tree-node/tree-node.types.js';
3
+ import type { FoldNode } from '../fold-node/fold-node.types.js';
4
4
  export type State<Id extends SerializableKey, Node extends TreeNode<Id, Node>> = {
5
- buffer: Node[];
6
- foldNode: FoldNodeRoot<Id>;
5
+ root: Node & BranchTreeNode<Id, Node>;
6
+ foldRoot: FoldNode<Id>;
7
7
  cursor: Cursor<Id>;
8
8
  };
9
9
  export type StateApi<Id extends SerializableKey, Node extends TreeNode<Id, Node>> = {
10
10
  getNodeAtCursor(state: State<Id, Node>): Node | undefined;
11
11
  /**
12
- * Reloads the root and all descendant branches that were loaded in the
13
- * previous state.
12
+ * Reloads the root's children and all descendant branches that were loaded in
13
+ * the previous state.
14
+ *
15
+ * `loadBranches([])` loads the root's direct children.
16
+ * `loadBranches(['src'])` loads the children of `src`, where 'src' is the
17
+ * id of a root's child.
14
18
  */
15
19
  resync(oldState: State<Id, Node>, loadBranches: (path: Id[]) => Promise<Node[]>): Promise<State<Id, Node>>;
16
20
  };
@@ -1 +1 @@
1
- {"version":3,"file":"state.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EACL,eAAe,EACf,QAAQ,EACT,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,YAAY,EACb,MAAM,iCAAiC,CAAC;AAEzC,MAAM,MAAM,KAAK,CACf,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B;IACF,MAAM,EAAE,IAAI,EAAE,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,CAClB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B;IACF,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAE1D;;;OAGG;IACH,MAAM,CACJ,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,EACzB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,GAC5C,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;CAC7B,CAAC"}
1
+ {"version":3,"file":"state.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,cAAc,EACd,eAAe,EACf,QAAQ,EACT,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAEhE,MAAM,MAAM,KAAK,CACf,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B;IACF,IAAI,EAAE,IAAI,GAAG,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACtC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI;IAClF,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAE1D;;;;;;;OAOG;IACH,MAAM,CACJ,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,EACzB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,GAC5C,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;CAC7B,CAAC"}
@@ -42,11 +42,9 @@ export declare const generatedClosedBranchNodeArb: fc.Arbitrary<NodeWithReachabl
42
42
  */
43
43
  export declare const generatedNodeArb: fc.Arbitrary<NodeWithReachableNodes>;
44
44
  /**
45
- * Generates an array of generated nodes with unique IDs suitable for use as
46
- * the root of a forest.
45
+ * Generates an array of generated nodes with unique sibling IDs.
47
46
  *
48
- * Root IDs must be unique because paths begin by looking up an ID in this
49
- * array.
47
+ * The result is suitable for use as the loaded children of an open branch.
50
48
  */
51
49
  export declare const generatedNodesArrayArb: fc.Arbitrary<NodeWithReachableNodes[]>;
52
50
  /**
@@ -56,8 +54,8 @@ export declare const generatedNodesArrayArb: fc.Arbitrary<NodeWithReachableNodes
56
54
  * Paths through closed branches stop at the closed branch because its
57
55
  * descendants are not loaded.
58
56
  */
59
- export declare const nodesArrayAndPathsArb: fc.Arbitrary<{
60
- entries: any[];
57
+ export declare const nodeAndPathsArb: fc.Arbitrary<{
58
+ root: any;
61
59
  pathEntries: NodeAtPath[];
62
60
  }>;
63
61
  /**
@@ -66,8 +64,8 @@ export declare const nodesArrayAndPathsArb: fc.Arbitrary<{
66
64
  * Every generated path is valid for `getAtPath`; unreachable paths are not
67
65
  * included.
68
66
  */
69
- export declare const nodesArrayAndPathAndExpectedArb: fc.Arbitrary<{
70
- entries: any[];
67
+ export declare const nodeAndPathAndExpectedArb: fc.Arbitrary<{
68
+ root: any;
71
69
  path: Path;
72
70
  expected: any;
73
71
  }>;
@@ -78,7 +76,7 @@ export declare const nodesArrayAndPathAndExpectedArb: fc.Arbitrary<{
78
76
  * valid, but a path through a closed branch cannot reach any descendants.
79
77
  */
80
78
  export declare const nodesArrayAndBranchPathArb: fc.Arbitrary<{
81
- entries: any[];
79
+ root: any;
82
80
  path: Path;
83
81
  expected: any;
84
82
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"tree-node.arb.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.arb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC;AASzB;;;GAGG;AACH,eAAO,MAAM,SAAS,sBAIpB,CAAC;AAEH;;GAEG;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAC1D,KAAK,IAAI,GAAG,UAAU,EAAE,CAAC;AAEzB,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,EAAE,UAAU,EAAE,CAAC;CAC9B,CAAC;AAyEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,sCAEhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,sCAExC,CAAC;AAaF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,SAAS,CAAC,sBAAsB,CA0C5D,CAAC;AAEP;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,wCAIjC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;EAOjC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B;;;;EAQzC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;EAcpC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,cAAc,qBAE1B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,4BAGhC,CAAC"}
1
+ {"version":3,"file":"tree-node.arb.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.arb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC;AASzB;;;GAGG;AACH,eAAO,MAAM,SAAS,sBAIpB,CAAC;AAEH;;GAEG;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAC1D,KAAK,IAAI,GAAG,UAAU,EAAE,CAAC;AAEzB,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,EAAE,UAAU,EAAE,CAAC;CAC9B,CAAC;AAqEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,sCAEhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,sCAExC,CAAC;AAaF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,SAAS,CAAC,sBAAsB,CA0C5D,CAAC;AAEP;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,wCAIjC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;EAK3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;EAQnC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;EAYpC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,cAAc,qBAE1B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,4BAGhC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tree-node.arb.debug.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-node.arb.debug.test.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.arb.debug.test.ts"],"names":[],"mappings":""}
@@ -22,7 +22,7 @@ const generatedLeafNodeWithReachableNodes = (id) => {
22
22
  const node = { id };
23
23
  return {
24
24
  node,
25
- reachableNodes: [{ path: [id], node }],
25
+ reachableNodes: [{ path: [], node }],
26
26
  };
27
27
  };
28
28
  /**
@@ -41,7 +41,7 @@ const generatedClosedBranchWithReachableNodes = (id) => {
41
41
  };
42
42
  return {
43
43
  node,
44
- reachableNodes: [{ path: [id], node }],
44
+ reachableNodes: [{ path: [], node }],
45
45
  };
46
46
  };
47
47
  /**
@@ -56,16 +56,13 @@ const generatedOpenBranchWithReachableNodes = (id, children) => {
56
56
  id,
57
57
  children: children.map(({ node }) => node),
58
58
  };
59
- const descendantNodes = children.flatMap(({ reachableNodes }) => reachableNodes.map(({ path, node }) => ({
60
- path: [id, ...path],
59
+ const descendantNodes = children.flatMap(({ node: child, reachableNodes }) => reachableNodes.map(({ path, node }) => ({
60
+ path: [child.id, ...path],
61
61
  node,
62
62
  })));
63
63
  return {
64
64
  node,
65
- reachableNodes: [
66
- { path: [id], node },
67
- ...descendantNodes,
68
- ],
65
+ reachableNodes: [{ path: [], node }, ...descendantNodes],
69
66
  };
70
67
  };
71
68
  /**
@@ -125,11 +122,9 @@ export const generatedNodeArb = fc.letrec((tie) => {
125
122
  };
126
123
  }).node;
127
124
  /**
128
- * Generates an array of generated nodes with unique IDs suitable for use as
129
- * the root of a forest.
125
+ * Generates an array of generated nodes with unique sibling IDs.
130
126
  *
131
- * Root IDs must be unique because paths begin by looking up an ID in this
132
- * array.
127
+ * The result is suitable for use as the loaded children of an open branch.
133
128
  */
134
129
  export const generatedNodesArrayArb = fc.uniqueArray(generatedNodeArb, {
135
130
  minLength: 0,
@@ -143,9 +138,9 @@ export const generatedNodesArrayArb = fc.uniqueArray(generatedNodeArb, {
143
138
  * Paths through closed branches stop at the closed branch because its
144
139
  * descendants are not loaded.
145
140
  */
146
- export const nodesArrayAndPathsArb = generatedNodesArrayArb.map((generatedNodes) => ({
147
- entries: generatedNodes.map(({ node }) => node),
148
- pathEntries: generatedNodes.flatMap(({ reachableNodes }) => reachableNodes),
141
+ export const nodeAndPathsArb = generatedNodeArb.map(({ node: root, reachableNodes }) => ({
142
+ root,
143
+ pathEntries: reachableNodes,
149
144
  }));
150
145
  /**
151
146
  * Generates root-level nodes and a path to one of their reachable nodes.
@@ -153,10 +148,10 @@ export const nodesArrayAndPathsArb = generatedNodesArrayArb.map((generatedNodes)
153
148
  * Every generated path is valid for `getAtPath`; unreachable paths are not
154
149
  * included.
155
150
  */
156
- export const nodesArrayAndPathAndExpectedArb = nodesArrayAndPathsArb
151
+ export const nodeAndPathAndExpectedArb = nodeAndPathsArb
157
152
  .filter(({ pathEntries }) => pathEntries.length > 0)
158
- .chain(({ entries, pathEntries }) => fc.constantFrom(...pathEntries).map(({ path, node }) => ({
159
- entries,
153
+ .chain(({ root, pathEntries }) => fc.constantFrom(...pathEntries).map(({ path, node }) => ({
154
+ root,
160
155
  path,
161
156
  expected: node,
162
157
  })));
@@ -166,14 +161,14 @@ export const nodesArrayAndPathAndExpectedArb = nodesArrayAndPathsArb
166
161
  * Both open and closed branches are included. A path to a closed branch is
167
162
  * valid, but a path through a closed branch cannot reach any descendants.
168
163
  */
169
- export const nodesArrayAndBranchPathArb = nodesArrayAndPathsArb
170
- .map(({ entries, pathEntries }) => ({
171
- entries,
164
+ export const nodesArrayAndBranchPathArb = nodeAndPathsArb
165
+ .map(({ root, pathEntries }) => ({
166
+ root,
172
167
  branchPathEntries: pathEntries.filter(({ node }) => 'children' in node),
173
168
  }))
174
169
  .filter(({ branchPathEntries }) => branchPathEntries.length > 0)
175
- .chain(({ entries, branchPathEntries }) => fc.constantFrom(...branchPathEntries).map(({ path, node }) => ({
176
- entries,
170
+ .chain(({ root, branchPathEntries }) => fc.constantFrom(...branchPathEntries).map(({ path, node }) => ({
171
+ root,
177
172
  path,
178
173
  expected: node,
179
174
  })));
@@ -10,5 +10,5 @@ import type { SerializableKey, TreeNode, TreeNodeApi } from './tree-node.types.j
10
10
  * Node IDs are compared using JavaScript value equality. Sibling IDs
11
11
  * should be unique.
12
12
  */
13
- export declare function createTreeNodeApi<Id extends SerializableKey, ChildNode extends TreeNode<Id, ChildNode>>(): TreeNodeApi<Id, ChildNode>;
13
+ export declare function createTreeNodeApi<Id extends SerializableKey, Node extends TreeNode<Id, Node>>(): TreeNodeApi<Id, Node>;
14
14
  //# sourceMappingURL=tree-node.impl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,eAAe,EACf,QAAQ,EACR,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,SAAS,eAAe,EAC1B,SAAS,SAAS,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,KACtC,WAAW,CAAC,EAAE,EAAE,SAAS,CAAC,CA0G9B"}
1
+ {"version":3,"file":"tree-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,eAAe,EACf,QAAQ,EACR,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,KAC5B,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,CAqGzB"}
@@ -11,7 +11,6 @@
11
11
  */
12
12
  export function createTreeNodeApi() {
13
13
  const treeNodeApi = {
14
- // Type Narrowers:
15
14
  isLeaf(node) {
16
15
  return !('children' in node);
17
16
  },
@@ -30,60 +29,54 @@ export function createTreeNodeApi() {
30
29
  getChildById(node, id) {
31
30
  return node.children.find((child) => child.id === id);
32
31
  },
33
- getAtPath(entries, path, selector) {
34
- if (path.length === 0) {
35
- return undefined;
36
- }
37
- // Accumulator
38
- let node = entries.find((candidate) => candidate.id === path[0]);
39
- for (let index = 1; node !== undefined && index < path.length; index += 1) {
40
- if (treeNodeApi.isOpenBranch(node)) {
41
- node = treeNodeApi.getChildById(node, path[index]);
32
+ getAtPath(root, path, selector) {
33
+ let node = root;
34
+ for (const id of path) {
35
+ if (!treeNodeApi.isBranch(node) || !treeNodeApi.isOpenBranch(node)) {
36
+ return undefined;
42
37
  }
43
- else {
44
- node = undefined;
38
+ const child = treeNodeApi.getChildById(node, id);
39
+ if (child === undefined) {
40
+ return undefined;
45
41
  }
42
+ node = child;
46
43
  }
47
- return node === undefined ? undefined : selector(node);
44
+ return selector(node);
48
45
  },
49
- modifyAtPath(entries, path, modifier) {
46
+ modifyAtPath(root, path, modifier) {
50
47
  if (path.length === 0) {
51
- return undefined;
48
+ return modifier(root);
52
49
  }
53
- // Only cloned arrays/nodes are modified below.
54
- const updatedEntries = [...entries];
55
- let currentEntries = updatedEntries;
56
- for (let index = 0; index < path.length; index += 1) {
57
- const id = path[index];
58
- const childIndex = currentEntries.findIndex((candidate) => candidate.id === id);
59
- if (childIndex === -1) {
60
- return undefined;
61
- }
62
- const child = currentEntries[childIndex];
63
- if (index === path.length - 1) {
64
- const replacement = modifier(child);
65
- if (replacement === undefined) {
66
- return undefined;
67
- }
68
- currentEntries[childIndex] = replacement;
69
- return updatedEntries;
70
- }
71
- if (!treeNodeApi.isBranch(child) || !treeNodeApi.isOpenBranch(child)) {
72
- // The path cannot continue through a leaf or closed branch.
73
- return undefined;
74
- }
75
- // Clone the child array before modifying it.
76
- const updatedChildren = [...treeNodeApi.getChildren(child)];
77
- // Clone the ancestor node and attach the cloned child array.
78
- currentEntries[childIndex] = {
79
- ...child,
80
- children: updatedChildren,
81
- };
82
- // Continue traversal through the cloned children.
83
- currentEntries = updatedChildren;
84
- }
85
- return undefined;
50
+ return modifyChildAtPath(root, path, modifier);
86
51
  },
87
52
  };
53
+ function modifyChildAtPath(node, path, modifier) {
54
+ const childId = path[0];
55
+ if (childId === undefined ||
56
+ !treeNodeApi.isBranch(node) ||
57
+ !treeNodeApi.isOpenBranch(node)) {
58
+ return undefined;
59
+ }
60
+ const childIndex = node.children.findIndex((child) => child.id === childId);
61
+ if (childIndex === -1) {
62
+ return undefined;
63
+ }
64
+ const child = node.children[childIndex];
65
+ if (child === undefined) {
66
+ return undefined;
67
+ }
68
+ const updatedChild = path.length === 1
69
+ ? modifier(child)
70
+ : modifyChildAtPath(child, path.slice(1), modifier);
71
+ if (updatedChild === undefined) {
72
+ return undefined;
73
+ }
74
+ const children = [...node.children];
75
+ children[childIndex] = updatedChild;
76
+ return {
77
+ ...node,
78
+ children,
79
+ };
80
+ }
88
81
  return treeNodeApi;
89
82
  }
@@ -16,7 +16,7 @@ export declare const serializableKeySchema: z.ZodUnion<readonly [z.ZodString, z.
16
16
  *
17
17
  * The concrete application can extend these schemas with additional fields.
18
18
  */
19
- export declare function createTreeNodeSchemas<Id extends SerializableKey, ChildNode extends TreeNode<Id, ChildNode>>(idSchema: z.ZodType<Id>, childSchema: z.ZodType<ChildNode>): {
19
+ export declare function createTreeNodeSchemas<Id extends SerializableKey, Node extends TreeNode<Id, Node>>(idSchema: z.ZodType<Id>, nodeSchema: z.ZodType<Node>): {
20
20
  leafSchema: z.ZodObject<{
21
21
  id: z.ZodType<Id, unknown, z.core.$ZodTypeInternals<Id, unknown>>;
22
22
  }, z.core.$strip>;
@@ -26,7 +26,7 @@ export declare function createTreeNodeSchemas<Id extends SerializableKey, ChildN
26
26
  }, z.core.$strip>;
27
27
  openBranchSchema: z.ZodObject<{
28
28
  id: z.ZodType<Id, unknown, z.core.$ZodTypeInternals<Id, unknown>>;
29
- children: z.ZodArray<z.ZodType<ChildNode, unknown, z.core.$ZodTypeInternals<ChildNode, unknown>>>;
29
+ children: z.ZodArray<z.ZodType<Node, unknown, z.core.$ZodTypeInternals<Node, unknown>>>;
30
30
  }, z.core.$strip>;
31
31
  };
32
32
  //# sourceMappingURL=tree-node.schemas.d.ts.map