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