@dxos/app-graph 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe
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 +216 -233
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +216 -233
- 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 +16 -16
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +19 -19
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts +0 -1
- 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 +31 -32
- package/src/graph-builder.test.ts +34 -33
- package/src/graph-builder.ts +50 -45
- package/src/graph.test.ts +3 -3
- package/src/graph.ts +115 -73
- package/src/signals-integration.test.ts +29 -28
- package/src/stories/EchoGraph.stories.tsx +28 -22
- package/src/stories/Tree.tsx +1 -1
- package/src/testing.ts +4 -4
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
2
|
|
|
3
3
|
// src/graph.ts
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { Atom, Registry } from "@effect-atom/atom-react";
|
|
5
|
+
import * as Function from "effect/Function";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Record from "effect/Record";
|
|
6
8
|
import { Event, Trigger } from "@dxos/async";
|
|
7
9
|
import { todo } from "@dxos/debug";
|
|
8
10
|
import { invariant } from "@dxos/invariant";
|
|
9
11
|
import { log } from "@dxos/log";
|
|
10
12
|
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
13
|
var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
25
14
|
var graphSymbol = Symbol("graph");
|
|
26
15
|
var getGraph = (node) => {
|
|
27
16
|
const graph = node[graphSymbol];
|
|
28
17
|
invariant(graph, "Node is not associated with a graph.", {
|
|
29
18
|
F: __dxlog_file,
|
|
30
|
-
L:
|
|
19
|
+
L: 29,
|
|
31
20
|
S: void 0,
|
|
32
21
|
A: [
|
|
33
22
|
"graph",
|
|
@@ -41,6 +30,108 @@ var ROOT_TYPE = "dxos.org/type/GraphRoot";
|
|
|
41
30
|
var ACTION_TYPE = "dxos.org/type/GraphAction";
|
|
42
31
|
var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
|
|
43
32
|
var Graph = class {
|
|
33
|
+
onNodeChanged = new Event();
|
|
34
|
+
_onExpand;
|
|
35
|
+
_onInitialize;
|
|
36
|
+
_onRemoveNode;
|
|
37
|
+
_registry;
|
|
38
|
+
_expanded = Record.empty();
|
|
39
|
+
_initialized = Record.empty();
|
|
40
|
+
_initialEdges = Record.empty();
|
|
41
|
+
_initialNodes = Record.fromEntries([
|
|
42
|
+
[
|
|
43
|
+
ROOT_ID,
|
|
44
|
+
this._constructNode({
|
|
45
|
+
id: ROOT_ID,
|
|
46
|
+
type: ROOT_TYPE,
|
|
47
|
+
data: null,
|
|
48
|
+
properties: {}
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
]);
|
|
52
|
+
/** @internal */
|
|
53
|
+
_node = Atom.family((id) => {
|
|
54
|
+
const initial = Option.flatten(Record.get(this._initialNodes, id));
|
|
55
|
+
return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:node:${id}`));
|
|
56
|
+
});
|
|
57
|
+
_nodeOrThrow = Atom.family((id) => {
|
|
58
|
+
return Atom.make((get2) => {
|
|
59
|
+
const node = get2(this._node(id));
|
|
60
|
+
invariant(Option.isSome(node), `Node not available: ${id}`, {
|
|
61
|
+
F: __dxlog_file,
|
|
62
|
+
L: 267,
|
|
63
|
+
S: this,
|
|
64
|
+
A: [
|
|
65
|
+
"Option.isSome(node)",
|
|
66
|
+
"`Node not available: ${id}`"
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
return node.value;
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
_edges = Atom.family((id) => {
|
|
73
|
+
const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
|
|
74
|
+
inbound: [],
|
|
75
|
+
outbound: []
|
|
76
|
+
})));
|
|
77
|
+
return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));
|
|
78
|
+
});
|
|
79
|
+
// NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
|
|
80
|
+
// TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
|
|
81
|
+
_connections = Atom.family((key) => {
|
|
82
|
+
return Atom.make((get2) => {
|
|
83
|
+
const [id, relation] = key.split("$");
|
|
84
|
+
const edges = get2(this._edges(id));
|
|
85
|
+
return edges[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
|
|
86
|
+
}).pipe(Atom.withLabel(`graph:connections:${key}`));
|
|
87
|
+
});
|
|
88
|
+
_actions = Atom.family((id) => {
|
|
89
|
+
return Atom.make((get2) => {
|
|
90
|
+
return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
|
|
91
|
+
}).pipe(Atom.withLabel(`graph:actions:${id}`));
|
|
92
|
+
});
|
|
93
|
+
_json = Atom.family((id) => {
|
|
94
|
+
return Atom.make((get2) => {
|
|
95
|
+
const toJSON = (node, seen = []) => {
|
|
96
|
+
const nodes = get2(this.connections(node.id));
|
|
97
|
+
const obj = {
|
|
98
|
+
id: node.id,
|
|
99
|
+
type: node.type
|
|
100
|
+
};
|
|
101
|
+
if (node.properties.label) {
|
|
102
|
+
obj.label = node.properties.label;
|
|
103
|
+
}
|
|
104
|
+
if (nodes.length) {
|
|
105
|
+
obj.nodes = nodes.map((n) => {
|
|
106
|
+
const nextSeen = [
|
|
107
|
+
...seen,
|
|
108
|
+
node.id
|
|
109
|
+
];
|
|
110
|
+
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
111
|
+
}).filter(isNonNullable);
|
|
112
|
+
}
|
|
113
|
+
return obj;
|
|
114
|
+
};
|
|
115
|
+
const root = get2(this.nodeOrThrow(id));
|
|
116
|
+
return toJSON(root);
|
|
117
|
+
}).pipe(Atom.withLabel(`graph:json:${id}`));
|
|
118
|
+
});
|
|
119
|
+
constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
|
|
120
|
+
this._registry = registry ?? Registry.make();
|
|
121
|
+
this._onInitialize = onInitialize;
|
|
122
|
+
this._onExpand = onExpand;
|
|
123
|
+
this._onRemoveNode = onRemoveNode;
|
|
124
|
+
if (nodes) {
|
|
125
|
+
nodes.forEach((node) => {
|
|
126
|
+
Record.set(this._initialNodes, node.id, this._constructNode(node));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (edges) {
|
|
130
|
+
Object.entries(edges).forEach(([source, edges2]) => {
|
|
131
|
+
Record.set(this._initialEdges, source, edges2);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
44
135
|
toJSON(id = ROOT_ID) {
|
|
45
136
|
return this._registry.get(this._json(id));
|
|
46
137
|
}
|
|
@@ -87,7 +178,7 @@ var Graph = class {
|
|
|
87
178
|
initialized
|
|
88
179
|
}, {
|
|
89
180
|
F: __dxlog_file,
|
|
90
|
-
L:
|
|
181
|
+
L: 399,
|
|
91
182
|
S: this,
|
|
92
183
|
C: (f, a) => f(...a)
|
|
93
184
|
});
|
|
@@ -104,7 +195,7 @@ var Graph = class {
|
|
|
104
195
|
expanded
|
|
105
196
|
}, {
|
|
106
197
|
F: __dxlog_file,
|
|
107
|
-
L:
|
|
198
|
+
L: 409,
|
|
108
199
|
S: this,
|
|
109
200
|
C: (f, a) => f(...a)
|
|
110
201
|
});
|
|
@@ -114,14 +205,14 @@ var Graph = class {
|
|
|
114
205
|
}
|
|
115
206
|
}
|
|
116
207
|
addNodes(nodes) {
|
|
117
|
-
|
|
208
|
+
Atom.batch(() => {
|
|
118
209
|
nodes.map((node) => this.addNode(node));
|
|
119
210
|
});
|
|
120
211
|
}
|
|
121
212
|
addNode({ nodes, edges, ...nodeArg }) {
|
|
122
213
|
const { id, type, data = null, properties = {} } = nodeArg;
|
|
123
|
-
const
|
|
124
|
-
const node = this._registry.get(
|
|
214
|
+
const nodeAtom = this._node(id);
|
|
215
|
+
const node = this._registry.get(nodeAtom);
|
|
125
216
|
Option.match(node, {
|
|
126
217
|
onSome: (node2) => {
|
|
127
218
|
const typeChanged = node2.type !== type;
|
|
@@ -134,7 +225,7 @@ var Graph = class {
|
|
|
134
225
|
propertiesChanged
|
|
135
226
|
}, {
|
|
136
227
|
F: __dxlog_file,
|
|
137
|
-
L:
|
|
228
|
+
L: 431,
|
|
138
229
|
S: this,
|
|
139
230
|
C: (f, a) => f(...a)
|
|
140
231
|
});
|
|
@@ -146,7 +237,7 @@ var Graph = class {
|
|
|
146
237
|
properties
|
|
147
238
|
}, {
|
|
148
239
|
F: __dxlog_file,
|
|
149
|
-
L:
|
|
240
|
+
L: 438,
|
|
150
241
|
S: this,
|
|
151
242
|
C: (f, a) => f(...a)
|
|
152
243
|
});
|
|
@@ -159,7 +250,7 @@ var Graph = class {
|
|
|
159
250
|
...properties
|
|
160
251
|
}
|
|
161
252
|
});
|
|
162
|
-
this._registry.set(
|
|
253
|
+
this._registry.set(nodeAtom, newNode);
|
|
163
254
|
this.onNodeChanged.emit({
|
|
164
255
|
id,
|
|
165
256
|
node: newNode
|
|
@@ -174,7 +265,7 @@ var Graph = class {
|
|
|
174
265
|
properties
|
|
175
266
|
}, {
|
|
176
267
|
F: __dxlog_file,
|
|
177
|
-
L:
|
|
268
|
+
L: 450,
|
|
178
269
|
S: this,
|
|
179
270
|
C: (f, a) => f(...a)
|
|
180
271
|
});
|
|
@@ -184,7 +275,7 @@ var Graph = class {
|
|
|
184
275
|
data,
|
|
185
276
|
properties
|
|
186
277
|
});
|
|
187
|
-
this._registry.set(
|
|
278
|
+
this._registry.set(nodeAtom, newNode);
|
|
188
279
|
this.onNodeChanged.emit({
|
|
189
280
|
id,
|
|
190
281
|
node: newNode
|
|
@@ -204,13 +295,13 @@ var Graph = class {
|
|
|
204
295
|
}
|
|
205
296
|
}
|
|
206
297
|
removeNodes(ids, edges = false) {
|
|
207
|
-
|
|
298
|
+
Atom.batch(() => {
|
|
208
299
|
ids.map((id) => this.removeNode(id, edges));
|
|
209
300
|
});
|
|
210
301
|
}
|
|
211
302
|
removeNode(id, edges = false) {
|
|
212
|
-
const
|
|
213
|
-
this._registry.set(
|
|
303
|
+
const nodeAtom = this._node(id);
|
|
304
|
+
this._registry.set(nodeAtom, Option.none());
|
|
214
305
|
this.onNodeChanged.emit({
|
|
215
306
|
id,
|
|
216
307
|
node: Option.none()
|
|
@@ -232,24 +323,24 @@ var Graph = class {
|
|
|
232
323
|
this._onRemoveNode?.(id);
|
|
233
324
|
}
|
|
234
325
|
addEdges(edges) {
|
|
235
|
-
|
|
326
|
+
Atom.batch(() => {
|
|
236
327
|
edges.map((edge) => this.addEdge(edge));
|
|
237
328
|
});
|
|
238
329
|
}
|
|
239
330
|
addEdge(edgeArg) {
|
|
240
|
-
const
|
|
241
|
-
const source = this._registry.get(
|
|
331
|
+
const sourceAtom = this._edges(edgeArg.source);
|
|
332
|
+
const source = this._registry.get(sourceAtom);
|
|
242
333
|
if (!source.outbound.includes(edgeArg.target)) {
|
|
243
334
|
log("add outbound edge", {
|
|
244
335
|
source: edgeArg.source,
|
|
245
336
|
target: edgeArg.target
|
|
246
337
|
}, {
|
|
247
338
|
F: __dxlog_file,
|
|
248
|
-
L:
|
|
339
|
+
L: 505,
|
|
249
340
|
S: this,
|
|
250
341
|
C: (f, a) => f(...a)
|
|
251
342
|
});
|
|
252
|
-
this._registry.set(
|
|
343
|
+
this._registry.set(sourceAtom, {
|
|
253
344
|
inbound: source.inbound,
|
|
254
345
|
outbound: [
|
|
255
346
|
...source.outbound,
|
|
@@ -257,19 +348,19 @@ var Graph = class {
|
|
|
257
348
|
]
|
|
258
349
|
});
|
|
259
350
|
}
|
|
260
|
-
const
|
|
261
|
-
const target = this._registry.get(
|
|
351
|
+
const targetAtom = this._edges(edgeArg.target);
|
|
352
|
+
const target = this._registry.get(targetAtom);
|
|
262
353
|
if (!target.inbound.includes(edgeArg.source)) {
|
|
263
354
|
log("add inbound edge", {
|
|
264
355
|
source: edgeArg.source,
|
|
265
356
|
target: edgeArg.target
|
|
266
357
|
}, {
|
|
267
358
|
F: __dxlog_file,
|
|
268
|
-
L:
|
|
359
|
+
L: 518,
|
|
269
360
|
S: this,
|
|
270
361
|
C: (f, a) => f(...a)
|
|
271
362
|
});
|
|
272
|
-
this._registry.set(
|
|
363
|
+
this._registry.set(targetAtom, {
|
|
273
364
|
inbound: [
|
|
274
365
|
...target.inbound,
|
|
275
366
|
edgeArg.source
|
|
@@ -279,30 +370,30 @@ var Graph = class {
|
|
|
279
370
|
}
|
|
280
371
|
}
|
|
281
372
|
removeEdges(edges, removeOrphans = false) {
|
|
282
|
-
|
|
373
|
+
Atom.batch(() => {
|
|
283
374
|
edges.map((edge) => this.removeEdge(edge, removeOrphans));
|
|
284
375
|
});
|
|
285
376
|
}
|
|
286
377
|
removeEdge(edgeArg, removeOrphans = false) {
|
|
287
|
-
const
|
|
288
|
-
const source = this._registry.get(
|
|
378
|
+
const sourceAtom = this._edges(edgeArg.source);
|
|
379
|
+
const source = this._registry.get(sourceAtom);
|
|
289
380
|
if (source.outbound.includes(edgeArg.target)) {
|
|
290
|
-
this._registry.set(
|
|
381
|
+
this._registry.set(sourceAtom, {
|
|
291
382
|
inbound: source.inbound,
|
|
292
383
|
outbound: source.outbound.filter((id) => id !== edgeArg.target)
|
|
293
384
|
});
|
|
294
385
|
}
|
|
295
|
-
const
|
|
296
|
-
const target = this._registry.get(
|
|
386
|
+
const targetAtom = this._edges(edgeArg.target);
|
|
387
|
+
const target = this._registry.get(targetAtom);
|
|
297
388
|
if (target.inbound.includes(edgeArg.source)) {
|
|
298
|
-
this._registry.set(
|
|
389
|
+
this._registry.set(targetAtom, {
|
|
299
390
|
inbound: target.inbound.filter((id) => id !== edgeArg.source),
|
|
300
391
|
outbound: target.outbound
|
|
301
392
|
});
|
|
302
393
|
}
|
|
303
394
|
if (removeOrphans) {
|
|
304
|
-
const source2 = this._registry.get(
|
|
305
|
-
const target2 = this._registry.get(
|
|
395
|
+
const source2 = this._registry.get(sourceAtom);
|
|
396
|
+
const target2 = this._registry.get(targetAtom);
|
|
306
397
|
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
|
|
307
398
|
this.removeNodes([
|
|
308
399
|
edgeArg.source
|
|
@@ -316,15 +407,15 @@ var Graph = class {
|
|
|
316
407
|
}
|
|
317
408
|
}
|
|
318
409
|
sortEdges(id, relation, order) {
|
|
319
|
-
const
|
|
320
|
-
const edges = this._registry.get(
|
|
410
|
+
const edgesAtom = this._edges(id);
|
|
411
|
+
const edges = this._registry.get(edgesAtom);
|
|
321
412
|
const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
|
|
322
413
|
const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
|
|
323
414
|
edges[relation].splice(0, edges[relation].length, ...[
|
|
324
415
|
...sorted,
|
|
325
416
|
...unsorted
|
|
326
417
|
]);
|
|
327
|
-
this._registry.set(
|
|
418
|
+
this._registry.set(edgesAtom, edges);
|
|
328
419
|
}
|
|
329
420
|
traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
|
|
330
421
|
if (path.includes(source)) {
|
|
@@ -348,7 +439,7 @@ var Graph = class {
|
|
|
348
439
|
]));
|
|
349
440
|
}
|
|
350
441
|
getPath({ source = "root", target }) {
|
|
351
|
-
return pipe(this.getNode(source), Option.flatMap((node) => {
|
|
442
|
+
return Function.pipe(this.getNode(source), Option.flatMap((node) => {
|
|
352
443
|
let found = Option.none();
|
|
353
444
|
this.traverse({
|
|
354
445
|
source: node.id,
|
|
@@ -389,111 +480,15 @@ var Graph = class {
|
|
|
389
480
|
...node
|
|
390
481
|
});
|
|
391
482
|
}
|
|
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((get) => {
|
|
418
|
-
const node = get(this._node(id));
|
|
419
|
-
invariant(Option.isSome(node), `Node not available: ${id}`, {
|
|
420
|
-
F: __dxlog_file,
|
|
421
|
-
L: 252,
|
|
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((get) => {
|
|
440
|
-
const [id, relation] = key.split("$");
|
|
441
|
-
const edges2 = get(this._edges(id));
|
|
442
|
-
return edges2[relation].map((id2) => get(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((get) => {
|
|
447
|
-
return get(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((get) => {
|
|
452
|
-
const toJSON = (node, seen = []) => {
|
|
453
|
-
const nodes2 = get(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 = get(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
483
|
};
|
|
492
484
|
|
|
493
485
|
// src/graph-builder.ts
|
|
494
|
-
import {
|
|
486
|
+
import { Atom as Atom2, Registry as Registry2 } from "@effect-atom/atom-react";
|
|
495
487
|
import { effect } from "@preact/signals-core";
|
|
496
|
-
import
|
|
488
|
+
import * as Array from "effect/Array";
|
|
489
|
+
import * as Function2 from "effect/Function";
|
|
490
|
+
import * as Option2 from "effect/Option";
|
|
491
|
+
import * as Record2 from "effect/Record";
|
|
497
492
|
import { log as log2 } from "@dxos/log";
|
|
498
493
|
import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
499
494
|
|
|
@@ -505,27 +500,14 @@ var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbo
|
|
|
505
500
|
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
506
501
|
|
|
507
502
|
// src/graph-builder.ts
|
|
508
|
-
function _define_property2(obj, key, value) {
|
|
509
|
-
if (key in obj) {
|
|
510
|
-
Object.defineProperty(obj, key, {
|
|
511
|
-
value,
|
|
512
|
-
enumerable: true,
|
|
513
|
-
configurable: true,
|
|
514
|
-
writable: true
|
|
515
|
-
});
|
|
516
|
-
} else {
|
|
517
|
-
obj[key] = value;
|
|
518
|
-
}
|
|
519
|
-
return obj;
|
|
520
|
-
}
|
|
521
503
|
var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
522
504
|
var createExtension = (extension) => {
|
|
523
505
|
const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
524
506
|
const getId = (key) => `${id}/${key}`;
|
|
525
|
-
const resolver = _resolver &&
|
|
526
|
-
const connector = _connector &&
|
|
527
|
-
const actionGroups = _actionGroups &&
|
|
528
|
-
const actions = _actions &&
|
|
507
|
+
const resolver = _resolver && Atom2.family((id2) => _resolver(id2).pipe(Atom2.withLabel(`graph-builder:_resolver:${id2}`)));
|
|
508
|
+
const connector = _connector && Atom2.family((node) => _connector(node).pipe(Atom2.withLabel(`graph-builder:_connector:${id}`)));
|
|
509
|
+
const actionGroups = _actionGroups && Atom2.family((node) => _actionGroups(node).pipe(Atom2.withLabel(`graph-builder:_actionGroups:${id}`)));
|
|
510
|
+
const actions = _actions && Atom2.family((node) => _actions(node).pipe(Atom2.withLabel(`graph-builder:_actions:${id}`)));
|
|
529
511
|
return [
|
|
530
512
|
resolver ? {
|
|
531
513
|
id: getId("resolver"),
|
|
@@ -536,30 +518,30 @@ var createExtension = (extension) => {
|
|
|
536
518
|
id: getId("connector"),
|
|
537
519
|
position,
|
|
538
520
|
relation,
|
|
539
|
-
connector:
|
|
521
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
540
522
|
try {
|
|
541
|
-
return
|
|
523
|
+
return get2(connector(node));
|
|
542
524
|
} catch {
|
|
543
525
|
log2.warn("Error in connector", {
|
|
544
526
|
id: getId("connector"),
|
|
545
527
|
node
|
|
546
528
|
}, {
|
|
547
529
|
F: __dxlog_file2,
|
|
548
|
-
L:
|
|
530
|
+
L: 114,
|
|
549
531
|
S: void 0,
|
|
550
532
|
C: (f, a) => f(...a)
|
|
551
533
|
});
|
|
552
534
|
return [];
|
|
553
535
|
}
|
|
554
|
-
}).pipe(
|
|
536
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
|
|
555
537
|
} : void 0,
|
|
556
538
|
actionGroups ? {
|
|
557
539
|
id: getId("actionGroups"),
|
|
558
540
|
position,
|
|
559
541
|
relation: "outbound",
|
|
560
|
-
connector:
|
|
542
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
561
543
|
try {
|
|
562
|
-
return
|
|
544
|
+
return get2(actionGroups(node)).map((arg) => ({
|
|
563
545
|
...arg,
|
|
564
546
|
data: actionGroupSymbol,
|
|
565
547
|
type: ACTION_GROUP_TYPE
|
|
@@ -570,21 +552,21 @@ var createExtension = (extension) => {
|
|
|
570
552
|
node
|
|
571
553
|
}, {
|
|
572
554
|
F: __dxlog_file2,
|
|
573
|
-
L:
|
|
555
|
+
L: 135,
|
|
574
556
|
S: void 0,
|
|
575
557
|
C: (f, a) => f(...a)
|
|
576
558
|
});
|
|
577
559
|
return [];
|
|
578
560
|
}
|
|
579
|
-
}).pipe(
|
|
561
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
580
562
|
} : void 0,
|
|
581
563
|
actions ? {
|
|
582
564
|
id: getId("actions"),
|
|
583
565
|
position,
|
|
584
566
|
relation: "outbound",
|
|
585
|
-
connector:
|
|
567
|
+
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
586
568
|
try {
|
|
587
|
-
return
|
|
569
|
+
return get2(actions(node)).map((arg) => ({
|
|
588
570
|
...arg,
|
|
589
571
|
type: ACTION_TYPE
|
|
590
572
|
}));
|
|
@@ -594,13 +576,13 @@ var createExtension = (extension) => {
|
|
|
594
576
|
node
|
|
595
577
|
}, {
|
|
596
578
|
F: __dxlog_file2,
|
|
597
|
-
L:
|
|
579
|
+
L: 152,
|
|
598
580
|
S: void 0,
|
|
599
581
|
C: (f, a) => f(...a)
|
|
600
582
|
});
|
|
601
583
|
return [];
|
|
602
584
|
}
|
|
603
|
-
}).pipe(
|
|
585
|
+
}).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
604
586
|
} : void 0
|
|
605
587
|
].filter(isNonNullable2);
|
|
606
588
|
};
|
|
@@ -618,6 +600,22 @@ var flattenExtensions = (extension, acc = []) => {
|
|
|
618
600
|
}
|
|
619
601
|
};
|
|
620
602
|
var GraphBuilder = class _GraphBuilder {
|
|
603
|
+
// TODO(wittjosiah): Use Context.
|
|
604
|
+
_subscriptions = /* @__PURE__ */ new Map();
|
|
605
|
+
_extensions = Atom2.make(Record2.empty()).pipe(Atom2.keepAlive, Atom2.withLabel("graph-builder:extensions"));
|
|
606
|
+
_initialized = {};
|
|
607
|
+
_registry;
|
|
608
|
+
_graph;
|
|
609
|
+
constructor({ registry, ...params } = {}) {
|
|
610
|
+
this._registry = registry ?? Registry2.make();
|
|
611
|
+
this._graph = new Graph({
|
|
612
|
+
...params,
|
|
613
|
+
registry: this._registry,
|
|
614
|
+
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
615
|
+
onInitialize: (id) => this._onInitialize(id),
|
|
616
|
+
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
617
|
+
});
|
|
618
|
+
}
|
|
621
619
|
static from(pickle, registry) {
|
|
622
620
|
if (!pickle) {
|
|
623
621
|
return new _GraphBuilder({
|
|
@@ -687,6 +685,27 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
687
685
|
this._subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
688
686
|
this._subscriptions.clear();
|
|
689
687
|
}
|
|
688
|
+
_resolvers = Atom2.family((id) => {
|
|
689
|
+
return Atom2.make((get2) => {
|
|
690
|
+
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);
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
_connectors = Atom2.family((key) => {
|
|
694
|
+
return Atom2.make((get2) => {
|
|
695
|
+
const [id, relation] = key.split("+");
|
|
696
|
+
const node = this._graph.node(id);
|
|
697
|
+
return Function2.pipe(
|
|
698
|
+
get2(this._extensions),
|
|
699
|
+
Record2.values,
|
|
700
|
+
// TODO(wittjosiah): Sort on write rather than read.
|
|
701
|
+
Array.sortBy(byPosition),
|
|
702
|
+
Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
703
|
+
Array.map(({ connector }) => connector?.(node)),
|
|
704
|
+
Array.filter(isNonNullable2),
|
|
705
|
+
Array.flatMap((result) => get2(result))
|
|
706
|
+
);
|
|
707
|
+
}).pipe(Atom2.withLabel(`graph-builder:connectors:${key}`));
|
|
708
|
+
});
|
|
690
709
|
_onExpand(id, relation) {
|
|
691
710
|
log2("onExpand", {
|
|
692
711
|
id,
|
|
@@ -694,7 +713,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
694
713
|
registry: getDebugName(this._registry)
|
|
695
714
|
}, {
|
|
696
715
|
F: __dxlog_file2,
|
|
697
|
-
L:
|
|
716
|
+
L: 329,
|
|
698
717
|
S: this,
|
|
699
718
|
C: (f, a) => f(...a)
|
|
700
719
|
});
|
|
@@ -711,12 +730,12 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
711
730
|
removed
|
|
712
731
|
}, {
|
|
713
732
|
F: __dxlog_file2,
|
|
714
|
-
L:
|
|
733
|
+
L: 340,
|
|
715
734
|
S: this,
|
|
716
735
|
C: (f, a) => f(...a)
|
|
717
736
|
});
|
|
718
737
|
const update = () => {
|
|
719
|
-
|
|
738
|
+
Atom2.batch(() => {
|
|
720
739
|
this._graph.removeEdges(removed.map((target) => ({
|
|
721
740
|
source: id,
|
|
722
741
|
target
|
|
@@ -748,7 +767,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
748
767
|
id
|
|
749
768
|
}, {
|
|
750
769
|
F: __dxlog_file2,
|
|
751
|
-
L:
|
|
770
|
+
L: 377,
|
|
752
771
|
S: this,
|
|
753
772
|
C: (f, a) => f(...a)
|
|
754
773
|
});
|
|
@@ -778,60 +797,24 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
778
797
|
this._subscriptions.get(id)?.();
|
|
779
798
|
this._subscriptions.delete(id);
|
|
780
799
|
}
|
|
781
|
-
constructor({ registry, ...params } = {}) {
|
|
782
|
-
_define_property2(this, "_subscriptions", /* @__PURE__ */ new Map());
|
|
783
|
-
_define_property2(this, "_extensions", Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions")));
|
|
784
|
-
_define_property2(this, "_initialized", {});
|
|
785
|
-
_define_property2(this, "_registry", void 0);
|
|
786
|
-
_define_property2(this, "_graph", void 0);
|
|
787
|
-
_define_property2(this, "_resolvers", Rx2.family((id) => {
|
|
788
|
-
return Rx2.make((get) => {
|
|
789
|
-
return pipe2(get(this._extensions), Record2.values, Array.sortBy(byPosition), Array.map(({ resolver }) => resolver), Array.filter(isNonNullable2), Array.map((resolver) => get(resolver(id))), Array.filter(isNonNullable2), Array.head);
|
|
790
|
-
});
|
|
791
|
-
}));
|
|
792
|
-
_define_property2(this, "_connectors", Rx2.family((key) => {
|
|
793
|
-
return Rx2.make((get) => {
|
|
794
|
-
const [id, relation] = key.split("+");
|
|
795
|
-
const node = this._graph.node(id);
|
|
796
|
-
return pipe2(
|
|
797
|
-
get(this._extensions),
|
|
798
|
-
Record2.values,
|
|
799
|
-
// TODO(wittjosiah): Sort on write rather than read.
|
|
800
|
-
Array.sortBy(byPosition),
|
|
801
|
-
Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
802
|
-
Array.map(({ connector }) => connector?.(node)),
|
|
803
|
-
Array.filter(isNonNullable2),
|
|
804
|
-
Array.flatMap((result) => get(result))
|
|
805
|
-
);
|
|
806
|
-
}).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
|
|
807
|
-
}));
|
|
808
|
-
this._registry = registry ?? Registry2.make();
|
|
809
|
-
this._graph = new Graph({
|
|
810
|
-
...params,
|
|
811
|
-
registry: this._registry,
|
|
812
|
-
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
813
|
-
onInitialize: (id) => this._onInitialize(id),
|
|
814
|
-
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
800
|
};
|
|
818
|
-
var
|
|
819
|
-
return
|
|
801
|
+
var atomFromSignal = (cb) => {
|
|
802
|
+
return Atom2.make((get2) => {
|
|
820
803
|
const dispose = effect(() => {
|
|
821
|
-
|
|
804
|
+
get2.setSelf(cb());
|
|
822
805
|
});
|
|
823
|
-
|
|
806
|
+
get2.addFinalizer(() => dispose());
|
|
824
807
|
return cb();
|
|
825
808
|
});
|
|
826
809
|
};
|
|
827
|
-
var observableFamily =
|
|
828
|
-
return
|
|
829
|
-
const subscription = observable.subscribe((value) =>
|
|
830
|
-
|
|
810
|
+
var observableFamily = Atom2.family((observable) => {
|
|
811
|
+
return Atom2.make((get2) => {
|
|
812
|
+
const subscription = observable.subscribe((value) => get2.setSelf(value));
|
|
813
|
+
get2.addFinalizer(() => subscription.unsubscribe());
|
|
831
814
|
return observable.get();
|
|
832
815
|
});
|
|
833
816
|
});
|
|
834
|
-
var
|
|
817
|
+
var atomFromObservable = (observable) => {
|
|
835
818
|
return observableFamily(observable);
|
|
836
819
|
};
|
|
837
820
|
export {
|
|
@@ -842,14 +825,14 @@ export {
|
|
|
842
825
|
ROOT_ID,
|
|
843
826
|
ROOT_TYPE,
|
|
844
827
|
actionGroupSymbol,
|
|
828
|
+
atomFromObservable,
|
|
829
|
+
atomFromSignal,
|
|
845
830
|
createExtension,
|
|
846
831
|
flattenExtensions,
|
|
847
832
|
getGraph,
|
|
848
833
|
isAction,
|
|
849
834
|
isActionGroup,
|
|
850
835
|
isActionLike,
|
|
851
|
-
isGraphNode
|
|
852
|
-
rxFromObservable,
|
|
853
|
-
rxFromSignal
|
|
836
|
+
isGraphNode
|
|
854
837
|
};
|
|
855
838
|
//# sourceMappingURL=index.mjs.map
|