@dxos/app-graph 0.6.3-main.9e4e207 → 0.6.3-next.2f65b78

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.
@@ -1,310 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { signal } from '@preact/signals-core';
6
- import { expect } from 'chai';
7
-
8
- import { describe, test } from '@dxos/test';
9
-
10
- import { ACTION_TYPE } from './graph';
11
- import { GraphBuilder, createExtension, memoize } from './graph-builder';
12
- import { type Node } from './node';
13
-
14
- const exampleId = (id: number) => `dx:test:${id}`;
15
- const EXAMPLE_ID = exampleId(1);
16
- const EXAMPLE_TYPE = 'dxos.org/type/example';
17
-
18
- describe('GraphBuilder', () => {
19
- describe('resolver', () => {
20
- test('works', () => {
21
- const builder = new GraphBuilder();
22
- const graph = builder.graph;
23
-
24
- {
25
- const node = graph.findNode(EXAMPLE_ID);
26
- expect(node).to.be.undefined;
27
- }
28
-
29
- builder.addExtension(
30
- createExtension({ id: 'resolver', resolver: () => ({ id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: 1 }) }),
31
- );
32
-
33
- {
34
- const node = graph.findNode(EXAMPLE_ID);
35
- expect(node?.id).to.equal(EXAMPLE_ID);
36
- expect(node?.type).to.equal(EXAMPLE_TYPE);
37
- expect(node?.data).to.equal(1);
38
- }
39
- });
40
-
41
- test('updates', () => {
42
- const builder = new GraphBuilder();
43
- const name = signal('default');
44
- builder.addExtension(
45
- createExtension({ id: 'resolver', resolver: () => ({ id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: name.value }) }),
46
- );
47
- const graph = builder.graph;
48
-
49
- const node = graph.findNode(EXAMPLE_ID);
50
- expect(node?.data).to.equal('default');
51
-
52
- name.value = 'updated';
53
- expect(node?.data).to.equal('updated');
54
- });
55
-
56
- test('memoize', () => {
57
- const builder = new GraphBuilder();
58
- const name = signal('default');
59
- let count = 0;
60
- let memoizedCount = 0;
61
- builder.addExtension(
62
- createExtension({
63
- id: 'resolver',
64
- resolver: () => {
65
- count++;
66
- memoize(() => {
67
- memoizedCount++;
68
- });
69
-
70
- return { id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: name.value };
71
- },
72
- }),
73
- );
74
- const graph = builder.graph;
75
-
76
- const node = graph.findNode(EXAMPLE_ID);
77
- expect(node?.data).to.equal('default');
78
- expect(count).to.equal(1);
79
- expect(memoizedCount).to.equal(1);
80
-
81
- name!.value = 'one';
82
- name!.value = 'two';
83
- name!.value = 'three';
84
-
85
- expect(node?.data).to.equal('three');
86
- expect(count).to.equal(4);
87
- expect(memoizedCount).to.equal(1);
88
- });
89
- });
90
-
91
- describe('connector', () => {
92
- test('works', () => {
93
- const builder = new GraphBuilder();
94
- const graph = builder.graph;
95
- builder.addExtension(
96
- createExtension({
97
- id: 'outbound-connector',
98
- connector: () => [{ id: 'child', type: EXAMPLE_TYPE, data: 2 }],
99
- }),
100
- );
101
- builder.addExtension(
102
- createExtension({
103
- id: 'inbound-connector',
104
- relation: 'inbound',
105
- connector: () => [{ id: 'parent', type: EXAMPLE_TYPE, data: 0 }],
106
- }),
107
- );
108
-
109
- const outbound = graph.nodes(graph.root);
110
- const inbound = graph.nodes(graph.root, { relation: 'inbound' });
111
-
112
- expect(outbound).has.length(1);
113
- expect(outbound?.[0].id).to.equal('child');
114
- expect(outbound?.[0].data).to.equal(2);
115
- expect(inbound).has.length(1);
116
- expect(inbound?.[0].id).to.equal('parent');
117
- expect(inbound?.[0].data).to.equal(0);
118
- });
119
-
120
- test('updates', () => {
121
- const name = signal('default');
122
- const builder = new GraphBuilder();
123
- builder.addExtension(
124
- createExtension({
125
- id: 'connector',
126
- connector: () => [{ id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: name, properties: { label: name.value } }],
127
- }),
128
- );
129
- const graph = builder.graph;
130
-
131
- const [node] = graph.nodes(graph.root);
132
- expect(node.properties.label).to.equal('default');
133
-
134
- name.value = 'updated';
135
- expect(node.properties.label).to.equal('updated');
136
- });
137
-
138
- test('removes', () => {
139
- const nodes = signal([
140
- { id: exampleId(1), type: EXAMPLE_TYPE, data: 1 },
141
- { id: exampleId(2), type: EXAMPLE_TYPE, data: 2 },
142
- ]);
143
-
144
- const builder = new GraphBuilder();
145
- builder.addExtension(
146
- createExtension({
147
- id: 'connector',
148
- connector: () => nodes.value,
149
- }),
150
- );
151
- const graph = builder.graph;
152
-
153
- {
154
- const nodes = graph.nodes(graph.root);
155
- expect(nodes).has.length(2);
156
- expect(nodes[0].id).to.equal(exampleId(1));
157
- }
158
-
159
- nodes.value = [{ id: exampleId(3), type: EXAMPLE_TYPE, data: 3 }];
160
-
161
- {
162
- const nodes = graph.nodes(graph.root);
163
- expect(nodes).has.length(1);
164
- expect(nodes[0].id).to.equal(exampleId(3));
165
- expect(graph.findNode(exampleId(1))).to.be.undefined;
166
- }
167
- });
168
-
169
- test('filters by type', () => {
170
- const builder = new GraphBuilder();
171
- builder.addExtension(
172
- createExtension({
173
- id: 'actions',
174
- connector: () => [{ id: 'not-action', type: EXAMPLE_TYPE, data: 1 }],
175
- actions: () => [{ id: 'action', data: () => {} }],
176
- }),
177
- );
178
- const graph = builder.graph;
179
-
180
- const actions = graph.actions(graph.root);
181
- expect(actions).has.length(1);
182
- expect(actions?.[0].id).to.equal('action');
183
- expect(actions?.[0].type).to.equal(ACTION_TYPE);
184
-
185
- const node = graph.findNode('not-action', EXAMPLE_TYPE);
186
- expect(node).to.be.undefined;
187
-
188
- const nodes = graph.nodes(graph.root);
189
- expect(nodes).has.length(1);
190
- expect(nodes?.[0].id).to.equal('not-action');
191
- expect(nodes?.[0].data).to.equal(1);
192
- });
193
-
194
- test('filters by callback', () => {
195
- const builder = new GraphBuilder();
196
- builder.addExtension(
197
- createExtension({
198
- id: 'filtered-connector',
199
- filter: (node): node is Node<null> => node.id === 'root',
200
- connector: () => [{ id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: 1 }],
201
- }),
202
- );
203
- const graph = builder.graph;
204
-
205
- const [node1] = graph.nodes(graph.root);
206
- expect(node1?.id).to.equal(EXAMPLE_ID);
207
-
208
- const nodes = graph.nodes(node1);
209
- expect(nodes).has.length(0);
210
- });
211
-
212
- test('memoize', () => {
213
- const builder = new GraphBuilder();
214
- const name = signal('default');
215
- let count = 0;
216
- let memoizedCount = 0;
217
- builder.addExtension(
218
- createExtension({
219
- id: 'connector',
220
- connector: () => {
221
- count++;
222
- memoize(() => {
223
- memoizedCount++;
224
- });
225
-
226
- return [{ id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: name, properties: { label: name.value } }];
227
- },
228
- }),
229
- );
230
- const graph = builder.graph;
231
-
232
- const [node] = graph.nodes(graph.root);
233
- expect(node.properties.label).to.equal('default');
234
- expect(count).to.equal(1);
235
- expect(memoizedCount).to.equal(1);
236
-
237
- name!.value = 'one';
238
- name!.value = 'two';
239
- name!.value = 'three';
240
-
241
- expect(node.properties.label).to.equal('three');
242
- expect(count).to.equal(4);
243
- expect(memoizedCount).to.equal(1);
244
- });
245
- });
246
-
247
- describe('traverse', () => {
248
- test('works', async () => {
249
- const builder = new GraphBuilder();
250
- builder.addExtension(
251
- createExtension({
252
- id: 'connector',
253
- connector: ({ node }) => {
254
- const data = node.data ? node.data + 1 : 1;
255
- return data > 5 ? [] : [{ id: `node-${data}`, type: EXAMPLE_TYPE, data }];
256
- },
257
- }),
258
- );
259
- const graph = builder.graph;
260
-
261
- let count = 0;
262
- await builder.traverse({
263
- node: graph.root,
264
- visitor: () => {
265
- count++;
266
- },
267
- });
268
-
269
- expect(count).to.equal(6);
270
- });
271
- });
272
-
273
- describe('multiples', () => {
274
- test('one of each with multiple memos', () => {
275
- const name = signal('default');
276
- const builder = new GraphBuilder();
277
- builder.addExtension(
278
- createExtension({
279
- id: 'extension',
280
- resolver: () => {
281
- const data = memoize(() => Math.random());
282
- return { id: EXAMPLE_ID, type: EXAMPLE_TYPE, data, properties: { name: name.value } };
283
- },
284
- connector: () => {
285
- const a = memoize(() => Math.random());
286
- const b = memoize(() => Math.random());
287
- const c = Math.random();
288
- return [{ id: `${EXAMPLE_ID}-child`, type: EXAMPLE_TYPE, data: { a, b, c } }];
289
- },
290
- }),
291
- );
292
- const graph = builder.graph;
293
-
294
- const one = graph.findNode(EXAMPLE_ID);
295
- const initialData = one!.data;
296
- const two = graph.nodes(one!)[0];
297
- const initialA = two?.data.a;
298
- const initialB = two?.data.b;
299
- const initialC = two?.data.c;
300
-
301
- name.value = 'updated';
302
-
303
- expect(one?.properties.name).to.equal('updated');
304
- expect(one?.data).to.equal(initialData);
305
- expect(two?.data.a).to.equal(initialA);
306
- expect(two?.data.b).to.equal(initialB);
307
- expect(two?.data.c).not.to.equal(initialC);
308
- });
309
- });
310
- });