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