@dxos/app-graph 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5

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.
Files changed (61) hide show
  1. package/dist/lib/browser/chunk-W47H2NND.mjs +1604 -0
  2. package/dist/lib/browser/chunk-W47H2NND.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +27 -820
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +39 -0
  7. package/dist/lib/browser/testing/index.mjs.map +7 -0
  8. package/dist/lib/node-esm/chunk-LYZWNJ7J.mjs +1605 -0
  9. package/dist/lib/node-esm/chunk-LYZWNJ7J.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +27 -821
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +40 -0
  14. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  15. package/dist/types/src/atoms.d.ts +8 -0
  16. package/dist/types/src/atoms.d.ts.map +1 -0
  17. package/dist/types/src/graph-builder.d.ts +113 -67
  18. package/dist/types/src/graph-builder.d.ts.map +1 -1
  19. package/dist/types/src/graph.d.ts +188 -222
  20. package/dist/types/src/graph.d.ts.map +1 -1
  21. package/dist/types/src/index.d.ts +7 -3
  22. package/dist/types/src/index.d.ts.map +1 -1
  23. package/dist/types/src/node-matcher.d.ts +244 -0
  24. package/dist/types/src/node-matcher.d.ts.map +1 -0
  25. package/dist/types/src/node-matcher.test.d.ts +2 -0
  26. package/dist/types/src/node-matcher.test.d.ts.map +1 -0
  27. package/dist/types/src/node.d.ts +50 -5
  28. package/dist/types/src/node.d.ts.map +1 -1
  29. package/dist/types/src/stories/EchoGraph.stories.d.ts +8 -10
  30. package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
  31. package/dist/types/src/testing/index.d.ts +2 -0
  32. package/dist/types/src/testing/index.d.ts.map +1 -0
  33. package/dist/types/src/testing/setup-graph-builder.d.ts +31 -0
  34. package/dist/types/src/testing/setup-graph-builder.d.ts.map +1 -0
  35. package/dist/types/src/util.d.ts +39 -0
  36. package/dist/types/src/util.d.ts.map +1 -0
  37. package/dist/types/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +47 -36
  39. package/src/atoms.ts +25 -0
  40. package/src/graph-builder.test.ts +1028 -144
  41. package/src/graph-builder.ts +719 -293
  42. package/src/graph.test.ts +451 -123
  43. package/src/graph.ts +1054 -403
  44. package/src/index.ts +10 -3
  45. package/src/node-matcher.test.ts +301 -0
  46. package/src/node-matcher.ts +314 -0
  47. package/src/node.ts +82 -8
  48. package/src/stories/EchoGraph.stories.tsx +173 -135
  49. package/src/stories/Tree.tsx +1 -1
  50. package/src/testing/index.ts +5 -0
  51. package/src/testing/setup-graph-builder.ts +41 -0
  52. package/src/util.ts +95 -0
  53. package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
  54. package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
  55. package/dist/types/src/signals-integration.test.d.ts +0 -2
  56. package/dist/types/src/signals-integration.test.d.ts.map +0 -1
  57. package/dist/types/src/testing.d.ts +0 -5
  58. package/dist/types/src/testing.d.ts.map +0 -1
  59. package/src/experimental/graph-projections.test.ts +0 -56
  60. package/src/signals-integration.test.ts +0 -218
  61. package/src/testing.ts +0 -20
