@dxos/app-graph 0.8.4-main.5ad4a44 → 0.8.4-main.66e292d
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 +201 -223
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +201 -223
- 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 +15 -15
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +18 -18
- 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.map +1 -1
- package/dist/types/src/testing.d.ts +3 -4
- package/dist/types/src/testing.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -22
- package/src/graph-builder.test.ts +26 -26
- package/src/graph-builder.ts +44 -42
- package/src/graph.test.ts +2 -2
- package/src/graph.ts +111 -71
- package/src/node.ts +1 -1
- package/src/signals-integration.test.ts +32 -27
- package/src/stories/EchoGraph.stories.tsx +32 -33
- package/src/stories/Tree.tsx +1 -1
- package/src/testing.ts +6 -5
- package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
- package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
- package/src/experimental/graph-projections.test.ts +0 -56
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/graph.ts
|
|
2
|
-
import {
|
|
2
|
+
import { Atom, Registry } from "@effect-atom/atom-react";
|
|
3
3
|
import * as Function from "effect/Function";
|
|
4
4
|
import * as Option from "effect/Option";
|
|
5
5
|
import * as Record from "effect/Record";
|
|
@@ -8,26 +8,13 @@ import { todo } from "@dxos/debug";
|
|
|
8
8
|
import { invariant } from "@dxos/invariant";
|
|
9
9
|
import { log } from "@dxos/log";
|
|
10
10
|
import { isNonNullable } from "@dxos/util";
|
|
11
|
-
function _define_property(obj, key, value) {
|
|
12
|
-
if (key in obj) {
|
|
13
|
-
Object.defineProperty(obj, key, {
|
|
14
|
-
value,
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true
|
|
18
|
-
});
|
|
19
|
-
} else {
|
|
20
|
-
obj[key] = value;
|
|
21
|
-
}
|
|
22
|
-
return obj;
|
|
23
|
-
}
|
|
24
11
|
var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
25
12
|
var graphSymbol = Symbol("graph");
|
|
26
13
|
var getGraph = (node) => {
|
|
27
14
|
const graph = node[graphSymbol];
|
|
28
15
|
invariant(graph, "Node is not associated with a graph.", {
|
|
29
16
|
F: __dxlog_file,
|
|
30
|
-
L:
|
|
17
|
+
L: 29,
|
|
31
18
|
S: void 0,
|
|
32
19
|
A: [
|
|
33
20
|
"graph",
|
|
@@ -41,6 +28,108 @@ var ROOT_TYPE = "dxos.org/type/GraphRoot";
|
|
|
41
28
|
var ACTION_TYPE = "dxos.org/type/GraphAction";
|
|
42
29
|
var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
|
|
43
30
|
var Graph = class {
|
|
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
|
+
]
|
|
66
|
+
});
|
|
67
|
+
return node.value;
|
|
68
|
+
});
|
|
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
|
|
98
|
+
};
|
|
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 } = {}) {
|
|
118
|
+
this._registry = registry ?? Registry.make();
|
|
119
|
+
this._onInitialize = onInitialize;
|
|
120
|
+
this._onExpand = onExpand;
|
|
121
|
+
this._onRemoveNode = onRemoveNode;
|
|
122
|
+
if (nodes) {
|
|
123
|
+
nodes.forEach((node) => {
|
|
124
|
+
Record.set(this._initialNodes, node.id, this._constructNode(node));
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (edges) {
|
|
128
|
+
Object.entries(edges).forEach(([source, edges2]) => {
|
|
129
|
+
Record.set(this._initialEdges, source, edges2);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
44
133
|
toJSON(id = ROOT_ID) {
|
|
45
134
|
return this._registry.get(this._json(id));
|
|
46
135
|
}
|
|
@@ -87,7 +176,7 @@ var Graph = class {
|
|
|
87
176
|
initialized
|
|
88
177
|
}, {
|
|
89
178
|
F: __dxlog_file,
|
|
90
|
-
L:
|
|
179
|
+
L: 399,
|
|
91
180
|
S: this,
|
|
92
181
|
C: (f, a) => f(...a)
|
|
93
182
|
});
|
|
@@ -104,7 +193,7 @@ var Graph = class {
|
|
|
104
193
|
expanded
|
|
105
194
|
}, {
|
|
106
195
|
F: __dxlog_file,
|
|
107
|
-
L:
|
|
196
|
+
L: 409,
|
|
108
197
|
S: this,
|
|
109
198
|
C: (f, a) => f(...a)
|
|
110
199
|
});
|
|
@@ -114,14 +203,14 @@ var Graph = class {
|
|
|
114
203
|
}
|
|
115
204
|
}
|
|
116
205
|
addNodes(nodes) {
|
|
117
|
-
|
|
206
|
+
Atom.batch(() => {
|
|
118
207
|
nodes.map((node) => this.addNode(node));
|
|
119
208
|
});
|
|
120
209
|
}
|
|
121
210
|
addNode({ nodes, edges, ...nodeArg }) {
|
|
122
211
|
const { id, type, data = null, properties = {} } = nodeArg;
|
|
123
|
-
const
|
|
124
|
-
const node = this._registry.get(
|
|
212
|
+
const nodeAtom = this._node(id);
|
|
213
|
+
const node = this._registry.get(nodeAtom);
|
|
125
214
|
Option.match(node, {
|
|
126
215
|
onSome: (node2) => {
|
|
127
216
|
const typeChanged = node2.type !== type;
|
|
@@ -134,7 +223,7 @@ var Graph = class {
|
|
|
134
223
|
propertiesChanged
|
|
135
224
|
}, {
|
|
136
225
|
F: __dxlog_file,
|
|
137
|
-
L:
|
|
226
|
+
L: 431,
|
|
138
227
|
S: this,
|
|
139
228
|
C: (f, a) => f(...a)
|
|
140
229
|
});
|
|
@@ -146,7 +235,7 @@ var Graph = class {
|
|
|
146
235
|
properties
|
|
147
236
|
}, {
|
|
148
237
|
F: __dxlog_file,
|
|
149
|
-
L:
|
|
238
|
+
L: 438,
|
|
150
239
|
S: this,
|
|
151
240
|
C: (f, a) => f(...a)
|
|
152
241
|
});
|
|
@@ -159,7 +248,7 @@ var Graph = class {
|
|
|
159
248
|
...properties
|
|
160
249
|
}
|
|
161
250
|
});
|
|
162
|
-
this._registry.set(
|
|
251
|
+
this._registry.set(nodeAtom, newNode);
|
|
163
252
|
this.onNodeChanged.emit({
|
|
164
253
|
id,
|
|
165
254
|
node: newNode
|
|
@@ -174,7 +263,7 @@ var Graph = class {
|
|
|
174
263
|
properties
|
|
175
264
|
}, {
|
|
176
265
|
F: __dxlog_file,
|
|
177
|
-
L:
|
|
266
|
+
L: 450,
|
|
178
267
|
S: this,
|
|
179
268
|
C: (f, a) => f(...a)
|
|
180
269
|
});
|
|
@@ -184,7 +273,7 @@ var Graph = class {
|
|
|
184
273
|
data,
|
|
185
274
|
properties
|
|
186
275
|
});
|
|
187
|
-
this._registry.set(
|
|
276
|
+
this._registry.set(nodeAtom, newNode);
|
|
188
277
|
this.onNodeChanged.emit({
|
|
189
278
|
id,
|
|
190
279
|
node: newNode
|
|
@@ -204,13 +293,13 @@ var Graph = class {
|
|
|
204
293
|
}
|
|
205
294
|
}
|
|
206
295
|
removeNodes(ids, edges = false) {
|
|
207
|
-
|
|
296
|
+
Atom.batch(() => {
|
|
208
297
|
ids.map((id) => this.removeNode(id, edges));
|
|
209
298
|
});
|
|
210
299
|
}
|
|
211
300
|
removeNode(id, edges = false) {
|
|
212
|
-
const
|
|
213
|
-
this._registry.set(
|
|
301
|
+
const nodeAtom = this._node(id);
|
|
302
|
+
this._registry.set(nodeAtom, Option.none());
|
|
214
303
|
this.onNodeChanged.emit({
|
|
215
304
|
id,
|
|
216
305
|
node: Option.none()
|
|
@@ -232,24 +321,24 @@ var Graph = class {
|
|
|
232
321
|
this._onRemoveNode?.(id);
|
|
233
322
|
}
|
|
234
323
|
addEdges(edges) {
|
|
235
|
-
|
|
324
|
+
Atom.batch(() => {
|
|
236
325
|
edges.map((edge) => this.addEdge(edge));
|
|
237
326
|
});
|
|
238
327
|
}
|
|
239
328
|
addEdge(edgeArg) {
|
|
240
|
-
const
|
|
241
|
-
const source = this._registry.get(
|
|
329
|
+
const sourceAtom = this._edges(edgeArg.source);
|
|
330
|
+
const source = this._registry.get(sourceAtom);
|
|
242
331
|
if (!source.outbound.includes(edgeArg.target)) {
|
|
243
332
|
log("add outbound edge", {
|
|
244
333
|
source: edgeArg.source,
|
|
245
334
|
target: edgeArg.target
|
|
246
335
|
}, {
|
|
247
336
|
F: __dxlog_file,
|
|
248
|
-
L:
|
|
337
|
+
L: 505,
|
|
249
338
|
S: this,
|
|
250
339
|
C: (f, a) => f(...a)
|
|
251
340
|
});
|
|
252
|
-
this._registry.set(
|
|
341
|
+
this._registry.set(sourceAtom, {
|
|
253
342
|
inbound: source.inbound,
|
|
254
343
|
outbound: [
|
|
255
344
|
...source.outbound,
|
|
@@ -257,19 +346,19 @@ var Graph = class {
|
|
|
257
346
|
]
|
|
258
347
|
});
|
|
259
348
|
}
|
|
260
|
-
const
|
|
261
|
-
const target = this._registry.get(
|
|
349
|
+
const targetAtom = this._edges(edgeArg.target);
|
|
350
|
+
const target = this._registry.get(targetAtom);
|
|
262
351
|
if (!target.inbound.includes(edgeArg.source)) {
|
|
263
352
|
log("add inbound edge", {
|
|
264
353
|
source: edgeArg.source,
|
|
265
354
|
target: edgeArg.target
|
|
266
355
|
}, {
|
|
267
356
|
F: __dxlog_file,
|
|
268
|
-
L:
|
|
357
|
+
L: 518,
|
|
269
358
|
S: this,
|
|
270
359
|
C: (f, a) => f(...a)
|
|
271
360
|
});
|
|
272
|
-
this._registry.set(
|
|
361
|
+
this._registry.set(targetAtom, {
|
|
273
362
|
inbound: [
|
|
274
363
|
...target.inbound,
|
|
275
364
|
edgeArg.source
|
|
@@ -279,30 +368,30 @@ var Graph = class {
|
|
|
279
368
|
}
|
|
280
369
|
}
|
|
281
370
|
removeEdges(edges, removeOrphans = false) {
|
|
282
|
-
|
|
371
|
+
Atom.batch(() => {
|
|
283
372
|
edges.map((edge) => this.removeEdge(edge, removeOrphans));
|
|
284
373
|
});
|
|
285
374
|
}
|
|
286
375
|
removeEdge(edgeArg, removeOrphans = false) {
|
|
287
|
-
const
|
|
288
|
-
const source = this._registry.get(
|
|
376
|
+
const sourceAtom = this._edges(edgeArg.source);
|
|
377
|
+
const source = this._registry.get(sourceAtom);
|
|
289
378
|
if (source.outbound.includes(edgeArg.target)) {
|
|
290
|
-
this._registry.set(
|
|
379
|
+
this._registry.set(sourceAtom, {
|
|
291
380
|
inbound: source.inbound,
|
|
292
381
|
outbound: source.outbound.filter((id) => id !== edgeArg.target)
|
|
293
382
|
});
|
|
294
383
|
}
|
|
295
|
-
const
|
|
296
|
-
const target = this._registry.get(
|
|
384
|
+
const targetAtom = this._edges(edgeArg.target);
|
|
385
|
+
const target = this._registry.get(targetAtom);
|
|
297
386
|
if (target.inbound.includes(edgeArg.source)) {
|
|
298
|
-
this._registry.set(
|
|
387
|
+
this._registry.set(targetAtom, {
|
|
299
388
|
inbound: target.inbound.filter((id) => id !== edgeArg.source),
|
|
300
389
|
outbound: target.outbound
|
|
301
390
|
});
|
|
302
391
|
}
|
|
303
392
|
if (removeOrphans) {
|
|
304
|
-
const source2 = this._registry.get(
|
|
305
|
-
const target2 = this._registry.get(
|
|
393
|
+
const source2 = this._registry.get(sourceAtom);
|
|
394
|
+
const target2 = this._registry.get(targetAtom);
|
|
306
395
|
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
|
|
307
396
|
this.removeNodes([
|
|
308
397
|
edgeArg.source
|
|
@@ -316,15 +405,15 @@ var Graph = class {
|
|
|
316
405
|
}
|
|
317
406
|
}
|
|
318
407
|
sortEdges(id, relation, order) {
|
|
319
|
-
const
|
|
320
|
-
const edges = this._registry.get(
|
|
408
|
+
const edgesAtom = this._edges(id);
|
|
409
|
+
const edges = this._registry.get(edgesAtom);
|
|
321
410
|
const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
|
|
322
411
|
const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
|
|
323
412
|
edges[relation].splice(0, edges[relation].length, ...[
|
|
324
413
|
...sorted,
|
|
325
414
|
...unsorted
|
|
326
415
|
]);
|
|
327
|
-
this._registry.set(
|
|
416
|
+
this._registry.set(edgesAtom, edges);
|
|
328
417
|
}
|
|
329
418
|
traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
|
|
330
419
|
if (path.includes(source)) {
|
|
@@ -389,109 +478,10 @@ var Graph = class {
|
|
|
389
478
|
...node
|
|
390
479
|
});
|
|
391
480
|
}
|
|
392
|
-
constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
|
|
393
|
-
_define_property(this, "onNodeChanged", new Event());
|
|
394
|
-
_define_property(this, "_onExpand", void 0);
|
|
395
|
-
_define_property(this, "_onInitialize", void 0);
|
|
396
|
-
_define_property(this, "_onRemoveNode", void 0);
|
|
397
|
-
_define_property(this, "_registry", void 0);
|
|
398
|
-
_define_property(this, "_expanded", Record.empty());
|
|
399
|
-
_define_property(this, "_initialized", Record.empty());
|
|
400
|
-
_define_property(this, "_initialEdges", Record.empty());
|
|
401
|
-
_define_property(this, "_initialNodes", Record.fromEntries([
|
|
402
|
-
[
|
|
403
|
-
ROOT_ID,
|
|
404
|
-
this._constructNode({
|
|
405
|
-
id: ROOT_ID,
|
|
406
|
-
type: ROOT_TYPE,
|
|
407
|
-
data: null,
|
|
408
|
-
properties: {}
|
|
409
|
-
})
|
|
410
|
-
]
|
|
411
|
-
]));
|
|
412
|
-
_define_property(this, "_node", Rx.family((id) => {
|
|
413
|
-
const initial = Option.flatten(Record.get(this._initialNodes, id));
|
|
414
|
-
return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
|
|
415
|
-
}));
|
|
416
|
-
_define_property(this, "_nodeOrThrow", Rx.family((id) => {
|
|
417
|
-
return Rx.make((get2) => {
|
|
418
|
-
const node = get2(this._node(id));
|
|
419
|
-
invariant(Option.isSome(node), `Node not available: ${id}`, {
|
|
420
|
-
F: __dxlog_file,
|
|
421
|
-
L: 254,
|
|
422
|
-
S: this,
|
|
423
|
-
A: [
|
|
424
|
-
"Option.isSome(node)",
|
|
425
|
-
"`Node not available: ${id}`"
|
|
426
|
-
]
|
|
427
|
-
});
|
|
428
|
-
return node.value;
|
|
429
|
-
});
|
|
430
|
-
}));
|
|
431
|
-
_define_property(this, "_edges", Rx.family((id) => {
|
|
432
|
-
const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
|
|
433
|
-
inbound: [],
|
|
434
|
-
outbound: []
|
|
435
|
-
})));
|
|
436
|
-
return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
|
|
437
|
-
}));
|
|
438
|
-
_define_property(this, "_connections", Rx.family((key) => {
|
|
439
|
-
return Rx.make((get2) => {
|
|
440
|
-
const [id, relation] = key.split("$");
|
|
441
|
-
const edges2 = get2(this._edges(id));
|
|
442
|
-
return edges2[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
|
|
443
|
-
}).pipe(Rx.withLabel(`graph:connections:${key}`));
|
|
444
|
-
}));
|
|
445
|
-
_define_property(this, "_actions", Rx.family((id) => {
|
|
446
|
-
return Rx.make((get2) => {
|
|
447
|
-
return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
|
|
448
|
-
}).pipe(Rx.withLabel(`graph:actions:${id}`));
|
|
449
|
-
}));
|
|
450
|
-
_define_property(this, "_json", Rx.family((id) => {
|
|
451
|
-
return Rx.make((get2) => {
|
|
452
|
-
const toJSON = (node, seen = []) => {
|
|
453
|
-
const nodes2 = get2(this.connections(node.id));
|
|
454
|
-
const obj = {
|
|
455
|
-
id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
|
|
456
|
-
type: node.type
|
|
457
|
-
};
|
|
458
|
-
if (node.properties.label) {
|
|
459
|
-
obj.label = node.properties.label;
|
|
460
|
-
}
|
|
461
|
-
if (nodes2.length) {
|
|
462
|
-
obj.nodes = nodes2.map((n) => {
|
|
463
|
-
const nextSeen = [
|
|
464
|
-
...seen,
|
|
465
|
-
node.id
|
|
466
|
-
];
|
|
467
|
-
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
468
|
-
}).filter(isNonNullable);
|
|
469
|
-
}
|
|
470
|
-
return obj;
|
|
471
|
-
};
|
|
472
|
-
const root = get2(this.nodeOrThrow(id));
|
|
473
|
-
return toJSON(root);
|
|
474
|
-
}).pipe(Rx.withLabel(`graph:json:${id}`));
|
|
475
|
-
}));
|
|
476
|
-
this._registry = registry ?? Registry.make();
|
|
477
|
-
this._onInitialize = onInitialize;
|
|
478
|
-
this._onExpand = onExpand;
|
|
479
|
-
this._onRemoveNode = onRemoveNode;
|
|
480
|
-
if (nodes) {
|
|
481
|
-
nodes.forEach((node) => {
|
|
482
|
-
Record.set(this._initialNodes, node.id, this._constructNode(node));
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
if (edges) {
|
|
486
|
-
Object.entries(edges).forEach(([source, edges2]) => {
|
|
487
|
-
Record.set(this._initialEdges, source, edges2);
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
481
|
};
|
|
492
482
|
|
|
493
483
|
// src/graph-builder.ts
|
|
494
|
-
import {
|
|
484
|
+
import { Atom as Atom2, Registry as Registry2 } from "@effect-atom/atom-react";
|
|
495
485
|
import { effect } from "@preact/signals-core";
|
|
496
486
|
import * as Array from "effect/Array";
|
|
497
487
|
import * as Function2 from "effect/Function";
|
|
@@ -508,27 +498,14 @@ var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbo
|
|
|
508
498
|
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
509
499
|
|
|
510
500
|
// src/graph-builder.ts
|
|
511
|
-
function _define_property2(obj, key, value) {
|
|
512
|
-
if (key in obj) {
|
|
513
|
-
Object.defineProperty(obj, key, {
|
|
514
|
-
value,
|
|
515
|
-
enumerable: true,
|
|
516
|
-
configurable: true,
|
|
517
|
-
writable: true
|
|
518
|
-
});
|
|
519
|
-
} else {
|
|
520
|
-
obj[key] = value;
|
|
521
|
-
}
|
|
522
|
-
return obj;
|
|
523
|
-
}
|
|
524
501
|
var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
525
502
|
var createExtension = (extension) => {
|
|
526
503
|
const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
527
504
|
const getId = (key) => `${id}/${key}`;
|
|
528
|
-
const resolver = _resolver &&
|
|
529
|
-
const connector = _connector &&
|
|
530
|
-
const actionGroups = _actionGroups &&
|
|
531
|
-
const actions = _actions &&
|
|
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}`)));
|
|
532
509
|
return [
|
|
533
510
|
resolver ? {
|
|
534
511
|
id: getId("resolver"),
|
|
@@ -539,7 +516,7 @@ var createExtension = (extension) => {
|
|
|
539
516
|
id: getId("connector"),
|
|
540
517
|
position,
|
|
541
518
|
relation,
|
|
542
|
-
connector:
|
|
519
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
543
520
|
try {
|
|
544
521
|
return get2(connector(node));
|
|
545
522
|
} catch {
|
|
@@ -548,19 +525,19 @@ var createExtension = (extension) => {
|
|
|
548
525
|
node
|
|
549
526
|
}, {
|
|
550
527
|
F: __dxlog_file2,
|
|
551
|
-
L:
|
|
528
|
+
L: 114,
|
|
552
529
|
S: void 0,
|
|
553
530
|
C: (f, a) => f(...a)
|
|
554
531
|
});
|
|
555
532
|
return [];
|
|
556
533
|
}
|
|
557
|
-
}).pipe(
|
|
534
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
|
|
558
535
|
} : void 0,
|
|
559
536
|
actionGroups ? {
|
|
560
537
|
id: getId("actionGroups"),
|
|
561
538
|
position,
|
|
562
539
|
relation: "outbound",
|
|
563
|
-
connector:
|
|
540
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
564
541
|
try {
|
|
565
542
|
return get2(actionGroups(node)).map((arg) => ({
|
|
566
543
|
...arg,
|
|
@@ -573,19 +550,19 @@ var createExtension = (extension) => {
|
|
|
573
550
|
node
|
|
574
551
|
}, {
|
|
575
552
|
F: __dxlog_file2,
|
|
576
|
-
L:
|
|
553
|
+
L: 135,
|
|
577
554
|
S: void 0,
|
|
578
555
|
C: (f, a) => f(...a)
|
|
579
556
|
});
|
|
580
557
|
return [];
|
|
581
558
|
}
|
|
582
|
-
}).pipe(
|
|
559
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
583
560
|
} : void 0,
|
|
584
561
|
actions ? {
|
|
585
562
|
id: getId("actions"),
|
|
586
563
|
position,
|
|
587
564
|
relation: "outbound",
|
|
588
|
-
connector:
|
|
565
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
589
566
|
try {
|
|
590
567
|
return get2(actions(node)).map((arg) => ({
|
|
591
568
|
...arg,
|
|
@@ -597,13 +574,13 @@ var createExtension = (extension) => {
|
|
|
597
574
|
node
|
|
598
575
|
}, {
|
|
599
576
|
F: __dxlog_file2,
|
|
600
|
-
L:
|
|
577
|
+
L: 152,
|
|
601
578
|
S: void 0,
|
|
602
579
|
C: (f, a) => f(...a)
|
|
603
580
|
});
|
|
604
581
|
return [];
|
|
605
582
|
}
|
|
606
|
-
}).pipe(
|
|
583
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
607
584
|
} : void 0
|
|
608
585
|
].filter(isNonNullable2);
|
|
609
586
|
};
|
|
@@ -621,6 +598,22 @@ var flattenExtensions = (extension, acc = []) => {
|
|
|
621
598
|
}
|
|
622
599
|
};
|
|
623
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;
|
|
607
|
+
constructor({ registry, ...params } = {}) {
|
|
608
|
+
this._registry = registry ?? Registry2.make();
|
|
609
|
+
this._graph = new Graph({
|
|
610
|
+
...params,
|
|
611
|
+
registry: this._registry,
|
|
612
|
+
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
613
|
+
onInitialize: (id) => this._onInitialize(id),
|
|
614
|
+
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
615
|
+
});
|
|
616
|
+
}
|
|
624
617
|
static from(pickle, registry) {
|
|
625
618
|
if (!pickle) {
|
|
626
619
|
return new _GraphBuilder({
|
|
@@ -690,6 +683,27 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
690
683
|
this._subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
691
684
|
this._subscriptions.clear();
|
|
692
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
|
+
});
|
|
693
707
|
_onExpand(id, relation) {
|
|
694
708
|
log2("onExpand", {
|
|
695
709
|
id,
|
|
@@ -697,7 +711,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
697
711
|
registry: getDebugName(this._registry)
|
|
698
712
|
}, {
|
|
699
713
|
F: __dxlog_file2,
|
|
700
|
-
L:
|
|
714
|
+
L: 329,
|
|
701
715
|
S: this,
|
|
702
716
|
C: (f, a) => f(...a)
|
|
703
717
|
});
|
|
@@ -714,12 +728,12 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
714
728
|
removed
|
|
715
729
|
}, {
|
|
716
730
|
F: __dxlog_file2,
|
|
717
|
-
L:
|
|
731
|
+
L: 340,
|
|
718
732
|
S: this,
|
|
719
733
|
C: (f, a) => f(...a)
|
|
720
734
|
});
|
|
721
735
|
const update = () => {
|
|
722
|
-
|
|
736
|
+
Atom2.batch(() => {
|
|
723
737
|
this._graph.removeEdges(removed.map((target) => ({
|
|
724
738
|
source: id,
|
|
725
739
|
target
|
|
@@ -751,7 +765,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
751
765
|
id
|
|
752
766
|
}, {
|
|
753
767
|
F: __dxlog_file2,
|
|
754
|
-
L:
|
|
768
|
+
L: 377,
|
|
755
769
|
S: this,
|
|
756
770
|
C: (f, a) => f(...a)
|
|
757
771
|
});
|
|
@@ -781,45 +795,9 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
781
795
|
this._subscriptions.get(id)?.();
|
|
782
796
|
this._subscriptions.delete(id);
|
|
783
797
|
}
|
|
784
|
-
constructor({ registry, ...params } = {}) {
|
|
785
|
-
_define_property2(this, "_subscriptions", /* @__PURE__ */ new Map());
|
|
786
|
-
_define_property2(this, "_extensions", Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions")));
|
|
787
|
-
_define_property2(this, "_initialized", {});
|
|
788
|
-
_define_property2(this, "_registry", void 0);
|
|
789
|
-
_define_property2(this, "_graph", void 0);
|
|
790
|
-
_define_property2(this, "_resolvers", Rx2.family((id) => {
|
|
791
|
-
return Rx2.make((get2) => {
|
|
792
|
-
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);
|
|
793
|
-
});
|
|
794
|
-
}));
|
|
795
|
-
_define_property2(this, "_connectors", Rx2.family((key) => {
|
|
796
|
-
return Rx2.make((get2) => {
|
|
797
|
-
const [id, relation] = key.split("+");
|
|
798
|
-
const node = this._graph.node(id);
|
|
799
|
-
return Function2.pipe(
|
|
800
|
-
get2(this._extensions),
|
|
801
|
-
Record2.values,
|
|
802
|
-
// TODO(wittjosiah): Sort on write rather than read.
|
|
803
|
-
Array.sortBy(byPosition),
|
|
804
|
-
Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
805
|
-
Array.map(({ connector }) => connector?.(node)),
|
|
806
|
-
Array.filter(isNonNullable2),
|
|
807
|
-
Array.flatMap((result) => get2(result))
|
|
808
|
-
);
|
|
809
|
-
}).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
|
|
810
|
-
}));
|
|
811
|
-
this._registry = registry ?? Registry2.make();
|
|
812
|
-
this._graph = new Graph({
|
|
813
|
-
...params,
|
|
814
|
-
registry: this._registry,
|
|
815
|
-
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
816
|
-
onInitialize: (id) => this._onInitialize(id),
|
|
817
|
-
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
798
|
};
|
|
821
|
-
var
|
|
822
|
-
return
|
|
799
|
+
var atomFromSignal = (cb) => {
|
|
800
|
+
return Atom2.make((get2) => {
|
|
823
801
|
const dispose = effect(() => {
|
|
824
802
|
get2.setSelf(cb());
|
|
825
803
|
});
|
|
@@ -827,14 +805,14 @@ var rxFromSignal = (cb) => {
|
|
|
827
805
|
return cb();
|
|
828
806
|
});
|
|
829
807
|
};
|
|
830
|
-
var observableFamily =
|
|
831
|
-
return
|
|
808
|
+
var observableFamily = Atom2.family((observable) => {
|
|
809
|
+
return Atom2.make((get2) => {
|
|
832
810
|
const subscription = observable.subscribe((value) => get2.setSelf(value));
|
|
833
811
|
get2.addFinalizer(() => subscription.unsubscribe());
|
|
834
812
|
return observable.get();
|
|
835
813
|
});
|
|
836
814
|
});
|
|
837
|
-
var
|
|
815
|
+
var atomFromObservable = (observable) => {
|
|
838
816
|
return observableFamily(observable);
|
|
839
817
|
};
|
|
840
818
|
export {
|
|
@@ -845,14 +823,14 @@ export {
|
|
|
845
823
|
ROOT_ID,
|
|
846
824
|
ROOT_TYPE,
|
|
847
825
|
actionGroupSymbol,
|
|
826
|
+
atomFromObservable,
|
|
827
|
+
atomFromSignal,
|
|
848
828
|
createExtension,
|
|
849
829
|
flattenExtensions,
|
|
850
830
|
getGraph,
|
|
851
831
|
isAction,
|
|
852
832
|
isActionGroup,
|
|
853
833
|
isActionLike,
|
|
854
|
-
isGraphNode
|
|
855
|
-
rxFromObservable,
|
|
856
|
-
rxFromSignal
|
|
834
|
+
isGraphNode
|
|
857
835
|
};
|
|
858
836
|
//# sourceMappingURL=index.mjs.map
|