dirvi-lib 0.8.0 → 0.8.2
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/app/app-api.d.ts +74 -0
- package/dist/app/app-api.d.ts.map +1 -0
- package/dist/app/app-api.js +11 -0
- package/dist/app/effect-to-action.d.ts +6 -0
- package/dist/app/effect-to-action.d.ts.map +1 -0
- package/dist/app/effect-to-action.js +74 -0
- package/dist/app/index.d.ts +6 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +5 -0
- package/dist/app/reducer-action.d.ts +22 -0
- package/dist/app/reducer-action.d.ts.map +1 -0
- package/dist/app/reducer.d.ts +5 -0
- package/dist/app/reducer.d.ts.map +1 -0
- package/dist/app/reducer.js +79 -0
- package/dist/app/view-api.d.ts +11 -0
- package/dist/app/view-api.d.ts.map +1 -0
- package/dist/index.d.ts +4 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- package/dist/input/application/index.d.ts.map +1 -0
- package/dist/input/application/intent-to-effect-no-state.test.d.ts.map +1 -0
- package/dist/input/application/intent-to-effect.d.ts +14 -0
- package/dist/input/application/intent-to-effect.d.ts.map +1 -0
- package/dist/{tree-surfer-ui → input}/application/intent-to-effect.js +36 -17
- package/dist/input/application/parse-command.d.ts +14 -0
- package/dist/input/application/parse-command.d.ts.map +1 -0
- package/dist/{tree-surfer-ui → input}/application/parse-command.js +13 -1
- package/dist/input/application/user-input-to-intent.d.ts.map +1 -0
- package/dist/input/application/user-input-to-intent.test.d.ts.map +1 -0
- package/dist/input/domain/effect.d.ts +55 -0
- package/dist/input/domain/effect.d.ts.map +1 -0
- package/dist/input/domain/index.d.ts.map +1 -0
- package/dist/input/domain/input-mode-state.d.ts.map +1 -0
- package/dist/input/domain/intent.d.ts.map +1 -0
- package/dist/input/domain/user-input.d.ts.map +1 -0
- package/dist/trees/cursor.d.ts.map +1 -0
- package/dist/trees/fold-node/deprecated/fold-node.impl.d.ts +10 -0
- package/dist/trees/fold-node/deprecated/fold-node.impl.d.ts.map +1 -0
- package/dist/trees/fold-node/deprecated/fold-node.impl.js +248 -0
- package/dist/trees/fold-node/deprecated/fold-node.test.d.ts +2 -0
- package/dist/trees/fold-node/deprecated/fold-node.test.d.ts.map +1 -0
- package/dist/trees/fold-node/deprecated/fold-node.test.js +130 -0
- package/dist/{tree-surfer/fold-node → trees/fold-node/deprecated}/fold-node.types.d.ts +15 -76
- package/dist/trees/fold-node/deprecated/fold-node.types.d.ts.map +1 -0
- package/dist/trees/fold-node/fold-node.impl.d.ts +16 -0
- package/dist/trees/fold-node/fold-node.impl.d.ts.map +1 -0
- package/dist/trees/fold-node/fold-node.impl.js +451 -0
- package/dist/trees/fold-node/fold-node.model.d.ts +120 -0
- package/dist/trees/fold-node/fold-node.model.d.ts.map +1 -0
- package/dist/trees/fold-node/fold-node.model.js +80 -0
- package/dist/trees/fold-node/fold-node.types.d.ts +206 -0
- package/dist/trees/fold-node/fold-node.types.d.ts.map +1 -0
- package/dist/trees/fold-node/index.d.ts +4 -0
- package/dist/trees/fold-node/index.d.ts.map +1 -0
- package/dist/trees/fold-node/index.js +3 -0
- package/dist/trees/index.d.ts +9 -0
- package/dist/trees/index.d.ts.map +1 -0
- package/dist/trees/index.js +8 -0
- package/dist/trees/nav-node/nav-node.impl.d.ts +29 -0
- package/dist/trees/nav-node/nav-node.impl.d.ts.map +1 -0
- package/dist/{tree-surfer → trees}/nav-node/nav-node.impl.js +89 -42
- package/dist/trees/nav-node/nav-node.types.d.ts +103 -0
- package/dist/trees/nav-node/nav-node.types.d.ts.map +1 -0
- package/dist/trees/state/state.impl.d.ts +8 -0
- package/dist/trees/state/state.impl.d.ts.map +1 -0
- package/dist/trees/state/state.impl.js +128 -0
- package/dist/trees/state/state.schemas.d.ts +25 -0
- package/dist/trees/state/state.schemas.d.ts.map +1 -0
- package/dist/trees/state/state.schemas.js +17 -0
- package/dist/trees/state/state.types.d.ts +36 -0
- package/dist/trees/state/state.types.d.ts.map +1 -0
- package/dist/trees/state/state.types.js +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.arb.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.arb.debug.test.d.ts.map +1 -0
- package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.debug.test.js +1 -1
- package/dist/trees/tree-node/deprecated/tree-node.impl.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.schemas.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.test.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.types.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.types.js +1 -0
- package/dist/trees/tree-node/index.d.ts +4 -0
- package/dist/trees/tree-node/index.d.ts.map +1 -0
- package/dist/trees/tree-node/index.js +3 -0
- package/dist/trees/tree-node/tree-node.arb.d.ts +104 -0
- package/dist/trees/tree-node/tree-node.arb.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.arb.js +191 -0
- package/dist/trees/tree-node/tree-node.impl.d.ts +15 -0
- package/dist/trees/tree-node/tree-node.impl.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.impl.js +286 -0
- package/dist/trees/tree-node/tree-node.model.d.ts +78 -0
- package/dist/trees/tree-node/tree-node.model.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.model.js +37 -0
- package/dist/trees/tree-node/tree-node.types.d.ts +419 -0
- package/dist/trees/tree-node/tree-node.types.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.types.js +1 -0
- package/package.json +1 -1
- package/dist/tree-surfer/cursor.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.arb.d.ts +0 -2
- package/dist/tree-surfer/fold-node/fold-node.arb.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts +0 -4
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.impl.js +0 -149
- package/dist/tree-surfer/fold-node/fold-node.schema.d.ts +0 -5
- package/dist/tree-surfer/fold-node/fold-node.schema.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.schema.js +0 -9
- package/dist/tree-surfer/fold-node/fold-node.types.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/tree-node.test.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/tree-node.test.js +0 -90
- package/dist/tree-surfer/index.d.ts +0 -13
- package/dist/tree-surfer/index.d.ts.map +0 -1
- package/dist/tree-surfer/index.js +0 -12
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts +0 -6
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts.map +0 -1
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts +0 -70
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts.map +0 -1
- package/dist/tree-surfer/state/state.impl.d.ts +0 -7
- package/dist/tree-surfer/state/state.impl.d.ts.map +0 -1
- package/dist/tree-surfer/state/state.impl.js +0 -89
- package/dist/tree-surfer/state/state.schemas.d.ts +0 -9
- package/dist/tree-surfer/state/state.schemas.d.ts.map +0 -1
- package/dist/tree-surfer/state/state.schemas.js +0 -8
- package/dist/tree-surfer/state/state.types.d.ts +0 -21
- package/dist/tree-surfer/state/state.types.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.debug.test.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.impl.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.schemas.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.test.d.ts +0 -2
- package/dist/tree-surfer/tree-node/tree-node.test.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.types.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/index.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts +0 -10
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/parse-command.d.ts +0 -4
- package/dist/tree-surfer-ui/application/parse-command.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/user-input-to-intent.test.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/effect.d.ts +0 -43
- package/dist/tree-surfer-ui/domain/effect.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/index.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/input-mode-state.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/intent.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/user-input.d.ts.map +0 -1
- /package/dist/{tree-surfer-ui/domain/effect.js → app/reducer-action.js} +0 -0
- /package/dist/{tree-surfer-ui/domain/input-mode-state.js → app/view-api.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/application/index.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/index.js +0 -0
- /package/dist/{tree-surfer-ui → input}/application/intent-to-effect-no-state.test.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/intent-to-effect-no-state.test.js +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.js +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.test.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.test.js +0 -0
- /package/dist/{tree-surfer-ui/domain/intent.js → input/domain/effect.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/index.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/index.js +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/input-mode-state.d.ts +0 -0
- /package/dist/{tree-surfer-ui/domain/user-input.js → input/domain/input-mode-state.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/intent.d.ts +0 -0
- /package/dist/{tree-surfer/fold-node/fold-node.arb.js → input/domain/intent.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/user-input.d.ts +0 -0
- /package/dist/{tree-surfer/fold-node/fold-node.types.js → input/domain/user-input.js} +0 -0
- /package/dist/{tree-surfer → trees}/cursor.d.ts +0 -0
- /package/dist/{tree-surfer → trees}/cursor.js +0 -0
- /package/dist/{tree-surfer/nav-node/nav-node.types.js → trees/fold-node/deprecated/fold-node.types.js} +0 -0
- /package/dist/{tree-surfer/state/state.types.js → trees/fold-node/fold-node.types.js} +0 -0
- /package/dist/{tree-surfer/tree-node/tree-node.types.js → trees/nav-node/nav-node.types.js} +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.debug.test.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.js +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.impl.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.impl.js +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.schemas.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.schemas.js +0 -0
- /package/dist/{tree-surfer/fold-node → trees/tree-node/deprecated}/tree-node.test.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.test.js +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.types.d.ts +0 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import type { SerializableKey, TreeNodeModel } from './tree-node.model.js';
|
|
2
|
+
/**
|
|
3
|
+
* A private type-level marker used to make {@link TreeNode} opaque.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
*
|
|
7
|
+
* This declaration intentionally has no runtime value: `declare` causes it
|
|
8
|
+
* to be erased when TypeScript emits JavaScript.
|
|
9
|
+
*
|
|
10
|
+
* WARNING: Brand must not be exported.
|
|
11
|
+
*
|
|
12
|
+
* The marker gives `TreeNode` a property whose key cannot be named by callers.
|
|
13
|
+
* Consequently, callers cannot construct a `TreeNode` using an ordinary
|
|
14
|
+
* object literal. The implementation module is responsible for constructing
|
|
15
|
+
* valid runtime values and exposing them through the public API.
|
|
16
|
+
*
|
|
17
|
+
* This is a compile-time abstraction boundary, not a security boundary.
|
|
18
|
+
* Consumers can still deliberately bypass it with `as unknown as TreeNode<…>`,
|
|
19
|
+
* just as they can bypass other TypeScript checks with assertions.
|
|
20
|
+
*/
|
|
21
|
+
declare const treeNodeBrand: unique symbol;
|
|
22
|
+
/**
|
|
23
|
+
* An immutable tree node with application-defined data.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
*
|
|
27
|
+
* `TreeNode` is intentionally opaque. Callers may hold, compare by reference,
|
|
28
|
+
* pass, store, and return nodes, but should use {@link TreeNodeApi} operations
|
|
29
|
+
* to create, inspect, and update them.
|
|
30
|
+
*
|
|
31
|
+
* In particular, callers do not depend on:
|
|
32
|
+
*
|
|
33
|
+
* - the runtime property used to store the node ID;
|
|
34
|
+
* - the runtime property used to store application data;
|
|
35
|
+
* - whether a node is represented as a leaf or a branch object;
|
|
36
|
+
* - how loaded child nodes are stored; or
|
|
37
|
+
* - how unloaded child state is represented internally.
|
|
38
|
+
*
|
|
39
|
+
* This allows the implementation to change its internal representation without
|
|
40
|
+
* requiring ordinary consumers to change.
|
|
41
|
+
*
|
|
42
|
+
* `TreeNode` values are intended to be immutable. Tree update operations
|
|
43
|
+
* return replacement nodes and do not mutate their inputs. This type does not,
|
|
44
|
+
* however, recursively freeze `Value`; applications should define their own
|
|
45
|
+
* value types with `readonly` properties when that is required.
|
|
46
|
+
*
|
|
47
|
+
* @typeParam Id - The type used to identify a node among its siblings.
|
|
48
|
+
* @typeParam Value - Application-owned data stored at each node.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* type MenuItem = Readonly<{
|
|
54
|
+
* label: string;
|
|
55
|
+
* href?: string;
|
|
56
|
+
* requiredRole: 'guest' | 'member' | 'admin';
|
|
57
|
+
* }>;
|
|
58
|
+
*
|
|
59
|
+
* type MenuTree = TreeNode<MenuId, MenuItem>;
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
*
|
|
64
|
+
* ```ts
|
|
65
|
+
* type DirectoryEntry = Readonly<{
|
|
66
|
+
* kind: 'file' | 'directory';
|
|
67
|
+
* name: string;
|
|
68
|
+
* sizeBytes?: number;
|
|
69
|
+
* }>;
|
|
70
|
+
*
|
|
71
|
+
* type DirectoryTree = TreeNode<DirectoryId, DirectoryEntry>;
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export type TreeNode<Id extends SerializableKey, Value> = {
|
|
75
|
+
/**
|
|
76
|
+
* A phantom type-level witness for `Id` and `Value`.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
*
|
|
80
|
+
* This property is not part of the intended runtime representation. Its
|
|
81
|
+
* purpose is to preserve the generic relationship between a tree node, its
|
|
82
|
+
* ID type, and its application-value type while keeping the node opaque.
|
|
83
|
+
*/
|
|
84
|
+
readonly [treeNodeBrand]: {
|
|
85
|
+
readonly id: Id;
|
|
86
|
+
readonly value: Value;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* The semantic child kind of tree nodes.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
*
|
|
94
|
+
* A node is exactly one of these:
|
|
95
|
+
*
|
|
96
|
+
* - `leaf`: The node cannot contain children.
|
|
97
|
+
* - `unloaded-branch`: The node may contain children, but its child collection
|
|
98
|
+
* has not been loaded and is therefore unavailable.
|
|
99
|
+
* - `loaded-branch`: The node has a loaded child collection. The collection may
|
|
100
|
+
* be empty.
|
|
101
|
+
*
|
|
102
|
+
* A loaded branch with zero children is distinct from a leaf:
|
|
103
|
+
*
|
|
104
|
+
* - a leaf can never contain children;
|
|
105
|
+
* - an empty loaded branch can contain children, but currently has none;
|
|
106
|
+
* - an unloaded branch may contain children, but they are not currently loaded.
|
|
107
|
+
*/
|
|
108
|
+
export type TreeNodeKind = 'leaf' | 'unloaded-branch' | 'loaded-branch';
|
|
109
|
+
/**
|
|
110
|
+
* Case handlers for inspecting an opaque {@link TreeNode}.
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
*
|
|
114
|
+
* `TreeNodeMatch` provides exhaustive pattern matching over the semantic state
|
|
115
|
+
* of a node. It is the preferred operation when behavior differs between
|
|
116
|
+
* leaves, unloaded branches, and loaded branches:
|
|
117
|
+
*
|
|
118
|
+
* - `leaf` receives no `children`, because a leaf cannot have children;
|
|
119
|
+
* - `unloadedBranch` receives no `children`, because its children are not loaded;
|
|
120
|
+
* - `loadedBranch` receives an iterable of loaded direct child nodes. No
|
|
121
|
+
* iteration-order guarantee is made.
|
|
122
|
+
*
|
|
123
|
+
* Every handler must return the same `Result` type.
|
|
124
|
+
*
|
|
125
|
+
* @typeParam Id - The type used to identify nodes among siblings.
|
|
126
|
+
* @typeParam Value - The application-specific value stored at each node.
|
|
127
|
+
* @typeParam Result - The common result type returned by all case handlers.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
*
|
|
131
|
+
* ```ts
|
|
132
|
+
* const label = api.match(node, {
|
|
133
|
+
* leaf: ({ value }) => value.label,
|
|
134
|
+
*
|
|
135
|
+
* unloadedBranch: ({ value }) => `${value.label} (loading…)`,
|
|
136
|
+
*
|
|
137
|
+
* loadedBranch: ({ value, children }) => {
|
|
138
|
+
* let childCount = 0;
|
|
139
|
+
*
|
|
140
|
+
* for (const _child of children) {
|
|
141
|
+
* childCount += 1;
|
|
142
|
+
* }
|
|
143
|
+
*
|
|
144
|
+
* return `${value.label} (${childCount})`;
|
|
145
|
+
* },
|
|
146
|
+
* });
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export type TreeNodeMatch<Id extends SerializableKey, Value, Result> = Readonly<{
|
|
150
|
+
leaf: (node: Readonly<{
|
|
151
|
+
id: Id;
|
|
152
|
+
value: Value;
|
|
153
|
+
}>) => Result;
|
|
154
|
+
unloadedBranch: (node: Readonly<{
|
|
155
|
+
id: Id;
|
|
156
|
+
value: Value;
|
|
157
|
+
}>) => Result;
|
|
158
|
+
loadedBranch: (node: Readonly<{
|
|
159
|
+
id: Id;
|
|
160
|
+
value: Value;
|
|
161
|
+
children: Iterable<TreeNode<Id, Value>>;
|
|
162
|
+
}>) => Result;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Operations for constructing, inspecting, and immutably updating tree nodes.
|
|
166
|
+
*
|
|
167
|
+
* @remarks
|
|
168
|
+
*
|
|
169
|
+
* A `TreeNodeApi` is specialized to one ID type and one application-value
|
|
170
|
+
* type. It owns the structural tree rules: leaf/branch state, child loading
|
|
171
|
+
* state, sibling-ID uniqueness, and immutable ancestor reconstruction.
|
|
172
|
+
*
|
|
173
|
+
* Child collections are unordered. Although operations expose children as
|
|
174
|
+
* `Iterable` values, callers must not rely on iteration order being stable,
|
|
175
|
+
* meaningful, or related to insertion order. The implementation may use an
|
|
176
|
+
* array, map, set, indexed store, or another representation internally.
|
|
177
|
+
*
|
|
178
|
+
* Tree nodes are plain immutable values at runtime. Update operations do not
|
|
179
|
+
* mutate supplied nodes or their loaded child collections. When an update
|
|
180
|
+
* succeeds, only nodes and child collections on the updated path need to be
|
|
181
|
+
* recreated; unrelated parts of the tree may retain their original object
|
|
182
|
+
* identity.
|
|
183
|
+
*
|
|
184
|
+
* A path is an array of IDs relative to a supplied root node. For example,
|
|
185
|
+
* given this tree:
|
|
186
|
+
*
|
|
187
|
+
* ```text
|
|
188
|
+
* root
|
|
189
|
+
* └── child
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* the root is addressed by `[]`, and `child` is addressed by `['child']`.
|
|
193
|
+
*
|
|
194
|
+
* Paths cannot pass through leaves or closed branches. A closed branch may be
|
|
195
|
+
* selected as the final node in a path, but its unloaded descendants cannot be
|
|
196
|
+
* addressed.
|
|
197
|
+
*
|
|
198
|
+
* @typeParam Id - The type used to identify nodes among siblings.
|
|
199
|
+
* @typeParam Value - The application-specific value stored at each node.
|
|
200
|
+
*/
|
|
201
|
+
export type TreeNodeApi<Id extends SerializableKey, Value> = Readonly<{
|
|
202
|
+
/**
|
|
203
|
+
* Creates a leaf node.
|
|
204
|
+
*
|
|
205
|
+
* A leaf cannot contain children. To convert an existing node to a leaf while
|
|
206
|
+
* retaining its ID and value, use {@link TreeNodeApi.toLeaf}.
|
|
207
|
+
*
|
|
208
|
+
* @param id - The ID that identifies this node among its siblings.
|
|
209
|
+
* @param value - Application-owned data stored on the node.
|
|
210
|
+
* @returns A new leaf node.
|
|
211
|
+
*/
|
|
212
|
+
createLeaf(id: Id, value: Value): TreeNode<Id, Value>;
|
|
213
|
+
/**
|
|
214
|
+
* Creates a branch whose children are not loaded.
|
|
215
|
+
*
|
|
216
|
+
* An unloaded branch may contain children, but its child collection is not
|
|
217
|
+
* currently available. It is distinct from both a leaf and a loaded branch
|
|
218
|
+
* with an empty child collection.
|
|
219
|
+
*/
|
|
220
|
+
createUnloadedBranch(id: Id, value: Value): TreeNode<Id, Value>;
|
|
221
|
+
/**
|
|
222
|
+
* Creates a branch with a loaded child collection.
|
|
223
|
+
*
|
|
224
|
+
* An empty child collection creates a loaded branch with no current children;
|
|
225
|
+
* it does not create a leaf.
|
|
226
|
+
*/
|
|
227
|
+
createLoadedBranch(id: Id, value: Value, children: Iterable<TreeNode<Id, Value>>): TreeNode<Id, Value> | undefined;
|
|
228
|
+
/**
|
|
229
|
+
* Returns a node's stable sibling ID.
|
|
230
|
+
*
|
|
231
|
+
* @param node - The node to inspect.
|
|
232
|
+
* @returns The ID identifying `node` among its siblings.
|
|
233
|
+
*/
|
|
234
|
+
id(node: TreeNode<Id, Value>): Id;
|
|
235
|
+
/**
|
|
236
|
+
* Returns application-owned data stored on a node.
|
|
237
|
+
*
|
|
238
|
+
* The value is returned by reference and is not cloned. Callers must not
|
|
239
|
+
* mutate it if the application treats tree nodes as immutable values.
|
|
240
|
+
*
|
|
241
|
+
* @param node - The node to inspect.
|
|
242
|
+
* @returns The value associated with `node`.
|
|
243
|
+
*/
|
|
244
|
+
value(node: TreeNode<Id, Value>): Value;
|
|
245
|
+
/**
|
|
246
|
+
* Returns the semantic kind of a node.
|
|
247
|
+
*
|
|
248
|
+
* Prefer {@link TreeNodeApi.match} when behavior differs by node kind and all
|
|
249
|
+
* three variants must be handled.
|
|
250
|
+
*
|
|
251
|
+
* @param node - The node to inspect.
|
|
252
|
+
* @returns Whether `node` is a leaf, unloaded branch, or loaded branch.
|
|
253
|
+
*/
|
|
254
|
+
kind(node: TreeNode<Id, Value>): TreeNodeKind;
|
|
255
|
+
/**
|
|
256
|
+
* Inspects a node by handling its semantic state exhaustively.
|
|
257
|
+
*
|
|
258
|
+
* @param node - The node to inspect.
|
|
259
|
+
* @param handlers - Case handlers for leaf, closed-branch, and open-branch
|
|
260
|
+
* states.
|
|
261
|
+
* @returns The value returned by the selected case handler.
|
|
262
|
+
*/
|
|
263
|
+
match<Result>(node: TreeNode<Id, Value>, handlers: TreeNodeMatch<Id, Value, Result>): Result;
|
|
264
|
+
/**
|
|
265
|
+
* Returns the loaded direct children of a loaded branch.
|
|
266
|
+
*
|
|
267
|
+
* The returned child nodes are existing values, not defensive clones. No
|
|
268
|
+
* iteration-order guarantee is made.
|
|
269
|
+
*
|
|
270
|
+
* Returns `undefined` when `node` is a leaf or an unloaded branch. Use
|
|
271
|
+
* {@link TreeNodeApi.kind} or {@link TreeNodeApi.match} when those cases need
|
|
272
|
+
* to be distinguished.
|
|
273
|
+
*
|
|
274
|
+
* @param node - The node whose direct children to inspect.
|
|
275
|
+
* @returns An iterable of loaded direct children, or `undefined` when children
|
|
276
|
+
* are unavailable because `node` is a leaf or closed branch.
|
|
277
|
+
*/
|
|
278
|
+
getLoadedChildren(node: TreeNode<Id, Value>): Iterable<TreeNode<Id, Value>> | undefined;
|
|
279
|
+
/**
|
|
280
|
+
* Finds a loaded direct child by sibling ID.
|
|
281
|
+
*
|
|
282
|
+
* The search is performed only among direct children. It does not traverse
|
|
283
|
+
* descendants.
|
|
284
|
+
*
|
|
285
|
+
* @param node - The node whose loaded direct children to search.
|
|
286
|
+
* @param id - The sibling ID to find.
|
|
287
|
+
* @returns The existing matching child, or `undefined` when `node` is not an
|
|
288
|
+
* open branch or does not have a direct child with `id`.
|
|
289
|
+
*/
|
|
290
|
+
findChildById(node: TreeNode<Id, Value>, id: Id): TreeNode<Id, Value> | undefined;
|
|
291
|
+
/**
|
|
292
|
+
* Returns an equivalent node with replacement application data.
|
|
293
|
+
*
|
|
294
|
+
* The returned node retains the original node's ID, semantic child state,
|
|
295
|
+
* and when applicable, existing child-node references. The supplied node is
|
|
296
|
+
* not mutated.
|
|
297
|
+
*
|
|
298
|
+
* @param node - The node to update.
|
|
299
|
+
* @param value - Replacement application-owned data.
|
|
300
|
+
* @returns A replacement node with `value`.
|
|
301
|
+
*/
|
|
302
|
+
withValue(node: TreeNode<Id, Value>, value: Value): TreeNode<Id, Value>;
|
|
303
|
+
/**
|
|
304
|
+
* Converts a node to a leaf.
|
|
305
|
+
*
|
|
306
|
+
* The returned node retains the source node's ID and application value.
|
|
307
|
+
* Any existing children, loaded or unloaded, are discarded.
|
|
308
|
+
*
|
|
309
|
+
* @param node - The node to convert.
|
|
310
|
+
* @returns A leaf node with the source node's ID and value.
|
|
311
|
+
*/
|
|
312
|
+
toLeaf(node: TreeNode<Id, Value>): TreeNode<Id, Value>;
|
|
313
|
+
/**
|
|
314
|
+
* Converts a node to a branch with unloaded children.
|
|
315
|
+
*
|
|
316
|
+
* The returned node retains the source node's ID and application value.
|
|
317
|
+
* Any currently loaded child collection is discarded.
|
|
318
|
+
*
|
|
319
|
+
* @param node - The node to convert.
|
|
320
|
+
* @returns A closed branch with the source node's ID and value.
|
|
321
|
+
*/
|
|
322
|
+
toUnloadedBranch(node: TreeNode<Id, Value>): TreeNode<Id, Value>;
|
|
323
|
+
/**
|
|
324
|
+
* Converts a node to an open branch with replacement loaded children.
|
|
325
|
+
*
|
|
326
|
+
* The returned node retains the source node's ID and application value.
|
|
327
|
+
* Any previous child state is replaced.
|
|
328
|
+
*
|
|
329
|
+
* Child collections are unordered. Callers must not rely on the iteration order
|
|
330
|
+
* of the supplied children being retained or exposed by the resulting node.
|
|
331
|
+
*
|
|
332
|
+
* Direct siblings must have unique IDs. If two or more supplied children have
|
|
333
|
+
* the same ID, no replacement node is created and this method returns
|
|
334
|
+
* `undefined`.
|
|
335
|
+
*
|
|
336
|
+
* The supplied node and child collection are not mutated.
|
|
337
|
+
*
|
|
338
|
+
* @param node - The node to convert or update.
|
|
339
|
+
* @param children - Replacement loaded direct children. Their IDs must be
|
|
340
|
+
* unique among direct siblings.
|
|
341
|
+
* @returns An open branch with the source node's ID and value, or `undefined`
|
|
342
|
+
* when `children` contains duplicate sibling IDs.
|
|
343
|
+
*/
|
|
344
|
+
withLoadedChildren(node: TreeNode<Id, Value>, children: Iterable<TreeNode<Id, Value>>): TreeNode<Id, Value> | undefined;
|
|
345
|
+
/**
|
|
346
|
+
* Finds the node addressed by a path relative to `root`.
|
|
347
|
+
*
|
|
348
|
+
* An empty path selects `root`. Resolution fails when a path refers to a
|
|
349
|
+
* missing child or attempts to pass through a leaf or unloaded branch.
|
|
350
|
+
*
|
|
351
|
+
* @param root - The root node relative to which `path` is interpreted.
|
|
352
|
+
* @param path - A sibling-ID path relative to `root`.
|
|
353
|
+
* @returns The existing node at `path`, or `undefined` when the path cannot
|
|
354
|
+
* be resolved.
|
|
355
|
+
*/
|
|
356
|
+
findAtPath(root: TreeNode<Id, Value>, path: readonly Id[]): TreeNode<Id, Value> | undefined;
|
|
357
|
+
/**
|
|
358
|
+
* Applies a selector to the node addressed by a path relative to `root`.
|
|
359
|
+
*
|
|
360
|
+
* The selector runs only after the complete path has been resolved. The
|
|
361
|
+
* selected node is supplied as the existing node value and is not cloned.
|
|
362
|
+
*
|
|
363
|
+
* An empty path selects `root`. Resolution fails when a path refers to a
|
|
364
|
+
* missing child or attempts to pass through a leaf or a closed branch.
|
|
365
|
+
*
|
|
366
|
+
* @param root - The root node relative to which `path` is interpreted.
|
|
367
|
+
* @param path - A sibling-ID path relative to `root`.
|
|
368
|
+
* @param selector - A function applied to the resolved node.
|
|
369
|
+
* @returns The selector result, or `undefined` when the path cannot be
|
|
370
|
+
* resolved or when `selector` itself returns `undefined`.
|
|
371
|
+
*/
|
|
372
|
+
selectAtPath<Result>(root: TreeNode<Id, Value>, path: readonly Id[], selector: (node: TreeNode<Id, Value>) => Result): Result | undefined;
|
|
373
|
+
/**
|
|
374
|
+
* Immutably replaces the node addressed by a path relative to `root`.
|
|
375
|
+
*
|
|
376
|
+
* The modifier runs only after the complete path has been resolved. Returning
|
|
377
|
+
* `undefined` aborts the operation and causes this method to return
|
|
378
|
+
* `undefined`.
|
|
379
|
+
*
|
|
380
|
+
* An empty path selects `root`. When a descendant is replaced, replacement
|
|
381
|
+
* nodes are created only along the path from `root` to that descendant. Nodes
|
|
382
|
+
* outside that path retain their original object identity.
|
|
383
|
+
*
|
|
384
|
+
* The modifier may return a node with a different ID. If it does, the
|
|
385
|
+
* replacement is subsequently addressed by its new ID rather than the old
|
|
386
|
+
* path segment.
|
|
387
|
+
*
|
|
388
|
+
* The update also fails when the replacement node's ID duplicates the ID of
|
|
389
|
+
* one of its new siblings. This can occur when `modifier` returns a node with
|
|
390
|
+
* a different ID.
|
|
391
|
+
*
|
|
392
|
+
* @param root - The root node relative to which `path` is interpreted.
|
|
393
|
+
* @param path - A sibling-ID path relative to `root`.
|
|
394
|
+
* @param update - Produces a replacement node, or `undefined` to abort.
|
|
395
|
+
* @returns A replacement root, or `undefined` when the path cannot be
|
|
396
|
+
* resolved, `modifier` aborts, or the replacement would create duplicate
|
|
397
|
+
* sibling IDs.
|
|
398
|
+
*/
|
|
399
|
+
updateAtPath(root: TreeNode<Id, Value>, path: readonly Id[], update: (node: TreeNode<Id, Value>) => TreeNode<Id, Value> | undefined): TreeNode<Id, Value> | undefined;
|
|
400
|
+
/**
|
|
401
|
+
* Converts an opaque runtime node into a public structural model.
|
|
402
|
+
*
|
|
403
|
+
* The returned model is a fresh recursive snapshot. It is suitable for
|
|
404
|
+
* serialization when `Id` and `Value` are serializable.
|
|
405
|
+
*/
|
|
406
|
+
toModel(node: TreeNode<Id, Value>): TreeNodeModel<Id, Value>;
|
|
407
|
+
/**
|
|
408
|
+
* Constructs an opaque tree from a public structural model.
|
|
409
|
+
*
|
|
410
|
+
* Returns `undefined` if any loaded child collection contains duplicate
|
|
411
|
+
* sibling IDs.
|
|
412
|
+
*
|
|
413
|
+
* This function assumes the model has already been validated as data of the
|
|
414
|
+
* expected shape. Use a schema/decoder at untrusted boundaries.
|
|
415
|
+
*/
|
|
416
|
+
fromModel(model: TreeNodeModel<Id, Value>): TreeNode<Id, Value> | undefined;
|
|
417
|
+
}>;
|
|
418
|
+
export {};
|
|
419
|
+
//# sourceMappingURL=tree-node.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-node.types.d.ts","sourceRoot":"","sources":["../../../src/trees/tree-node/tree-node.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/tree-surfer/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,MAAM,CAAC,EAAE,IAAI,SAAS,EAAE,EAAE,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,CAAC,CAAC,UAAU,EAC9D,QAAQ,EAAE,QAAQ,wBAGnB;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,CAAC,EAAE,IAAI;IAC1B;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IAEpD;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC;IAElC;;;;;OAKG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,OAAO,CAAC;CAC/E,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC,CAcnD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fold-node.arb.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.arb.ts"],"names":[],"mappings":""}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { FoldNodeApi, FoldNodeService } from './fold-node.types.js';
|
|
2
|
-
import type { SerializableKey } from '../tree-node/tree-node.types.js';
|
|
3
|
-
export declare function createFoldNodeService<Id extends SerializableKey>(foldNodeApi: FoldNodeApi<Id>): FoldNodeService<Id>;
|
|
4
|
-
//# sourceMappingURL=fold-node.impl.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fold-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACX,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAgBvE,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,eAAe,EAC9D,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,GAC3B,eAAe,CAAC,EAAE,CAAC,CAwNrB"}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
function getFoldedChildById(node, id) {
|
|
2
|
-
return node.foldedChildren.find((child) => child.id === id);
|
|
3
|
-
}
|
|
4
|
-
function hasFoldedChildWithId(node, id) {
|
|
5
|
-
return getFoldedChildById(node, id) !== undefined;
|
|
6
|
-
}
|
|
7
|
-
export function createFoldNodeService(foldNodeApi) {
|
|
8
|
-
function createEmptyNode(id) {
|
|
9
|
-
return {
|
|
10
|
-
id,
|
|
11
|
-
children: [],
|
|
12
|
-
foldedChildren: [],
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
createEmptyNode,
|
|
17
|
-
getIfEntryFoldedAtPath(rootNode, path, entryId) {
|
|
18
|
-
const node = foldNodeApi.getAtPath(rootNode, path, (candidate) => candidate);
|
|
19
|
-
return node !== undefined && hasFoldedChildWithId(node, entryId);
|
|
20
|
-
},
|
|
21
|
-
foldedEntriesAtPath(rootNode, path) {
|
|
22
|
-
const node = foldNodeApi.getAtPath(rootNode, path, (candidate) => candidate);
|
|
23
|
-
return node?.foldedChildren.map((child) => child.id);
|
|
24
|
-
},
|
|
25
|
-
addFoldedEntryAtPath(rootNode, path, entryId) {
|
|
26
|
-
const rootWithPath = ensurePath(rootNode, path);
|
|
27
|
-
if (rootWithPath === undefined) {
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
return foldNodeApi.modifyAtPath(rootWithPath, path, (node) => addFoldedEntry(node, entryId));
|
|
31
|
-
},
|
|
32
|
-
removeFoldedEntryAtPath(rootNode, path, entryId) {
|
|
33
|
-
return foldNodeApi.modifyAtPath(rootNode, path, (node) => removeFoldedEntry(node, entryId));
|
|
34
|
-
},
|
|
35
|
-
clearFoldedEntriesAtPath(rootNode, path) {
|
|
36
|
-
return foldNodeApi.modifyAtPath(rootNode, path, (node) => clearFoldedEntries(node));
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
// Node-local operations.
|
|
40
|
-
//
|
|
41
|
-
// These functions update only the selected node. Path traversal and immutable
|
|
42
|
-
// ancestor updates are handled by FoldNodeApi.
|
|
43
|
-
function addFoldedEntry(node, entryId) {
|
|
44
|
-
const existingFoldedChild = getFoldedChildById(node, entryId);
|
|
45
|
-
if (existingFoldedChild !== undefined) {
|
|
46
|
-
return node;
|
|
47
|
-
}
|
|
48
|
-
const childIndex = node.children.findIndex((child) => child.id === entryId);
|
|
49
|
-
const child = childIndex === -1 ? createEmptyNode(entryId) : node.children[childIndex];
|
|
50
|
-
const children = childIndex === -1
|
|
51
|
-
? node.children
|
|
52
|
-
: node.children.filter((_, index) => index !== childIndex);
|
|
53
|
-
return {
|
|
54
|
-
...node,
|
|
55
|
-
children,
|
|
56
|
-
foldedChildren: [...node.foldedChildren, child],
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
function removeFoldedEntry(node, entryId) {
|
|
60
|
-
const foldedChildIndex = node.foldedChildren.findIndex((child) => child.id === entryId);
|
|
61
|
-
if (foldedChildIndex === -1) {
|
|
62
|
-
return node;
|
|
63
|
-
}
|
|
64
|
-
const foldedChild = node.foldedChildren[foldedChildIndex];
|
|
65
|
-
const foldedChildren = node.foldedChildren.filter((_, index) => index !== foldedChildIndex);
|
|
66
|
-
const hasNestedFoldState = foldedChild.children.length > 0 || foldedChild.foldedChildren.length > 0;
|
|
67
|
-
return {
|
|
68
|
-
...node,
|
|
69
|
-
children: hasNestedFoldState
|
|
70
|
-
? [...node.children, foldedChild]
|
|
71
|
-
: node.children,
|
|
72
|
-
foldedChildren,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function clearFoldedEntries(node) {
|
|
76
|
-
if (node.foldedChildren.length === 0) {
|
|
77
|
-
return node;
|
|
78
|
-
}
|
|
79
|
-
const children = [...node.children];
|
|
80
|
-
for (const foldedChild of node.foldedChildren) {
|
|
81
|
-
const hasNestedFoldState = foldedChild.children.length > 0 ||
|
|
82
|
-
foldedChild.foldedChildren.length > 0;
|
|
83
|
-
if (hasNestedFoldState) {
|
|
84
|
-
children.push(foldedChild);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
...node,
|
|
89
|
-
children,
|
|
90
|
-
foldedChildren: [],
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Ensures that the requested path exists in the fold-state tree.
|
|
95
|
-
*
|
|
96
|
-
* The path is relative to `rootNode`; an empty path selects the root.
|
|
97
|
-
* This creates fold nodes only and does not modify the buffer tree.
|
|
98
|
-
*/
|
|
99
|
-
function ensurePath(rootNode, path) {
|
|
100
|
-
if (path.length === 0) {
|
|
101
|
-
return rootNode;
|
|
102
|
-
}
|
|
103
|
-
const children = ensureChildPath(rootNode, path, 0);
|
|
104
|
-
if (children === undefined) {
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
if (children === rootNode.children) {
|
|
108
|
-
return rootNode;
|
|
109
|
-
}
|
|
110
|
-
return {
|
|
111
|
-
...rootNode,
|
|
112
|
-
children,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function ensureChildPath(parent, path, pathIndex) {
|
|
116
|
-
const id = path[pathIndex];
|
|
117
|
-
if (id === undefined) {
|
|
118
|
-
return parent.children;
|
|
119
|
-
}
|
|
120
|
-
if (hasFoldedChildWithId(parent, id)) {
|
|
121
|
-
return undefined;
|
|
122
|
-
}
|
|
123
|
-
const children = parent.children;
|
|
124
|
-
const childIndex = children.findIndex((child) => child.id === id);
|
|
125
|
-
const child = childIndex === -1 ? createEmptyNode(id) : children[childIndex];
|
|
126
|
-
let updatedChild = child;
|
|
127
|
-
if (pathIndex < path.length - 1) {
|
|
128
|
-
const updatedChildren = ensureChildPath(child, path, pathIndex + 1);
|
|
129
|
-
if (updatedChildren === undefined) {
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
if (updatedChildren !== child.children) {
|
|
133
|
-
updatedChild = {
|
|
134
|
-
...child,
|
|
135
|
-
children: updatedChildren,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (childIndex === -1) {
|
|
140
|
-
return [...children, updatedChild];
|
|
141
|
-
}
|
|
142
|
-
if (updatedChild === child) {
|
|
143
|
-
return children;
|
|
144
|
-
}
|
|
145
|
-
const result = [...children];
|
|
146
|
-
result[childIndex] = updatedChild;
|
|
147
|
-
return result;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { FoldNode } from './fold-node.types.js';
|
|
3
|
-
import { SerializableKey } from '../tree-node/tree-node.types.js';
|
|
4
|
-
export declare function createFoldNodeSchemas<Id extends SerializableKey>(idSchema: z.ZodType<Id>): z.ZodType<FoldNode<Id>>;
|
|
5
|
-
//# sourceMappingURL=fold-node.schema.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fold-node.schema.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,eAAe,EAC9D,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GACtB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAYzB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fold-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,MAAM,QAAQ,CAAC,EAAE,SAAS,eAAe,IAAI;IACjD,EAAE,EAAE,EAAE,CAAC;IACP,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IACzB,cAAc,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,WAAW,CAAC,EAAE,SAAS,eAAe,IAAI,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;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;IAC5B,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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tree-node.test.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/tree-node.test.ts"],"names":[],"mappings":""}
|