@@ -1,831 +1,38 @@
1
- // src/graph.ts
2
- import { Registry, Rx } from "@effect-rx/rx-react";
3
- import { Option, Record, pipe } from "effect";
4
- import { Event, Trigger } from "@dxos/async";
5
- import { todo } from "@dxos/debug";
6
- import { invariant } from "@dxos/invariant";
7
- import { log } from "@dxos/log";
8
- import { isNonNullable } from "@dxos/util";
9
- var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
10
- var graphSymbol = Symbol("graph");
11
- var getGraph = (node) => {
12
- const graph = node[graphSymbol];
13
- invariant(graph, "Node is not associated with a graph.", {
14
- F: __dxlog_file,
15
- L: 25,
16
- S: void 0,
17
- A: [
18
- "graph",
19
- "'Node is not associated with a graph.'"
20
- ]
21
- });
22
- return graph;
23
- };
24
- var ROOT_ID = "root";
25
- var ROOT_TYPE = "dxos.org/type/GraphRoot";
26
- var ACTION_TYPE = "dxos.org/type/GraphAction";
27
- var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
28
- var Graph = class {
29
- onNodeChanged = new Event();
30
- _onExpand;
31
- _onInitialize;
32
- _onRemoveNode;
33
- _registry;
34
- _expanded = Record.empty();
35
- _initialized = Record.empty();
36
- _initialEdges = Record.empty();
37
- _initialNodes = Record.fromEntries([
38
- [
39
- ROOT_ID,
40
- this._constructNode({
41
- id: ROOT_ID,
42
- type: ROOT_TYPE,
43
- data: null,
44
- properties: {}
45
- })
46
- ]
47
- ]);
48
- /** @internal */
49
- _node = Rx.family((id) => {
50
- const initial = Option.flatten(Record.get(this._initialNodes, id));
51
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
52
- });
53
- _nodeOrThrow = Rx.family((id) => {
54
- return Rx.make((get) => {
55
- const node = get(this._node(id));
56
- invariant(Option.isSome(node), `Node not available: ${id}`, {
57
- F: __dxlog_file,
58
- L: 252,
59
- S: this,
60
- A: [
61
- "Option.isSome(node)",
62
- "`Node not available: ${id}`"
63
- ]
64
- });
65
- return node.value;
66
- });
67
- });
68
- _edges = Rx.family((id) => {
69
- const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
70
- inbound: [],
71
- outbound: []
72
- })));
73
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
74
- });
75
- // NOTE: Currently the argument to the family needs to be referentially stable for the rx to be referentially stable.
76
- // TODO(wittjosiah): Rx feature request, support for something akin to `ComplexMap` to allow for complex arguments.
77
- _connections = Rx.family((key) => {
78
- return Rx.make((get) => {
79
- const [id, relation] = key.split("$");
80
- const edges = get(this._edges(id));
81
- return edges[relation].map((id2) => get(this._node(id2))).filter(Option.isSome).map((o) => o.value);
82
- }).pipe(Rx.withLabel(`graph:connections:${key}`));
83
- });
84
- _actions = Rx.family((id) => {
85
- return Rx.make((get) => {
86
- return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
87
- }).pipe(Rx.withLabel(`graph:actions:${id}`));
88
- });
89
- _json = Rx.family((id) => {
90
- return Rx.make((get) => {
91
- const toJSON = (node, seen = []) => {
92
- const nodes = get(this.connections(node.id));
93
- const obj = {
94
- id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
95
- type: node.type
96
- };
97
- if (node.properties.label) {
98
- obj.label = node.properties.label;
99
- }
100
- if (nodes.length) {
101
- obj.nodes = nodes.map((n) => {
102
- const nextSeen = [
103
- ...seen,
104
- node.id
105
- ];
106
- return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
107
- }).filter(isNonNullable);
108
- }
109
- return obj;
110
- };
111
- const root = get(this.nodeOrThrow(id));
112
- return toJSON(root);
113
- }).pipe(Rx.withLabel(`graph:json:${id}`));
114
- });
115
- constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
116
- this._registry = registry ?? Registry.make();
117
- this._onInitialize = onInitialize;
118
- this._onExpand = onExpand;
119
- this._onRemoveNode = onRemoveNode;
120
- if (nodes) {
121
- nodes.forEach((node) => {
122
- Record.set(this._initialNodes, node.id, this._constructNode(node));
123
- });
124
- }
125
- if (edges) {
126
- Object.entries(edges).forEach(([source, edges2]) => {
127
- Record.set(this._initialEdges, source, edges2);
128
- });
129
- }
130
- }
131
- toJSON(id = ROOT_ID) {
132
- return this._registry.get(this._json(id));
133
- }
134
- json(id = ROOT_ID) {
135
- return this._json(id);
136
- }
137
- node(id) {
138
- return this._node(id);
139
- }
140
- nodeOrThrow(id) {
141
- return this._nodeOrThrow(id);
142
- }
143
- connections(id, relation = "outbound") {
144
- return this._connections(`${id}$${relation}`);
145
- }
146
- actions(id) {
147
- return this._actions(id);
148
- }
149
- edges(id) {
150
- return this._edges(id);
151
- }
152
- get root() {
153
- return this.getNodeOrThrow(ROOT_ID);
154
- }
155
- getNode(id) {
156
- return this._registry.get(this.node(id));
157
- }
158
- getNodeOrThrow(id) {
159
- return this._registry.get(this.nodeOrThrow(id));
160
- }
161
- getConnections(id, relation = "outbound") {
162
- return this._registry.get(this.connections(id, relation));
163
- }
164
- getActions(id) {
165
- return this._registry.get(this.actions(id));
166
- }
167
- getEdges(id) {
168
- return this._registry.get(this.edges(id));
169
- }
170
- async initialize(id) {
171
- const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
172
- log("initialize", {
173
- id,
174
- initialized
175
- }, {
176
- F: __dxlog_file,
177
- L: 384,
178
- S: this,
179
- C: (f, a) => f(...a)
180
- });
181
- if (!initialized) {
182
- await this._onInitialize?.(id);
183
- Record.set(this._initialized, id, true);
184
- }
185
- }
186
- expand(id, relation = "outbound") {
187
- const key = `${id}$${relation}`;
188
- const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
189
- log("expand", {
190
- key,
191
- expanded
192
- }, {
193
- F: __dxlog_file,
194
- L: 394,
195
- S: this,
196
- C: (f, a) => f(...a)
197
- });
198
- if (!expanded) {
199
- this._onExpand?.(id, relation);
200
- Record.set(this._expanded, key, true);
201
- }
202
- }
203
- addNodes(nodes) {
204
- Rx.batch(() => {
205
- nodes.map((node) => this.addNode(node));
206
- });
207
- }
208
- addNode({ nodes, edges, ...nodeArg }) {
209
- const { id, type, data = null, properties = {} } = nodeArg;
210
- const nodeRx = this._node(id);
211
- const node = this._registry.get(nodeRx);
212
- Option.match(node, {
213
- onSome: (node2) => {
214
- const typeChanged = node2.type !== type;
215
- const dataChanged = node2.data !== data;
216
- const propertiesChanged = Object.keys(properties).some((key) => node2.properties[key] !== properties[key]);
217
- log("existing node", {
218
- id,
219
- typeChanged,
220
- dataChanged,
221
- propertiesChanged
222
- }, {
223
- F: __dxlog_file,
224
- L: 416,
225
- S: this,
226
- C: (f, a) => f(...a)
227
- });
228
- if (typeChanged || dataChanged || propertiesChanged) {
229
- log("updating node", {
230
- id,
231
- type,
232
- data,
233
- properties
234
- }, {
235
- F: __dxlog_file,
236
- L: 418,
237
- S: this,
238
- C: (f, a) => f(...a)
239
- });
240
- const newNode = Option.some({
241
- ...node2,
242
- type,
243
- data,
244
- properties: {
245
- ...node2.properties,
246
- ...properties
247
- }
248
- });
249
- this._registry.set(nodeRx, newNode);
250
- this.onNodeChanged.emit({
251
- id,
252
- node: newNode
253
- });
254
- }
255
- },
256
- onNone: () => {
257
- log("new node", {
258
- id,
259
- type,
260
- data,
261
- properties
262
- }, {
263
- F: __dxlog_file,
264
- L: 425,
265
- S: this,
266
- C: (f, a) => f(...a)
267
- });
268
- const newNode = this._constructNode({
269
- id,
270
- type,
271
- data,
272
- properties
273
- });
274
- this._registry.set(nodeRx, newNode);
275
- this.onNodeChanged.emit({
276
- id,
277
- node: newNode
278
- });
279
- }
280
- });
281
- if (nodes) {
282
- this.addNodes(nodes);
283
- const _edges = nodes.map((node2) => ({
284
- source: id,
285
- target: node2.id
286
- }));
287
- this.addEdges(_edges);
288
- }
289
- if (edges) {
290
- todo();
291
- }
292
- }
293
- removeNodes(ids, edges = false) {
294
- Rx.batch(() => {
295
- ids.map((id) => this.removeNode(id, edges));
296
- });
297
- }
298
- removeNode(id, edges = false) {
299
- const nodeRx = this._node(id);
300
- this._registry.set(nodeRx, Option.none());
301
- this.onNodeChanged.emit({
302
- id,
303
- node: Option.none()
304
- });
305
- if (edges) {
306
- const { inbound, outbound } = this._registry.get(this._edges(id));
307
- const edges2 = [
308
- ...inbound.map((source) => ({
309
- source,
310
- target: id
311
- })),
312
- ...outbound.map((target) => ({
313
- source: id,
314
- target
315
- }))
316
- ];
317
- this.removeEdges(edges2);
318
- }
319
- this._onRemoveNode?.(id);
320
- }
321
- addEdges(edges) {
322
- Rx.batch(() => {
323
- edges.map((edge) => this.addEdge(edge));
324
- });
325
- }
326
- addEdge(edgeArg) {
327
- const sourceRx = this._edges(edgeArg.source);
328
- const source = this._registry.get(sourceRx);
329
- if (!source.outbound.includes(edgeArg.target)) {
330
- log("add outbound edge", {
331
- source: edgeArg.source,
332
- target: edgeArg.target
333
- }, {
334
- F: __dxlog_file,
335
- L: 480,
336
- S: this,
337
- C: (f, a) => f(...a)
338
- });
339
- this._registry.set(sourceRx, {
340
- inbound: source.inbound,
341
- outbound: [
342
- ...source.outbound,
343
- edgeArg.target
344
- ]
345
- });
346
- }
347
- const targetRx = this._edges(edgeArg.target);
348
- const target = this._registry.get(targetRx);
349
- if (!target.inbound.includes(edgeArg.source)) {
350
- log("add inbound edge", {
351
- source: edgeArg.source,
352
- target: edgeArg.target
353
- }, {
354
- F: __dxlog_file,
355
- L: 487,
356
- S: this,
357
- C: (f, a) => f(...a)
358
- });
359
- this._registry.set(targetRx, {
360
- inbound: [
361
- ...target.inbound,
362
- edgeArg.source
363
- ],
364
- outbound: target.outbound
365
- });
366
- }
367
- }
368
- removeEdges(edges, removeOrphans = false) {
369
- Rx.batch(() => {
370
- edges.map((edge) => this.removeEdge(edge, removeOrphans));
371
- });
372
- }
373
- removeEdge(edgeArg, removeOrphans = false) {
374
- const sourceRx = this._edges(edgeArg.source);
375
- const source = this._registry.get(sourceRx);
376
- if (source.outbound.includes(edgeArg.target)) {
377
- this._registry.set(sourceRx, {
378
- inbound: source.inbound,
379
- outbound: source.outbound.filter((id) => id !== edgeArg.target)
380
- });
381
- }
382
- const targetRx = this._edges(edgeArg.target);
383
- const target = this._registry.get(targetRx);
384
- if (target.inbound.includes(edgeArg.source)) {
385
- this._registry.set(targetRx, {
386
- inbound: target.inbound.filter((id) => id !== edgeArg.source),
387
- outbound: target.outbound
388
- });
389
- }
390
- if (removeOrphans) {
391
- const source2 = this._registry.get(sourceRx);
392
- const target2 = this._registry.get(targetRx);
393
- if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
394
- this.removeNodes([
395
- edgeArg.source
396
- ]);
397
- }
398
- if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== ROOT_ID) {
399
- this.removeNodes([
400
- edgeArg.target
401
- ]);
402
- }
403
- }
404
- }
405
- sortEdges(id, relation, order) {
406
- const edgesRx = this._edges(id);
407
- const edges = this._registry.get(edgesRx);
408
- const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
409
- const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
410
- edges[relation].splice(0, edges[relation].length, ...[
411
- ...sorted,
412
- ...unsorted
413
- ]);
414
- this._registry.set(edgesRx, edges);
415
- }
416
- traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
417
- if (path.includes(source)) {
418
- return;
419
- }
420
- const node = this.getNodeOrThrow(source);
421
- const shouldContinue = visitor(node, [
422
- ...path,
423
- source
424
- ]);
425
- if (shouldContinue === false) {
426
- return;
427
- }
428
- Object.values(this.getConnections(source, relation)).forEach((child) => this.traverse({
429
- source: child.id,
430
- relation,
431
- visitor
432
- }, [
433
- ...path,
434
- source
435
- ]));
436
- }
437
- getPath({ source = "root", target }) {
438
- return pipe(this.getNode(source), Option.flatMap((node) => {
439
- let found = Option.none();
440
- this.traverse({
441
- source: node.id,
442
- visitor: (node2, path) => {
443
- if (Option.isSome(found)) {
444
- return false;
445
- }
446
- if (node2.id === target) {
447
- found = Option.some(path);
448
- }
449
- }
450
- });
451
- return found;
452
- }));
453
- }
454
- async waitForPath(params, { timeout = 5e3, interval = 500 } = {}) {
455
- const path = this.getPath(params);
456
- if (Option.isSome(path)) {
457
- return path.value;
458
- }
459
- const trigger = new Trigger();
460
- const i = setInterval(() => {
461
- const path2 = this.getPath(params);
462
- if (Option.isSome(path2)) {
463
- trigger.wake(path2.value);
464
- }
465
- }, interval);
466
- return trigger.wait({
467
- timeout
468
- }).finally(() => clearInterval(i));
469
- }
470
- /** @internal */
471
- _constructNode(node) {
472
- return Option.some({
473
- [graphSymbol]: this,
474
- data: null,
475
- properties: {},
476
- ...node
477
- });
478
- }
479
- };
480
-
481
- // src/graph-builder.ts
482
- import { Registry as Registry2, Rx as Rx2 } from "@effect-rx/rx-react";
483
- import { effect } from "@preact/signals-core";
484
- import { Array, Option as Option2, Record as Record2, pipe as pipe2 } from "effect";
485
- import { log as log2 } from "@dxos/log";
486
- import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
1
+ import {
2
+ __export,
3
+ getParentId,
4
+ getSegmentId,
5
+ graph_builder_exports,
6
+ graph_exports,
7
+ node_exports,
8
+ node_matcher_exports,
9
+ qualifyId
10
+ } from "./chunk-W47H2NND.mjs";
487
11
 
