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.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/tree-surfer/cursor.d.ts +52 -26
- package/dist/tree-surfer/cursor.d.ts.map +1 -1
- package/dist/tree-surfer/cursor.js +19 -44
- package/dist/tree-surfer/fold-node/fold-node.arb.d.ts +2 -0
- package/dist/tree-surfer/fold-node/fold-node.arb.d.ts.map +1 -0
- package/dist/tree-surfer/fold-node/fold-node.arb.js +1 -0
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts +3 -4
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts.map +1 -1
- package/dist/tree-surfer/fold-node/fold-node.impl.js +73 -67
- package/dist/tree-surfer/fold-node/fold-node.schema.d.ts +2 -5
- package/dist/tree-surfer/fold-node/fold-node.schema.d.ts.map +1 -1
- package/dist/tree-surfer/fold-node/fold-node.schema.js +2 -9
- package/dist/tree-surfer/fold-node/fold-node.types.d.ts +169 -46
- package/dist/tree-surfer/fold-node/fold-node.types.d.ts.map +1 -1
- package/dist/tree-surfer/fold-node/tree-node.test.d.ts +2 -0
- package/dist/tree-surfer/fold-node/tree-node.test.d.ts.map +1 -0
- package/dist/tree-surfer/fold-node/tree-node.test.js +90 -0
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts +5 -5
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts.map +1 -1
- package/dist/tree-surfer/nav-node/nav-node.impl.js +84 -99
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts +62 -34
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts.map +1 -1
- package/dist/tree-surfer/nav-node/nav-node.types.js +1 -3
- package/dist/tree-surfer/state/state.impl.d.ts.map +1 -1
- package/dist/tree-surfer/state/state.impl.js +34 -36
- package/dist/tree-surfer/state/state.schemas.d.ts +3 -3
- package/dist/tree-surfer/state/state.schemas.d.ts.map +1 -1
- package/dist/tree-surfer/state/state.schemas.js +3 -3
- package/dist/tree-surfer/state/state.types.d.ts +11 -7
- package/dist/tree-surfer/state/state.types.d.ts.map +1 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.d.ts +7 -9
- package/dist/tree-surfer/tree-node/tree-node.arb.d.ts.map +1 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.debug.test.d.ts +2 -0
- package/dist/tree-surfer/tree-node/tree-node.arb.debug.test.d.ts.map +1 -0
- package/dist/tree-surfer/tree-node/tree-node.arb.js +18 -23
- package/dist/tree-surfer/tree-node/tree-node.impl.d.ts +1 -1
- package/dist/tree-surfer/tree-node/tree-node.impl.d.ts.map +1 -1
- package/dist/tree-surfer/tree-node/tree-node.impl.js +41 -48
- package/dist/tree-surfer/tree-node/tree-node.schemas.d.ts +2 -2
- package/dist/tree-surfer/tree-node/tree-node.schemas.d.ts.map +1 -1
- package/dist/tree-surfer/tree-node/tree-node.schemas.js +2 -2
- package/dist/tree-surfer/tree-node/tree-node.test.js +76 -81
- package/dist/tree-surfer/tree-node/tree-node.types.d.ts +14 -17
- package/dist/tree-surfer/tree-node/tree-node.types.d.ts.map +1 -1
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts +6 -2
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts.map +1 -1
- package/dist/tree-surfer-ui/application/intent-to-effect.js +1 -12
- package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts +10 -2
- package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts.map +1 -1
- package/dist/tree-surfer-ui/application/user-input-to-intent.js +12 -5
- package/dist/tree-surfer-ui/domain/effect.d.ts +6 -8
- package/dist/tree-surfer-ui/domain/effect.d.ts.map +1 -1
- package/dist/tree-surfer-ui/domain/index.d.ts +1 -1
- package/dist/tree-surfer-ui/domain/index.d.ts.map +1 -1
- package/dist/tree-surfer-ui/domain/index.js +1 -1
- package/dist/tree-surfer-ui/domain/{input-state.d.ts → input-mode-state.d.ts} +2 -2
- package/dist/tree-surfer-ui/domain/input-mode-state.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.debug.d.ts +0 -2
- package/dist/tree-surfer/tree-node/tree-node.arb.debug.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/input-state.d.ts.map +0 -1
- /package/dist/tree-surfer/tree-node/{tree-node.arb.debug.js → tree-node.arb.debug.test.js} +0 -0
- /package/dist/tree-surfer-ui/domain/{input-state.js → input-mode-state.js} +0 -0
|
@@ -1,42 +1,70 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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
|
-
*
|
|
6
|
+
* Synthetic UI entry representing folded children.
|
|
7
|
+
*
|
|
8
|
+
* It is absent when this directory has no folded children.
|
|
23
9
|
*/
|
|
24
|
-
|
|
10
|
+
folded: NavFoldEntry<Id> | null;
|
|
25
11
|
/**
|
|
26
|
-
*
|
|
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
|
-
|
|
15
|
+
entries: NavEntry<Id>[];
|
|
29
16
|
};
|
|
30
|
-
export type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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":"AAAA,OAAO,EACL,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/state/state.impl.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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
|
|
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(
|
|
9
|
-
|
|
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
|
|
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(
|
|
25
|
-
const
|
|
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.
|
|
39
|
+
children: reloadedChild.root.children,
|
|
34
40
|
};
|
|
35
41
|
});
|
|
36
|
-
if (
|
|
37
|
-
|
|
42
|
+
if (updatedRoot !== undefined && treeNodeApi.isOpenBranch(updatedRoot)) {
|
|
43
|
+
newRoot = updatedRoot;
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
root: newRoot,
|
|
48
|
+
foldRoot: newFoldNode,
|
|
43
49
|
};
|
|
44
50
|
}
|
|
45
51
|
/**
|
|
46
|
-
* Currently the cursor just goes to
|
|
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,
|
|
57
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
79
|
-
const cursor = resyncCursor(oldState, reloaded.
|
|
80
|
-
|
|
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
|
-
|
|
86
|
-
|
|
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>>(
|
|
5
|
-
|
|
6
|
-
|
|
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,
|
|
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(
|
|
2
|
+
export function createStateSchema(rootSchema, foldNodeRootSchema, cursorSchema) {
|
|
3
3
|
return z.object({
|
|
4
|
-
|
|
5
|
-
|
|
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 {
|
|
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
|
-
|
|
6
|
-
|
|
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
|
|
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;
|
|
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
|
|
46
|
-
* the root of a forest.
|
|
45
|
+
* Generates an array of generated nodes with unique sibling IDs.
|
|
47
46
|
*
|
|
48
|
-
*
|
|
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
|
|
60
|
-
|
|
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
|
|
70
|
-
|
|
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
|
-
|
|
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;
|
|
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 @@
|
|
|
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: [
|
|
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: [
|
|
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
|
|
129
|
-
* the root of a forest.
|
|
125
|
+
* Generates an array of generated nodes with unique sibling IDs.
|
|
130
126
|
*
|
|
131
|
-
*
|
|
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
|
|
147
|
-
|
|
148
|
-
pathEntries:
|
|
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
|
|
151
|
+
export const nodeAndPathAndExpectedArb = nodeAndPathsArb
|
|
157
152
|
.filter(({ pathEntries }) => pathEntries.length > 0)
|
|
158
|
-
.chain(({
|
|
159
|
-
|
|
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 =
|
|
170
|
-
.map(({
|
|
171
|
-
|
|
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(({
|
|
176
|
-
|
|
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,
|
|
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,
|
|
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(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
44
|
-
|
|
38
|
+
const child = treeNodeApi.getChildById(node, id);
|
|
39
|
+
if (child === undefined) {
|
|
40
|
+
return undefined;
|
|
45
41
|
}
|
|
42
|
+
node = child;
|
|
46
43
|
}
|
|
47
|
-
return
|
|
44
|
+
return selector(node);
|
|
48
45
|
},
|
|
49
|
-
modifyAtPath(
|
|
46
|
+
modifyAtPath(root, path, modifier) {
|
|
50
47
|
if (path.length === 0) {
|
|
51
|
-
return
|
|
48
|
+
return modifier(root);
|
|
52
49
|
}
|
|
53
|
-
|
|
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,
|
|
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<
|
|
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
|