@dxos/app-graph 0.8.4-main.7ace549 → 0.8.4-main.8360d9e660
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.
- package/dist/lib/browser/index.mjs +1345 -602
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1344 -602
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/atoms.d.ts +8 -0
- package/dist/types/src/atoms.d.ts.map +1 -0
- package/dist/types/src/graph-builder.d.ts +111 -65
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +179 -213
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node-matcher.d.ts +218 -0
- package/dist/types/src/node-matcher.d.ts.map +1 -0
- package/dist/types/src/node-matcher.test.d.ts +2 -0
- package/dist/types/src/node-matcher.test.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +44 -5
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +34 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -34
- package/src/atoms.ts +25 -0
- package/src/graph-builder.test.ts +870 -112
- package/src/graph-builder.ts +696 -284
- package/src/graph.test.ts +448 -120
- package/src/graph.ts +1024 -413
- package/src/index.ts +9 -3
- package/src/node-matcher.test.ts +301 -0
- package/src/node-matcher.ts +282 -0
- package/src/node.ts +56 -8
- package/src/stories/EchoGraph.stories.tsx +148 -108
- package/src/stories/Tree.tsx +2 -2
- package/src/util.ts +71 -0
- package/dist/types/src/signals-integration.test.d.ts +0 -2
- package/dist/types/src/signals-integration.test.d.ts.map +0 -1
- package/dist/types/src/testing.d.ts +0 -4
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/signals-integration.test.ts +0 -223
- package/src/testing.ts +0 -21
|
@@ -1,20 +1,149 @@
|
|
|
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
|
+
};
|
|
6
|
+
|
|
7
|
+
// src/atoms.ts
|
|
8
|
+
var atoms_exports = {};
|
|
9
|
+
__export(atoms_exports, {
|
|
10
|
+
fromObservable: () => fromObservable
|
|
11
|
+
});
|
|
12
|
+
import { Atom } from "@effect-atom/atom-react";
|
|
13
|
+
var observableFamily = Atom.family((observable) => {
|
|
14
|
+
return Atom.make((get2) => {
|
|
15
|
+
const subscription = observable.subscribe((value) => get2.setSelf(value));
|
|
16
|
+
get2.addFinalizer(() => subscription.unsubscribe());
|
|
17
|
+
return observable.get();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
var fromObservable = (observable) => {
|
|
21
|
+
return observableFamily(observable);
|
|
22
|
+
};
|
|
23
|
+
|
|
1
24
|
// src/graph.ts
|
|
2
|
-
|
|
25
|
+
var graph_exports = {};
|
|
26
|
+
__export(graph_exports, {
|
|
27
|
+
GraphKind: () => GraphKind,
|
|
28
|
+
GraphTypeId: () => GraphTypeId,
|
|
29
|
+
addEdge: () => addEdge,
|
|
30
|
+
addEdges: () => addEdges,
|
|
31
|
+
addNode: () => addNode,
|
|
32
|
+
addNodes: () => addNodes,
|
|
33
|
+
expand: () => expand,
|
|
34
|
+
getActions: () => getActions,
|
|
35
|
+
getConnections: () => getConnections,
|
|
36
|
+
getEdges: () => getEdges,
|
|
37
|
+
getGraph: () => getGraph,
|
|
38
|
+
getNode: () => getNode,
|
|
39
|
+
getNodeOrThrow: () => getNodeOrThrow,
|
|
40
|
+
getPath: () => getPath,
|
|
41
|
+
getRoot: () => getRoot,
|
|
42
|
+
initialize: () => initialize,
|
|
43
|
+
make: () => make,
|
|
44
|
+
relationFromKey: () => relationFromKey,
|
|
45
|
+
relationKey: () => relationKey,
|
|
46
|
+
removeEdge: () => removeEdge,
|
|
47
|
+
removeEdges: () => removeEdges,
|
|
48
|
+
removeNode: () => removeNode,
|
|
49
|
+
removeNodes: () => removeNodes,
|
|
50
|
+
sortEdges: () => sortEdges,
|
|
51
|
+
toJSON: () => toJSON,
|
|
52
|
+
traverse: () => traverse,
|
|
53
|
+
waitForPath: () => waitForPath
|
|
54
|
+
});
|
|
55
|
+
import { Atom as Atom2, Registry } from "@effect-atom/atom-react";
|
|
3
56
|
import * as Function from "effect/Function";
|
|
4
57
|
import * as Option from "effect/Option";
|
|
58
|
+
import * as Pipeable from "effect/Pipeable";
|
|
5
59
|
import * as Record from "effect/Record";
|
|
6
60
|
import { Event, Trigger } from "@dxos/async";
|
|
7
61
|
import { todo } from "@dxos/debug";
|
|
8
|
-
import { invariant } from "@dxos/invariant";
|
|
62
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
9
63
|
import { log } from "@dxos/log";
|
|
10
64
|
import { isNonNullable } from "@dxos/util";
|
|
11
|
-
|
|
12
|
-
|
|
65
|
+
|
|
66
|
+
// src/node.ts
|
|
67
|
+
var node_exports = {};
|
|
68
|
+
__export(node_exports, {
|
|
69
|
+
ActionGroupType: () => ActionGroupType,
|
|
70
|
+
ActionType: () => ActionType,
|
|
71
|
+
RootId: () => RootId,
|
|
72
|
+
RootType: () => RootType,
|
|
73
|
+
actionGroupSymbol: () => actionGroupSymbol,
|
|
74
|
+
actionRelation: () => actionRelation,
|
|
75
|
+
childRelation: () => childRelation,
|
|
76
|
+
isAction: () => isAction,
|
|
77
|
+
isActionGroup: () => isActionGroup,
|
|
78
|
+
isActionLike: () => isActionLike,
|
|
79
|
+
isGraphNode: () => isGraphNode,
|
|
80
|
+
relation: () => relation
|
|
81
|
+
});
|
|
82
|
+
var RootId = "root";
|
|
83
|
+
var RootType = "org.dxos.type.graph-root";
|
|
84
|
+
var ActionType = "org.dxos.type.graph-action";
|
|
85
|
+
var ActionGroupType = "org.dxos.type.graph-action-group";
|
|
86
|
+
var relation = (kind, direction = "outbound") => ({
|
|
87
|
+
kind,
|
|
88
|
+
direction
|
|
89
|
+
});
|
|
90
|
+
var childRelation = (direction = "outbound") => relation("child", direction);
|
|
91
|
+
var actionRelation = (direction = "outbound") => relation("action", direction);
|
|
92
|
+
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
93
|
+
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ActionType : false;
|
|
94
|
+
var actionGroupSymbol = /* @__PURE__ */ Symbol("ActionGroup");
|
|
95
|
+
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ActionGroupType : false;
|
|
96
|
+
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
97
|
+
|
|
98
|
+
// src/util.ts
|
|
99
|
+
import { invariant } from "@dxos/invariant";
|
|
100
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/util.ts";
|
|
101
|
+
var Separators = {
|
|
102
|
+
primary: "",
|
|
103
|
+
secondary: "",
|
|
104
|
+
path: "/"
|
|
105
|
+
};
|
|
106
|
+
var normalizeRelation = (relation2) => relation2 == null ? childRelation() : typeof relation2 === "string" ? relation(relation2) : relation2;
|
|
107
|
+
var shallowEqual = (a, b) => {
|
|
108
|
+
if (a === b) return true;
|
|
109
|
+
if (a == null || b == null || typeof a !== "object" || typeof b !== "object") return false;
|
|
110
|
+
const keysA = Object.keys(a);
|
|
111
|
+
const keysB = Object.keys(b);
|
|
112
|
+
if (keysA.length !== keysB.length) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return keysA.every((k) => a[k] === b[k]);
|
|
116
|
+
};
|
|
117
|
+
var nodeArgsUnchanged = (prev, next) => {
|
|
118
|
+
if (prev.length !== next.length) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return prev.every((prevNode, idx) => {
|
|
122
|
+
const nextNode = next[idx];
|
|
123
|
+
return prevNode.id === nextNode.id && prevNode.type === nextNode.type && shallowEqual(prevNode.data, nextNode.data) && shallowEqual(prevNode.properties, nextNode.properties);
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
var qualifyId = (parentId, segmentId) => `${parentId}${Separators.path}${segmentId}`;
|
|
127
|
+
var validateSegmentId = (id) => {
|
|
128
|
+
invariant(!id.includes(Separators.path), `Node segment ID must not contain '${Separators.path}': ${id}`, {
|
|
129
|
+
F: __dxlog_file,
|
|
130
|
+
L: 70,
|
|
131
|
+
S: void 0,
|
|
132
|
+
A: [
|
|
133
|
+
"!id.includes(Separators.path)",
|
|
134
|
+
"`Node segment ID must not contain '${Separators.path}': ${id}`"
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/graph.ts
|
|
140
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
141
|
+
var graphSymbol = /* @__PURE__ */ Symbol("graph");
|
|
13
142
|
var getGraph = (node) => {
|
|
14
143
|
const graph = node[graphSymbol];
|
|
15
|
-
|
|
16
|
-
F:
|
|
17
|
-
L:
|
|
144
|
+
invariant2(graph, "Node is not associated with a graph.", {
|
|
145
|
+
F: __dxlog_file2,
|
|
146
|
+
L: 33,
|
|
18
147
|
S: void 0,
|
|
19
148
|
A: [
|
|
20
149
|
"graph",
|
|
@@ -23,41 +152,45 @@ var getGraph = (node) => {
|
|
|
23
152
|
});
|
|
24
153
|
return graph;
|
|
25
154
|
};
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
|
|
155
|
+
var GraphTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-graph/Graph");
|
|
156
|
+
var GraphKind = /* @__PURE__ */ Symbol.for("@dxos/app-graph/GraphKind");
|
|
157
|
+
var GraphImpl = class {
|
|
158
|
+
[GraphTypeId] = GraphTypeId;
|
|
159
|
+
[GraphKind] = "writable";
|
|
160
|
+
pipe() {
|
|
161
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
162
|
+
}
|
|
31
163
|
onNodeChanged = new Event();
|
|
32
164
|
_onExpand;
|
|
33
165
|
_onInitialize;
|
|
34
166
|
_onRemoveNode;
|
|
35
167
|
_registry;
|
|
36
168
|
_expanded = Record.empty();
|
|
169
|
+
_pendingExpands = /* @__PURE__ */ new Set();
|
|
37
170
|
_initialized = Record.empty();
|
|
38
171
|
_initialEdges = Record.empty();
|
|
39
172
|
_initialNodes = Record.fromEntries([
|
|
40
173
|
[
|
|
41
|
-
|
|
174
|
+
RootId,
|
|
42
175
|
this._constructNode({
|
|
43
|
-
id:
|
|
44
|
-
type:
|
|
176
|
+
id: RootId,
|
|
177
|
+
type: RootType,
|
|
45
178
|
data: null,
|
|
46
179
|
properties: {}
|
|
47
180
|
})
|
|
48
181
|
]
|
|
49
182
|
]);
|
|
50
183
|
/** @internal */
|
|
51
|
-
_node =
|
|
184
|
+
_node = Atom2.family((id) => {
|
|
52
185
|
const initial = Option.flatten(Record.get(this._initialNodes, id));
|
|
53
|
-
return
|
|
186
|
+
return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:node:${id}`));
|
|
54
187
|
});
|
|
55
|
-
_nodeOrThrow =
|
|
56
|
-
return
|
|
188
|
+
_nodeOrThrow = Atom2.family((id) => {
|
|
189
|
+
return Atom2.make((get2) => {
|
|
57
190
|
const node = get2(this._node(id));
|
|
58
|
-
|
|
59
|
-
F:
|
|
60
|
-
L:
|
|
191
|
+
invariant2(Option.isSome(node), `Node not available: ${id}`, {
|
|
192
|
+
F: __dxlog_file2,
|
|
193
|
+
L: 172,
|
|
61
194
|
S: this,
|
|
62
195
|
A: [
|
|
63
196
|
"Option.isSome(node)",
|
|
@@ -67,31 +200,34 @@ var Graph = class {
|
|
|
67
200
|
return node.value;
|
|
68
201
|
});
|
|
69
202
|
});
|
|
70
|
-
_edges =
|
|
71
|
-
const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
|
|
72
|
-
|
|
73
|
-
outbound: []
|
|
74
|
-
})));
|
|
75
|
-
return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));
|
|
203
|
+
_edges = Atom2.family((id) => {
|
|
204
|
+
const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({})));
|
|
205
|
+
return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:edges:${id}`));
|
|
76
206
|
});
|
|
77
207
|
// NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
|
|
78
208
|
// TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
|
|
79
|
-
_connections =
|
|
80
|
-
return
|
|
81
|
-
|
|
209
|
+
_connections = Atom2.family((key) => {
|
|
210
|
+
return Atom2.make((get2) => {
|
|
211
|
+
if (!key || key.indexOf(Separators.primary) <= 0) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
const { id, relation: relation2 } = relationFromConnectionKey(key);
|
|
82
215
|
const edges = get2(this._edges(id));
|
|
83
|
-
return edges[
|
|
84
|
-
}).pipe(
|
|
216
|
+
return (edges[relationKey(relation2)] ?? []).map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
|
|
217
|
+
}).pipe(Atom2.withLabel(`graph:connections:${key}`));
|
|
85
218
|
});
|
|
86
|
-
_actions =
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
|
|
219
|
+
_actions = Atom2.family((id) => {
|
|
220
|
+
return Atom2.make((get2) => {
|
|
221
|
+
if (!id) {
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
return get2(this._connections(connectionKey(id, actionRelation())));
|
|
225
|
+
}).pipe(Atom2.withLabel(`graph:actions:${id}`));
|
|
90
226
|
});
|
|
91
|
-
_json =
|
|
92
|
-
return
|
|
93
|
-
const
|
|
94
|
-
const nodes = get2(this.
|
|
227
|
+
_json = Atom2.family((id) => {
|
|
228
|
+
return Atom2.make((get2) => {
|
|
229
|
+
const toJSON2 = (node, seen = []) => {
|
|
230
|
+
const nodes = get2(this._connections(connectionKey(node.id, "child")));
|
|
95
231
|
const obj = {
|
|
96
232
|
id: node.id,
|
|
97
233
|
type: node.type
|
|
@@ -105,14 +241,14 @@ var Graph = class {
|
|
|
105
241
|
...seen,
|
|
106
242
|
node.id
|
|
107
243
|
];
|
|
108
|
-
return nextSeen.includes(n.id) ? void 0 :
|
|
244
|
+
return nextSeen.includes(n.id) ? void 0 : toJSON2(n, nextSeen);
|
|
109
245
|
}).filter(isNonNullable);
|
|
110
246
|
}
|
|
111
247
|
return obj;
|
|
112
248
|
};
|
|
113
|
-
const root = get2(this.
|
|
114
|
-
return
|
|
115
|
-
}).pipe(
|
|
249
|
+
const root = get2(this._nodeOrThrow(id));
|
|
250
|
+
return toJSON2(root);
|
|
251
|
+
}).pipe(Atom2.withLabel(`graph:json:${id}`));
|
|
116
252
|
});
|
|
117
253
|
constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
|
|
118
254
|
this._registry = registry ?? Registry.make();
|
|
@@ -130,502 +266,860 @@ var Graph = class {
|
|
|
130
266
|
});
|
|
131
267
|
}
|
|
132
268
|
}
|
|
133
|
-
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
json(id = ROOT_ID) {
|
|
137
|
-
return this._json(id);
|
|
269
|
+
json(id = RootId) {
|
|
270
|
+
return jsonImpl(this, id);
|
|
138
271
|
}
|
|
139
272
|
node(id) {
|
|
140
|
-
return this
|
|
273
|
+
return nodeImpl(this, id);
|
|
141
274
|
}
|
|
142
275
|
nodeOrThrow(id) {
|
|
143
|
-
return this
|
|
276
|
+
return nodeOrThrowImpl(this, id);
|
|
144
277
|
}
|
|
145
|
-
connections(id,
|
|
146
|
-
return this
|
|
278
|
+
connections(id, relation2) {
|
|
279
|
+
return connectionsImpl(this, id, relation2);
|
|
147
280
|
}
|
|
148
281
|
actions(id) {
|
|
149
|
-
return this
|
|
282
|
+
return actionsImpl(this, id);
|
|
150
283
|
}
|
|
151
284
|
edges(id) {
|
|
152
|
-
return this
|
|
285
|
+
return edgesImpl(this, id);
|
|
153
286
|
}
|
|
154
|
-
|
|
155
|
-
|
|
287
|
+
/** @internal */
|
|
288
|
+
_constructNode(node) {
|
|
289
|
+
return Option.some({
|
|
290
|
+
[graphSymbol]: this,
|
|
291
|
+
data: null,
|
|
292
|
+
properties: {},
|
|
293
|
+
...node
|
|
294
|
+
});
|
|
156
295
|
}
|
|
157
|
-
|
|
158
|
-
|
|
296
|
+
};
|
|
297
|
+
var getInternal = (graph) => {
|
|
298
|
+
return graph;
|
|
299
|
+
};
|
|
300
|
+
var toJSON = (graph, id = RootId) => {
|
|
301
|
+
const internal = getInternal(graph);
|
|
302
|
+
return internal._registry.get(internal._json(id));
|
|
303
|
+
};
|
|
304
|
+
var jsonImpl = (graph, id = RootId) => {
|
|
305
|
+
const internal = getInternal(graph);
|
|
306
|
+
return internal._json(id);
|
|
307
|
+
};
|
|
308
|
+
var nodeImpl = (graph, id) => {
|
|
309
|
+
const internal = getInternal(graph);
|
|
310
|
+
return internal._node(id);
|
|
311
|
+
};
|
|
312
|
+
var nodeOrThrowImpl = (graph, id) => {
|
|
313
|
+
const internal = getInternal(graph);
|
|
314
|
+
return internal._nodeOrThrow(id);
|
|
315
|
+
};
|
|
316
|
+
var connectionsImpl = (graph, id, relation2) => {
|
|
317
|
+
const internal = getInternal(graph);
|
|
318
|
+
return internal._connections(connectionKey(id, relation2));
|
|
319
|
+
};
|
|
320
|
+
var actionsImpl = (graph, id) => {
|
|
321
|
+
const internal = getInternal(graph);
|
|
322
|
+
return internal._actions(id);
|
|
323
|
+
};
|
|
324
|
+
var edgesImpl = (graph, id) => {
|
|
325
|
+
const internal = getInternal(graph);
|
|
326
|
+
return internal._edges(id);
|
|
327
|
+
};
|
|
328
|
+
var getNodeImpl = (graph, id) => {
|
|
329
|
+
const internal = getInternal(graph);
|
|
330
|
+
return internal._registry.get(nodeImpl(graph, id));
|
|
331
|
+
};
|
|
332
|
+
function getNode(graphOrId, id) {
|
|
333
|
+
if (typeof graphOrId === "string") {
|
|
334
|
+
const id2 = graphOrId;
|
|
335
|
+
return (graph) => getNodeImpl(graph, id2);
|
|
336
|
+
} else {
|
|
337
|
+
const graph = graphOrId;
|
|
338
|
+
return getNodeImpl(graph, id);
|
|
159
339
|
}
|
|
160
|
-
|
|
161
|
-
|
|
340
|
+
}
|
|
341
|
+
var getNodeOrThrowImpl = (graph, id) => {
|
|
342
|
+
const internal = getInternal(graph);
|
|
343
|
+
return internal._registry.get(nodeOrThrowImpl(graph, id));
|
|
344
|
+
};
|
|
345
|
+
function getNodeOrThrow(graphOrId, id) {
|
|
346
|
+
if (typeof graphOrId === "string") {
|
|
347
|
+
const id2 = graphOrId;
|
|
348
|
+
return (graph) => getNodeOrThrowImpl(graph, id2);
|
|
349
|
+
} else {
|
|
350
|
+
const graph = graphOrId;
|
|
351
|
+
return getNodeOrThrowImpl(graph, id);
|
|
162
352
|
}
|
|
163
|
-
|
|
164
|
-
|
|
353
|
+
}
|
|
354
|
+
function getRoot(graph) {
|
|
355
|
+
return getNodeOrThrowImpl(graph, RootId);
|
|
356
|
+
}
|
|
357
|
+
var getConnectionsImpl = (graph, id, relation2) => {
|
|
358
|
+
const internal = getInternal(graph);
|
|
359
|
+
return internal._registry.get(connectionsImpl(graph, id, relation2));
|
|
360
|
+
};
|
|
361
|
+
function getConnections(graphOrId, idOrRelation, relation2) {
|
|
362
|
+
if (typeof graphOrId === "string") {
|
|
363
|
+
const id = graphOrId;
|
|
364
|
+
const rel = idOrRelation;
|
|
365
|
+
return (graph) => getConnectionsImpl(graph, id, rel);
|
|
366
|
+
} else {
|
|
367
|
+
const graph = graphOrId;
|
|
368
|
+
const id = idOrRelation;
|
|
369
|
+
invariant2(relation2 !== void 0, "Relation is required.", {
|
|
370
|
+
F: __dxlog_file2,
|
|
371
|
+
L: 446,
|
|
372
|
+
S: this,
|
|
373
|
+
A: [
|
|
374
|
+
"relation !== undefined",
|
|
375
|
+
"'Relation is required.'"
|
|
376
|
+
]
|
|
377
|
+
});
|
|
378
|
+
const rel = relation2;
|
|
379
|
+
return getConnectionsImpl(graph, id, rel);
|
|
165
380
|
}
|
|
166
|
-
|
|
167
|
-
|
|
381
|
+
}
|
|
382
|
+
var getActionsImpl = (graph, id) => {
|
|
383
|
+
const internal = getInternal(graph);
|
|
384
|
+
return internal._registry.get(actionsImpl(graph, id));
|
|
385
|
+
};
|
|
386
|
+
function getActions(graphOrId, id) {
|
|
387
|
+
if (typeof graphOrId === "string") {
|
|
388
|
+
const id2 = graphOrId;
|
|
389
|
+
return (graph) => getActionsImpl(graph, id2);
|
|
390
|
+
} else {
|
|
391
|
+
const graph = graphOrId;
|
|
392
|
+
return getActionsImpl(graph, id);
|
|
168
393
|
}
|
|
169
|
-
|
|
170
|
-
|
|
394
|
+
}
|
|
395
|
+
var getEdgesImpl = (graph, id) => {
|
|
396
|
+
const internal = getInternal(graph);
|
|
397
|
+
return internal._registry.get(edgesImpl(graph, id));
|
|
398
|
+
};
|
|
399
|
+
function getEdges(graphOrId, id) {
|
|
400
|
+
if (typeof graphOrId === "string") {
|
|
401
|
+
const id2 = graphOrId;
|
|
402
|
+
return (graph) => getEdgesImpl(graph, id2);
|
|
403
|
+
} else {
|
|
404
|
+
const graph = graphOrId;
|
|
405
|
+
return getEdgesImpl(graph, id);
|
|
171
406
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
407
|
+
}
|
|
408
|
+
var traverseImpl = (graph, options, path = []) => {
|
|
409
|
+
const { visitor, source = RootId, relation: relation2 } = options;
|
|
410
|
+
if (path.includes(source)) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const node = getNodeOrThrow(graph, source);
|
|
414
|
+
const shouldContinue = visitor(node, [
|
|
415
|
+
...path,
|
|
416
|
+
source
|
|
417
|
+
]);
|
|
418
|
+
if (shouldContinue === false) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const relations = Array.isArray(relation2) ? relation2 : [
|
|
422
|
+
relation2
|
|
423
|
+
];
|
|
424
|
+
const seen = /* @__PURE__ */ new Set();
|
|
425
|
+
for (const rel of relations) {
|
|
426
|
+
for (const connected of getConnections(graph, source, rel)) {
|
|
427
|
+
if (!seen.has(connected.id)) {
|
|
428
|
+
seen.add(connected.id);
|
|
429
|
+
traverseImpl(graph, {
|
|
430
|
+
source: connected.id,
|
|
431
|
+
relation: relation2,
|
|
432
|
+
visitor
|
|
433
|
+
}, [
|
|
434
|
+
...path,
|
|
435
|
+
source
|
|
436
|
+
]);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
function traverse(graphOrOptions, optionsOrPath, path) {
|
|
442
|
+
if (typeof graphOrOptions === "object" && "visitor" in graphOrOptions) {
|
|
443
|
+
const options = graphOrOptions;
|
|
444
|
+
const pathArg = Array.isArray(optionsOrPath) ? optionsOrPath : void 0;
|
|
445
|
+
return (graph) => traverseImpl(graph, options, pathArg);
|
|
446
|
+
} else {
|
|
447
|
+
const graph = graphOrOptions;
|
|
448
|
+
const options = optionsOrPath;
|
|
449
|
+
const pathArg = path ?? (Array.isArray(optionsOrPath) ? optionsOrPath : void 0);
|
|
450
|
+
return traverseImpl(graph, options, pathArg);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
var getPathImpl = (graph, params) => {
|
|
454
|
+
return Function.pipe(getNode(graph, params.source ?? "root"), Option.flatMap((node) => {
|
|
455
|
+
let found = Option.none();
|
|
456
|
+
traverseImpl(graph, {
|
|
457
|
+
source: node.id,
|
|
458
|
+
relation: "child",
|
|
459
|
+
visitor: (node2, path) => {
|
|
460
|
+
if (Option.isSome(found)) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
if (node2.id === params.target) {
|
|
464
|
+
found = Option.some(path);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
182
467
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
468
|
+
return found;
|
|
469
|
+
}));
|
|
470
|
+
};
|
|
471
|
+
function getPath(graphOrParams, params) {
|
|
472
|
+
if (params === void 0 && typeof graphOrParams === "object" && "target" in graphOrParams) {
|
|
473
|
+
const params2 = graphOrParams;
|
|
474
|
+
return (graph) => getPathImpl(graph, params2);
|
|
475
|
+
} else {
|
|
476
|
+
const graph = graphOrParams;
|
|
477
|
+
return getPathImpl(graph, params);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
var waitForPathImpl = (graph, params, options) => {
|
|
481
|
+
const { timeout = 5e3, interval = 500 } = options ?? {};
|
|
482
|
+
const path = getPathImpl(graph, params);
|
|
483
|
+
if (Option.isSome(path)) {
|
|
484
|
+
return Promise.resolve(path.value);
|
|
485
|
+
}
|
|
486
|
+
const trigger = new Trigger();
|
|
487
|
+
const i = setInterval(() => {
|
|
488
|
+
const path2 = getPathImpl(graph, params);
|
|
489
|
+
if (Option.isSome(path2)) {
|
|
490
|
+
trigger.wake(path2.value);
|
|
186
491
|
}
|
|
492
|
+
}, interval);
|
|
493
|
+
return trigger.wait({
|
|
494
|
+
timeout
|
|
495
|
+
}).finally(() => clearInterval(i));
|
|
496
|
+
};
|
|
497
|
+
function waitForPath(graphOrParams, paramsOrOptions, options) {
|
|
498
|
+
if (typeof graphOrParams === "object" && "target" in graphOrParams) {
|
|
499
|
+
const params = graphOrParams;
|
|
500
|
+
const opts = typeof paramsOrOptions === "object" && !("target" in paramsOrOptions) ? paramsOrOptions : void 0;
|
|
501
|
+
return (graph) => waitForPathImpl(graph, params, opts);
|
|
502
|
+
} else {
|
|
503
|
+
const graph = graphOrParams;
|
|
504
|
+
const params = paramsOrOptions;
|
|
505
|
+
return waitForPathImpl(graph, params, options);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
var initializeImpl = async (graph, id) => {
|
|
509
|
+
const internal = getInternal(graph);
|
|
510
|
+
const initialized = Record.get(internal._initialized, id).pipe(Option.getOrElse(() => false));
|
|
511
|
+
log("initialize", {
|
|
512
|
+
id,
|
|
513
|
+
initialized
|
|
514
|
+
}, {
|
|
515
|
+
F: __dxlog_file2,
|
|
516
|
+
L: 668,
|
|
517
|
+
S: void 0,
|
|
518
|
+
C: (f, a) => f(...a)
|
|
519
|
+
});
|
|
520
|
+
if (!initialized) {
|
|
521
|
+
Record.set(internal._initialized, id, true);
|
|
522
|
+
await internal._onInitialize?.(id);
|
|
523
|
+
}
|
|
524
|
+
return graph;
|
|
525
|
+
};
|
|
526
|
+
function initialize(graphOrId, id) {
|
|
527
|
+
if (typeof graphOrId === "string") {
|
|
528
|
+
const id2 = graphOrId;
|
|
529
|
+
return (graph) => initializeImpl(graph, id2);
|
|
530
|
+
} else {
|
|
531
|
+
const graph = graphOrId;
|
|
532
|
+
return initializeImpl(graph, id);
|
|
187
533
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
534
|
+
}
|
|
535
|
+
var expandImpl = (graph, id, relation2) => {
|
|
536
|
+
const internal = getInternal(graph);
|
|
537
|
+
const normalizedRelation = normalizeRelation(relation2);
|
|
538
|
+
const key = `${id}${Separators.primary}${relationKey(normalizedRelation)}`;
|
|
539
|
+
const nodeOpt = internal._registry.get(internal._node(id));
|
|
540
|
+
if (Option.isNone(nodeOpt)) {
|
|
541
|
+
internal._pendingExpands.add(key);
|
|
191
542
|
log("expand", {
|
|
192
543
|
key,
|
|
193
|
-
|
|
544
|
+
deferred: true
|
|
194
545
|
}, {
|
|
195
|
-
F:
|
|
196
|
-
L:
|
|
197
|
-
S:
|
|
546
|
+
F: __dxlog_file2,
|
|
547
|
+
L: 714,
|
|
548
|
+
S: void 0,
|
|
198
549
|
C: (f, a) => f(...a)
|
|
199
550
|
});
|
|
200
|
-
|
|
201
|
-
this._onExpand?.(id, relation);
|
|
202
|
-
Record.set(this._expanded, key, true);
|
|
203
|
-
}
|
|
551
|
+
return graph;
|
|
204
552
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
553
|
+
const expanded = Record.get(internal._expanded, key).pipe(Option.getOrElse(() => false));
|
|
554
|
+
log("expand", {
|
|
555
|
+
key,
|
|
556
|
+
expanded
|
|
557
|
+
}, {
|
|
558
|
+
F: __dxlog_file2,
|
|
559
|
+
L: 719,
|
|
560
|
+
S: void 0,
|
|
561
|
+
C: (f, a) => f(...a)
|
|
562
|
+
});
|
|
563
|
+
if (!expanded) {
|
|
564
|
+
Record.set(internal._expanded, key, true);
|
|
565
|
+
internal._onExpand?.(id, normalizedRelation);
|
|
566
|
+
}
|
|
567
|
+
return graph;
|
|
568
|
+
};
|
|
569
|
+
function expand(graphOrId, idOrRelation, relation2) {
|
|
570
|
+
if (typeof graphOrId === "string") {
|
|
571
|
+
const id = graphOrId;
|
|
572
|
+
const rel = idOrRelation;
|
|
573
|
+
return (graph) => expandImpl(graph, id, rel);
|
|
574
|
+
} else {
|
|
575
|
+
const graph = graphOrId;
|
|
576
|
+
const id = idOrRelation;
|
|
577
|
+
invariant2(relation2 !== void 0, "Relation is required.", {
|
|
578
|
+
F: __dxlog_file2,
|
|
579
|
+
L: 755,
|
|
580
|
+
S: this,
|
|
581
|
+
A: [
|
|
582
|
+
"relation !== undefined",
|
|
583
|
+
"'Relation is required.'"
|
|
584
|
+
]
|
|
208
585
|
});
|
|
586
|
+
const rel = relation2;
|
|
587
|
+
return expandImpl(graph, id, rel);
|
|
209
588
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
589
|
+
}
|
|
590
|
+
var sortEdgesImpl = (graph, id, relation2, order) => {
|
|
591
|
+
const internal = getInternal(graph);
|
|
592
|
+
const edgesAtom = internal._edges(id);
|
|
593
|
+
const edges = internal._registry.get(edgesAtom);
|
|
594
|
+
const relationId = relationKey(relation2);
|
|
595
|
+
const current = edges[relationId] ?? [];
|
|
596
|
+
const unsorted = current.filter((id2) => !order.includes(id2));
|
|
597
|
+
const sorted = order.filter((id2) => current.includes(id2));
|
|
598
|
+
const newOrder = [
|
|
599
|
+
...sorted,
|
|
600
|
+
...unsorted
|
|
601
|
+
];
|
|
602
|
+
if (newOrder.length === current.length && newOrder.every((id2, i) => id2 === current[i])) {
|
|
603
|
+
return graph;
|
|
604
|
+
}
|
|
605
|
+
internal._registry.set(edgesAtom, {
|
|
606
|
+
...edges,
|
|
607
|
+
[relationId]: newOrder
|
|
608
|
+
});
|
|
609
|
+
return graph;
|
|
610
|
+
};
|
|
611
|
+
function sortEdges(graphOrId, idOrRelation, relationOrOrder, order) {
|
|
612
|
+
if (typeof graphOrId === "string") {
|
|
613
|
+
const id = graphOrId;
|
|
614
|
+
const relation2 = idOrRelation;
|
|
615
|
+
const order2 = relationOrOrder;
|
|
616
|
+
return (graph) => sortEdgesImpl(graph, id, relation2, order2);
|
|
617
|
+
} else {
|
|
618
|
+
const graph = graphOrId;
|
|
619
|
+
const id = idOrRelation;
|
|
620
|
+
const relation2 = relationOrOrder;
|
|
621
|
+
return sortEdgesImpl(graph, id, relation2, order);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
var addNodesImpl = (graph, nodes) => {
|
|
625
|
+
Atom2.batch(() => {
|
|
626
|
+
nodes.map((node) => addNodeImpl(graph, node));
|
|
627
|
+
});
|
|
628
|
+
return graph;
|
|
629
|
+
};
|
|
630
|
+
function addNodes(graphOrNodes, nodes) {
|
|
631
|
+
if (nodes === void 0) {
|
|
632
|
+
const nodes2 = graphOrNodes;
|
|
633
|
+
return (graph) => addNodesImpl(graph, nodes2);
|
|
634
|
+
} else {
|
|
635
|
+
const graph = graphOrNodes;
|
|
636
|
+
return addNodesImpl(graph, nodes);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
var addNodeImpl = (graph, nodeArg) => {
|
|
640
|
+
const internal = getInternal(graph);
|
|
641
|
+
const { nodes, edges, id, type, data = null, properties = {}, ...rest } = nodeArg;
|
|
642
|
+
const nodeAtom = internal._node(id);
|
|
643
|
+
const existingNode = internal._registry.get(nodeAtom);
|
|
644
|
+
Option.match(existingNode, {
|
|
645
|
+
onSome: (existing) => {
|
|
646
|
+
const typeChanged = existing.type !== type;
|
|
647
|
+
const dataChanged = !shallowEqual(existing.data, data);
|
|
648
|
+
const propertiesChanged = Object.keys(properties).some((key) => existing.properties[key] !== properties[key]);
|
|
649
|
+
log("existing node", {
|
|
650
|
+
id,
|
|
651
|
+
typeChanged,
|
|
652
|
+
dataChanged,
|
|
653
|
+
propertiesChanged
|
|
654
|
+
}, {
|
|
655
|
+
F: __dxlog_file2,
|
|
656
|
+
L: 877,
|
|
657
|
+
S: void 0,
|
|
658
|
+
C: (f, a) => f(...a)
|
|
659
|
+
});
|
|
660
|
+
if (typeChanged || dataChanged || propertiesChanged) {
|
|
661
|
+
log("updating node", {
|
|
260
662
|
id,
|
|
261
663
|
type,
|
|
262
664
|
data,
|
|
263
665
|
properties
|
|
264
666
|
}, {
|
|
265
|
-
F:
|
|
266
|
-
L:
|
|
267
|
-
S:
|
|
667
|
+
F: __dxlog_file2,
|
|
668
|
+
L: 884,
|
|
669
|
+
S: void 0,
|
|
268
670
|
C: (f, a) => f(...a)
|
|
269
671
|
});
|
|
270
|
-
const newNode =
|
|
271
|
-
|
|
672
|
+
const newNode = Option.some({
|
|
673
|
+
...existing,
|
|
674
|
+
...rest,
|
|
272
675
|
type,
|
|
273
676
|
data,
|
|
274
|
-
properties
|
|
677
|
+
properties: {
|
|
678
|
+
...existing.properties,
|
|
679
|
+
...properties
|
|
680
|
+
}
|
|
275
681
|
});
|
|
276
|
-
|
|
277
|
-
|
|
682
|
+
internal._registry.set(nodeAtom, newNode);
|
|
683
|
+
graph.onNodeChanged.emit({
|
|
278
684
|
id,
|
|
279
685
|
node: newNode
|
|
280
686
|
});
|
|
281
687
|
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
this.addEdges(_edges);
|
|
290
|
-
}
|
|
291
|
-
if (edges) {
|
|
292
|
-
todo();
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
removeNodes(ids, edges = false) {
|
|
296
|
-
Atom.batch(() => {
|
|
297
|
-
ids.map((id) => this.removeNode(id, edges));
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
removeNode(id, edges = false) {
|
|
301
|
-
const nodeAtom = this._node(id);
|
|
302
|
-
this._registry.set(nodeAtom, Option.none());
|
|
303
|
-
this.onNodeChanged.emit({
|
|
304
|
-
id,
|
|
305
|
-
node: Option.none()
|
|
306
|
-
});
|
|
307
|
-
if (edges) {
|
|
308
|
-
const { inbound, outbound } = this._registry.get(this._edges(id));
|
|
309
|
-
const edges2 = [
|
|
310
|
-
...inbound.map((source) => ({
|
|
311
|
-
source,
|
|
312
|
-
target: id
|
|
313
|
-
})),
|
|
314
|
-
...outbound.map((target) => ({
|
|
315
|
-
source: id,
|
|
316
|
-
target
|
|
317
|
-
}))
|
|
318
|
-
];
|
|
319
|
-
this.removeEdges(edges2);
|
|
320
|
-
}
|
|
321
|
-
this._onRemoveNode?.(id);
|
|
322
|
-
}
|
|
323
|
-
addEdges(edges) {
|
|
324
|
-
Atom.batch(() => {
|
|
325
|
-
edges.map((edge) => this.addEdge(edge));
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
addEdge(edgeArg) {
|
|
329
|
-
const sourceAtom = this._edges(edgeArg.source);
|
|
330
|
-
const source = this._registry.get(sourceAtom);
|
|
331
|
-
if (!source.outbound.includes(edgeArg.target)) {
|
|
332
|
-
log("add outbound edge", {
|
|
333
|
-
source: edgeArg.source,
|
|
334
|
-
target: edgeArg.target
|
|
688
|
+
},
|
|
689
|
+
onNone: () => {
|
|
690
|
+
log("new node", {
|
|
691
|
+
id,
|
|
692
|
+
type,
|
|
693
|
+
data,
|
|
694
|
+
properties
|
|
335
695
|
}, {
|
|
336
|
-
F:
|
|
337
|
-
L:
|
|
338
|
-
S:
|
|
696
|
+
F: __dxlog_file2,
|
|
697
|
+
L: 897,
|
|
698
|
+
S: void 0,
|
|
339
699
|
C: (f, a) => f(...a)
|
|
340
700
|
});
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
const targetAtom = this._edges(edgeArg.target);
|
|
350
|
-
const target = this._registry.get(targetAtom);
|
|
351
|
-
if (!target.inbound.includes(edgeArg.source)) {
|
|
352
|
-
log("add inbound edge", {
|
|
353
|
-
source: edgeArg.source,
|
|
354
|
-
target: edgeArg.target
|
|
355
|
-
}, {
|
|
356
|
-
F: __dxlog_file,
|
|
357
|
-
L: 518,
|
|
358
|
-
S: this,
|
|
359
|
-
C: (f, a) => f(...a)
|
|
701
|
+
const newNode = internal._constructNode({
|
|
702
|
+
id,
|
|
703
|
+
type,
|
|
704
|
+
data,
|
|
705
|
+
properties,
|
|
706
|
+
...rest
|
|
360
707
|
});
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
],
|
|
366
|
-
outbound: target.outbound
|
|
708
|
+
internal._registry.set(nodeAtom, newNode);
|
|
709
|
+
graph.onNodeChanged.emit({
|
|
710
|
+
id,
|
|
711
|
+
node: newNode
|
|
367
712
|
});
|
|
713
|
+
const prefix = `${id}${Separators.primary}`;
|
|
714
|
+
const toApply = [
|
|
715
|
+
...internal._pendingExpands
|
|
716
|
+
].filter((k) => k.startsWith(prefix));
|
|
717
|
+
for (const pendingKey of toApply) {
|
|
718
|
+
internal._pendingExpands.delete(pendingKey);
|
|
719
|
+
const relation2 = relationFromKey(pendingKey.slice(prefix.length));
|
|
720
|
+
Record.set(internal._expanded, pendingKey, true);
|
|
721
|
+
internal._onExpand?.(id, relation2);
|
|
722
|
+
}
|
|
368
723
|
}
|
|
724
|
+
});
|
|
725
|
+
if (nodes) {
|
|
726
|
+
addNodesImpl(graph, nodes);
|
|
727
|
+
const _edges = nodes.map((node) => ({
|
|
728
|
+
source: id,
|
|
729
|
+
target: node.id,
|
|
730
|
+
relation: "child"
|
|
731
|
+
}));
|
|
732
|
+
addEdgesImpl(graph, _edges);
|
|
369
733
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
edges.map((edge) => this.removeEdge(edge, removeOrphans));
|
|
373
|
-
});
|
|
734
|
+
if (edges) {
|
|
735
|
+
todo();
|
|
374
736
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
737
|
+
return graph;
|
|
738
|
+
};
|
|
739
|
+
function addNode(graphOrNodeArg, nodeArg) {
|
|
740
|
+
if (nodeArg === void 0) {
|
|
741
|
+
const nodeArg2 = graphOrNodeArg;
|
|
742
|
+
return (graph) => addNodeImpl(graph, nodeArg2);
|
|
743
|
+
} else {
|
|
744
|
+
const graph = graphOrNodeArg;
|
|
745
|
+
return addNodeImpl(graph, nodeArg);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
var removeNodesImpl = (graph, ids, edges = false) => {
|
|
749
|
+
Atom2.batch(() => {
|
|
750
|
+
ids.map((id) => removeNodeImpl(graph, id, edges));
|
|
751
|
+
});
|
|
752
|
+
return graph;
|
|
753
|
+
};
|
|
754
|
+
function removeNodes(graphOrIds, idsOrEdges, edges) {
|
|
755
|
+
if (Array.isArray(graphOrIds)) {
|
|
756
|
+
const ids = graphOrIds;
|
|
757
|
+
const edgesArg = typeof idsOrEdges === "boolean" ? idsOrEdges : false;
|
|
758
|
+
return (graph) => removeNodesImpl(graph, ids, edgesArg);
|
|
759
|
+
} else {
|
|
760
|
+
const graph = graphOrIds;
|
|
761
|
+
const ids = idsOrEdges;
|
|
762
|
+
const edgesArg = edges ?? false;
|
|
763
|
+
return removeNodesImpl(graph, ids, edgesArg);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
var removeNodeImpl = (graph, id, edges = false) => {
|
|
767
|
+
const internal = getInternal(graph);
|
|
768
|
+
const nodeAtom = internal._node(id);
|
|
769
|
+
internal._registry.set(nodeAtom, Option.none());
|
|
770
|
+
graph.onNodeChanged.emit({
|
|
771
|
+
id,
|
|
772
|
+
node: Option.none()
|
|
773
|
+
});
|
|
774
|
+
if (edges) {
|
|
775
|
+
const nodeEdges = internal._registry.get(internal._edges(id));
|
|
776
|
+
const edgesToRemove = [];
|
|
777
|
+
for (const [relationKeyValue, relatedIds] of Object.entries(nodeEdges)) {
|
|
778
|
+
const relation2 = relationFromKey(relationKeyValue);
|
|
779
|
+
const isInboundRelation = relation2.direction === "inbound";
|
|
780
|
+
for (const relatedId of relatedIds) {
|
|
781
|
+
if (isInboundRelation) {
|
|
782
|
+
edgesToRemove.push({
|
|
783
|
+
source: relatedId,
|
|
784
|
+
target: id,
|
|
785
|
+
relation: inverseRelation(relation2)
|
|
786
|
+
});
|
|
787
|
+
} else {
|
|
788
|
+
edgesToRemove.push({
|
|
789
|
+
source: id,
|
|
790
|
+
target: relatedId,
|
|
791
|
+
relation: relation2
|
|
792
|
+
});
|
|
793
|
+
}
|
|
404
794
|
}
|
|
405
795
|
}
|
|
796
|
+
removeEdgesImpl(graph, edgesToRemove);
|
|
406
797
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
798
|
+
internal._onRemoveNode?.(id);
|
|
799
|
+
return graph;
|
|
800
|
+
};
|
|
801
|
+
function removeNode(graphOrId, idOrEdges, edges) {
|
|
802
|
+
if (typeof graphOrId === "string") {
|
|
803
|
+
const id = graphOrId;
|
|
804
|
+
const edgesArg = typeof idOrEdges === "boolean" ? idOrEdges : false;
|
|
805
|
+
return (graph) => removeNodeImpl(graph, id, edgesArg);
|
|
806
|
+
} else {
|
|
807
|
+
const graph = graphOrId;
|
|
808
|
+
const id = idOrEdges;
|
|
809
|
+
const edgesArg = edges ?? false;
|
|
810
|
+
return removeNodeImpl(graph, id, edgesArg);
|
|
417
811
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
relation,
|
|
433
|
-
visitor
|
|
434
|
-
}, [
|
|
435
|
-
...path,
|
|
436
|
-
source
|
|
437
|
-
]));
|
|
438
|
-
}
|
|
439
|
-
getPath({ source = "root", target }) {
|
|
440
|
-
return Function.pipe(this.getNode(source), Option.flatMap((node) => {
|
|
441
|
-
let found = Option.none();
|
|
442
|
-
this.traverse({
|
|
443
|
-
source: node.id,
|
|
444
|
-
visitor: (node2, path) => {
|
|
445
|
-
if (Option.isSome(found)) {
|
|
446
|
-
return false;
|
|
447
|
-
}
|
|
448
|
-
if (node2.id === target) {
|
|
449
|
-
found = Option.some(path);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
return found;
|
|
454
|
-
}));
|
|
812
|
+
}
|
|
813
|
+
var addEdgesImpl = (graph, edges) => {
|
|
814
|
+
Atom2.batch(() => {
|
|
815
|
+
edges.map((edge) => addEdgeImpl(graph, edge));
|
|
816
|
+
});
|
|
817
|
+
return graph;
|
|
818
|
+
};
|
|
819
|
+
function addEdges(graphOrEdges, edges) {
|
|
820
|
+
if (edges === void 0) {
|
|
821
|
+
const edges2 = graphOrEdges;
|
|
822
|
+
return (graph) => addEdgesImpl(graph, edges2);
|
|
823
|
+
} else {
|
|
824
|
+
const graph = graphOrEdges;
|
|
825
|
+
return addEdgesImpl(graph, edges);
|
|
455
826
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
827
|
+
}
|
|
828
|
+
var addEdgeImpl = (graph, edgeArg) => {
|
|
829
|
+
const relation2 = normalizeRelation(edgeArg.relation);
|
|
830
|
+
const relationId = relationKey(relation2);
|
|
831
|
+
const inverse = inverseRelation(relation2);
|
|
832
|
+
const inverseId = relationKey(inverse);
|
|
833
|
+
const internal = getInternal(graph);
|
|
834
|
+
const sourceAtom = internal._edges(edgeArg.source);
|
|
835
|
+
const source = internal._registry.get(sourceAtom);
|
|
836
|
+
const sourceList = source[relationId] ?? [];
|
|
837
|
+
if (!sourceList.includes(edgeArg.target)) {
|
|
838
|
+
log("add edge", {
|
|
839
|
+
source: edgeArg.source,
|
|
840
|
+
target: edgeArg.target,
|
|
841
|
+
relation: relationId
|
|
842
|
+
}, {
|
|
843
|
+
F: __dxlog_file2,
|
|
844
|
+
L: 1081,
|
|
845
|
+
S: void 0,
|
|
846
|
+
C: (f, a) => f(...a)
|
|
847
|
+
});
|
|
848
|
+
internal._registry.set(sourceAtom, {
|
|
849
|
+
...source,
|
|
850
|
+
[relationId]: [
|
|
851
|
+
...sourceList,
|
|
852
|
+
edgeArg.target
|
|
853
|
+
]
|
|
854
|
+
});
|
|
471
855
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
856
|
+
const targetAtom = internal._edges(edgeArg.target);
|
|
857
|
+
const target = internal._registry.get(targetAtom);
|
|
858
|
+
const targetList = target[inverseId] ?? [];
|
|
859
|
+
if (!targetList.includes(edgeArg.source)) {
|
|
860
|
+
log("add inverse edge", {
|
|
861
|
+
source: edgeArg.source,
|
|
862
|
+
target: edgeArg.target,
|
|
863
|
+
relation: inverseId
|
|
864
|
+
}, {
|
|
865
|
+
F: __dxlog_file2,
|
|
866
|
+
L: 1089,
|
|
867
|
+
S: void 0,
|
|
868
|
+
C: (f, a) => f(...a)
|
|
869
|
+
});
|
|
870
|
+
internal._registry.set(targetAtom, {
|
|
871
|
+
...target,
|
|
872
|
+
[inverseId]: [
|
|
873
|
+
...targetList,
|
|
874
|
+
edgeArg.source
|
|
875
|
+
]
|
|
479
876
|
});
|
|
480
877
|
}
|
|
878
|
+
return graph;
|
|
879
|
+
};
|
|
880
|
+
function addEdge(graphOrEdgeArg, edgeArg) {
|
|
881
|
+
if (edgeArg === void 0) {
|
|
882
|
+
const edgeArg2 = graphOrEdgeArg;
|
|
883
|
+
return (graph) => addEdgeImpl(graph, edgeArg2);
|
|
884
|
+
} else {
|
|
885
|
+
const graph = graphOrEdgeArg;
|
|
886
|
+
return addEdgeImpl(graph, edgeArg);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
var removeEdgesImpl = (graph, edges, removeOrphans = false) => {
|
|
890
|
+
Atom2.batch(() => {
|
|
891
|
+
edges.map((edge) => removeEdgeImpl(graph, edge, removeOrphans));
|
|
892
|
+
});
|
|
893
|
+
return graph;
|
|
894
|
+
};
|
|
895
|
+
function removeEdges(graphOrEdges, edgesOrRemoveOrphans, removeOrphans) {
|
|
896
|
+
if (Array.isArray(graphOrEdges)) {
|
|
897
|
+
const edges = graphOrEdges;
|
|
898
|
+
const removeOrphansArg = typeof edgesOrRemoveOrphans === "boolean" ? edgesOrRemoveOrphans : false;
|
|
899
|
+
return (graph) => removeEdgesImpl(graph, edges, removeOrphansArg);
|
|
900
|
+
} else {
|
|
901
|
+
const graph = graphOrEdges;
|
|
902
|
+
const edges = edgesOrRemoveOrphans;
|
|
903
|
+
const removeOrphansArg = removeOrphans ?? false;
|
|
904
|
+
return removeEdgesImpl(graph, edges, removeOrphansArg);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
var removeEdgeImpl = (graph, edgeArg, removeOrphans = false) => {
|
|
908
|
+
const relation2 = normalizeRelation(edgeArg.relation);
|
|
909
|
+
const relationId = relationKey(relation2);
|
|
910
|
+
const inverse = inverseRelation(relation2);
|
|
911
|
+
const inverseId = relationKey(inverse);
|
|
912
|
+
const internal = getInternal(graph);
|
|
913
|
+
const sourceAtom = internal._edges(edgeArg.source);
|
|
914
|
+
const source = internal._registry.get(sourceAtom);
|
|
915
|
+
const sourceList = source[relationId] ?? [];
|
|
916
|
+
if (sourceList.includes(edgeArg.target)) {
|
|
917
|
+
internal._registry.set(sourceAtom, {
|
|
918
|
+
...source,
|
|
919
|
+
[relationId]: sourceList.filter((id) => id !== edgeArg.target)
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
const targetAtom = internal._edges(edgeArg.target);
|
|
923
|
+
const target = internal._registry.get(targetAtom);
|
|
924
|
+
const targetList = target[inverseId] ?? [];
|
|
925
|
+
if (targetList.includes(edgeArg.source)) {
|
|
926
|
+
internal._registry.set(targetAtom, {
|
|
927
|
+
...target,
|
|
928
|
+
[inverseId]: targetList.filter((id) => id !== edgeArg.source)
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
if (removeOrphans) {
|
|
932
|
+
const sourceAfter = internal._registry.get(sourceAtom);
|
|
933
|
+
const targetAfter = internal._registry.get(targetAtom);
|
|
934
|
+
const isEmpty = (edges) => Object.values(edges).every((ids) => ids.length === 0);
|
|
935
|
+
if (isEmpty(sourceAfter) && edgeArg.source !== RootId) {
|
|
936
|
+
removeNodesImpl(graph, [
|
|
937
|
+
edgeArg.source
|
|
938
|
+
]);
|
|
939
|
+
}
|
|
940
|
+
if (isEmpty(targetAfter) && edgeArg.target !== RootId) {
|
|
941
|
+
removeNodesImpl(graph, [
|
|
942
|
+
edgeArg.target
|
|
943
|
+
]);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return graph;
|
|
947
|
+
};
|
|
948
|
+
function removeEdge(graphOrEdgeArg, edgeArgOrRemoveOrphans, removeOrphans) {
|
|
949
|
+
if (edgeArgOrRemoveOrphans === void 0 || typeof edgeArgOrRemoveOrphans === "boolean" || "source" in graphOrEdgeArg) {
|
|
950
|
+
const edgeArg = graphOrEdgeArg;
|
|
951
|
+
const removeOrphansArg = typeof edgeArgOrRemoveOrphans === "boolean" ? edgeArgOrRemoveOrphans : false;
|
|
952
|
+
return (graph) => removeEdgeImpl(graph, edgeArg, removeOrphansArg);
|
|
953
|
+
} else {
|
|
954
|
+
const graph = graphOrEdgeArg;
|
|
955
|
+
const edgeArg = edgeArgOrRemoveOrphans;
|
|
956
|
+
const removeOrphansArg = removeOrphans ?? false;
|
|
957
|
+
return removeEdgeImpl(graph, edgeArg, removeOrphansArg);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
var make = (params) => {
|
|
961
|
+
return new GraphImpl(params);
|
|
962
|
+
};
|
|
963
|
+
var relationKey = (relation2) => {
|
|
964
|
+
const normalized = normalizeRelation(relation2);
|
|
965
|
+
return `${normalized.kind}${Separators.secondary}${normalized.direction}`;
|
|
966
|
+
};
|
|
967
|
+
var relationFromKey = (encoded) => {
|
|
968
|
+
const separatorIndex = encoded.lastIndexOf(Separators.secondary);
|
|
969
|
+
invariant2(separatorIndex > 0 && separatorIndex < encoded.length - 1, `Invalid relation key: ${encoded}`, {
|
|
970
|
+
F: __dxlog_file2,
|
|
971
|
+
L: 1234,
|
|
972
|
+
S: void 0,
|
|
973
|
+
A: [
|
|
974
|
+
"separatorIndex > 0 && separatorIndex < encoded.length - 1",
|
|
975
|
+
"`Invalid relation key: ${encoded}`"
|
|
976
|
+
]
|
|
977
|
+
});
|
|
978
|
+
const kind = encoded.slice(0, separatorIndex);
|
|
979
|
+
const directionRaw = encoded.slice(separatorIndex + 1);
|
|
980
|
+
invariant2(directionRaw === "outbound" || directionRaw === "inbound", `Invalid relation direction: ${directionRaw}`, {
|
|
981
|
+
F: __dxlog_file2,
|
|
982
|
+
L: 1237,
|
|
983
|
+
S: void 0,
|
|
984
|
+
A: [
|
|
985
|
+
"directionRaw === 'outbound' || directionRaw === 'inbound'",
|
|
986
|
+
"`Invalid relation direction: ${directionRaw}`"
|
|
987
|
+
]
|
|
988
|
+
});
|
|
989
|
+
return relation(kind, directionRaw);
|
|
990
|
+
};
|
|
991
|
+
var connectionKey = (id, relation2) => `${id}${Separators.primary}${relationKey(relation2)}`;
|
|
992
|
+
var relationFromConnectionKey = (key) => {
|
|
993
|
+
const separatorIndex = key.indexOf(Separators.primary);
|
|
994
|
+
invariant2(separatorIndex > 0 && separatorIndex < key.length - 1, `Invalid connection key: ${key}`, {
|
|
995
|
+
F: __dxlog_file2,
|
|
996
|
+
L: 1246,
|
|
997
|
+
S: void 0,
|
|
998
|
+
A: [
|
|
999
|
+
"separatorIndex > 0 && separatorIndex < key.length - 1",
|
|
1000
|
+
"`Invalid connection key: ${key}`"
|
|
1001
|
+
]
|
|
1002
|
+
});
|
|
1003
|
+
const id = key.slice(0, separatorIndex);
|
|
1004
|
+
const encodedRelation = key.slice(separatorIndex + 1);
|
|
1005
|
+
return {
|
|
1006
|
+
id,
|
|
1007
|
+
relation: relationFromKey(encodedRelation)
|
|
1008
|
+
};
|
|
1009
|
+
};
|
|
1010
|
+
var inverseRelation = (relation2) => {
|
|
1011
|
+
const normalized = normalizeRelation(relation2);
|
|
1012
|
+
return relation(normalized.kind, normalized.direction === "outbound" ? "inbound" : "outbound");
|
|
481
1013
|
};
|
|
482
1014
|
|
|
483
1015
|
// src/graph-builder.ts
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
1016
|
+
var graph_builder_exports = {};
|
|
1017
|
+
__export(graph_builder_exports, {
|
|
1018
|
+
GraphBuilderTypeId: () => GraphBuilderTypeId,
|
|
1019
|
+
addExtension: () => addExtension,
|
|
1020
|
+
createConnector: () => createConnector,
|
|
1021
|
+
createExtension: () => createExtension,
|
|
1022
|
+
createExtensionRaw: () => createExtensionRaw,
|
|
1023
|
+
createTypeExtension: () => createTypeExtension,
|
|
1024
|
+
destroy: () => destroy,
|
|
1025
|
+
explore: () => explore,
|
|
1026
|
+
flattenExtensions: () => flattenExtensions,
|
|
1027
|
+
flush: () => flush,
|
|
1028
|
+
from: () => from,
|
|
1029
|
+
make: () => make2,
|
|
1030
|
+
removeExtension: () => removeExtension
|
|
1031
|
+
});
|
|
1032
|
+
import { Atom as Atom3, Registry as Registry2 } from "@effect-atom/atom-react";
|
|
1033
|
+
import * as Array2 from "effect/Array";
|
|
1034
|
+
import * as Effect from "effect/Effect";
|
|
487
1035
|
import * as Function2 from "effect/Function";
|
|
488
|
-
import * as
|
|
1036
|
+
import * as Option3 from "effect/Option";
|
|
1037
|
+
import * as Pipeable2 from "effect/Pipeable";
|
|
489
1038
|
import * as Record2 from "effect/Record";
|
|
1039
|
+
import { scheduleTask, yieldOrContinue } from "main-thread-scheduling";
|
|
490
1040
|
import { log as log2 } from "@dxos/log";
|
|
491
|
-
import { byPosition, getDebugName,
|
|
492
|
-
|
|
493
|
-
// src/node.ts
|
|
494
|
-
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
495
|
-
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ACTION_TYPE : false;
|
|
496
|
-
var actionGroupSymbol = Symbol("ActionGroup");
|
|
497
|
-
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
|
|
498
|
-
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
1041
|
+
import { byPosition, getDebugName, isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
499
1042
|
|
|
500
|
-
// src/
|
|
501
|
-
var
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
L: 114,
|
|
529
|
-
S: void 0,
|
|
530
|
-
C: (f, a) => f(...a)
|
|
531
|
-
});
|
|
532
|
-
return [];
|
|
533
|
-
}
|
|
534
|
-
}).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
|
|
535
|
-
} : void 0,
|
|
536
|
-
actionGroups ? {
|
|
537
|
-
id: getId("actionGroups"),
|
|
538
|
-
position,
|
|
539
|
-
relation: "outbound",
|
|
540
|
-
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
541
|
-
try {
|
|
542
|
-
return get2(actionGroups(node)).map((arg) => ({
|
|
543
|
-
...arg,
|
|
544
|
-
data: actionGroupSymbol,
|
|
545
|
-
type: ACTION_GROUP_TYPE
|
|
546
|
-
}));
|
|
547
|
-
} catch {
|
|
548
|
-
log2.warn("Error in actionGroups", {
|
|
549
|
-
id: getId("actionGroups"),
|
|
550
|
-
node
|
|
551
|
-
}, {
|
|
552
|
-
F: __dxlog_file2,
|
|
553
|
-
L: 135,
|
|
554
|
-
S: void 0,
|
|
555
|
-
C: (f, a) => f(...a)
|
|
556
|
-
});
|
|
557
|
-
return [];
|
|
558
|
-
}
|
|
559
|
-
}).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
560
|
-
} : void 0,
|
|
561
|
-
actions ? {
|
|
562
|
-
id: getId("actions"),
|
|
563
|
-
position,
|
|
564
|
-
relation: "outbound",
|
|
565
|
-
connector: Atom2.family((node) => Atom2.make((get2) => {
|
|
566
|
-
try {
|
|
567
|
-
return get2(actions(node)).map((arg) => ({
|
|
568
|
-
...arg,
|
|
569
|
-
type: ACTION_TYPE
|
|
570
|
-
}));
|
|
571
|
-
} catch {
|
|
572
|
-
log2.warn("Error in actions", {
|
|
573
|
-
id: getId("actions"),
|
|
574
|
-
node
|
|
575
|
-
}, {
|
|
576
|
-
F: __dxlog_file2,
|
|
577
|
-
L: 152,
|
|
578
|
-
S: void 0,
|
|
579
|
-
C: (f, a) => f(...a)
|
|
580
|
-
});
|
|
581
|
-
return [];
|
|
582
|
-
}
|
|
583
|
-
}).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
584
|
-
} : void 0
|
|
585
|
-
].filter(isNonNullable2);
|
|
1043
|
+
// src/node-matcher.ts
|
|
1044
|
+
var node_matcher_exports = {};
|
|
1045
|
+
__export(node_matcher_exports, {
|
|
1046
|
+
whenAll: () => whenAll,
|
|
1047
|
+
whenAny: () => whenAny,
|
|
1048
|
+
whenEchoObject: () => whenEchoObject,
|
|
1049
|
+
whenEchoObjectMatches: () => whenEchoObjectMatches,
|
|
1050
|
+
whenEchoType: () => whenEchoType,
|
|
1051
|
+
whenEchoTypeMatches: () => whenEchoTypeMatches,
|
|
1052
|
+
whenId: () => whenId,
|
|
1053
|
+
whenNodeType: () => whenNodeType,
|
|
1054
|
+
whenNot: () => whenNot,
|
|
1055
|
+
whenRoot: () => whenRoot
|
|
1056
|
+
});
|
|
1057
|
+
import * as Option2 from "effect/Option";
|
|
1058
|
+
import { Obj } from "@dxos/echo";
|
|
1059
|
+
var whenRoot = (node) => node.id === RootId ? Option2.some(node) : Option2.none();
|
|
1060
|
+
var whenId = (id) => (node) => node.id === id ? Option2.some(node) : Option2.none();
|
|
1061
|
+
var whenNodeType = (type) => (node) => node.type === type ? Option2.some(node) : Option2.none();
|
|
1062
|
+
var whenEchoType = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node.data) : Option2.none();
|
|
1063
|
+
var whenEchoObject = (node) => Obj.isObject(node.data) ? Option2.some(node.data) : Option2.none();
|
|
1064
|
+
var whenAll = (...matchers) => (node) => {
|
|
1065
|
+
for (const candidate of matchers) {
|
|
1066
|
+
if (Option2.isNone(candidate(node))) {
|
|
1067
|
+
return Option2.none();
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
return Option2.some(node);
|
|
586
1071
|
};
|
|
587
|
-
var
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
];
|
|
593
|
-
} else {
|
|
594
|
-
return [
|
|
595
|
-
...acc,
|
|
596
|
-
extension
|
|
597
|
-
];
|
|
1072
|
+
var whenAny = (...matchers) => (node) => {
|
|
1073
|
+
for (const candidate of matchers) {
|
|
1074
|
+
if (Option2.isSome(candidate(node))) {
|
|
1075
|
+
return Option2.some(node);
|
|
1076
|
+
}
|
|
598
1077
|
}
|
|
1078
|
+
return Option2.none();
|
|
599
1079
|
};
|
|
600
|
-
var
|
|
1080
|
+
var whenEchoTypeMatches = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node) : Option2.none();
|
|
1081
|
+
var whenEchoObjectMatches = (node) => Obj.isObject(node.data) ? Option2.some(node) : Option2.none();
|
|
1082
|
+
var whenNot = (matcher) => (node) => Option2.isNone(matcher(node)) ? Option2.some(node) : Option2.none();
|
|
1083
|
+
|
|
1084
|
+
// src/graph-builder.ts
|
|
1085
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
1086
|
+
var GraphBuilderTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-graph/GraphBuilder");
|
|
1087
|
+
var GraphBuilderImpl = class {
|
|
1088
|
+
[GraphBuilderTypeId] = GraphBuilderTypeId;
|
|
1089
|
+
pipe() {
|
|
1090
|
+
return Pipeable2.pipeArguments(this, arguments);
|
|
1091
|
+
}
|
|
601
1092
|
// TODO(wittjosiah): Use Context.
|
|
1093
|
+
/** Active subscriptions keyed by composite ID, cleaned up on node removal. */
|
|
602
1094
|
_subscriptions = /* @__PURE__ */ new Map();
|
|
603
|
-
|
|
1095
|
+
/** Connector updates pending flush, keyed by connector key. */
|
|
1096
|
+
_dirtyConnectors = /* @__PURE__ */ new Map();
|
|
1097
|
+
/** Last-flushed node IDs per connector key, used for edge removal on update. */
|
|
1098
|
+
_connectorPrevious = /* @__PURE__ */ new Map();
|
|
1099
|
+
/** Last-flushed node args per connector key, used for change detection. */
|
|
1100
|
+
_connectorPreviousArgs = /* @__PURE__ */ new Map();
|
|
1101
|
+
/** Whether a dirty-flush task is already scheduled. */
|
|
1102
|
+
_flushScheduled = false;
|
|
1103
|
+
/** Resolves when the current flush completes. */
|
|
1104
|
+
_flushPromise = Promise.resolve();
|
|
1105
|
+
/** Registered builder extensions keyed by extension ID. */
|
|
1106
|
+
_extensions = Atom3.make(Record2.empty()).pipe(Atom3.keepAlive, Atom3.withLabel("graph-builder:extensions"));
|
|
1107
|
+
/** Triggers signalling that a node's resolver has fired at least once. */
|
|
604
1108
|
_initialized = {};
|
|
1109
|
+
/** Shared atom registry for reactive subscriptions. */
|
|
605
1110
|
_registry;
|
|
1111
|
+
/** Backing graph with internal accessors for node atoms and construction. */
|
|
606
1112
|
_graph;
|
|
607
1113
|
constructor({ registry, ...params } = {}) {
|
|
608
1114
|
this._registry = registry ?? Registry2.make();
|
|
609
|
-
|
|
1115
|
+
const graph = make({
|
|
610
1116
|
...params,
|
|
611
1117
|
registry: this._registry,
|
|
612
|
-
onExpand: (id,
|
|
1118
|
+
onExpand: (id, relation2) => this._onExpand(id, relation2),
|
|
613
1119
|
onInitialize: (id) => this._onInitialize(id),
|
|
614
1120
|
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
615
1121
|
});
|
|
616
|
-
|
|
617
|
-
static from(pickle, registry) {
|
|
618
|
-
if (!pickle) {
|
|
619
|
-
return new _GraphBuilder({
|
|
620
|
-
registry
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
const { nodes, edges } = JSON.parse(pickle);
|
|
624
|
-
return new _GraphBuilder({
|
|
625
|
-
nodes,
|
|
626
|
-
edges,
|
|
627
|
-
registry
|
|
628
|
-
});
|
|
1122
|
+
this._graph = graph;
|
|
629
1123
|
}
|
|
630
1124
|
get graph() {
|
|
631
1125
|
return this._graph;
|
|
@@ -633,155 +1127,151 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
633
1127
|
get extensions() {
|
|
634
1128
|
return this._extensions;
|
|
635
1129
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
node.id
|
|
660
|
-
]);
|
|
661
|
-
if (shouldContinue === false) {
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
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))));
|
|
665
|
-
await Promise.all(nodes.map((nodeArg) => {
|
|
666
|
-
registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
|
|
667
|
-
return this.explore({
|
|
668
|
-
registry,
|
|
669
|
-
source: nodeArg.id,
|
|
670
|
-
relation,
|
|
671
|
-
visitor
|
|
672
|
-
}, [
|
|
673
|
-
...path,
|
|
674
|
-
node.id
|
|
675
|
-
]);
|
|
676
|
-
}));
|
|
677
|
-
if (registry !== this._registry) {
|
|
678
|
-
registry.reset();
|
|
679
|
-
registry.dispose();
|
|
1130
|
+
/** Apply a set of node changes for a single connector key. */
|
|
1131
|
+
_applyConnectorUpdate(key, nodes, previous) {
|
|
1132
|
+
const { id, relation: relation2 } = relationFromConnectorKey(key);
|
|
1133
|
+
const ids = nodes.map((node) => node.id);
|
|
1134
|
+
const removed = previous.filter((pid) => !ids.includes(pid));
|
|
1135
|
+
this._connectorPrevious.set(key, ids);
|
|
1136
|
+
this._connectorPreviousArgs.set(key, nodes);
|
|
1137
|
+
removeEdges(this._graph, removed.map((target) => ({
|
|
1138
|
+
source: id,
|
|
1139
|
+
target,
|
|
1140
|
+
relation: relation2
|
|
1141
|
+
})), true);
|
|
1142
|
+
addNodes(this._graph, nodes);
|
|
1143
|
+
addEdges(this._graph, nodes.map((node) => ({
|
|
1144
|
+
source: id,
|
|
1145
|
+
target: node.id,
|
|
1146
|
+
relation: relation2
|
|
1147
|
+
})));
|
|
1148
|
+
if (ids.length > 0) {
|
|
1149
|
+
const sortedIds = [
|
|
1150
|
+
...nodes
|
|
1151
|
+
].sort((a, b) => byPosition(a.properties ?? {}, b.properties ?? {})).map((n) => n.id);
|
|
1152
|
+
sortEdges(this._graph, id, relation2, sortedIds);
|
|
680
1153
|
}
|
|
681
1154
|
}
|
|
682
|
-
|
|
683
|
-
this.
|
|
684
|
-
|
|
1155
|
+
_scheduleDirtyFlush() {
|
|
1156
|
+
if (!this._flushScheduled) {
|
|
1157
|
+
this._flushScheduled = true;
|
|
1158
|
+
this._flushPromise = scheduleTask(() => {
|
|
1159
|
+
this._flushScheduled = false;
|
|
1160
|
+
while (this._dirtyConnectors.size > 0) {
|
|
1161
|
+
const entries = [
|
|
1162
|
+
...this._dirtyConnectors.entries()
|
|
1163
|
+
];
|
|
1164
|
+
this._dirtyConnectors.clear();
|
|
1165
|
+
Atom3.batch(() => {
|
|
1166
|
+
for (const [key, { nodes, previous }] of entries) {
|
|
1167
|
+
this._applyConnectorUpdate(key, nodes, previous);
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
}, {
|
|
1172
|
+
strategy: "smooth"
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
685
1175
|
}
|
|
686
|
-
_resolvers =
|
|
687
|
-
return
|
|
688
|
-
return Function2.pipe(get2(this._extensions), Record2.values,
|
|
1176
|
+
_resolvers = Atom3.family((id) => {
|
|
1177
|
+
return Atom3.make((get2) => {
|
|
1178
|
+
return Function2.pipe(get2(this._extensions), Record2.values, Array2.sortBy(byPosition), Array2.map(({ resolver }) => resolver), Array2.filter(isNonNullable2), Array2.map((resolver) => get2(resolver(id))), Array2.filter(isNonNullable2), Array2.head);
|
|
689
1179
|
});
|
|
690
1180
|
});
|
|
691
|
-
_connectors =
|
|
692
|
-
return
|
|
693
|
-
const
|
|
1181
|
+
_connectors = Atom3.family((key) => {
|
|
1182
|
+
return Atom3.make((get2) => {
|
|
1183
|
+
const { id, relation: relation2 } = relationFromConnectorKey(key);
|
|
694
1184
|
const node = this._graph.node(id);
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
1185
|
+
const sourceNode = Option3.getOrElse(get2(node), () => void 0);
|
|
1186
|
+
if (!sourceNode) {
|
|
1187
|
+
return [];
|
|
1188
|
+
}
|
|
1189
|
+
const extensions = Function2.pipe(get2(this._extensions), Record2.values, Array2.sortBy(byPosition), Array2.filter((ext) => relationKey(ext.relation ?? "child") === relationKey(relation2) && ext.connector != null));
|
|
1190
|
+
const nodes = [];
|
|
1191
|
+
for (const ext of extensions) {
|
|
1192
|
+
const result = get2(ext.connector(node));
|
|
1193
|
+
nodes.push(...result);
|
|
1194
|
+
}
|
|
1195
|
+
return nodes;
|
|
1196
|
+
}).pipe(Atom3.withLabel(`graph-builder:connectors:${key}`));
|
|
706
1197
|
});
|
|
707
|
-
_onExpand(id,
|
|
1198
|
+
_onExpand(id, relation2) {
|
|
708
1199
|
log2("onExpand", {
|
|
709
1200
|
id,
|
|
710
|
-
relation,
|
|
1201
|
+
relation: relation2,
|
|
711
1202
|
registry: getDebugName(this._registry)
|
|
712
1203
|
}, {
|
|
713
|
-
F:
|
|
714
|
-
L:
|
|
1204
|
+
F: __dxlog_file3,
|
|
1205
|
+
L: 261,
|
|
715
1206
|
S: this,
|
|
716
1207
|
C: (f, a) => f(...a)
|
|
717
1208
|
});
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
1209
|
+
this._expandRelation(id, relation2);
|
|
1210
|
+
if (relation2.kind === "child" && relation2.direction === "outbound") {
|
|
1211
|
+
expand(this._graph, id, "action");
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
_expandRelation(id, relation2) {
|
|
1215
|
+
const key = connectorKey(id, relation2);
|
|
1216
|
+
const connectors = this._connectors(key);
|
|
1217
|
+
const cancel = this._registry.subscribe(connectors, (rawNodes) => {
|
|
1218
|
+
const nodes = qualifyNodeArgs(id)(rawNodes);
|
|
1219
|
+
const previous = this._connectorPrevious.get(key) ?? [];
|
|
721
1220
|
const ids = nodes.map((n) => n.id);
|
|
722
|
-
|
|
723
|
-
|
|
1221
|
+
if (ids.length === previous.length && ids.every((nodeId, idx) => nodeId === previous[idx])) {
|
|
1222
|
+
const prevArgs = this._connectorPreviousArgs.get(key);
|
|
1223
|
+
if (prevArgs && nodeArgsUnchanged(prevArgs, nodes)) {
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
724
1227
|
log2("update", {
|
|
725
1228
|
id,
|
|
726
|
-
relation,
|
|
727
|
-
ids
|
|
728
|
-
removed
|
|
1229
|
+
relation: relation2,
|
|
1230
|
+
ids
|
|
729
1231
|
}, {
|
|
730
|
-
F:
|
|
731
|
-
L:
|
|
1232
|
+
F: __dxlog_file3,
|
|
1233
|
+
L: 288,
|
|
732
1234
|
S: this,
|
|
733
1235
|
C: (f, a) => f(...a)
|
|
734
1236
|
});
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
})), true);
|
|
741
|
-
this._graph.addNodes(nodes);
|
|
742
|
-
this._graph.addEdges(nodes.map((node) => relation === "outbound" ? {
|
|
743
|
-
source: id,
|
|
744
|
-
target: node.id
|
|
745
|
-
} : {
|
|
746
|
-
source: node.id,
|
|
747
|
-
target: id
|
|
748
|
-
}));
|
|
749
|
-
this._graph.sortEdges(id, relation, nodes.map(({ id: id2 }) => id2));
|
|
750
|
-
});
|
|
751
|
-
};
|
|
752
|
-
if (typeof requestAnimationFrame === "function") {
|
|
753
|
-
requestAnimationFrame(update);
|
|
754
|
-
} else {
|
|
755
|
-
update();
|
|
756
|
-
}
|
|
1237
|
+
this._dirtyConnectors.set(key, {
|
|
1238
|
+
nodes,
|
|
1239
|
+
previous
|
|
1240
|
+
});
|
|
1241
|
+
this._scheduleDirtyFlush();
|
|
757
1242
|
}, {
|
|
758
1243
|
immediate: true
|
|
759
1244
|
});
|
|
760
|
-
this._subscriptions.set(id, cancel);
|
|
1245
|
+
this._subscriptions.set(subscriptionKey(id, "expand", key), cancel);
|
|
761
1246
|
}
|
|
762
1247
|
// TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
|
|
763
1248
|
async _onInitialize(id) {
|
|
764
1249
|
log2("onInitialize", {
|
|
765
1250
|
id
|
|
766
1251
|
}, {
|
|
767
|
-
F:
|
|
768
|
-
L:
|
|
1252
|
+
F: __dxlog_file3,
|
|
1253
|
+
L: 300,
|
|
769
1254
|
S: this,
|
|
770
1255
|
C: (f, a) => f(...a)
|
|
771
1256
|
});
|
|
772
1257
|
const resolver = this._resolvers(id);
|
|
773
1258
|
const cancel = this._registry.subscribe(resolver, (node) => {
|
|
774
1259
|
const trigger = this._initialized[id];
|
|
775
|
-
|
|
1260
|
+
Option3.match(node, {
|
|
776
1261
|
onSome: (node2) => {
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
]);
|
|
1262
|
+
const connectorOwned = [
|
|
1263
|
+
...this._connectorPrevious.values()
|
|
1264
|
+
].some((ids) => ids.includes(id));
|
|
1265
|
+
if (!connectorOwned) {
|
|
1266
|
+
addNodes(this._graph, [
|
|
1267
|
+
node2
|
|
1268
|
+
]);
|
|
1269
|
+
}
|
|
780
1270
|
trigger?.wake();
|
|
781
1271
|
},
|
|
782
1272
|
onNone: () => {
|
|
783
1273
|
trigger?.wake();
|
|
784
|
-
this._graph
|
|
1274
|
+
removeNodes(this._graph, [
|
|
785
1275
|
id
|
|
786
1276
|
]);
|
|
787
1277
|
}
|
|
@@ -789,48 +1279,301 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
789
1279
|
}, {
|
|
790
1280
|
immediate: true
|
|
791
1281
|
});
|
|
792
|
-
this._subscriptions.set(id, cancel);
|
|
1282
|
+
this._subscriptions.set(subscriptionKey(id, "init"), cancel);
|
|
793
1283
|
}
|
|
794
1284
|
_onRemoveNode(id) {
|
|
795
|
-
|
|
796
|
-
this._subscriptions
|
|
1285
|
+
const prefix = `${id}${Separators.primary}`;
|
|
1286
|
+
for (const [key, cleanup] of this._subscriptions) {
|
|
1287
|
+
if (key.startsWith(prefix)) {
|
|
1288
|
+
cleanup();
|
|
1289
|
+
this._subscriptions.delete(key);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
797
1292
|
}
|
|
798
1293
|
};
|
|
799
|
-
var
|
|
800
|
-
return
|
|
801
|
-
|
|
802
|
-
|
|
1294
|
+
var make2 = (params) => {
|
|
1295
|
+
return new GraphBuilderImpl(params);
|
|
1296
|
+
};
|
|
1297
|
+
var from = (pickle, registry) => {
|
|
1298
|
+
if (!pickle) {
|
|
1299
|
+
return make2({
|
|
1300
|
+
registry
|
|
803
1301
|
});
|
|
804
|
-
|
|
805
|
-
|
|
1302
|
+
}
|
|
1303
|
+
const { nodes, edges } = JSON.parse(pickle);
|
|
1304
|
+
return make2({
|
|
1305
|
+
nodes,
|
|
1306
|
+
edges,
|
|
1307
|
+
registry
|
|
806
1308
|
});
|
|
807
1309
|
};
|
|
808
|
-
var
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1310
|
+
var addExtensionImpl = (builder, extensions) => {
|
|
1311
|
+
const internal = builder;
|
|
1312
|
+
flattenExtensions(extensions).forEach((extension) => {
|
|
1313
|
+
const extensions2 = internal._registry.get(internal._extensions);
|
|
1314
|
+
internal._registry.set(internal._extensions, Record2.set(extensions2, extension.id, extension));
|
|
1315
|
+
});
|
|
1316
|
+
return builder;
|
|
1317
|
+
};
|
|
1318
|
+
function addExtension(builderOrExtensions, extensions) {
|
|
1319
|
+
if (extensions === void 0) {
|
|
1320
|
+
const extensions2 = builderOrExtensions;
|
|
1321
|
+
return (builder) => addExtensionImpl(builder, extensions2);
|
|
1322
|
+
} else {
|
|
1323
|
+
const builder = builderOrExtensions;
|
|
1324
|
+
return addExtensionImpl(builder, extensions);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
var removeExtensionImpl = (builder, id) => {
|
|
1328
|
+
const internal = builder;
|
|
1329
|
+
const extensions = internal._registry.get(internal._extensions);
|
|
1330
|
+
internal._registry.set(internal._extensions, Record2.remove(extensions, id));
|
|
1331
|
+
return builder;
|
|
1332
|
+
};
|
|
1333
|
+
function removeExtension(builderOrId, id) {
|
|
1334
|
+
if (typeof builderOrId === "string") {
|
|
1335
|
+
const id2 = builderOrId;
|
|
1336
|
+
return (builder) => removeExtensionImpl(builder, id2);
|
|
1337
|
+
} else {
|
|
1338
|
+
const builder = builderOrId;
|
|
1339
|
+
return removeExtensionImpl(builder, id);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
var exploreImpl = async (builder, options, path = []) => {
|
|
1343
|
+
const internal = builder;
|
|
1344
|
+
const { registry = Registry2.make(), source = RootId, relation: relation2, visitor } = options;
|
|
1345
|
+
if (path.includes(source)) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
await yieldOrContinue("idle");
|
|
1349
|
+
const node = registry.get(internal._graph.nodeOrThrow(source));
|
|
1350
|
+
const shouldContinue = await visitor(node, [
|
|
1351
|
+
...path,
|
|
1352
|
+
node.id
|
|
1353
|
+
]);
|
|
1354
|
+
if (shouldContinue === false) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
const nodes = Function2.pipe(internal._registry.get(internal._extensions), Record2.values, Array2.map((extension) => extension.connector), Array2.filter(isNonNullable2), Array2.flatMap((connector) => registry.get(connector(internal._graph.node(source)))), qualifyNodeArgs(source));
|
|
1358
|
+
await Promise.all(nodes.map((nodeArg) => {
|
|
1359
|
+
registry.set(internal._graph._node(nodeArg.id), internal._graph._constructNode(nodeArg));
|
|
1360
|
+
return exploreImpl(builder, {
|
|
1361
|
+
registry,
|
|
1362
|
+
source: nodeArg.id,
|
|
1363
|
+
relation: relation2,
|
|
1364
|
+
visitor
|
|
1365
|
+
}, [
|
|
1366
|
+
...path,
|
|
1367
|
+
node.id
|
|
1368
|
+
]);
|
|
1369
|
+
}));
|
|
1370
|
+
if (registry !== internal._registry) {
|
|
1371
|
+
registry.reset();
|
|
1372
|
+
registry.dispose();
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
function explore(builderOrOptions, optionsOrPath, path) {
|
|
1376
|
+
if (typeof builderOrOptions === "object" && "visitor" in builderOrOptions) {
|
|
1377
|
+
const options = builderOrOptions;
|
|
1378
|
+
const path2 = Array2.isArray(optionsOrPath) ? optionsOrPath : void 0;
|
|
1379
|
+
return (builder) => exploreImpl(builder, options, path2);
|
|
1380
|
+
} else {
|
|
1381
|
+
const builder = builderOrOptions;
|
|
1382
|
+
const options = optionsOrPath;
|
|
1383
|
+
const pathArg = path ?? (Array2.isArray(optionsOrPath) ? optionsOrPath : void 0);
|
|
1384
|
+
return exploreImpl(builder, options, pathArg);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
var destroyImpl = (builder) => {
|
|
1388
|
+
const internal = builder;
|
|
1389
|
+
internal._subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
1390
|
+
internal._subscriptions.clear();
|
|
1391
|
+
};
|
|
1392
|
+
function destroy(builder) {
|
|
1393
|
+
if (builder === void 0) {
|
|
1394
|
+
return (builder2) => destroyImpl(builder2);
|
|
1395
|
+
} else {
|
|
1396
|
+
return destroyImpl(builder);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
var flush = (builder) => {
|
|
1400
|
+
return builder._flushPromise;
|
|
1401
|
+
};
|
|
1402
|
+
var createExtensionRaw = (extension) => {
|
|
1403
|
+
const { id, position = "static", relation: relation2 = "child", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
1404
|
+
const normalizedRelation = normalizeRelation(relation2);
|
|
1405
|
+
const getId = (key) => `${id}/${key}`;
|
|
1406
|
+
const resolver = _resolver && Atom3.family((id2) => _resolver(id2).pipe(Atom3.withLabel(`graph-builder:_resolver:${id2}`)));
|
|
1407
|
+
const connector = _connector && Atom3.family((node) => _connector(node).pipe(Atom3.withLabel(`graph-builder:_connector:${id}`)));
|
|
1408
|
+
const actionGroups = _actionGroups && Atom3.family((node) => _actionGroups(node).pipe(Atom3.withLabel(`graph-builder:_actionGroups:${id}`)));
|
|
1409
|
+
const actions = _actions && Atom3.family((node) => _actions(node).pipe(Atom3.withLabel(`graph-builder:_actions:${id}`)));
|
|
1410
|
+
return [
|
|
1411
|
+
resolver ? {
|
|
1412
|
+
id: getId("resolver"),
|
|
1413
|
+
position,
|
|
1414
|
+
resolver
|
|
1415
|
+
} : void 0,
|
|
1416
|
+
connector ? {
|
|
1417
|
+
id: getId("connector"),
|
|
1418
|
+
position,
|
|
1419
|
+
relation: normalizedRelation,
|
|
1420
|
+
connector: Atom3.family((node) => Atom3.make((get2) => {
|
|
1421
|
+
try {
|
|
1422
|
+
return get2(connector(node));
|
|
1423
|
+
} catch (error) {
|
|
1424
|
+
log2.warn("Error in connector", {
|
|
1425
|
+
id: getId("connector"),
|
|
1426
|
+
node,
|
|
1427
|
+
error
|
|
1428
|
+
}, {
|
|
1429
|
+
F: __dxlog_file3,
|
|
1430
|
+
L: 596,
|
|
1431
|
+
S: void 0,
|
|
1432
|
+
C: (f, a) => f(...a)
|
|
1433
|
+
});
|
|
1434
|
+
return [];
|
|
1435
|
+
}
|
|
1436
|
+
}).pipe(Atom3.withLabel(`graph-builder:connector:${id}`)))
|
|
1437
|
+
} : void 0,
|
|
1438
|
+
actionGroups ? {
|
|
1439
|
+
id: getId("actionGroups"),
|
|
1440
|
+
position,
|
|
1441
|
+
relation: actionRelation(),
|
|
1442
|
+
connector: Atom3.family((node) => Atom3.make((get2) => {
|
|
1443
|
+
try {
|
|
1444
|
+
return get2(actionGroups(node)).map((arg) => ({
|
|
1445
|
+
...arg,
|
|
1446
|
+
data: actionGroupSymbol,
|
|
1447
|
+
type: ActionGroupType
|
|
1448
|
+
}));
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
log2.warn("Error in actionGroups", {
|
|
1451
|
+
id: getId("actionGroups"),
|
|
1452
|
+
node,
|
|
1453
|
+
error
|
|
1454
|
+
}, {
|
|
1455
|
+
F: __dxlog_file3,
|
|
1456
|
+
L: 617,
|
|
1457
|
+
S: void 0,
|
|
1458
|
+
C: (f, a) => f(...a)
|
|
1459
|
+
});
|
|
1460
|
+
return [];
|
|
1461
|
+
}
|
|
1462
|
+
}).pipe(Atom3.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
1463
|
+
} : void 0,
|
|
1464
|
+
actions ? {
|
|
1465
|
+
id: getId("actions"),
|
|
1466
|
+
position,
|
|
1467
|
+
relation: actionRelation(),
|
|
1468
|
+
connector: Atom3.family((node) => Atom3.make((get2) => {
|
|
1469
|
+
try {
|
|
1470
|
+
return get2(actions(node)).map((arg) => ({
|
|
1471
|
+
...arg,
|
|
1472
|
+
type: ActionType
|
|
1473
|
+
}));
|
|
1474
|
+
} catch (error) {
|
|
1475
|
+
log2.warn("Error in actions", {
|
|
1476
|
+
id: getId("actions"),
|
|
1477
|
+
node,
|
|
1478
|
+
error
|
|
1479
|
+
}, {
|
|
1480
|
+
F: __dxlog_file3,
|
|
1481
|
+
L: 634,
|
|
1482
|
+
S: void 0,
|
|
1483
|
+
C: (f, a) => f(...a)
|
|
1484
|
+
});
|
|
1485
|
+
return [];
|
|
1486
|
+
}
|
|
1487
|
+
}).pipe(Atom3.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
1488
|
+
} : void 0
|
|
1489
|
+
].filter(isNonNullable2);
|
|
1490
|
+
};
|
|
1491
|
+
var runEffectSyncWithFallback = (effect, context2, extensionId, fallback) => {
|
|
1492
|
+
return Effect.runSync(effect.pipe(Effect.provide(context2), Effect.catchAll((error) => {
|
|
1493
|
+
log2.warn("Extension failed", {
|
|
1494
|
+
extension: extensionId,
|
|
1495
|
+
error
|
|
1496
|
+
}, {
|
|
1497
|
+
F: __dxlog_file3,
|
|
1498
|
+
L: 677,
|
|
1499
|
+
S: void 0,
|
|
1500
|
+
C: (f, a) => f(...a)
|
|
1501
|
+
});
|
|
1502
|
+
return Effect.succeed(fallback);
|
|
1503
|
+
})));
|
|
1504
|
+
};
|
|
1505
|
+
var createExtension = (options) => Effect.map(Effect.context(), (context2) => {
|
|
1506
|
+
const { id, match: match3, actions, connector, resolver, relation: relation2, position } = options;
|
|
1507
|
+
const connectorExtension = connector ? createConnectorWithRuntime(id, match3, connector, context2) : void 0;
|
|
1508
|
+
const actionsExtension = actions ? (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(match3), Option3.map((matched) => runEffectSyncWithFallback(actions(matched, get2), context2, id, []).map((action) => ({
|
|
1509
|
+
...action,
|
|
1510
|
+
// Attach captured context for action execution.
|
|
1511
|
+
_actionContext: context2
|
|
1512
|
+
}))), Option3.getOrElse(() => []))) : void 0;
|
|
1513
|
+
const resolverExtension = resolver ? (nodeId) => Atom3.make((get2) => runEffectSyncWithFallback(resolver(nodeId, get2), context2, id, null) ?? null) : void 0;
|
|
1514
|
+
return createExtensionRaw({
|
|
1515
|
+
id,
|
|
1516
|
+
relation: relation2,
|
|
1517
|
+
position,
|
|
1518
|
+
connector: connectorExtension,
|
|
1519
|
+
actions: actionsExtension,
|
|
1520
|
+
resolver: resolverExtension
|
|
813
1521
|
});
|
|
814
1522
|
});
|
|
815
|
-
var
|
|
816
|
-
return
|
|
1523
|
+
var createConnector = (matcher, factory) => {
|
|
1524
|
+
return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => factory(data, get2)), Option3.getOrElse(() => [])));
|
|
1525
|
+
};
|
|
1526
|
+
var createConnectorWithRuntime = (extensionId, matcher, factory, context2) => {
|
|
1527
|
+
return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => runEffectSyncWithFallback(factory(data, get2), context2, extensionId, [])), Option3.getOrElse(() => [])));
|
|
1528
|
+
};
|
|
1529
|
+
var createTypeExtension = (options) => {
|
|
1530
|
+
const { id, type, actions, connector, relation: relation2, position } = options;
|
|
1531
|
+
return createExtension({
|
|
1532
|
+
id,
|
|
1533
|
+
match: whenEchoType(type),
|
|
1534
|
+
actions,
|
|
1535
|
+
connector,
|
|
1536
|
+
relation: relation2,
|
|
1537
|
+
position
|
|
1538
|
+
});
|
|
1539
|
+
};
|
|
1540
|
+
var qualifyNodeArgs = (parentId) => (nodes) => nodes.map((node) => {
|
|
1541
|
+
validateSegmentId(node.id);
|
|
1542
|
+
const qualified = qualifyId(parentId, node.id);
|
|
1543
|
+
return {
|
|
1544
|
+
...node,
|
|
1545
|
+
id: qualified,
|
|
1546
|
+
nodes: node.nodes ? qualifyNodeArgs(qualified)(node.nodes) : void 0
|
|
1547
|
+
};
|
|
1548
|
+
});
|
|
1549
|
+
var connectorKey = (id, relation2) => `${id}${Separators.primary}${relationKey(relation2)}`;
|
|
1550
|
+
var relationFromConnectorKey = (key) => {
|
|
1551
|
+
const separatorIndex = key.indexOf(Separators.primary);
|
|
1552
|
+
const id = key.slice(0, separatorIndex);
|
|
1553
|
+
return {
|
|
1554
|
+
id,
|
|
1555
|
+
relation: relationFromKey(key.slice(separatorIndex + 1))
|
|
1556
|
+
};
|
|
1557
|
+
};
|
|
1558
|
+
var subscriptionKey = (id, kind, detail) => detail != null ? `${id}${Separators.primary}${kind}${Separators.primary}${detail}` : `${id}${Separators.primary}${kind}`;
|
|
1559
|
+
var flattenExtensions = (extension, acc = []) => {
|
|
1560
|
+
if (Array2.isArray(extension)) {
|
|
1561
|
+
return [
|
|
1562
|
+
...acc,
|
|
1563
|
+
...extension.flatMap((ext) => flattenExtensions(ext, acc))
|
|
1564
|
+
];
|
|
1565
|
+
} else {
|
|
1566
|
+
return [
|
|
1567
|
+
...acc,
|
|
1568
|
+
extension
|
|
1569
|
+
];
|
|
1570
|
+
}
|
|
817
1571
|
};
|
|
818
1572
|
export {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
ROOT_TYPE,
|
|
825
|
-
actionGroupSymbol,
|
|
826
|
-
atomFromObservable,
|
|
827
|
-
atomFromSignal,
|
|
828
|
-
createExtension,
|
|
829
|
-
flattenExtensions,
|
|
830
|
-
getGraph,
|
|
831
|
-
isAction,
|
|
832
|
-
isActionGroup,
|
|
833
|
-
isActionLike,
|
|
834
|
-
isGraphNode
|
|
1573
|
+
atoms_exports as CreateAtom,
|
|
1574
|
+
graph_exports as Graph,
|
|
1575
|
+
graph_builder_exports as GraphBuilder,
|
|
1576
|
+
node_exports as Node,
|
|
1577
|
+
node_matcher_exports as NodeMatcher
|
|
835
1578
|
};
|
|
836
1579
|
//# sourceMappingURL=index.mjs.map
|