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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-node.schemas.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEjE;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,iDAA6C,CAAC;AAEhF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,SAAS,eAAe,EAC1B,
|
|
1
|
+
{"version":3,"file":"tree-node.schemas.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEjE;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,iDAA6C,CAAC;AAEhF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;EAoBrD"}
|
|
@@ -15,7 +15,7 @@ export const serializableKeySchema = z.union([z.string(), z.number().finite()]);
|
|
|
15
15
|
*
|
|
16
16
|
* The concrete application can extend these schemas with additional fields.
|
|
17
17
|
*/
|
|
18
|
-
export function createTreeNodeSchemas(idSchema,
|
|
18
|
+
export function createTreeNodeSchemas(idSchema, nodeSchema) {
|
|
19
19
|
const leafSchema = z.object({
|
|
20
20
|
id: idSchema,
|
|
21
21
|
});
|
|
@@ -25,7 +25,7 @@ export function createTreeNodeSchemas(idSchema, childSchema) {
|
|
|
25
25
|
});
|
|
26
26
|
const openBranchSchema = z.object({
|
|
27
27
|
id: idSchema,
|
|
28
|
-
children: z.array(
|
|
28
|
+
children: z.array(nodeSchema),
|
|
29
29
|
});
|
|
30
30
|
return {
|
|
31
31
|
leafSchema,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import * as fc from 'fast-check';
|
|
3
3
|
import { createTreeNodeApi } from './tree-node.impl.js';
|
|
4
|
-
import { newBranchesOrNullArb, nodesArrayAndBranchPathArb,
|
|
4
|
+
import { newBranchesOrNullArb, nodesArrayAndBranchPathArb, nodeAndPathAndExpectedArb, } from './tree-node.arb.js';
|
|
5
5
|
const api = createTreeNodeApi();
|
|
6
6
|
describe('getChildById', () => {
|
|
7
7
|
it('UT: returns the matching direct child', () => {
|
|
@@ -23,23 +23,21 @@ describe('getChildById', () => {
|
|
|
23
23
|
describe('getAtPath', () => {
|
|
24
24
|
// Using `selector = vi.fn...` here is too heavy
|
|
25
25
|
it('applies selector to the node at a valid path', () => {
|
|
26
|
-
fc.assert(fc.property(
|
|
27
|
-
expect(api.getAtPath(
|
|
28
|
-
expect(api.getAtPath(
|
|
26
|
+
fc.assert(fc.property(nodeAndPathAndExpectedArb, ({ root, path, expected }) => {
|
|
27
|
+
expect(api.getAtPath(root, path, (node) => node)).toBe(expected);
|
|
28
|
+
expect(api.getAtPath(root, path, (node) => node.id)).toBe(expected.id);
|
|
29
29
|
}));
|
|
30
30
|
});
|
|
31
31
|
it('UT: calls the selector once with the resolved node', () => {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
];
|
|
32
|
+
const child = { id: 'child' };
|
|
33
|
+
const root = {
|
|
34
|
+
id: 'root',
|
|
35
|
+
children: [child],
|
|
36
|
+
};
|
|
39
37
|
const selector = vi.fn((node) => node.id);
|
|
40
|
-
expect(api.getAtPath(
|
|
38
|
+
expect(api.getAtPath(root, ['child'], selector)).toBe('child');
|
|
41
39
|
expect(selector).toHaveBeenCalledOnce();
|
|
42
|
-
expect(selector).toHaveBeenCalledWith(
|
|
40
|
+
expect(selector).toHaveBeenCalledWith(child);
|
|
43
41
|
});
|
|
44
42
|
it('UT: returns undefined for an invalid root path without calling the selector', () => {
|
|
45
43
|
const selector = vi.fn((node) => node.id);
|
|
@@ -48,38 +46,35 @@ describe('getAtPath', () => {
|
|
|
48
46
|
expect(selector).not.toHaveBeenCalled();
|
|
49
47
|
});
|
|
50
48
|
it('UT: returns undefined when a child is missing from an open branch', () => {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
},
|
|
56
|
-
];
|
|
49
|
+
const root = {
|
|
50
|
+
id: 'root',
|
|
51
|
+
children: [{ id: 'child' }],
|
|
52
|
+
};
|
|
57
53
|
const selector = vi.fn((node) => node.id);
|
|
58
|
-
const result = api.getAtPath(
|
|
54
|
+
const result = api.getAtPath(root, ['root', 'missing'], selector);
|
|
59
55
|
expect(result).toBeUndefined();
|
|
60
56
|
expect(selector).not.toHaveBeenCalled();
|
|
61
57
|
});
|
|
62
|
-
it('UT:
|
|
58
|
+
it('UT: resolves the root for an empty path', () => {
|
|
59
|
+
const root = { id: 'root' };
|
|
63
60
|
const selector = vi.fn((node) => node.id);
|
|
64
|
-
|
|
65
|
-
expect(
|
|
66
|
-
expect(selector).
|
|
61
|
+
expect(api.getAtPath(root, [], selector)).toBe('root');
|
|
62
|
+
expect(selector).toHaveBeenCalledOnce();
|
|
63
|
+
expect(selector).toHaveBeenCalledWith(root);
|
|
67
64
|
});
|
|
68
65
|
it('UT: returns undefined through a closed branch without calling the selector', () => {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
74
|
-
];
|
|
66
|
+
const root = {
|
|
67
|
+
id: 'root',
|
|
68
|
+
children: null,
|
|
69
|
+
};
|
|
75
70
|
const selector = vi.fn((node) => node.id);
|
|
76
|
-
const result = api.getAtPath(
|
|
71
|
+
const result = api.getAtPath(root, ['child'], selector);
|
|
77
72
|
expect(result).toBeUndefined();
|
|
78
73
|
expect(selector).not.toHaveBeenCalled();
|
|
79
74
|
});
|
|
80
75
|
it('UT: returns undefined when the selector returns undefined', () => {
|
|
81
76
|
const selector = vi.fn((_node) => undefined);
|
|
82
|
-
const result = api.getAtPath(
|
|
77
|
+
const result = api.getAtPath({ id: 'root' }, [], selector);
|
|
83
78
|
expect(result).toBeUndefined();
|
|
84
79
|
expect(selector).toHaveBeenCalledOnce();
|
|
85
80
|
expect(selector).toHaveBeenCalledWith({ id: 'root' });
|
|
@@ -87,31 +82,31 @@ describe('getAtPath', () => {
|
|
|
87
82
|
});
|
|
88
83
|
describe('modifyAtPath', () => {
|
|
89
84
|
it('replaces the generated node', () => {
|
|
90
|
-
fc.assert(fc.property(
|
|
85
|
+
fc.assert(fc.property(nodeAndPathAndExpectedArb, ({ root, path, expected }) => {
|
|
91
86
|
const replacement = {
|
|
92
87
|
id: expected.id,
|
|
93
88
|
};
|
|
94
|
-
const
|
|
95
|
-
expect(
|
|
96
|
-
if (
|
|
89
|
+
const updatedRoot = api.modifyAtPath(root, path, () => replacement);
|
|
90
|
+
expect(updatedRoot).not.toBeUndefined();
|
|
91
|
+
if (updatedRoot === undefined) {
|
|
97
92
|
return;
|
|
98
93
|
}
|
|
99
|
-
expect(api.getAtPath(
|
|
100
|
-
expect(api.getAtPath(
|
|
94
|
+
expect(api.getAtPath(updatedRoot, path, (node) => node)).toBe(replacement);
|
|
95
|
+
expect(api.getAtPath(root, path, (node) => node)).toBe(expected);
|
|
101
96
|
}));
|
|
102
|
-
},
|
|
97
|
+
}, 12000);
|
|
103
98
|
it('replaces children at a branch path', () => {
|
|
104
|
-
fc.assert(fc.property(nodesArrayAndBranchPathArb, newBranchesOrNullArb, ({
|
|
99
|
+
fc.assert(fc.property(nodesArrayAndBranchPathArb, newBranchesOrNullArb, ({ root, path, expected }, newBranches) => {
|
|
105
100
|
expect(api.isBranch(expected)).toBe(true);
|
|
106
|
-
const
|
|
101
|
+
const updatedRoot = api.modifyAtPath(root, path, (node) => ({
|
|
107
102
|
...node,
|
|
108
103
|
children: newBranches,
|
|
109
104
|
}));
|
|
110
|
-
expect(
|
|
111
|
-
if (
|
|
105
|
+
expect(updatedRoot).not.toBeUndefined();
|
|
106
|
+
if (updatedRoot === undefined) {
|
|
112
107
|
return;
|
|
113
108
|
}
|
|
114
|
-
const updatedNode = api.getAtPath(
|
|
109
|
+
const updatedNode = api.getAtPath(updatedRoot, path, (node) => node);
|
|
115
110
|
expect(updatedNode).not.toBeUndefined();
|
|
116
111
|
expect(updatedNode).not.toBe(expected);
|
|
117
112
|
if (updatedNode === undefined ||
|
|
@@ -122,69 +117,69 @@ describe('modifyAtPath', () => {
|
|
|
122
117
|
if (api.isOpenBranch(updatedNode)) {
|
|
123
118
|
expect([...api.getChildren(updatedNode)]).toStrictEqual(newBranches);
|
|
124
119
|
}
|
|
125
|
-
expect(api.getAtPath(
|
|
120
|
+
expect(api.getAtPath(root, path, (node) => node)).toBe(expected);
|
|
126
121
|
}));
|
|
127
122
|
});
|
|
128
123
|
it('UT: calls the modifier once with the resolved node', () => {
|
|
129
124
|
const child = { id: 'child' };
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
},
|
|
135
|
-
];
|
|
125
|
+
const root = {
|
|
126
|
+
id: 'root',
|
|
127
|
+
children: [child],
|
|
128
|
+
};
|
|
136
129
|
const replacement = { id: 'replacement' };
|
|
137
130
|
const modifier = vi.fn(() => replacement);
|
|
138
|
-
const
|
|
139
|
-
expect(
|
|
131
|
+
const updatedRoot = api.modifyAtPath(root, ['child'], modifier);
|
|
132
|
+
expect(updatedRoot).toBeDefined();
|
|
140
133
|
expect(modifier).toHaveBeenCalledOnce();
|
|
141
134
|
expect(modifier).toHaveBeenCalledWith(child);
|
|
142
|
-
expect(api.getAtPath(
|
|
143
|
-
expect(api.getAtPath(
|
|
135
|
+
expect(api.getAtPath(updatedRoot, ['replacement'], (node) => node)).toBe(replacement);
|
|
136
|
+
expect(api.getAtPath(updatedRoot, ['child'], (node) => node)).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
it('UT: modifies the root for an empty path', () => {
|
|
139
|
+
const root = { id: 'root' };
|
|
140
|
+
const replacement = { id: 'replacement' };
|
|
141
|
+
const modifier = vi.fn(() => replacement);
|
|
142
|
+
const updatedRoot = api.modifyAtPath(root, [], modifier);
|
|
143
|
+
expect(updatedRoot).toBe(replacement);
|
|
144
|
+
expect(modifier).toHaveBeenCalledOnce();
|
|
145
|
+
expect(modifier).toHaveBeenCalledWith(root);
|
|
144
146
|
});
|
|
145
147
|
it.each([
|
|
146
|
-
{
|
|
147
|
-
name: 'an empty path',
|
|
148
|
-
entries: [{ id: 'root' }],
|
|
149
|
-
path: [],
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
name: 'a missing root',
|
|
153
|
-
entries: [{ id: 'root' }],
|
|
154
|
-
path: ['missing'],
|
|
155
|
-
},
|
|
156
148
|
{
|
|
157
149
|
name: 'a missing child',
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
],
|
|
164
|
-
path: ['root', 'missing'],
|
|
150
|
+
root: {
|
|
151
|
+
id: 'root',
|
|
152
|
+
children: [],
|
|
153
|
+
},
|
|
154
|
+
path: ['missing'],
|
|
165
155
|
},
|
|
166
156
|
{
|
|
167
157
|
name: 'a path through a leaf',
|
|
168
|
-
|
|
169
|
-
|
|
158
|
+
root: {
|
|
159
|
+
id: 'root',
|
|
160
|
+
},
|
|
161
|
+
path: ['child'],
|
|
170
162
|
},
|
|
171
163
|
{
|
|
172
164
|
name: 'a path through a closed branch',
|
|
173
|
-
|
|
174
|
-
|
|
165
|
+
root: {
|
|
166
|
+
id: 'root',
|
|
167
|
+
children: null,
|
|
168
|
+
},
|
|
169
|
+
path: ['child'],
|
|
175
170
|
},
|
|
176
|
-
])('UT: returns undefined and does not call the modifier', ({
|
|
171
|
+
])('UT: returns undefined and does not call the modifier', ({ root, path }) => {
|
|
177
172
|
const modifier = vi.fn((node) => node);
|
|
178
|
-
const result = api.modifyAtPath(
|
|
173
|
+
const result = api.modifyAtPath(root, path, modifier);
|
|
179
174
|
expect(result).toBeUndefined();
|
|
180
175
|
expect(modifier).not.toHaveBeenCalled();
|
|
181
176
|
});
|
|
182
177
|
it('UT: returns undefined when the modifier aborts', () => {
|
|
183
|
-
const root =
|
|
178
|
+
const root = { id: 'root' };
|
|
184
179
|
const modifier = vi.fn(() => undefined);
|
|
185
|
-
const result = api.modifyAtPath(root, [
|
|
180
|
+
const result = api.modifyAtPath(root, [], modifier);
|
|
186
181
|
expect(result).toBeUndefined();
|
|
187
182
|
expect(modifier).toHaveBeenCalledOnce();
|
|
188
|
-
expect(modifier).toHaveBeenCalledWith(root
|
|
183
|
+
expect(modifier).toHaveBeenCalledWith(root);
|
|
189
184
|
});
|
|
190
185
|
});
|
|
@@ -32,8 +32,7 @@ export type SerializableKey = string | number;
|
|
|
32
32
|
*
|
|
33
33
|
* @remarks
|
|
34
34
|
*
|
|
35
|
-
* A node's `id` identifies it among its siblings
|
|
36
|
-
* paths through the tree.
|
|
35
|
+
* A node's `id` identifies it among its siblings.
|
|
37
36
|
*
|
|
38
37
|
* Nodes are discriminated by the shape of their `children` property:
|
|
39
38
|
*
|
|
@@ -79,23 +78,21 @@ export type ClosedBranchTreeNode<Id extends SerializableKey> = {
|
|
|
79
78
|
children: null;
|
|
80
79
|
};
|
|
81
80
|
/**
|
|
82
|
-
* Operations for inspecting and immutably updating a tree node
|
|
81
|
+
* Operations for inspecting and immutably updating a tree rooted at a node.
|
|
83
82
|
*
|
|
84
83
|
* @remarks
|
|
85
84
|
*
|
|
86
|
-
* A path is an array of IDs
|
|
87
|
-
* its descendants.
|
|
85
|
+
* A path is an array of IDs relative to the supplied root node.
|
|
88
86
|
*
|
|
89
87
|
* For example, given tree with IDs:
|
|
90
88
|
*
|
|
91
89
|
* root
|
|
92
90
|
* └── child
|
|
93
91
|
*
|
|
94
|
-
* the path to `child` is `['
|
|
92
|
+
* the path to `root` is `[]`, and the path to `child` is `['child']`.
|
|
95
93
|
*
|
|
96
94
|
* Paths cannot pass through leaves or closed branches. A closed branch may be
|
|
97
|
-
* the final node in a path. An empty path
|
|
98
|
-
* invalid for both lookup and modification operations.
|
|
95
|
+
* the final node in a path. An empty path identifies the root node.
|
|
99
96
|
*
|
|
100
97
|
* @typeParam Id - The type of node IDs.
|
|
101
98
|
* @typeParam Node - The application-specific recursive node type.
|
|
@@ -124,20 +121,20 @@ export type TreeNodeApi<Id extends SerializableKey, Node extends TreeNode<Id, No
|
|
|
124
121
|
*/
|
|
125
122
|
getChildById(node: OpenBranchTreeNode<Id, Node>, id: Id): Node | undefined;
|
|
126
123
|
/**
|
|
127
|
-
* Applies a selector to the node at a path
|
|
124
|
+
* Applies a selector to the node at a path relative to `root`.
|
|
128
125
|
*
|
|
129
126
|
* The selector is called only after the complete path has been resolved.
|
|
130
127
|
* The selected node is not cloned.
|
|
131
128
|
*
|
|
132
|
-
* @param
|
|
133
|
-
* @param path -
|
|
129
|
+
* @param root - The node searching through.
|
|
130
|
+
* @param path - Path relative to root, with empty selecting the root.
|
|
134
131
|
* @param selector - The function to apply to the resolved node.
|
|
135
132
|
* @returns The selector result, or `undefined` when the path cannot be
|
|
136
133
|
* resolved or the selector returns `undefined`.
|
|
137
134
|
*/
|
|
138
|
-
getAtPath<Result>(
|
|
135
|
+
getAtPath<Result>(root: Node, path: readonly Id[], selector: (node: Node) => Result): Result | undefined;
|
|
139
136
|
/**
|
|
140
|
-
* Immutably replaces the node at a path
|
|
137
|
+
* Immutably replaces the node at a path relative to `root`.
|
|
141
138
|
*
|
|
142
139
|
* The modifier is called only after the complete path has been resolved.
|
|
143
140
|
* Returning `undefined` aborts the modification.
|
|
@@ -146,12 +143,12 @@ export type TreeNodeApi<Id extends SerializableKey, Node extends TreeNode<Id, No
|
|
|
146
143
|
* Unrelated nodes and arrays retain their original object identity. The
|
|
147
144
|
* input array is never modified.
|
|
148
145
|
*
|
|
149
|
-
* @param
|
|
150
|
-
* @param path - A
|
|
146
|
+
* @param root - The root node to modify.
|
|
147
|
+
* @param path - A path relative to root. An empty path selects the root.
|
|
151
148
|
* @param modifier - Produces the replacement node.
|
|
152
|
-
* @returns A new
|
|
149
|
+
* @returns A new root, or `undefined` when the path cannot be resolved or
|
|
153
150
|
* the modifier returns `undefined`.
|
|
154
151
|
*/
|
|
155
|
-
modifyAtPath(
|
|
152
|
+
modifyAtPath(root: Node, path: readonly Id[], modifier: (node: Node) => Node | undefined): Node | undefined;
|
|
156
153
|
};
|
|
157
154
|
//# sourceMappingURL=tree-node.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C
|
|
1
|
+
{"version":3,"file":"tree-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,MAAM,QAAQ,CAClB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B,YAAY,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;AAEhD,+BAA+B;AAC/B,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,eAAe,IAAI;IACrD,EAAE,EAAE,EAAE,CAAC;IACP,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,cAAc,CACxB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B,kBAAkB,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAC;AAK5D,uDAAuD;AACvD,MAAM,MAAM,kBAAkB,CAC5B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B;IACF,EAAE,EAAE,EAAE,CAAC;IACP,QAAQ,EAAE,IAAI,EAAE,CAAC;CAClB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,MAAM,oBAAoB,CAAC,EAAE,SAAS,eAAe,IAAI;IAC7D,EAAE,EAAE,EAAE,CAAC;IACP,QAAQ,EAAE,IAAI,CAAC;CAChB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,WAAW,CACrB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B;IACF,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IACpD,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC9D,cAAc,CACZ,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,GAC7B,IAAI,IAAI,oBAAoB,CAAC,EAAE,CAAC,CAAC;IACpC,YAAY,CACV,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,GAC7B,IAAI,IAAI,kBAAkB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAExC;;;;;;;;OAQG;IACH,WAAW,CAAC,IAAI,EAAE,kBAAkB,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEhE;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE,kBAAkB,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IAE3E;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,MAAM,EACd,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,SAAS,EAAE,EAAE,EACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,GAC/B,MAAM,GAAG,SAAS,CAAC;IAEtB;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CACV,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,SAAS,EAAE,EAAE,EACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,SAAS,GACzC,IAAI,GAAG,SAAS,CAAC;CACrB,CAAC"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { SerializableKey, TreeNode, TreeNodeApi } from '../../tree-surfer/index.js';
|
|
2
2
|
import { Effect, Intent } from '../domain/index.js';
|
|
3
3
|
import { CursorApi, State, StateApi } from '../../tree-surfer/index.js';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* By design "effect = intent + state", so it awaits based on the intent and
|
|
6
|
+
* the current state whether an effect should be executed.
|
|
7
|
+
*/
|
|
8
|
+
export type IntentToEffect<Id extends SerializableKey, Node extends TreeNode<Id, Node>> = (intent: Intent, state: State<Id, Node>) => Effect<Id, Node> | undefined;
|
|
9
|
+
export declare function createIntentToEffect<Id extends SerializableKey, Node extends TreeNode<Id, Node>>(stateApi: StateApi<Id, Node>, cursorApi: CursorApi<Id>, treeNodeApi: TreeNodeApi<Id, Node>): IntentToEffect<Id, Node>;
|
|
6
10
|
//# sourceMappingURL=intent-to-effect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-to-effect.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/application/intent-to-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,MAAM,EAAgB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"intent-to-effect.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/application/intent-to-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,MAAM,EAAgB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAGxE;;;GAGG;AACH,MAAM,MAAM,cAAc,CACxB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAC7B,CACF,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,KACnB,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC;AAElC,wBAAgB,oBAAoB,CAClC,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAE/B,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,EAC5B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,GACjC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAmE1B"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { parseCommand } from './parse-command.js';
|
|
2
|
-
// Factory method, since Apis are needed to derive intent
|
|
3
2
|
export function createIntentToEffect(stateApi, cursorApi, treeNodeApi) {
|
|
4
3
|
return (intent, state) => {
|
|
5
4
|
switch (intent.intentType) {
|
|
@@ -73,10 +72,6 @@ function normalBufferToEffectResult(updatedNormalBuffer) {
|
|
|
73
72
|
normalBuffer: updatedNormalBuffer,
|
|
74
73
|
},
|
|
75
74
|
};
|
|
76
|
-
case 'za':
|
|
77
|
-
return dispatchAction({
|
|
78
|
-
effectActionType: 'toggleFold',
|
|
79
|
-
});
|
|
80
75
|
case 'zc':
|
|
81
76
|
return dispatchAction({
|
|
82
77
|
effectActionType: 'fold',
|
|
@@ -98,12 +93,6 @@ function normalBufferToEffectResult(updatedNormalBuffer) {
|
|
|
98
93
|
function normalInteractRightToEffect(state, stateApi, cursorApi, treeNodeApi) {
|
|
99
94
|
const currentEntry = stateApi.getNodeAtCursor(state);
|
|
100
95
|
if (currentEntry === undefined) {
|
|
101
|
-
if (state.cursor.kind === 'fold') {
|
|
102
|
-
return {
|
|
103
|
-
effectType: 'peekFold',
|
|
104
|
-
parentPath: state.cursor.parentPath
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
96
|
return undefined;
|
|
108
97
|
}
|
|
109
98
|
const path = cursorApi.getPath(state.cursor);
|
|
@@ -126,7 +115,7 @@ function normalInteractRightToEffect(state, stateApi, cursorApi, treeNodeApi) {
|
|
|
126
115
|
return;
|
|
127
116
|
}
|
|
128
117
|
function normalInteractLeftToEffect(state) {
|
|
129
|
-
if (state.cursor.
|
|
118
|
+
if (state.cursor.length === 0) {
|
|
130
119
|
return undefined;
|
|
131
120
|
}
|
|
132
121
|
return dispatchAction({
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
import { UserInput,
|
|
2
|
-
|
|
1
|
+
import { UserInput, InputModeState, Intent } from '../domain/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* By design "intent = input + mode + modeState", so it interprets the key
|
|
4
|
+
* inputs depending on the mode and input so far. No context in terms of UI.
|
|
5
|
+
*
|
|
6
|
+
* @param userInput - the key user input.
|
|
7
|
+
* @param inputModeState - the current mode and the user inputs so far.
|
|
8
|
+
* @returns The user's intent.
|
|
9
|
+
*/
|
|
10
|
+
export declare function userInputToIntent(userInput: UserInput, inputModeState: InputModeState): Intent | undefined;
|
|
3
11
|
//# sourceMappingURL=user-input-to-intent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-input-to-intent.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/application/user-input-to-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"user-input-to-intent.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/application/user-input-to-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEvE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,cAAc,GAC7B,MAAM,GAAG,SAAS,CAQpB"}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* By design "intent = input + mode + modeState", so it interprets the key
|
|
3
|
+
* inputs depending on the mode and input so far. No context in terms of UI.
|
|
4
|
+
*
|
|
5
|
+
* @param userInput - the key user input.
|
|
6
|
+
* @param inputModeState - the current mode and the user inputs so far.
|
|
7
|
+
* @returns The user's intent.
|
|
8
|
+
*/
|
|
9
|
+
export function userInputToIntent(userInput, inputModeState) {
|
|
10
|
+
switch (inputModeState.inputMode) {
|
|
4
11
|
case 'normal':
|
|
5
|
-
return normalUserInputToIntent(userInput,
|
|
12
|
+
return normalUserInputToIntent(userInput, inputModeState.normalBuffer);
|
|
6
13
|
case 'command':
|
|
7
|
-
return commandUserInputToIntent(userInput,
|
|
14
|
+
return commandUserInputToIntent(userInput, inputModeState.commandLine);
|
|
8
15
|
}
|
|
9
16
|
}
|
|
10
17
|
function normalUserInputToIntent(userInput, normalBuffer) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { InputModeState } from './input-mode-state.js';
|
|
2
2
|
import { SerializableKey, TreeNode } from '../../tree-surfer/index.js';
|
|
3
|
-
export type Effect<Id extends SerializableKey,
|
|
3
|
+
export type Effect<Id extends SerializableKey, Node extends TreeNode<Id, Node>> = {
|
|
4
4
|
effectType: 'dispatchEffectAction';
|
|
5
|
-
action: EffectAction<Id,
|
|
5
|
+
action: EffectAction<Id, Node>;
|
|
6
6
|
} | {
|
|
7
7
|
effectType: 'loadBranchEntries';
|
|
8
8
|
path: Id[];
|
|
@@ -23,23 +23,21 @@ export type Effect<Id extends SerializableKey, BufferNode extends TreeNode<Id, B
|
|
|
23
23
|
exitMessage: string;
|
|
24
24
|
} | {
|
|
25
25
|
effectType: 'setInputState';
|
|
26
|
-
inputState:
|
|
26
|
+
inputState: InputModeState;
|
|
27
27
|
};
|
|
28
|
-
export type EffectAction<Id extends SerializableKey,
|
|
28
|
+
export type EffectAction<Id extends SerializableKey, Node extends TreeNode<Id, Node>> = {
|
|
29
29
|
effectActionType: 'nextEntry';
|
|
30
30
|
} | {
|
|
31
31
|
effectActionType: 'prevEntry';
|
|
32
32
|
} | {
|
|
33
33
|
effectActionType: 'setBranchEntries';
|
|
34
34
|
path: Id[];
|
|
35
|
-
entries:
|
|
35
|
+
entries: Node[] | null;
|
|
36
36
|
} | {
|
|
37
37
|
effectActionType: 'navigateToParent';
|
|
38
38
|
} | {
|
|
39
39
|
effectActionType: 'fold';
|
|
40
40
|
} | {
|
|
41
41
|
effectActionType: 'unfold';
|
|
42
|
-
} | {
|
|
43
|
-
effectActionType: 'toggleFold';
|
|
44
42
|
};
|
|
45
43
|
//# sourceMappingURL=effect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/domain/effect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/domain/effect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAEvE,MAAM,MAAM,MAAM,CAChB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAE7B;IACE,UAAU,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;CAChC,GACD;IACE,UAAU,EAAE,mBAAmB,CAAC;IAChC,IAAI,EAAE,EAAE,EAAE,CAAC;CACZ,GACD;IACE,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;CAC3B,GACD;IACE,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB,GACD;IACE,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,UAAU,EAAE,wBAAwB,CAAC;CACtC,GACD;IACE,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,GACD;IACE,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,cAAc,CAAC;CAC5B,CAAC;AAGN,MAAM,MAAM,YAAY,CACtB,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAE7B;IACE,gBAAgB,EAAE,WAAW,CAAC;CAC/B,GACD;IACE,gBAAgB,EAAE,WAAW,CAAC;CAC/B,GACD;IACE,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,IAAI,EAAE,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;CACxB,GACD;IACE,gBAAgB,EAAE,kBAAkB,CAAC;CACtC,GACD;IACE,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GACD;IACE,gBAAgB,EAAE,QAAQ,CAAC;CAC5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/domain/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/domain/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-mode-state.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/domain/input-mode-state.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB;IACE,SAAS,EAAE,QAAQ,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tree-node.arb.debug.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/tree-node/tree-node.arb.debug.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"input-state.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer-ui/domain/input-state.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB;IACE,SAAS,EAAE,QAAQ,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC"}
|
|
File without changes
|
|
File without changes
|