@dxos/app-graph 0.8.4-main.ead640a → 0.8.4-main.f466a3d56e

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