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
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './tree-surfer-ui/application/user-input-to-intent.js';
|
|
2
2
|
export * from './tree-surfer-ui/application/intent-to-effect.js';
|
|
3
3
|
export * from './tree-surfer-ui/domain/effect.js';
|
|
4
|
-
export * from './tree-surfer-ui/domain/input-state.js';
|
|
4
|
+
export * from './tree-surfer-ui/domain/input-mode-state.js';
|
|
5
5
|
export * from './tree-surfer-ui/domain/intent.js';
|
|
6
6
|
export * from './tree-surfer-ui/domain/user-input.js';
|
|
7
7
|
export * from './tree-surfer/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sDAAsD,CAAC;AACrE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,mCAAmC,CAAC;AAClD,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sDAAsD,CAAC;AACrE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,mCAAmC,CAAC;AAClD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './tree-surfer-ui/application/user-input-to-intent.js';
|
|
2
2
|
export * from './tree-surfer-ui/application/intent-to-effect.js';
|
|
3
3
|
export * from './tree-surfer-ui/domain/effect.js';
|
|
4
|
-
export * from './tree-surfer-ui/domain/input-state.js';
|
|
4
|
+
export * from './tree-surfer-ui/domain/input-mode-state.js';
|
|
5
5
|
export * from './tree-surfer-ui/domain/intent.js';
|
|
6
6
|
export * from './tree-surfer-ui/domain/user-input.js';
|
|
7
7
|
export * from './tree-surfer/index.js';
|
|
@@ -1,32 +1,58 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
2
|
+
/**
|
|
3
|
+
* A root-relative path identifying the current tree position.
|
|
4
|
+
*
|
|
5
|
+
* The empty path identifies the tree root. A non-empty path identifies a
|
|
6
|
+
* descendant by following child IDs from the root.
|
|
7
|
+
*
|
|
8
|
+
* For example, given:
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* root
|
|
12
|
+
* └── src
|
|
13
|
+
* └── main.ts
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* the cursors are:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* [] // root
|
|
20
|
+
* ['src'] // src
|
|
21
|
+
* ['src', 'main.ts'] // main.ts
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @typeParam Id - The type of node IDs.
|
|
25
|
+
*/
|
|
26
|
+
export type Cursor<Id> = readonly Id[];
|
|
27
|
+
/**
|
|
28
|
+
* Creates a schema for root-relative tree cursors.
|
|
29
|
+
*
|
|
30
|
+
* The schema validates the IDs in the path, but does not verify that the path
|
|
31
|
+
* exists in a particular tree.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createCursorSchema<IdSchema extends z.ZodTypeAny>(idSchema: IdSchema): z.ZodArray<IdSchema>;
|
|
34
|
+
/**
|
|
35
|
+
* Operations for comparing and inspecting root-relative tree cursors.
|
|
36
|
+
*
|
|
37
|
+
* @typeParam Id - The type of node IDs.
|
|
38
|
+
*/
|
|
25
39
|
export type CursorApi<Id> = {
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Tests whether two cursors identify the same tree position.
|
|
42
|
+
*/
|
|
28
43
|
equal(left: Cursor<Id>, right: Cursor<Id>): boolean;
|
|
29
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Returns a mutable copy of the cursor path.
|
|
46
|
+
*
|
|
47
|
+
* The empty path identifies the tree root.
|
|
48
|
+
*/
|
|
49
|
+
getPath(cursor: Cursor<Id>): Id[];
|
|
50
|
+
/**
|
|
51
|
+
* Tests whether the cursor is within the subtree at `entryPath`.
|
|
52
|
+
*
|
|
53
|
+
* The subtree includes the node at `entryPath` itself. Therefore, equal
|
|
54
|
+
* paths return `true`, and an empty `entryPath` contains every cursor.
|
|
55
|
+
*/
|
|
30
56
|
cursorBelongsToSubtree(cursor: Cursor<Id>, entryPath: readonly Id[]): boolean;
|
|
31
57
|
};
|
|
32
58
|
export declare function createCursorApi<Id>(): CursorApi<Id>;
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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,57 +1,29 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Creates a schema for root-relative tree cursors.
|
|
4
|
+
*
|
|
5
|
+
* The schema validates the IDs in the path, but does not verify that the path
|
|
6
|
+
* exists in a particular tree.
|
|
7
|
+
*/
|
|
6
8
|
export function createCursorSchema(idSchema) {
|
|
7
|
-
|
|
8
|
-
return z.discriminatedUnion('kind', [
|
|
9
|
-
z.object({
|
|
10
|
-
kind: z.literal(CursorKind.Entry),
|
|
11
|
-
parentPath: parentPathSchema,
|
|
12
|
-
entryId: idSchema,
|
|
13
|
-
}),
|
|
14
|
-
z.object({
|
|
15
|
-
kind: z.literal(CursorKind.Fold),
|
|
16
|
-
parentPath: parentPathSchema,
|
|
17
|
-
}),
|
|
18
|
-
]);
|
|
9
|
+
return z.array(idSchema);
|
|
19
10
|
}
|
|
20
11
|
export function createCursorApi() {
|
|
21
|
-
|
|
22
|
-
isEntry(cursor) {
|
|
23
|
-
return cursor.kind === CursorKind.Entry;
|
|
24
|
-
},
|
|
25
|
-
isFold(cursor) {
|
|
26
|
-
return cursor.kind === CursorKind.Fold;
|
|
27
|
-
},
|
|
12
|
+
return {
|
|
28
13
|
equal(left, right) {
|
|
29
|
-
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
if (cursorApi.isFold(left)) {
|
|
33
|
-
return cursorApi.isFold(right);
|
|
34
|
-
}
|
|
35
|
-
return cursorApi.isEntry(right) && left.entryId === right.entryId;
|
|
14
|
+
return idPathEqual(left, right);
|
|
36
15
|
},
|
|
37
16
|
getPath(cursor) {
|
|
38
|
-
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
return [...cursor.parentPath, cursor.entryId];
|
|
17
|
+
return [...cursor];
|
|
42
18
|
},
|
|
43
19
|
cursorBelongsToSubtree(cursor, entryPath) {
|
|
44
|
-
|
|
45
|
-
return isStrictPathPrefix(entryPath, cursor.parentPath);
|
|
46
|
-
}
|
|
47
|
-
const cursorPath = [...cursor.parentPath, cursor.entryId];
|
|
48
|
-
return isStrictPathPrefix(entryPath, cursorPath);
|
|
20
|
+
return isPathPrefix(entryPath, cursor);
|
|
49
21
|
},
|
|
50
22
|
};
|
|
51
|
-
return cursorApi;
|
|
52
23
|
}
|
|
53
24
|
/**
|
|
54
|
-
* Returns true when both paths contain the same IDs in the same
|
|
25
|
+
* Returns true when both root-relative paths contain the same IDs in the same
|
|
26
|
+
* order.
|
|
55
27
|
*/
|
|
56
28
|
function idPathEqual(left, right) {
|
|
57
29
|
if (left.length !== right.length) {
|
|
@@ -65,10 +37,13 @@ function idPathEqual(left, right) {
|
|
|
65
37
|
return true;
|
|
66
38
|
}
|
|
67
39
|
/**
|
|
68
|
-
* Returns true when `prefix` is a
|
|
40
|
+
* Returns true when `prefix` is a prefix of `path`.
|
|
41
|
+
*
|
|
42
|
+
* Equal paths are included. An empty prefix is therefore a prefix of every
|
|
43
|
+
* path.
|
|
69
44
|
*/
|
|
70
|
-
function
|
|
71
|
-
if (prefix.length
|
|
45
|
+
function isPathPrefix(prefix, path) {
|
|
46
|
+
if (prefix.length > path.length) {
|
|
72
47
|
return false;
|
|
73
48
|
}
|
|
74
49
|
for (let index = 0; index < prefix.length; index += 1) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-node.arb.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.arb.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SerializableKey } from '../tree-node/tree-node.types.js';
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function createFoldNodeService<Id extends SerializableKey>(foldNodeApi: FoldNodeApi<Id>, createChild: (id: Id) => FoldNode<Id>): FoldNodeService<Id>;
|
|
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>;
|
|
5
4
|
//# sourceMappingURL=fold-node.impl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fold-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.impl.ts"],"names":[],"mappings":"
|
|
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,110 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return node.children;
|
|
7
|
-
},
|
|
8
|
-
getChildById(node, id) {
|
|
9
|
-
return node.children.find((child) => child.id === id);
|
|
10
|
-
},
|
|
11
|
-
getAtPath(rootNode, path, selector) {
|
|
12
|
-
return treeNodeApi.getAtPath(rootNode.children, path, selector);
|
|
13
|
-
},
|
|
14
|
-
modifyAtPath(rootNode, path, modifier) {
|
|
15
|
-
const children = treeNodeApi.modifyAtPath(rootNode.children, path, modifier);
|
|
16
|
-
if (children === undefined) {
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
return {
|
|
20
|
-
...rootNode,
|
|
21
|
-
children,
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
};
|
|
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;
|
|
25
6
|
}
|
|
26
|
-
export function createFoldNodeService(foldNodeApi
|
|
7
|
+
export function createFoldNodeService(foldNodeApi) {
|
|
8
|
+
function createEmptyNode(id) {
|
|
9
|
+
return {
|
|
10
|
+
id,
|
|
11
|
+
children: [],
|
|
12
|
+
foldedChildren: [],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
27
15
|
return {
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
children: [],
|
|
31
|
-
folds: new Set(),
|
|
32
|
-
};
|
|
33
|
-
},
|
|
16
|
+
createEmptyNode,
|
|
34
17
|
getIfEntryFoldedAtPath(rootNode, path, entryId) {
|
|
35
|
-
if (path.length === 0) {
|
|
36
|
-
return rootNode.folds.has(entryId);
|
|
37
|
-
}
|
|
38
18
|
const node = foldNodeApi.getAtPath(rootNode, path, (candidate) => candidate);
|
|
39
|
-
return node !== undefined && node
|
|
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);
|
|
40
24
|
},
|
|
41
25
|
addFoldedEntryAtPath(rootNode, path, entryId) {
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
26
|
+
const rootWithPath = ensurePath(rootNode, path);
|
|
27
|
+
if (rootWithPath === undefined) {
|
|
28
|
+
return undefined;
|
|
45
29
|
}
|
|
46
|
-
return foldNodeApi.modifyAtPath(
|
|
30
|
+
return foldNodeApi.modifyAtPath(rootWithPath, path, (node) => addFoldedEntry(node, entryId));
|
|
47
31
|
},
|
|
48
32
|
removeFoldedEntryAtPath(rootNode, path, entryId) {
|
|
49
|
-
if (path.length === 0) {
|
|
50
|
-
return removeFoldedEntry(rootNode, entryId);
|
|
51
|
-
}
|
|
52
33
|
return foldNodeApi.modifyAtPath(rootNode, path, (node) => removeFoldedEntry(node, entryId));
|
|
53
34
|
},
|
|
54
35
|
clearFoldedEntriesAtPath(rootNode, path) {
|
|
55
|
-
|
|
56
|
-
return clearFoldedEntries(rootNode);
|
|
57
|
-
}
|
|
58
|
-
return foldNodeApi.modifyAtPath(rootNode, path, clearFoldedEntries);
|
|
36
|
+
return foldNodeApi.modifyAtPath(rootNode, path, (node) => clearFoldedEntries(node));
|
|
59
37
|
},
|
|
60
38
|
};
|
|
61
|
-
//
|
|
62
|
-
// `Node extends FoldNodeRoot<Id> | FoldNode<Id>` is used to create two
|
|
63
|
-
// versions of functions: one for the root and one for the children.
|
|
64
|
-
// "Flat" functions
|
|
39
|
+
// Node-local operations.
|
|
65
40
|
//
|
|
66
|
-
//
|
|
41
|
+
// These functions update only the selected node. Path traversal and immutable
|
|
42
|
+
// ancestor updates are handled by FoldNodeApi.
|
|
67
43
|
function addFoldedEntry(node, entryId) {
|
|
68
|
-
|
|
44
|
+
const existingFoldedChild = getFoldedChildById(node, entryId);
|
|
45
|
+
if (existingFoldedChild !== undefined) {
|
|
69
46
|
return node;
|
|
70
47
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
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);
|
|
73
53
|
return {
|
|
74
54
|
...node,
|
|
75
|
-
|
|
55
|
+
children,
|
|
56
|
+
foldedChildren: [...node.foldedChildren, child],
|
|
76
57
|
};
|
|
77
58
|
}
|
|
78
59
|
function removeFoldedEntry(node, entryId) {
|
|
79
|
-
|
|
60
|
+
const foldedChildIndex = node.foldedChildren.findIndex((child) => child.id === entryId);
|
|
61
|
+
if (foldedChildIndex === -1) {
|
|
80
62
|
return node;
|
|
81
63
|
}
|
|
82
|
-
const
|
|
83
|
-
|
|
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;
|
|
84
67
|
return {
|
|
85
68
|
...node,
|
|
86
|
-
|
|
69
|
+
children: hasNestedFoldState
|
|
70
|
+
? [...node.children, foldedChild]
|
|
71
|
+
: node.children,
|
|
72
|
+
foldedChildren,
|
|
87
73
|
};
|
|
88
74
|
}
|
|
89
75
|
function clearFoldedEntries(node) {
|
|
90
|
-
if (node.
|
|
76
|
+
if (node.foldedChildren.length === 0) {
|
|
91
77
|
return node;
|
|
92
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
|
+
}
|
|
93
87
|
return {
|
|
94
88
|
...node,
|
|
95
|
-
|
|
89
|
+
children,
|
|
90
|
+
foldedChildren: [],
|
|
96
91
|
};
|
|
97
92
|
}
|
|
98
93
|
/**
|
|
99
94
|
* Ensures that the requested path exists in the fold-state tree.
|
|
100
95
|
*
|
|
101
|
-
*
|
|
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.
|
|
102
98
|
*/
|
|
103
99
|
function ensurePath(rootNode, path) {
|
|
104
100
|
if (path.length === 0) {
|
|
105
101
|
return rootNode;
|
|
106
102
|
}
|
|
107
|
-
const children = ensureChildPath(rootNode
|
|
103
|
+
const children = ensureChildPath(rootNode, path, 0);
|
|
104
|
+
if (children === undefined) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
108
107
|
if (children === rootNode.children) {
|
|
109
108
|
return rootNode;
|
|
110
109
|
}
|
|
@@ -113,16 +112,23 @@ export function createFoldNodeService(foldNodeApi, createChild) {
|
|
|
113
112
|
children,
|
|
114
113
|
};
|
|
115
114
|
}
|
|
116
|
-
function ensureChildPath(
|
|
115
|
+
function ensureChildPath(parent, path, pathIndex) {
|
|
117
116
|
const id = path[pathIndex];
|
|
118
117
|
if (id === undefined) {
|
|
119
|
-
return children;
|
|
118
|
+
return parent.children;
|
|
120
119
|
}
|
|
120
|
+
if (hasFoldedChildWithId(parent, id)) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const children = parent.children;
|
|
121
124
|
const childIndex = children.findIndex((child) => child.id === id);
|
|
122
|
-
const child = childIndex === -1 ?
|
|
125
|
+
const child = childIndex === -1 ? createEmptyNode(id) : children[childIndex];
|
|
123
126
|
let updatedChild = child;
|
|
124
127
|
if (pathIndex < path.length - 1) {
|
|
125
|
-
const updatedChildren = ensureChildPath(child
|
|
128
|
+
const updatedChildren = ensureChildPath(child, path, pathIndex + 1);
|
|
129
|
+
if (updatedChildren === undefined) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
126
132
|
if (updatedChildren !== child.children) {
|
|
127
133
|
updatedChild = {
|
|
128
134
|
...child,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { FoldNode
|
|
2
|
+
import type { FoldNode } from './fold-node.types.js';
|
|
3
3
|
import { SerializableKey } from '../tree-node/tree-node.types.js';
|
|
4
|
-
export declare function createFoldNodeSchemas<Id extends SerializableKey>(idSchema: z.ZodType<Id>):
|
|
5
|
-
foldNodeSchema: z.ZodType<FoldNode<Id>, unknown, z.core.$ZodTypeInternals<FoldNode<Id>, unknown>>;
|
|
6
|
-
foldNodeRootSchema: z.ZodType<FoldNodeRoot<Id>, unknown, z.core.$ZodTypeInternals<FoldNodeRoot<Id>, unknown>>;
|
|
7
|
-
};
|
|
4
|
+
export declare function createFoldNodeSchemas<Id extends SerializableKey>(idSchema: z.ZodType<Id>): z.ZodType<FoldNode<Id>>;
|
|
8
5
|
//# sourceMappingURL=fold-node.schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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"}
|
|
@@ -3,14 +3,7 @@ export function createFoldNodeSchemas(idSchema) {
|
|
|
3
3
|
const foldNodeSchema = z.lazy(() => z.object({
|
|
4
4
|
id: idSchema,
|
|
5
5
|
children: z.array(foldNodeSchema),
|
|
6
|
-
|
|
6
|
+
foldedChildren: z.array(foldNodeSchema),
|
|
7
7
|
}));
|
|
8
|
-
|
|
9
|
-
children: z.array(foldNodeSchema),
|
|
10
|
-
folds: z.array(idSchema).transform((ids) => new Set(ids)),
|
|
11
|
-
});
|
|
12
|
-
return {
|
|
13
|
-
foldNodeSchema,
|
|
14
|
-
foldNodeRootSchema,
|
|
15
|
-
};
|
|
8
|
+
return foldNodeSchema;
|
|
16
9
|
}
|