488
- // src/node.ts
489
- var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
490
- var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ACTION_TYPE : false;
491
- var actionGroupSymbol = Symbol("ActionGroup");
492
- var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
493
- var isActionLike = (data) => isAction(data) || isActionGroup(data);
494
-
495
- // src/graph-builder.ts
496
- var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
497
- var createExtension = (extension) => {
498
- const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
499
- const getId = (key) => `${id}/${key}`;
500
- const resolver = _resolver && Rx2.family((id2) => _resolver(id2).pipe(Rx2.withLabel(`graph-builder:_resolver:${id2}`)));
501
- const connector = _connector && Rx2.family((node) => _connector(node).pipe(Rx2.withLabel(`graph-builder:_connector:${id}`)));
502
- const actionGroups = _actionGroups && Rx2.family((node) => _actionGroups(node).pipe(Rx2.withLabel(`graph-builder:_actionGroups:${id}`)));
503
- const actions = _actions && Rx2.family((node) => _actions(node).pipe(Rx2.withLabel(`graph-builder:_actions:${id}`)));
504
- return [
505
- resolver ? {
506
- id: getId("resolver"),
507
- position,
508
- resolver
509
- } : void 0,
510
- connector ? {
511
- id: getId("connector"),
512
- position,
513
- relation,
514
- connector: Rx2.family((node) => Rx2.make((get) => {
515
- try {
516
- return get(connector(node));
517
- } catch {
518
- log2.warn("Error in connector", {
519
- id: getId("connector"),
520
- node
521
- }, {
522
- F: __dxlog_file2,
523
- L: 109,
524
- S: void 0,
525
- C: (f, a) => f(...a)
526
- });
527
- return [];
528
- }
529
- }).pipe(Rx2.withLabel(`graph-builder:connector:${id}`)))
530
- } : void 0,
531
- actionGroups ? {
532
- id: getId("actionGroups"),
533
- position,
534
- relation: "outbound",
535
- connector: Rx2.family((node) => Rx2.make((get) => {
536
- try {
537
- return get(actionGroups(node)).map((arg) => ({
538
- ...arg,
539
- data: actionGroupSymbol,
540
- type: ACTION_GROUP_TYPE
541
- }));
542
- } catch {
543
- log2.warn("Error in actionGroups", {
544
- id: getId("actionGroups"),
545
- node
546
- }, {
547
- F: __dxlog_file2,
548
- L: 130,
549
- S: void 0,
550
- C: (f, a) => f(...a)
551
- });
552
- return [];
553
- }
554
- }).pipe(Rx2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
555
- } : void 0,
556
- actions ? {
557
- id: getId("actions"),
558
- position,
559
- relation: "outbound",
560
- connector: Rx2.family((node) => Rx2.make((get) => {
561
- try {
562
- return get(actions(node)).map((arg) => ({
563
- ...arg,
564
- type: ACTION_TYPE
565
- }));
566
- } catch {
567
- log2.warn("Error in actions", {
568
- id: getId("actions"),
569
- node
570
- }, {
571
- F: __dxlog_file2,
572
- L: 147,
573
- S: void 0,
574
- C: (f, a) => f(...a)
575
- });
576
- return [];
577
- }
578
- }).pipe(Rx2.withLabel(`graph-builder:connector:actions:${id}`)))
579
- } : void 0
580
- ].filter(isNonNullable2);
581
- };
582
- var flattenExtensions = (extension, acc = []) => {
583
- if (Array.isArray(extension)) {
584
- return [
585
- ...acc,
586
- ...extension.flatMap((ext) => flattenExtensions(ext, acc))
587
- ];
588
- } else {
589
- return [
590
- ...acc,
591
- extension
592
- ];
593
- }
594
- };
595
- var GraphBuilder = class _GraphBuilder {
596
- // TODO(wittjosiah): Use Context.
597
- _subscriptions = /* @__PURE__ */ new Map();
598
- _extensions = Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions"));
599
- _initialized = {};
600
- _registry;
601
- _graph;
602
- constructor({ registry, ...params } = {}) {
603
- this._registry = registry ?? Registry2.make();
604
- this._graph = new Graph({
605
- ...params,
606
- registry: this._registry,
607
- onExpand: (id, relation) => this._onExpand(id, relation),
608
- onInitialize: (id) => this._onInitialize(id),
609
- onRemoveNode: (id) => this._onRemoveNode(id)
610
- });
611
- }
612
- static from(pickle, registry) {
613
- if (!pickle) {
614
- return new _GraphBuilder({
615
- registry
616
- });
617
- }
618
- const { nodes, edges } = JSON.parse(pickle);
619
- return new _GraphBuilder({
620
- nodes,
621
- edges,
622
- registry
623
- });
624
- }
625
- get graph() {
626
- return this._graph;
627
- }
628
- get extensions() {
629
- return this._extensions;
630
- }
631
- addExtension(extensions) {
632
- flattenExtensions(extensions).forEach((extension) => {
633
- const extensions2 = this._registry.get(this._extensions);
634
- this._registry.set(this._extensions, Record2.set(extensions2, extension.id, extension));
635
- });
636
- return this;
637
- }
638
- removeExtension(id) {
639
- const extensions = this._registry.get(this._extensions);
640
- this._registry.set(this._extensions, Record2.remove(extensions, id));
641
- return this;
642
- }
643
- async explore({ registry = Registry2.make(), source = ROOT_ID, relation = "outbound", visitor }, path = []) {
644
- if (path.includes(source)) {
645
- return;
646
- }
647
- if (!isNode()) {
648
- const { yieldOrContinue } = await import("main-thread-scheduling");
649
- await yieldOrContinue("idle");
650
- }
651
- const node = registry.get(this._graph.nodeOrThrow(source));
652
- const shouldContinue = await visitor(node, [
653
- ...path,
654
- node.id
655
- ]);
656
- if (shouldContinue === false) {
657
- return;
658
- }
659
- const nodes = Object.values(this._registry.get(this._extensions)).filter((extension) => relation === (extension.relation ?? "outbound")).map((extension) => extension.connector).filter(isNonNullable2).flatMap((connector) => registry.get(connector(this._graph.node(source))));
660
- await Promise.all(nodes.map((nodeArg) => {
661
- registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
662
- return this.explore({
663
- registry,
664
- source: nodeArg.id,
665
- relation,
666
- visitor
667
- }, [
668
- ...path,
669
- node.id
670
- ]);
671
- }));
672
- if (registry !== this._registry) {
673
- registry.reset();
674
- registry.dispose();
675
- }
676
- }
677
- destroy() {
678
- this._subscriptions.forEach((unsubscribe) => unsubscribe());
679
- this._subscriptions.clear();
680
- }
681
- _resolvers = Rx2.family((id) => {
682
- return Rx2.make((get) => {
683
- 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);
684
- });
685
- });
686
- _connectors = Rx2.family((key) => {
687
- return Rx2.make((get) => {
688
- const [id, relation] = key.split("+");
689
- const node = this._graph.node(id);
690
- return pipe2(
691
- get(this._extensions),
692
- Record2.values,
693
- // TODO(wittjosiah): Sort on write rather than read.
694
- Array.sortBy(byPosition),
695
- Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
696
- Array.map(({ connector }) => connector?.(node)),
697
- Array.filter(isNonNullable2),
698
- Array.flatMap((result) => get(result))
699
- );
700
- }).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
701
- });
702
- _onExpand(id, relation) {
703
- log2("onExpand", {
704
- id,
705
- relation,
706
- registry: getDebugName(this._registry)
707
- }, {
708
- F: __dxlog_file2,
709
- L: 324,
710
- S: this,
711
- C: (f, a) => f(...a)
712
- });
713
- const connectors = this._connectors(`${id}+${relation}`);
714
- let previous = [];
715
- const cancel = this._registry.subscribe(connectors, (nodes) => {
716
- const ids = nodes.map((n) => n.id);
717
- const removed = previous.filter((id2) => !ids.includes(id2));
718
- previous = ids;
719
- log2("update", {
720
- id,
721
- relation,
722
- ids,
723
- removed
724
- }, {
725
- F: __dxlog_file2,
726
- L: 335,
727
- S: this,
728
- C: (f, a) => f(...a)
729
- });
730
- const update = () => {
731
- Rx2.batch(() => {
732
- this._graph.removeEdges(removed.map((target) => ({
733
- source: id,
734
- target
735
- })), true);
736
- this._graph.addNodes(nodes);
737
- this._graph.addEdges(nodes.map((node) => relation === "outbound" ? {
738
- source: id,
739
- target: node.id
740
- } : {
741
- source: node.id,
742
- target: id
743
- }));
744
- this._graph.sortEdges(id, relation, nodes.map(({ id: id2 }) => id2));
745
- });
746
- };
747
- if (typeof requestAnimationFrame === "function") {
748
- requestAnimationFrame(update);
749
- } else {
750
- update();
751
- }
752
- }, {
753
- immediate: true
754
- });
755
- this._subscriptions.set(id, cancel);
756
- }
757
- // TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
758
- async _onInitialize(id) {
759
- log2("onInitialize", {
760
- id
761
- }, {
762
- F: __dxlog_file2,
763
- L: 372,
764
- S: this,
765
- C: (f, a) => f(...a)
766
- });
767
- const resolver = this._resolvers(id);
768
- const cancel = this._registry.subscribe(resolver, (node) => {
769
- const trigger = this._initialized[id];
770
- Option2.match(node, {
771
- onSome: (node2) => {
772
- this._graph.addNodes([
773
- node2
774
- ]);
775
- trigger?.wake();
776
- },
777
- onNone: () => {
778
- trigger?.wake();
779
- this._graph.removeNodes([
780
- id
781
- ]);
782
- }
783
- });
784
- }, {
785
- immediate: true
786
- });
787
- this._subscriptions.set(id, cancel);
788
- }
789
- _onRemoveNode(id) {
790
- this._subscriptions.get(id)?.();
791
- this._subscriptions.delete(id);
792
- }
793
- };
794
- var rxFromSignal = (cb) => {
795
- return Rx2.make((get) => {
796
- const dispose = effect(() => {
797
- get.setSelf(cb());
798
- });
799
- get.addFinalizer(() => dispose());
800
- return cb();
801
- });
802
- };
803
- var observableFamily = Rx2.family((observable) => {
804
- return Rx2.make((get) => {
12
+ // src/atoms.ts
13
+ var atoms_exports = {};
14
+ __export(atoms_exports, {
15
+ fromObservable: () => fromObservable
16
+ });
17
+ import { Atom } from "@effect-atom/atom-react";
18
+ var observableFamily = Atom.family((observable) => {
19
+ return Atom.make((get) => {
805
20
  const subscription = observable.subscribe((value) => get.setSelf(value));
806
21
  get.addFinalizer(() => subscription.unsubscribe());
807
22
  return observable.get();
808
23
  });
809
24
  });
810
- var rxFromObservable = (observable) => {
25
+ var fromObservable = (observable) => {
811
26
  return observableFamily(observable);
812
27
  };
813
28
  export {
814
- ACTION_GROUP_TYPE,
815
- ACTION_TYPE,
816
- Graph,
817
- GraphBuilder,
818
- ROOT_ID,
819
- ROOT_TYPE,
820
- actionGroupSymbol,
821
- createExtension,
822
- flattenExtensions,
823
- getGraph,
824
- isAction,
825
- isActionGroup,
826
- isActionLike,
827
- isGraphNode,
828
- rxFromObservable,
829
- rxFromSignal
29
+ atoms_exports as CreateAtom,
30
+ graph_exports as Graph,
31
+ graph_builder_exports as GraphBuilder,
32
+ node_exports as Node,
33
+ node_matcher_exports as NodeMatcher,
34
+ getParentId,
35
+ getSegmentId,
36
+ qualifyId
830
37
  };
831
38
  //# sourceMappingURL=index.mjs.map