@dxos/graph 0.8.4-main.84f28bd → 0.8.4-main.937b3ca

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.
@@ -1,29 +1,158 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
2
7
 
3
- // src/model.ts
4
- import { effect } from "@preact/signals-core";
5
- import { inspectCustom } from "@dxos/debug";
6
- import { failedInvariant, invariant as invariant2 } from "@dxos/invariant";
7
- import { live } from "@dxos/live-object";
8
- import { isNotFalsy, removeBy } from "@dxos/util";
9
-
10
- // src/util.ts
8
+ // src/selection.ts
9
+ import { Atom, Registry } from "@effect-atom/atom-react";
11
10
  import { invariant } from "@dxos/invariant";
12
- var __dxlog_file = "/__w/dxos/dxos/packages/common/graph/src/util.ts";
11
+ var __dxlog_file = "/__w/dxos/dxos/packages/common/graph/src/selection.ts";
12
+ var SelectionModel = class {
13
+ _singleSelect;
14
+ _registry;
15
+ _selected;
16
+ constructor(_singleSelect = false) {
17
+ this._singleSelect = _singleSelect;
18
+ this._registry = Registry.make();
19
+ this._selected = Atom.make(/* @__PURE__ */ new Set());
20
+ }
21
+ /**
22
+ * Returns the selected IDs atom for subscription.
23
+ */
24
+ get selected() {
25
+ return this._selected;
26
+ }
27
+ /**
28
+ * Gets the current selected IDs as a Set.
29
+ */
30
+ getSelected() {
31
+ return this._registry.get(this._selected);
32
+ }
33
+ /**
34
+ * Gets the current selected IDs as an array.
35
+ */
36
+ getSelectedIds() {
37
+ return Array.from(this._registry.get(this._selected).values());
38
+ }
39
+ /**
40
+ * Subscribe to selection changes.
41
+ */
42
+ subscribe(cb) {
43
+ this._registry.get(this._selected);
44
+ return this._registry.subscribe(this._selected, () => {
45
+ cb(this._registry.get(this._selected));
46
+ });
47
+ }
48
+ toJSON() {
49
+ return {
50
+ selected: this.getSelectedIds()
51
+ };
52
+ }
53
+ /**
54
+ * Gets the current selection size.
55
+ */
56
+ getSize() {
57
+ return this._registry.get(this._selected).size;
58
+ }
59
+ contains(id) {
60
+ return this._registry.get(this._selected).has(id);
61
+ }
62
+ clear() {
63
+ this._registry.set(this._selected, /* @__PURE__ */ new Set());
64
+ }
65
+ add(id) {
66
+ invariant(id, void 0, {
67
+ F: __dxlog_file,
68
+ L: 76,
69
+ S: this,
70
+ A: [
71
+ "id",
72
+ ""
73
+ ]
74
+ });
75
+ const current = this._registry.get(this._selected);
76
+ this._registry.set(this._selected, new Set(this._singleSelect ? [
77
+ id
78
+ ] : [
79
+ ...Array.from(current.values()),
80
+ id
81
+ ]));
82
+ }
83
+ remove(id) {
84
+ invariant(id, void 0, {
85
+ F: __dxlog_file,
86
+ L: 85,
87
+ S: this,
88
+ A: [
89
+ "id",
90
+ ""
91
+ ]
92
+ });
93
+ const current = this._registry.get(this._selected);
94
+ this._registry.set(this._selected, new Set(Array.from(current.values()).filter((_id) => _id !== id)));
95
+ }
96
+ // TODO(burdon): Handle single select.
97
+ setSelected(ids, subtract = false) {
98
+ const current = this._registry.get(this._selected);
99
+ this._registry.set(this._selected, /* @__PURE__ */ new Set([
100
+ ...subtract ? Array.from(current.values()) : [],
101
+ ...ids
102
+ ]));
103
+ }
104
+ toggleSelected(ids, subtract = false) {
105
+ const current = this._registry.get(this._selected);
106
+ const set = new Set(subtract ? Array.from(current.values()) : void 0);
107
+ ids.forEach((id) => {
108
+ if (current.has(id)) {
109
+ set.delete(id);
110
+ } else {
111
+ set.add(id);
112
+ }
113
+ });
114
+ this._registry.set(this._selected, set);
115
+ }
116
+ };
117
+
118
+ // src/Graph.ts
119
+ var Graph_exports = {};
120
+ __export(Graph_exports, {
121
+ Edge: () => Edge,
122
+ Graph: () => Graph,
123
+ Node: () => Node,
124
+ createEdgeId: () => createEdgeId,
125
+ parseEdgeId: () => parseEdgeId
126
+ });
127
+ import * as Schema from "effect/Schema";
128
+ import { invariant as invariant2 } from "@dxos/invariant";
129
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/common/graph/src/Graph.ts";
130
+ var Node = Schema.Struct({
131
+ id: Schema.String,
132
+ type: Schema.optional(Schema.String),
133
+ data: Schema.optional(Schema.Any)
134
+ });
135
+ var Edge = Schema.Struct({
136
+ id: Schema.String,
137
+ type: Schema.optional(Schema.String),
138
+ source: Schema.String,
139
+ target: Schema.String,
140
+ data: Schema.optional(Schema.Any)
141
+ });
13
142
  var KEY_REGEX = /\w+/;
