@dxos/graph 0.8.4-main.66e292d → 0.8.4-main.69d29f4

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 { isTruthy, 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,19 +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 {
60
207
  _graph;
61
208
  /**
209
+ * Optional function to wrap mutations.
210
+ * When set, all graph mutations are wrapped in this function.
211
+ */
212
+ _change;
213
+ /**
62
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).
63
217
  */
64
- constructor(graph) {
218
+ constructor(graph, change) {
65
219
  this._graph = graph ?? {
66
220
  nodes: [],
67
221
  edges: []
68
222
  };
223
+ this._change = change;
69
224
  }
70
225
  [inspectCustom]() {
71
226
  return this.toJSON();
@@ -133,9 +288,22 @@ var ReadonlyGraphModel = class {
133
288
  }
134
289
  };
135
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
+ }
136
302
  clear() {
137
- this._graph.nodes.length = 0;
138
- this._graph.edges.length = 0;
303
+ this._mutate((graph) => {
304
+ graph.nodes.length = 0;
305
+ graph.edges.length = 0;
306
+ });
139
307
  return this;
140
308
  }
141
309
  addGraph(graph) {
@@ -151,43 +319,45 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
151
319
  return this;
152
320
  }
153
321
  addNode(node) {
154
- invariant2(node.id, "ID is required", {
155
- F: __dxlog_file2,
156
- L: 157,
322
+ invariant3(node.id, "ID is required", {
323
+ F: __dxlog_file3,
324
+ L: 182,
157
325
  S: this,
158
326
  A: [
159
327
  "node.id",
160
328
  "'ID is required'"
161
329
  ]
162
330
  });
163
- invariant2(!this.findNode(node.id), `node already exists: ${node.id}`, {
164
- F: __dxlog_file2,
165
- L: 158,
331
+ invariant3(!this.findNode(node.id), `node already exists: ${node.id}`, {
332
+ F: __dxlog_file3,
333
+ L: 183,
166
334
  S: this,
167
335
  A: [
168
336
  "!this.findNode(node.id)",
169
337
  "`node already exists: ${node.id}`"
170
338
  ]
171
339
  });
172
- this._graph.nodes.push(node);
340
+ this._mutate((graph) => {
341
+ graph.nodes.push(node);
342
+ });
173
343
  return node;
174
344
  }
175
345
  addNodes(nodes) {
176
346
  return nodes.map((node) => this.addNode(node));
177
347
  }
178
348
  addEdge(edge) {
179
- invariant2(edge.source, void 0, {
180
- F: __dxlog_file2,
181
- L: 168,
349
+ invariant3(edge.source, void 0, {
350
+ F: __dxlog_file3,
351
+ L: 195,
182
352
  S: this,
183
353
  A: [
184
354
  "edge.source",
185
355
  ""
186
356
  ]
187
357
  });
188
- invariant2(edge.target, void 0, {
189
- F: __dxlog_file2,
190
- L: 169,
358
+ invariant3(edge.target, void 0, {
359
+ F: __dxlog_file3,
360
+ L: 196,
191
361
  S: this,
192
362
  A: [
193
363
  "edge.target",
@@ -200,27 +370,33 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
200
370
  ...edge
201
371
  };
202
372
  }
203
- invariant2(!this.findNode(edge.id), void 0, {
204
- F: __dxlog_file2,
205
- L: 174,
373
+ invariant3(!this.findNode(edge.id), void 0, {
374
+ F: __dxlog_file3,
375
+ L: 201,
206
376
  S: this,
207
377
  A: [
208
378
  "!this.findNode(edge.id!)",
209
379
  ""
210
380
  ]
211
381
  });
212
- this._graph.edges.push(edge);
382
+ this._mutate((graph) => {
383
+ graph.edges.push(edge);
384
+ });
213
385
  return edge;
214
386
  }
215
387
  addEdges(edges) {
216
388
  return edges.map((edge) => this.addEdge(edge));
217
389
  }
218
390
  removeNode(id) {
219
- const edges = removeBy(this._graph.edges, (edge) => edge.source === id || edge.target === id);
220
- 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
+ });
221
397
  return this.copy({
222
- nodes,
223
- edges
398
+ nodes: removedNodes,
399
+ edges: removedEdges
224
400
  });
225
401
  }
226
402
  removeNodes(ids) {
@@ -228,10 +404,13 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
228
404
  return this.copy().addGraphs(graphs);
229
405
  }
230
406
  removeEdge(id) {
231
- 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
+ });
232
411
  return this.copy({
233
412
  nodes: [],
234
- edges
413
+ edges: removedEdges
235
414
  });
236
415
  }
237
416
  removeEdges(ids) {
@@ -239,7 +418,7 @@ var AbstractGraphModel = class extends ReadonlyGraphModel {
239
418
  return this.copy().addGraphs(graphs);
240
419
  }
241
420
  };
242
- var AbstractGraphBuilder = class {
421
+ var AbstractBuilder = class {
243
422
  _model;
244
423
  constructor(_model) {
245
424
  this._model = _model;
@@ -273,153 +452,178 @@ var AbstractGraphBuilder = class {
273
452
  };
274
453
  var GraphModel = class _GraphModel extends AbstractGraphModel {
275
454
  get builder() {
276
- return new GraphBuilder(this);
455
+ return new Builder(this);
277
456
  }
278
457
  copy(graph) {
279
- return new _GraphModel({
280
- nodes: graph?.nodes ?? [],
281
- edges: graph?.edges ?? []
282
- });
458
+ return new _GraphModel(graph);
283
459
  }
284
460
  };
285
- var subscribe = (model, cb, fire = false) => {
286
- if (fire) {
287
- cb(model, model.graph);
288
- }
289
- return effect(() => {
290
- cb(model, model.graph);
291
- });
292
- };
293
461
  var ReactiveGraphModel = class _ReactiveGraphModel extends GraphModel {
294
- constructor(graph) {
295
- super(live({
462
+ _registry;
463
+ _graphAtom;
464
+ constructor(_registry, graph) {
465
+ const initialGraph = {
296
466
  nodes: graph?.nodes ?? [],
297
467
  edges: graph?.edges ?? []
298
- }));
468
+ };
469
+ super(initialGraph), this._registry = _registry;
470
+ this._graphAtom = Atom2.make(initialGraph);
299
471
  }
300
- copy(graph) {
301
- return new _ReactiveGraphModel(graph);
472
+ get registry() {
473
+ return this._registry;
302
474
  }
303
- subscribe(cb, fire = false) {
304
- return subscribe(this, cb, fire);
475
+ /**
476
+ * Get the graph atom for reactive subscriptions.
477
+ */
478
+ get graphAtom() {
479
+ return this._graphAtom;
305
480
  }
306
- };
307
- var GraphBuilder = class extends AbstractGraphBuilder {
308
- call(cb) {
309
- cb(this);
310
- return this;
481
+ get graph() {
482
+ return this._registry.get(this._graphAtom);
311
483
  }
312
- };
313
-
314
- // src/selection.ts
315
- import { computed, signal } from "@preact/signals-core";
316
- import { invariant as invariant3 } from "@dxos/invariant";
317
- var __dxlog_file3 = "/__w/dxos/dxos/packages/common/graph/src/selection.ts";
318
- var SelectionModel = class {
319
- _singleSelect;
320
- _selected = signal(/* @__PURE__ */ new Set());
321
- _selectedIds = computed(() => Array.from(this._selected.value.values()));
322
- constructor(_singleSelect = false) {
323
- this._singleSelect = _singleSelect;
484
+ get nodes() {
485
+ return this.graph.nodes;
324
486
  }
325
- toJSON() {
326
- return {
327
- selected: Array.from(this._selected.value.values())
328
- };
487
+ get edges() {
488
+ return this.graph.edges;
329
489
  }
330
- get size() {
331
- return this._selected.value.size;
490
+ copy(graph) {
491
+ return new _ReactiveGraphModel(this._registry, graph);
332
492
  }
333
- get selected() {
334
- return this._selectedIds;
493
+ clear() {
494
+ this._registry.set(this._graphAtom, {
495
+ nodes: [],
496
+ edges: []
497
+ });
498
+ return this;
335
499
  }
336
- contains(id) {
337
- 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;
338
506
  }
339
- clear() {
340
- 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;
341
535
  }
342
- add(id) {
343
- invariant3(id, void 0, {
536
+ addEdge(edge) {
537
+ invariant3(edge.source, void 0, {
344
538
  F: __dxlog_file3,
345
- L: 41,
539
+ L: 385,
346
540
  S: this,
347
541
  A: [
348
- "id",
542
+ "edge.source",
349
543
  ""
350
544
  ]
351
545
  });
352
- this._selected.value = new Set(this._singleSelect ? [
353
- id
354
- ] : [
355
- ...Array.from(this._selected.value.values()),
356
- id
357
- ]);
358
- }
359
- remove(id) {
360
- invariant3(id, void 0, {
546
+ invariant3(edge.target, void 0, {
361
547
  F: __dxlog_file3,
362
- L: 48,
548
+ L: 386,
363
549
  S: this,
364
550
  A: [
365
- "id",
551
+ "edge.target",
366
552
  ""
367
553
  ]
368
554
  });
369
- this._selected.value = new Set(Array.from(this._selected.value.values()).filter((_id) => _id !== id));
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!)",
567
+ ""
568
+ ]
569
+ });
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;
370
579
  }
371
- // TODO(burdon): Handle single select.
372
- setSelected(ids, shift = false) {
373
- this._selected.value = /* @__PURE__ */ new Set([
374
- ...shift ? Array.from(this._selected.value.values()) : [],
375
- ...ids
376
- ]);
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
+ });
377
592
  }
378
- toggleSelected(ids, shift = false) {
379
- const set = new Set(shift ? Array.from(this._selected.value.values()) : void 0);
380
- ids.forEach((id) => {
381
- if (this._selected.value.has(id)) {
382
- set.delete(id);
383
- } else {
384
- set.add(id);
385
- }
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);
386
615
  });
387
- this._selected.value = set;
388
616
  }
389
617
  };
390
-
391
- // src/types.ts
392
- import * as Schema from "effect/Schema";
393
- var BaseGraphNode = Schema.Struct({
394
- id: Schema.String,
395
- type: Schema.optional(Schema.String),
396
- data: Schema.optional(Schema.Any)
397
- });
398
- var BaseGraphEdge = Schema.Struct({
399
- id: Schema.String,
400
- type: Schema.optional(Schema.String),
401
- source: Schema.String,
402
- target: Schema.String,
403
- data: Schema.optional(Schema.Any)
404
- });
405
- var Graph = Schema.Struct({
406
- id: Schema.optional(Schema.String),
407
- nodes: Schema.mutable(Schema.Array(BaseGraphNode)),
408
- edges: Schema.mutable(Schema.Array(BaseGraphEdge))
409
- });
618
+ var Builder = class extends AbstractBuilder {
619
+ call(cb) {
620
+ cb(this);
621
+ return this;
622
+ }
623
+ };
410
624
  export {
411
- AbstractGraphBuilder,
412
- AbstractGraphModel,
413
- BaseGraphEdge,
414
- BaseGraphNode,
415
- Graph,
416
- GraphBuilder,
417
- GraphModel,
418
- ReactiveGraphModel,
419
- ReadonlyGraphModel,
420
- SelectionModel,
421
- createEdgeId,
422
- parseEdgeId,
423
- subscribe
625
+ Graph_exports as Graph,
626
+ GraphModel_exports as GraphModel,
627
+ SelectionModel
424
628
  };
425
629
  //# sourceMappingURL=index.mjs.map