@dxos/app-graph 0.8.4-main.f9ba587 → 0.8.4-main.fffef41
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/lib/browser/index.mjs +249 -191
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +249 -191
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/graph-builder.d.ts +29 -18
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +25 -21
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +1 -1
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts +8 -10
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/src/testing.d.ts +3 -3
- package/dist/types/src/testing.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -34
- package/src/graph-builder.test.ts +90 -32
- package/src/graph-builder.ts +109 -60
- package/src/graph.test.ts +4 -4
- package/src/graph.ts +130 -89
- package/src/node.ts +5 -3
- package/src/signals-integration.test.ts +29 -28
- package/src/stories/EchoGraph.stories.tsx +49 -39
- package/src/stories/Tree.tsx +1 -1
- package/src/testing.ts +4 -4
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/graph.ts
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { Atom, Registry } from "@effect-atom/atom-react";
|
|
3
|
+
import * as Function from "effect/Function";
|
|
4
|
+
import * as Option from "effect/Option";
|
|
5
|
+
import * as Record from "effect/Record";
|
|
4
6
|
import { Event, Trigger } from "@dxos/async";
|
|
5
7
|
import { todo } from "@dxos/debug";
|
|
6
8
|
import { invariant } from "@dxos/invariant";
|
|
@@ -12,7 +14,7 @@ var getGraph = (node) => {
|
|
|
12
14
|
const graph = node[graphSymbol];
|
|
13
15
|
invariant(graph, "Node is not associated with a graph.", {
|
|
14
16
|
F: __dxlog_file,
|
|
15
|
-
L:
|
|
17
|
+
L: 29,
|
|
16
18
|
S: void 0,
|
|
17
19
|
A: [
|
|
18
20
|
"graph",
|
|
@@ -26,90 +28,95 @@ var ROOT_TYPE = "dxos.org/type/GraphRoot";
|
|
|
26
28
|
var ACTION_TYPE = "dxos.org/type/GraphAction";
|
|
27
29
|
var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
|
|
28
30
|
var Graph = class {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
31
|
+
onNodeChanged = new Event();
|
|
32
|
+
_onExpand;
|
|
33
|
+
_onInitialize;
|
|
34
|
+
_onRemoveNode;
|
|
35
|
+
_registry;
|
|
36
|
+
_expanded = Record.empty();
|
|
37
|
+
_initialized = Record.empty();
|
|
38
|
+
_initialEdges = Record.empty();
|
|
39
|
+
_initialNodes = Record.fromEntries([
|
|
40
|
+
[
|
|
41
|
+
ROOT_ID,
|
|
42
|
+
this._constructNode({
|
|
43
|
+
id: ROOT_ID,
|
|
44
|
+
type: ROOT_TYPE,
|
|
45
|
+
data: null,
|
|
46
|
+
properties: {}
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
]);
|
|
50
|
+
/** @internal */
|
|
51
|
+
_node = Atom.family((id) => {
|
|
52
|
+
const initial = Option.flatten(Record.get(this._initialNodes, id));
|
|
53
|
+
return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:node:${id}`));
|
|
54
|
+
});
|
|
55
|
+
_nodeOrThrow = Atom.family((id) => {
|
|
56
|
+
return Atom.make((get2) => {
|
|
57
|
+
const node = get2(this._node(id));
|
|
58
|
+
invariant(Option.isSome(node), `Node not available: ${id}`, {
|
|
59
|
+
F: __dxlog_file,
|
|
60
|
+
L: 267,
|
|
61
|
+
S: this,
|
|
62
|
+
A: [
|
|
63
|
+
"Option.isSome(node)",
|
|
64
|
+
"`Node not available: ${id}`"
|
|
65
|
+
]
|
|
63
66
|
});
|
|
67
|
+
return node.value;
|
|
64
68
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (node.properties.label) {
|
|
95
|
-
obj.label = node.properties.label;
|
|
96
|
-
}
|
|
97
|
-
if (nodes.length) {
|
|
98
|
-
obj.nodes = nodes.map((n) => {
|
|
99
|
-
const nextSeen = [
|
|
100
|
-
...seen,
|
|
101
|
-
node.id
|
|
102
|
-
];
|
|
103
|
-
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
104
|
-
}).filter(isNonNullable);
|
|
105
|
-
}
|
|
106
|
-
return obj;
|
|
69
|
+
});
|
|
70
|
+
_edges = Atom.family((id) => {
|
|
71
|
+
const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
|
|
72
|
+
inbound: [],
|
|
73
|
+
outbound: []
|
|
74
|
+
})));
|
|
75
|
+
return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));
|
|
76
|
+
});
|
|
77
|
+
// NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
|
|
78
|
+
// TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
|
|
79
|
+
_connections = Atom.family((key) => {
|
|
80
|
+
return Atom.make((get2) => {
|
|
81
|
+
const [id, relation] = key.split("$");
|
|
82
|
+
const edges = get2(this._edges(id));
|
|
83
|
+
return edges[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
|
|
84
|
+
}).pipe(Atom.withLabel(`graph:connections:${key}`));
|
|
85
|
+
});
|
|
86
|
+
_actions = Atom.family((id) => {
|
|
87
|
+
return Atom.make((get2) => {
|
|
88
|
+
return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
|
|
89
|
+
}).pipe(Atom.withLabel(`graph:actions:${id}`));
|
|
90
|
+
});
|
|
91
|
+
_json = Atom.family((id) => {
|
|
92
|
+
return Atom.make((get2) => {
|
|
93
|
+
const toJSON = (node, seen = []) => {
|
|
94
|
+
const nodes = get2(this.connections(node.id));
|
|
95
|
+
const obj = {
|
|
96
|
+
id: node.id,
|
|
97
|
+
type: node.type
|
|
107
98
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
99
|
+
if (node.properties.label) {
|
|
100
|
+
obj.label = node.properties.label;
|
|
101
|
+
}
|
|
102
|
+
if (nodes.length) {
|
|
103
|
+
obj.nodes = nodes.map((n) => {
|
|
104
|
+
const nextSeen = [
|
|
105
|
+
...seen,
|
|
106
|
+
node.id
|
|
107
|
+
];
|
|
108
|
+
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
109
|
+
}).filter(isNonNullable);
|
|
110
|
+
}
|
|
111
|
+
return obj;
|
|
112
|
+
};
|
|
113
|
+
const root = get2(this.nodeOrThrow(id));
|
|
114
|
+
return toJSON(root);
|
|
115
|
+
}).pipe(Atom.withLabel(`graph:json:${id}`));
|
|
116
|
+
});
|
|
117
|
+
constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
|
|
112
118
|
this._registry = registry ?? Registry.make();
|
|
119
|
+
this._onInitialize = onInitialize;
|
|
113
120
|
this._onExpand = onExpand;
|
|
114
121
|
this._onRemoveNode = onRemoveNode;
|
|
115
122
|
if (nodes) {
|
|
@@ -162,15 +169,22 @@ var Graph = class {
|
|
|
162
169
|
getEdges(id) {
|
|
163
170
|
return this._registry.get(this.edges(id));
|
|
164
171
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
async initialize(id) {
|
|
173
|
+
const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
|
|
174
|
+
log("initialize", {
|
|
175
|
+
id,
|
|
176
|
+
initialized
|
|
177
|
+
}, {
|
|
178
|
+
F: __dxlog_file,
|
|
179
|
+
L: 399,
|
|
180
|
+
S: this,
|
|
181
|
+
C: (f, a) => f(...a)
|
|
182
|
+
});
|
|
183
|
+
if (!initialized) {
|
|
184
|
+
await this._onInitialize?.(id);
|
|
185
|
+
Record.set(this._initialized, id, true);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
174
188
|
expand(id, relation = "outbound") {
|
|
175
189
|
const key = `${id}$${relation}`;
|
|
176
190
|
const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
|
|
@@ -179,7 +193,7 @@ var Graph = class {
|
|
|
179
193
|
expanded
|
|
180
194
|
}, {
|
|
181
195
|
F: __dxlog_file,
|
|
182
|
-
L:
|
|
196
|
+
L: 409,
|
|
183
197
|
S: this,
|
|
184
198
|
C: (f, a) => f(...a)
|
|
185
199
|
});
|
|
@@ -189,14 +203,14 @@ var Graph = class {
|
|
|
189
203
|
}
|
|
190
204
|
}
|
|
191
205
|
addNodes(nodes) {
|
|
192
|
-
|
|
206
|
+
Atom.batch(() => {
|
|
193
207
|
nodes.map((node) => this.addNode(node));
|
|
194
208
|
});
|
|
195
209
|
}
|
|
196
210
|
addNode({ nodes, edges, ...nodeArg }) {
|
|
197
211
|
const { id, type, data = null, properties = {} } = nodeArg;
|
|
198
|
-
const
|
|
199
|
-
const node = this._registry.get(
|
|
212
|
+
const nodeAtom = this._node(id);
|
|
213
|
+
const node = this._registry.get(nodeAtom);
|
|
200
214
|
Option.match(node, {
|
|
201
215
|
onSome: (node2) => {
|
|
202
216
|
const typeChanged = node2.type !== type;
|
|
@@ -209,7 +223,7 @@ var Graph = class {
|
|
|
209
223
|
propertiesChanged
|
|
210
224
|
}, {
|
|
211
225
|
F: __dxlog_file,
|
|
212
|
-
L:
|
|
226
|
+
L: 431,
|
|
213
227
|
S: this,
|
|
214
228
|
C: (f, a) => f(...a)
|
|
215
229
|
});
|
|
@@ -221,7 +235,7 @@ var Graph = class {
|
|
|
221
235
|
properties
|
|
222
236
|
}, {
|
|
223
237
|
F: __dxlog_file,
|
|
224
|
-
L:
|
|
238
|
+
L: 438,
|
|
225
239
|
S: this,
|
|
226
240
|
C: (f, a) => f(...a)
|
|
227
241
|
});
|
|
@@ -234,7 +248,7 @@ var Graph = class {
|
|
|
234
248
|
...properties
|
|
235
249
|
}
|
|
236
250
|
});
|
|
237
|
-
this._registry.set(
|
|
251
|
+
this._registry.set(nodeAtom, newNode);
|
|
238
252
|
this.onNodeChanged.emit({
|
|
239
253
|
id,
|
|
240
254
|
node: newNode
|
|
@@ -249,7 +263,7 @@ var Graph = class {
|
|
|
249
263
|
properties
|
|
250
264
|
}, {
|
|
251
265
|
F: __dxlog_file,
|
|
252
|
-
L:
|
|
266
|
+
L: 450,
|
|
253
267
|
S: this,
|
|
254
268
|
C: (f, a) => f(...a)
|
|
255
269
|
});
|
|
@@ -259,7 +273,7 @@ var Graph = class {
|
|
|
259
273
|
data,
|
|
260
274
|
properties
|
|
261
275
|
});
|
|
262
|
-
this._registry.set(
|
|
276
|
+
this._registry.set(nodeAtom, newNode);
|
|
263
277
|
this.onNodeChanged.emit({
|
|
264
278
|
id,
|
|
265
279
|
node: newNode
|
|
@@ -279,13 +293,13 @@ var Graph = class {
|
|
|
279
293
|
}
|
|
280
294
|
}
|
|
281
295
|
removeNodes(ids, edges = false) {
|
|
282
|
-
|
|
296
|
+
Atom.batch(() => {
|
|
283
297
|
ids.map((id) => this.removeNode(id, edges));
|
|
284
298
|
});
|
|
285
299
|
}
|
|
286
300
|
removeNode(id, edges = false) {
|
|
287
|
-
const
|
|
288
|
-
this._registry.set(
|
|
301
|
+
const nodeAtom = this._node(id);
|
|
302
|
+
this._registry.set(nodeAtom, Option.none());
|
|
289
303
|
this.onNodeChanged.emit({
|
|
290
304
|
id,
|
|
291
305
|
node: Option.none()
|
|
@@ -307,24 +321,24 @@ var Graph = class {
|
|
|
307
321
|
this._onRemoveNode?.(id);
|
|
308
322
|
}
|
|
309
323
|
addEdges(edges) {
|
|
310
|
-
|
|
324
|
+
Atom.batch(() => {
|
|
311
325
|
edges.map((edge) => this.addEdge(edge));
|
|
312
326
|
});
|
|
313
327
|
}
|
|
314
328
|
addEdge(edgeArg) {
|
|
315
|
-
const
|
|
316
|
-
const source = this._registry.get(
|
|
329
|
+
const sourceAtom = this._edges(edgeArg.source);
|
|
330
|
+
const source = this._registry.get(sourceAtom);
|
|
317
331
|
if (!source.outbound.includes(edgeArg.target)) {
|
|
318
332
|
log("add outbound edge", {
|
|
319
333
|
source: edgeArg.source,
|
|
320
334
|
target: edgeArg.target
|
|
321
335
|
}, {
|
|
322
336
|
F: __dxlog_file,
|
|
323
|
-
L:
|
|
337
|
+
L: 505,
|
|
324
338
|
S: this,
|
|
325
339
|
C: (f, a) => f(...a)
|
|
326
340
|
});
|
|
327
|
-
this._registry.set(
|
|
341
|
+
this._registry.set(sourceAtom, {
|
|
328
342
|
inbound: source.inbound,
|
|
329
343
|
outbound: [
|
|
330
344
|
...source.outbound,
|
|
@@ -332,19 +346,19 @@ var Graph = class {
|
|
|
332
346
|
]
|
|
333
347
|
});
|
|
334
348
|
}
|
|
335
|
-
const
|
|
336
|
-
const target = this._registry.get(
|
|
349
|
+
const targetAtom = this._edges(edgeArg.target);
|
|
350
|
+
const target = this._registry.get(targetAtom);
|
|
337
351
|
if (!target.inbound.includes(edgeArg.source)) {
|
|
338
352
|
log("add inbound edge", {
|
|
339
353
|
source: edgeArg.source,
|
|
340
354
|
target: edgeArg.target
|
|
341
355
|
}, {
|
|
342
356
|
F: __dxlog_file,
|
|
343
|
-
L:
|
|
357
|
+
L: 518,
|
|
344
358
|
S: this,
|
|
345
359
|
C: (f, a) => f(...a)
|
|
346
360
|
});
|
|
347
|
-
this._registry.set(
|
|
361
|
+
this._registry.set(targetAtom, {
|
|
348
362
|
inbound: [
|
|
349
363
|
...target.inbound,
|
|
350
364
|
edgeArg.source
|
|
@@ -354,30 +368,30 @@ var Graph = class {
|
|
|
354
368
|
}
|
|
355
369
|
}
|
|
356
370
|
removeEdges(edges, removeOrphans = false) {
|
|
357
|
-
|
|
371
|
+
Atom.batch(() => {
|
|
358
372
|
edges.map((edge) => this.removeEdge(edge, removeOrphans));
|
|
359
373
|
});
|
|
360
374
|
}
|
|
361
375
|
removeEdge(edgeArg, removeOrphans = false) {
|
|
362
|
-
const
|
|
363
|
-
const source = this._registry.get(
|
|
376
|
+
const sourceAtom = this._edges(edgeArg.source);
|
|
377
|
+
const source = this._registry.get(sourceAtom);
|
|
364
378
|
if (source.outbound.includes(edgeArg.target)) {
|
|
365
|
-
this._registry.set(
|
|
379
|
+
this._registry.set(sourceAtom, {
|
|
366
380
|
inbound: source.inbound,
|
|
367
381
|
outbound: source.outbound.filter((id) => id !== edgeArg.target)
|
|
368
382
|
});
|
|
369
383
|
}
|
|
370
|
-
const
|
|
371
|
-
const target = this._registry.get(
|
|
384
|
+
const targetAtom = this._edges(edgeArg.target);
|
|
385
|
+
const target = this._registry.get(targetAtom);
|
|
372
386
|
if (target.inbound.includes(edgeArg.source)) {
|
|
373
|
-
this._registry.set(
|
|
387
|
+
this._registry.set(targetAtom, {
|
|
374
388
|
inbound: target.inbound.filter((id) => id !== edgeArg.source),
|
|
375
389
|
outbound: target.outbound
|
|
376
390
|
});
|
|
377
391
|
}
|
|
378
392
|
if (removeOrphans) {
|
|
379
|
-
const source2 = this._registry.get(
|
|
380
|
-
const target2 = this._registry.get(
|
|
393
|
+
const source2 = this._registry.get(sourceAtom);
|
|
394
|
+
const target2 = this._registry.get(targetAtom);
|
|
381
395
|
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
|
|
382
396
|
this.removeNodes([
|
|
383
397
|
edgeArg.source
|
|
@@ -391,15 +405,15 @@ var Graph = class {
|
|
|
391
405
|
}
|
|
392
406
|
}
|
|
393
407
|
sortEdges(id, relation, order) {
|
|
394
|
-
const
|
|
395
|
-
const edges = this._registry.get(
|
|
408
|
+
const edgesAtom = this._edges(id);
|
|
409
|
+
const edges = this._registry.get(edgesAtom);
|
|
396
410
|
const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
|
|
397
411
|
const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
|
|
398
412
|
edges[relation].splice(0, edges[relation].length, ...[
|
|
399
413
|
...sorted,
|
|
400
414
|
...unsorted
|
|
401
415
|
]);
|
|
402
|
-
this._registry.set(
|
|
416
|
+
this._registry.set(edgesAtom, edges);
|
|
403
417
|
}
|
|
404
418
|
traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
|
|
405
419
|
if (path.includes(source)) {
|
|
@@ -423,7 +437,7 @@ var Graph = class {
|
|
|
423
437
|
]));
|
|
424
438
|
}
|
|
425
439
|
getPath({ source = "root", target }) {
|
|
426
|
-
return pipe(this.getNode(source), Option.flatMap((node) => {
|
|
440
|
+
return Function.pipe(this.getNode(source), Option.flatMap((node) => {
|
|
427
441
|
let found = Option.none();
|
|
428
442
|
this.traverse({
|
|
429
443
|
source: node.id,
|
|
@@ -467,57 +481,65 @@ var Graph = class {
|
|
|
467
481
|
};
|
|
468
482
|
|
|
469
483
|
// src/graph-builder.ts
|
|
470
|
-
import {
|
|
484
|
+
import { Atom as Atom2, Registry as Registry2 } from "@effect-atom/atom-react";
|
|
471
485
|
import { effect } from "@preact/signals-core";
|
|
472
|
-
import
|
|
486
|
+
import * as Array from "effect/Array";
|
|
487
|
+
import * as Function2 from "effect/Function";
|
|
488
|
+
import * as Option2 from "effect/Option";
|
|
489
|
+
import * as Record2 from "effect/Record";
|
|
473
490
|
import { log as log2 } from "@dxos/log";
|
|
474
491
|
import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
475
492
|
|
|
476
493
|
// src/node.ts
|
|
477
494
|
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
478
|
-
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
|
|
495
|
+
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ACTION_TYPE : false;
|
|
479
496
|
var actionGroupSymbol = Symbol("ActionGroup");
|
|
480
|
-
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
|
|
497
|
+
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
|
|
481
498
|
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
482
499
|
|
|
483
500
|
// src/graph-builder.ts
|
|
484
501
|
var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
485
502
|
var createExtension = (extension) => {
|
|
486
|
-
const { id, position = "static", relation = "outbound", connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
503
|
+
const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
487
504
|
const getId = (key) => `${id}/${key}`;
|
|
488
|
-
const
|
|
489
|
-
const
|
|
490
|
-
const
|
|
505
|
+
const resolver = _resolver && Atom2.family((id2) => _resolver(id2).pipe(Atom2.withLabel(`graph-builder:_resolver:${id2}`)));
|
|
506
|
+
const connector = _connector && Atom2.family((node) => _connector(node).pipe(Atom2.withLabel(`graph-builder:_connector:${id}`)));
|
|
507
|
+
const actionGroups = _actionGroups && Atom2.family((node) => _actionGroups(node).pipe(Atom2.withLabel(`graph-builder:_actionGroups:${id}`)));
|
|
508
|
+
const actions = _actions && Atom2.family((node) => _actions(node).pipe(Atom2.withLabel(`graph-builder:_actions:${id}`)));
|
|
491
509
|
return [
|
|
492
|
-
|
|
510
|
+
resolver ? {
|
|
511
|
+
id: getId("resolver"),
|
|
512
|
+
position,
|
|
513
|
+
resolver
|
|
514
|
+
} : void 0,
|
|
493
515
|
connector ? {
|
|
494
516
|
id: getId("connector"),
|
|
495
517
|
position,
|
|
496
518
|
relation,
|
|
497
|
-
connector:
|
|
519
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
498
520
|
try {
|
|
499
|
-
return
|
|
521
|
+
return get2(connector(node));
|
|
500
522
|
} catch {
|
|
501
523
|
log2.warn("Error in connector", {
|
|
502
524
|
id: getId("connector"),
|
|
503
525
|
node
|
|
504
526
|
}, {
|
|
505
527
|
F: __dxlog_file2,
|
|
506
|
-
L:
|
|
528
|
+
L: 114,
|
|
507
529
|
S: void 0,
|
|
508
530
|
C: (f, a) => f(...a)
|
|
509
531
|
});
|
|
510
532
|
return [];
|
|
511
533
|
}
|
|
512
|
-
}).pipe(
|
|
534
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
|
|
513
535
|
} : void 0,
|
|
514
536
|
actionGroups ? {
|
|
515
537
|
id: getId("actionGroups"),
|
|
516
538
|
position,
|
|
517
539
|
relation: "outbound",
|
|
518
|
-
connector:
|
|
540
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
519
541
|
try {
|
|
520
|
-
return
|
|
542
|
+
return get2(actionGroups(node)).map((arg) => ({
|
|
521
543
|
...arg,
|
|
522
544
|
data: actionGroupSymbol,
|
|
523
545
|
type: ACTION_GROUP_TYPE
|
|
@@ -528,21 +550,21 @@ var createExtension = (extension) => {
|
|
|
528
550
|
node
|
|
529
551
|
}, {
|
|
530
552
|
F: __dxlog_file2,
|
|
531
|
-
L:
|
|
553
|
+
L: 135,
|
|
532
554
|
S: void 0,
|
|
533
555
|
C: (f, a) => f(...a)
|
|
534
556
|
});
|
|
535
557
|
return [];
|
|
536
558
|
}
|
|
537
|
-
}).pipe(
|
|
559
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
538
560
|
} : void 0,
|
|
539
561
|
actions ? {
|
|
540
562
|
id: getId("actions"),
|
|
541
563
|
position,
|
|
542
564
|
relation: "outbound",
|
|
543
|
-
connector:
|
|
565
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
544
566
|
try {
|
|
545
|
-
return
|
|
567
|
+
return get2(actions(node)).map((arg) => ({
|
|
546
568
|
...arg,
|
|
547
569
|
type: ACTION_TYPE
|
|
548
570
|
}));
|
|
@@ -552,13 +574,13 @@ var createExtension = (extension) => {
|
|
|
552
574
|
node
|
|
553
575
|
}, {
|
|
554
576
|
F: __dxlog_file2,
|
|
555
|
-
L:
|
|
577
|
+
L: 152,
|
|
556
578
|
S: void 0,
|
|
557
579
|
C: (f, a) => f(...a)
|
|
558
580
|
});
|
|
559
581
|
return [];
|
|
560
582
|
}
|
|
561
|
-
}).pipe(
|
|
583
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
562
584
|
} : void 0
|
|
563
585
|
].filter(isNonNullable2);
|
|
564
586
|
};
|
|
@@ -576,32 +598,19 @@ var flattenExtensions = (extension, acc = []) => {
|
|
|
576
598
|
}
|
|
577
599
|
};
|
|
578
600
|
var GraphBuilder = class _GraphBuilder {
|
|
601
|
+
// TODO(wittjosiah): Use Context.
|
|
602
|
+
_subscriptions = /* @__PURE__ */ new Map();
|
|
603
|
+
_extensions = Atom2.make(Record2.empty()).pipe(Atom2.keepAlive, Atom2.withLabel("graph-builder:extensions"));
|
|
604
|
+
_initialized = {};
|
|
605
|
+
_registry;
|
|
606
|
+
_graph;
|
|
579
607
|
constructor({ registry, ...params } = {}) {
|
|
580
|
-
// TODO(wittjosiah): Use Context.
|
|
581
|
-
this._connectorSubscriptions = /* @__PURE__ */ new Map();
|
|
582
|
-
this._extensions = Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions"));
|
|
583
|
-
this._connectors = Rx2.family((key) => {
|
|
584
|
-
return Rx2.make((get) => {
|
|
585
|
-
const [id, relation] = key.split("+");
|
|
586
|
-
const node = this._graph.node(id);
|
|
587
|
-
return pipe2(
|
|
588
|
-
get(this._extensions),
|
|
589
|
-
Record2.values,
|
|
590
|
-
// TODO(wittjosiah): Sort on write rather than read.
|
|
591
|
-
Array.sortBy(byPosition),
|
|
592
|
-
Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
593
|
-
Array.map(({ connector }) => connector?.(node)),
|
|
594
|
-
Array.filter(isNonNullable2),
|
|
595
|
-
Array.flatMap((result) => get(result))
|
|
596
|
-
);
|
|
597
|
-
}).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
|
|
598
|
-
});
|
|
599
608
|
this._registry = registry ?? Registry2.make();
|
|
600
609
|
this._graph = new Graph({
|
|
601
610
|
...params,
|
|
602
611
|
registry: this._registry,
|
|
603
612
|
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
604
|
-
|
|
613
|
+
onInitialize: (id) => this._onInitialize(id),
|
|
605
614
|
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
606
615
|
});
|
|
607
616
|
}
|
|
@@ -671,9 +680,30 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
671
680
|
}
|
|
672
681
|
}
|
|
673
682
|
destroy() {
|
|
674
|
-
this.
|
|
675
|
-
this.
|
|
683
|
+
this._subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
684
|
+
this._subscriptions.clear();
|
|
676
685
|
}
|
|
686
|
+
_resolvers = Atom2.family((id) => {
|
|
687
|
+
return Atom2.make((get2) => {
|
|
688
|
+
return Function2.pipe(get2(this._extensions), Record2.values, Array.sortBy(byPosition), Array.map(({ resolver }) => resolver), Array.filter(isNonNullable2), Array.map((resolver) => get2(resolver(id))), Array.filter(isNonNullable2), Array.head);
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
_connectors = Atom2.family((key) => {
|
|
692
|
+
return Atom2.make((get2) => {
|
|
693
|
+
const [id, relation] = key.split("+");
|
|
694
|
+
const node = this._graph.node(id);
|
|
695
|
+
return Function2.pipe(
|
|
696
|
+
get2(this._extensions),
|
|
697
|
+
Record2.values,
|
|
698
|
+
// TODO(wittjosiah): Sort on write rather than read.
|
|
699
|
+
Array.sortBy(byPosition),
|
|
700
|
+
Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
701
|
+
Array.map(({ connector }) => connector?.(node)),
|
|
702
|
+
Array.filter(isNonNullable2),
|
|
703
|
+
Array.flatMap((result) => get2(result))
|
|
704
|
+
);
|
|
705
|
+
}).pipe(Atom2.withLabel(`graph-builder:connectors:${key}`));
|
|
706
|
+
});
|
|
677
707
|
_onExpand(id, relation) {
|
|
678
708
|
log2("onExpand", {
|
|
679
709
|
id,
|
|
@@ -681,7 +711,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
681
711
|
registry: getDebugName(this._registry)
|
|
682
712
|
}, {
|
|
683
713
|
F: __dxlog_file2,
|
|
684
|
-
L:
|
|
714
|
+
L: 329,
|
|
685
715
|
S: this,
|
|
686
716
|
C: (f, a) => f(...a)
|
|
687
717
|
});
|
|
@@ -698,12 +728,12 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
698
728
|
removed
|
|
699
729
|
}, {
|
|
700
730
|
F: __dxlog_file2,
|
|
701
|
-
L:
|
|
731
|
+
L: 340,
|
|
702
732
|
S: this,
|
|
703
733
|
C: (f, a) => f(...a)
|
|
704
734
|
});
|
|
705
735
|
const update = () => {
|
|
706
|
-
|
|
736
|
+
Atom2.batch(() => {
|
|
707
737
|
this._graph.removeEdges(removed.map((target) => ({
|
|
708
738
|
source: id,
|
|
709
739
|
target
|
|
@@ -727,34 +757,62 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
727
757
|
}, {
|
|
728
758
|
immediate: true
|
|
729
759
|
});
|
|
730
|
-
this.
|
|
760
|
+
this._subscriptions.set(id, cancel);
|
|
761
|
+
}
|
|
762
|
+
// TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
|
|
763
|
+
async _onInitialize(id) {
|
|
764
|
+
log2("onInitialize", {
|
|
765
|
+
id
|
|
766
|
+
}, {
|
|
767
|
+
F: __dxlog_file2,
|
|
768
|
+
L: 377,
|
|
769
|
+
S: this,
|
|
770
|
+
C: (f, a) => f(...a)
|
|
771
|
+
});
|
|
772
|
+
const resolver = this._resolvers(id);
|
|
773
|
+
const cancel = this._registry.subscribe(resolver, (node) => {
|
|
774
|
+
const trigger = this._initialized[id];
|
|
775
|
+
Option2.match(node, {
|
|
776
|
+
onSome: (node2) => {
|
|
777
|
+
this._graph.addNodes([
|
|
778
|
+
node2
|
|
779
|
+
]);
|
|
780
|
+
trigger?.wake();
|
|
781
|
+
},
|
|
782
|
+
onNone: () => {
|
|
783
|
+
trigger?.wake();
|
|
784
|
+
this._graph.removeNodes([
|
|
785
|
+
id
|
|
786
|
+
]);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
}, {
|
|
790
|
+
immediate: true
|
|
791
|
+
});
|
|
792
|
+
this._subscriptions.set(id, cancel);
|
|
731
793
|
}
|
|
732
|
-
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
733
|
-
// private async _onInitialize(id: string) {
|
|
734
|
-
// log('onInitialize', { id });
|
|
735
|
-
// }
|
|
736
794
|
_onRemoveNode(id) {
|
|
737
|
-
this.
|
|
738
|
-
this.
|
|
795
|
+
this._subscriptions.get(id)?.();
|
|
796
|
+
this._subscriptions.delete(id);
|
|
739
797
|
}
|
|
740
798
|
};
|
|
741
|
-
var
|
|
742
|
-
return
|
|
799
|
+
var atomFromSignal = (cb) => {
|
|
800
|
+
return Atom2.make((get2) => {
|
|
743
801
|
const dispose = effect(() => {
|
|
744
|
-
|
|
802
|
+
get2.setSelf(cb());
|
|
745
803
|
});
|
|
746
|
-
|
|
804
|
+
get2.addFinalizer(() => dispose());
|
|
747
805
|
return cb();
|
|
748
806
|
});
|
|
749
807
|
};
|
|
750
|
-
var observableFamily =
|
|
751
|
-
return
|
|
752
|
-
const subscription = observable.subscribe((value) =>
|
|
753
|
-
|
|
808
|
+
var observableFamily = Atom2.family((observable) => {
|
|
809
|
+
return Atom2.make((get2) => {
|
|
810
|
+
const subscription = observable.subscribe((value) => get2.setSelf(value));
|
|
811
|
+
get2.addFinalizer(() => subscription.unsubscribe());
|
|
754
812
|
return observable.get();
|
|
755
813
|
});
|
|
756
814
|
});
|
|
757
|
-
var
|
|
815
|
+
var atomFromObservable = (observable) => {
|
|
758
816
|
return observableFamily(observable);
|
|
759
817
|
};
|
|
760
818
|
export {
|
|
@@ -765,14 +823,14 @@ export {
|
|
|
765
823
|
ROOT_ID,
|
|
766
824
|
ROOT_TYPE,
|
|
767
825
|
actionGroupSymbol,
|
|
826
|
+
atomFromObservable,
|
|
827
|
+
atomFromSignal,
|
|
768
828
|
createExtension,
|
|
769
829
|
flattenExtensions,
|
|
770
830
|
getGraph,
|
|
771
831
|
isAction,
|
|
772
832
|
isActionGroup,
|
|
773
833
|
isActionLike,
|
|
774
|
-
isGraphNode
|
|
775
|
-
rxFromObservable,
|
|
776
|
-
rxFromSignal
|
|
834
|
+
isGraphNode
|
|
777
835
|
};
|
|
778
836
|
//# sourceMappingURL=index.mjs.map
|