14
143
  var createEdgeId = ({ source, target, relation }) => {
15
- invariant(source.match(KEY_REGEX), `invalid source: ${source}`, {
16
- F: __dxlog_file,
17
- L: 13,
144
+ invariant2(source.match(KEY_REGEX), `invalid source: ${source}`, {
145
+ F: __dxlog_file2,
146
+ L: 52,
18
147
  S: void 0,
19
148
  A: [
20
149
  "source.match(KEY_REGEX)",
21
150
  "`invalid source: ${source}`"
22
151
  ]
23
152
  });
24
- invariant(target.match(KEY_REGEX), `invalid target: ${target}`, {
25
- F: __dxlog_file,
26
- L: 14,
153
+ invariant2(target.match(KEY_REGEX), `invalid target: ${target}`, {
154
+ F: __dxlog_file2,
155
+ L: 53,
27
156
  S: void 0,
28
157
  A: [
29
158
  "target.match(KEY_REGEX)",
@@ -38,9 +167,9 @@ var createEdgeId = ({ source, target, relation }) => {
38
167
  };
39
168
  var parseEdgeId = (id) => {
40
169
  const [source, relation, target] = id.split("_");
41
- invariant(source.length && target.length, void 0, {
42
- F: __dxlog_file,
43
- L: 20,
170
+ invariant2(source.length && target.length, void 0, {
171
+ F: __dxlog_file2,
172
+ L: 59,
44
173
  S: void 0,
45
174
  A: [
46
175
  "source.length && target.length",
@@ -53,18 +182,45 @@ var parseEdgeId = (id) => {
53
182
  target
54
183
  };
55
184
  };
185
+ var Graph = Schema.Struct({
186
+ id: Schema.optional(Schema.String),
187
+ nodes: Schema.mutable(Schema.Array(Node)),
188
+ edges: Schema.mutable(Schema.Array(Edge))
189
+ });
56
190
 
57
- // src/model.ts
58
- var __dxlog_file2 = "/__w/dxos/dxos/packages/common/graph/src/model.ts";
191
+ // src/GraphModel.ts
192
+ var GraphModel_exports = {};
193
+ __export(GraphModel_exports, {
194
+ AbstractBuilder: () => AbstractBuilder,
195
+ AbstractGraphModel: () => AbstractGraphModel,
196
+ Builder: () => Builder,
197
+ GraphModel: () => GraphModel,
198
+ ReactiveGraphModel: () => ReactiveGraphModel,
199
+ ReadonlyGraphModel: () => ReadonlyGraphModel
200
+ });
201
+ import { Atom as Atom2 } from "@effect-atom/atom-react";
202
+ import { inspectCustom } from "@dxos/debug";
203
+ import { failedInvariant, invariant as invariant3 } from "@dxos/invariant";
204
+ import { isTruthy, removeBy } from "@dxos/util";
205
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/common/graph/src/GraphModel.ts";
59
206
  var ReadonlyGraphModel = class {
207
+ _graph;
208
+ /**
209
+ * Optional function to wrap mutations.
210
+ * When set, all graph mutations are wrapped in this function.
211
+ */
212
+ _change;
60
213
  /**
61
214
  * NOTE: Pass in simple Graph or Live.
215
+ * @param graph - The graph data.
216
+ * @param change - Optional function to wrap mutations (e.g., Obj.change for ECHO objects).
62
217
  */
63
- constructor(graph) {
218
+ constructor(graph, change) {
64
219
  this._graph = graph ?? {
65
220
  nodes: [],
66
221
  edges: []
67
222
  };
223
+ this._change = change;
68
224
  }
69
225
  [inspectCustom]() {
70
226
  return this.toJSON();
@@ -124,7 +280,7 @@ var ReadonlyGraphModel = class {
124
280
  visited.add(root.id);
125
281
  const targets = this.filterEdges({
126
282
  source: root.id
127
- }).map((edge) => this.getNode(edge.target)).filter(isNotFalsy);
283
+ }).map((edge) => this.getNode(edge.target)).filter(isTruthy);
128
284
  return [
129
285
  root,
130
286
  ...targets.flatMap((target) => this._traverse(target, visited))
@@ -132,9 +288,22 @@ var ReadonlyGraphModel = class {
132
288
  }
133
289
  };
134
290
  var AbstractGraphModel = class extends ReadonlyGraphModel {
291
+ /**
292
+ * Execute a mutation on the graph.
293
+ * If a change function is set, wraps the mutation in it.
294
+ */
295
+ _mutate(fn) {
296
+ if (this._change != null) {
297
+ this._change(() => fn(this._graph));
298
+ } else {
299
+ fn(this._graph);
300
+ }
301
+ }
135
302
  clear() {
136
- this._graph.nodes.length = 0;
137
- this._graph.edges.length = 0;
303
+ this._mutate((graph) => {
304
+ graph.nodes.length = 0;
305
+ graph.edges.length = 0;
306
+ });
138
307
  return this;
139
308
  }
140
309
  addGraph(graph) {
@@ -150,43 +319,45 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
150
319
  return this;
151
320
  }
152
321
  addNode(node) {
153
- invariant2(node.id, "ID is required", {
154
- F: __dxlog_file2,
155
- L: 157,
322
+ invariant3(node.id, "ID is required", {
323
+ F: __dxlog_file3,
324
+ L: 182,
156
325
  S: this,
157
326
  A: [
158
327
  "node.id",
159
328
  "'ID is required'"
160
329
  ]
161
330
  });
162
- invariant2(!this.findNode(node.id), `node already exists: ${node.id}`, {
163
- F: __dxlog_file2,
164
- L: 158,
331
+ invariant3(!this.findNode(node.id), `node already exists: ${node.id}`, {
332
+ F: __dxlog_file3,
333
+ L: 183,
165
334
  S: this,
166
335
  A: [
167
336
  "!this.findNode(node.id)",
168
337
  "`node already exists: ${node.id}`"
169
338
  ]
170
339
  });
171
- this._graph.nodes.push(node);
340
+ this._mutate((graph) => {
341
+ graph.nodes.push(node);
342
+ });
172
343
  return node;
173
344
  }
174
345
  addNodes(nodes) {
175
346
  return nodes.map((node) => this.addNode(node));
176
347
  }
177
348
  addEdge(edge) {
178
- invariant2(edge.source, void 0, {
179
- F: __dxlog_file2,
180
- L: 168,
349
+ invariant3(edge.source, void 0, {
350
+ F: __dxlog_file3,
351
+ L: 195,
181
352
  S: this,
182
353
  A: [
183
354
  "edge.source",
184
355
  ""
185
356
  ]
186
357
  });
187
- invariant2(edge.target, void 0, {
188
- F: __dxlog_file2,
189
- L: 169,
358
+ invariant3(edge.target, void 0, {
359
+ F: __dxlog_file3,
360
+ L: 196,
190
361
  S: this,
191
362
  A: [
192
363
  "edge.target",
@@ -199,27 +370,33 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
199
370
  ...edge
200
371
  };
201
372
  }
202
- invariant2(!this.findNode(edge.id), void 0, {
203
- F: __dxlog_file2,
204
- L: 174,
373
+ invariant3(!this.findNode(edge.id), void 0, {
374
+ F: __dxlog_file3,
375
+ L: 201,
205
376
  S: this,
206
377
  A: [
207
378
  "!this.findNode(edge.id!)",
208
379
  ""
209
380
  ]
210
381
  });
211
- this._graph.edges.push(edge);
382
+ this._mutate((graph) => {
383
+ graph.edges.push(edge);
384
+ });
212
385
  return edge;
213
386
  }
214
387
  addEdges(edges) {
215
388
  return edges.map((edge) => this.addEdge(edge));
216
389
  }
217
390
  removeNode(id) {
218
- const edges = removeBy(this._graph.edges, (edge) => edge.source === id || edge.target === id);
219
- const nodes = removeBy(this._graph.nodes, (node) => node.id === id);
391
+ let removedEdges = [];
392
+ let removedNodes = [];
393
+ this._mutate((graph) => {
394
+ removedEdges = removeBy(graph.edges, (edge) => edge.source === id || edge.target === id);
395
+ removedNodes = removeBy(graph.nodes, (node) => node.id === id);
396
+ });
220
397
  return this.copy({
221
- nodes,
222
- edges
398
+ nodes: removedNodes,
399
+ edges: removedEdges
223
400
  });
224
401
  }
225
402
  removeNodes(ids) {
@@ -227,10 +404,13 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
227
404
  return this.copy().addGraphs(graphs);
228
405
  }
229
406
  removeEdge(id) {
230
- const edges = removeBy(this._graph.edges, (edge) => edge.id === id);
407
+ let removedEdges = [];
408
+ this._mutate((graph) => {
409
+ removedEdges = removeBy(graph.edges, (edge) => edge.id === id);
410
+ });
231
411
  return this.copy({
232
412
  nodes: [],
233
- edges
413
+ edges: removedEdges
234
414
  });
235
415
  }
236
416
  removeEdges(ids) {
@@ -238,7 +418,8 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
238
418
  return this.copy().addGraphs(graphs);
239
419
  }
240
420
  };
241
- var AbstractGraphBuilder = class {
421
+ var AbstractBuilder = class {
422
+ _model;
242
423
  constructor(_model) {
243
424
  this._model = _model;
244
425
  }
@@ -271,152 +452,178 @@ var AbstractGraphBuilder = class {
271
452
  };
272
453
  var GraphModel = class _GraphModel extends AbstractGraphModel {
273
454
  get builder() {
274
- return new GraphBuilder(this);
455
+ return new Builder(this);
275
456
  }
276
457
  copy(graph) {
277
- return new _GraphModel({
278
- nodes: graph?.nodes ?? [],
279
- edges: graph?.edges ?? []
280
- });
458
+ return new _GraphModel(graph);
281
459
  }
282
460
  };
283
- var subscribe = (model, cb, fire = false) => {
284
- if (fire) {
285
- cb(model, model.graph);
286
- }
287
- return effect(() => {
288
- cb(model, model.graph);
289
- });
290
- };
291
461
  var ReactiveGraphModel = class _ReactiveGraphModel extends GraphModel {
292
- constructor(graph) {
293
- super(live({
462
+ _registry;
463
+ _graphAtom;
464
+ constructor(_registry, graph) {
465
+ const initialGraph = {
294
466
  nodes: graph?.nodes ?? [],
295
467
  edges: graph?.edges ?? []
296
- }));
468
+ };
469
+ super(initialGraph), this._registry = _registry;
470
+ this._graphAtom = Atom2.make(initialGraph);
297
471
  }
298
- copy(graph) {
299
- return new _ReactiveGraphModel(graph);
472
+ get registry() {
473
+ return this._registry;
300
474
  }
301
- subscribe(cb, fire = false) {
302
- return subscribe(this, cb, fire);
475
+ /**
476
+ * Get the graph atom for reactive subscriptions.
477
+ */
478
+ get graphAtom() {
479
+ return this._graphAtom;
303
480
  }
304
- };
305
- var GraphBuilder = class extends AbstractGraphBuilder {
306
- call(cb) {
307
- cb(this);
308
- return this;
481
+ get graph() {
482
+ return this._registry.get(this._graphAtom);
309
483
  }
310
- };
311
-
312
- // src/selection.ts
313
- import { computed, signal } from "@preact/signals-core";
314
- import { invariant as invariant3 } from "@dxos/invariant";
315
- var __dxlog_file3 = "/__w/dxos/dxos/packages/common/graph/src/selection.ts";
316
- var SelectionModel = class {
317
- constructor(_singleSelect = false) {
318
- this._singleSelect = _singleSelect;
319
- this._selected = signal(/* @__PURE__ */ new Set());
320
- this._selectedIds = computed(() => Array.from(this._selected.value.values()));
484
+ get nodes() {
485
+ return this.graph.nodes;
321
486
  }
322
- toJSON() {
323
- return {
324
- selected: Array.from(this._selected.value.values())
325
- };
487
+ get edges() {
488
+ return this.graph.edges;
326
489
  }
327
- get size() {
328
- return this._selected.value.size;
490
+ copy(graph) {
491
+ return new _ReactiveGraphModel(this._registry, graph);
329
492
  }
330
- get selected() {
331
- return this._selectedIds;
493
+ clear() {
494
+ this._registry.set(this._graphAtom, {
495
+ nodes: [],
496
+ edges: []
497
+ });
498
+ return this;
332
499
  }
333
- contains(id) {
334
- return this._selected.value.has(id);
500
+ /**
501
+ * Set the entire graph at once, triggering a single notification.
502
+ */
503
+ setGraph(graph) {
504
+ this._registry.set(this._graphAtom, graph);
505
+ return this;
335
506
  }
336
- clear() {
337
- this._selected.value = /* @__PURE__ */ new Set();
507
+ addNode(node) {
508
+ invariant3(node.id, "ID is required", {
509
+ F: __dxlog_file3,
510
+ L: 374,
511
+ S: this,
512
+ A: [
513
+ "node.id",
514
+ "'ID is required'"
515
+ ]
516
+ });
517
+ invariant3(!this.findNode(node.id), `node already exists: ${node.id}`, {
518
+ F: __dxlog_file3,
519
+ L: 375,
520
+ S: this,
521
+ A: [
522
+ "!this.findNode(node.id)",
523
+ "`node already exists: ${node.id}`"
524
+ ]
525
+ });
526
+ const current = this._registry.get(this._graphAtom);
527
+ this._registry.set(this._graphAtom, {
528
+ ...current,
529
+ nodes: [
530
+ ...current.nodes,
531
+ node
532
+ ]
533
+ });
534
+ return node;
338
535
  }
339
- add(id) {
340
- invariant3(id, void 0, {
536
+ addEdge(edge) {
537
+ invariant3(edge.source, void 0, {
341
538
  F: __dxlog_file3,
342
- L: 41,
539
+ L: 385,
343
540
  S: this,
344
541
  A: [
345
- "id",
542
+ "edge.source",
346
543
  ""
347
544
  ]
348
545
  });
349
- this._selected.value = new Set(this._singleSelect ? [
350
- id
351
- ] : [
352
- ...Array.from(this._selected.value.values()),
353
- id
354
- ]);
355
- }
356
- remove(id) {
357
- invariant3(id, void 0, {
546
+ invariant3(edge.target, void 0, {
358
547
  F: __dxlog_file3,
359
- L: 48,
548
+ L: 386,
360
549
  S: this,
361
550
  A: [
362
- "id",
551
+ "edge.target",
552
+ ""
553
+ ]
554
+ });
555
+ if (!edge.id) {
556
+ edge = {
557
+ id: createEdgeId(edge),
558
+ ...edge
559
+ };
560
+ }
561
+ invariant3(!this.findNode(edge.id), void 0, {
562
+ F: __dxlog_file3,
563
+ L: 390,
564
+ S: this,
565
+ A: [
566
+ "!this.findNode(edge.id!)",
363
567
  ""
364
568
  ]
365
569
  });
366
- this._selected.value = new Set(Array.from(this._selected.value.values()).filter((_id) => _id !== id));
570
+ const current = this._registry.get(this._graphAtom);
571
+ this._registry.set(this._graphAtom, {
572
+ ...current,
573
+ edges: [
574
+ ...current.edges,
575
+ edge
576
+ ]
577
+ });
578
+ return edge;
367
579
  }
368
- // TODO(burdon): Handle single select.
369
- setSelected(ids, shift = false) {
370
- this._selected.value = /* @__PURE__ */ new Set([
371
- ...shift ? Array.from(this._selected.value.values()) : [],
372
- ...ids
373
- ]);
580
+ removeNode(id) {
581
+ const current = this._registry.get(this._graphAtom);
582
+ const removedEdges = current.edges.filter((edge) => edge.source === id || edge.target === id);
583
+ const removedNodes = current.nodes.filter((node) => node.id === id);
584
+ this._registry.set(this._graphAtom, {
585
+ nodes: current.nodes.filter((node) => node.id !== id),
586
+ edges: current.edges.filter((edge) => edge.source !== id && edge.target !== id)
587
+ });
588
+ return this.copy({
589
+ nodes: removedNodes,
590
+ edges: removedEdges
591
+ });
374
592
  }
375
- toggleSelected(ids, shift = false) {
376
- const set = new Set(shift ? Array.from(this._selected.value.values()) : void 0);
377
- ids.forEach((id) => {
378
- if (this._selected.value.has(id)) {
379
- set.delete(id);
380
- } else {
381
- set.add(id);
382
- }
593
+ removeEdge(id) {
594
+ const current = this._registry.get(this._graphAtom);
595
+ const removedEdges = current.edges.filter((edge) => edge.id === id);
596
+ this._registry.set(this._graphAtom, {
597
+ ...current,
598
+ edges: current.edges.filter((edge) => edge.id !== id)
599
+ });
600
+ return this.copy({
601
+ nodes: [],
602
+ edges: removedEdges
603
+ });
604
+ }
605
+ /**
606
+ * Subscribe to graph changes.
607
+ */
608
+ subscribe(cb, fire = false) {
609
+ if (fire) {
610
+ cb(this, this.graph);
611
+ }
612
+ this._registry.get(this._graphAtom);
613
+ return this._registry.subscribe(this._graphAtom, () => {
614
+ cb(this, this.graph);
383
615
  });
384
- this._selected.value = set;
385
616
  }
386
617
  };
387
-
388
- // src/types.ts
389
- import { Schema } from "effect";
390
- var BaseGraphNode = Schema.Struct({
391
- id: Schema.String,
392
- type: Schema.optional(Schema.String),
393
- data: Schema.optional(Schema.Any)
394
- });
395
- var BaseGraphEdge = Schema.Struct({
396
- id: Schema.String,
397
- type: Schema.optional(Schema.String),
398
- source: Schema.String,
399
- target: Schema.String,
400
- data: Schema.optional(Schema.Any)
401
- });
402
- var Graph = Schema.Struct({
403
- id: Schema.optional(Schema.String),
404
- nodes: Schema.mutable(Schema.Array(BaseGraphNode)),
405
- edges: Schema.mutable(Schema.Array(BaseGraphEdge))
406
- });
618
+ var Builder = class extends AbstractBuilder {
619
+ call(cb) {
620
+ cb(this);
621
+ return this;
622
+ }
623
+ };
407
624
  export {
408
- AbstractGraphBuilder,
409
- AbstractGraphModel,
410
- BaseGraphEdge,
411
- BaseGraphNode,
412
- Graph,
413
- GraphBuilder,
414
- GraphModel,
415
- ReactiveGraphModel,
416
- ReadonlyGraphModel,
417
- SelectionModel,
418
- createEdgeId,
419
- parseEdgeId,
420
- subscribe
625
+ Graph_exports as Graph,
626
+ GraphModel_exports as GraphModel,
627
+ SelectionModel
421
628
  };
422
629
  //# sourceMappingURL=index.mjs.map