@dxos/app-graph 0.8.4-main.b97322e → 0.8.4-main.bc674ce
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 +1131 -612
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1130 -612
- 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 +113 -60
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +183 -209
- 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 +32 -3
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts +8 -10
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +37 -35
- package/src/atoms.ts +25 -0
- package/src/graph-builder.test.ts +571 -97
- package/src/graph-builder.ts +600 -258
- package/src/graph.test.ts +300 -107
- package/src/graph.ts +971 -400
- package/src/index.ts +9 -3
- package/src/node-matcher.test.ts +301 -0
- package/src/node-matcher.ts +284 -0
- package/src/node.ts +39 -6
- package/src/stories/EchoGraph.stories.tsx +119 -108
- package/src/stories/Tree.tsx +2 -2
- package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
- package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
- 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 -5
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/experimental/graph-projections.test.ts +0 -56
- package/src/signals-integration.test.ts +0 -218
- package/src/testing.ts +0 -20
|
@@ -1,18 +1,97 @@
|
|
|
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
|
-
|
|
3
|
-
|
|
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
|
+
removeEdge: () => removeEdge,
|
|
45
|
+
removeEdges: () => removeEdges,
|
|
46
|
+
removeNode: () => removeNode,
|
|
47
|
+
removeNodes: () => removeNodes,
|
|
48
|
+
sortEdges: () => sortEdges,
|
|
49
|
+
toJSON: () => toJSON,
|
|
50
|
+
traverse: () => traverse,
|
|
51
|
+
waitForPath: () => waitForPath
|
|
52
|
+
});
|
|
53
|
+
import { Atom as Atom2, Registry } from "@effect-atom/atom-react";
|
|
54
|
+
import * as Function from "effect/Function";
|
|
55
|
+
import * as Option from "effect/Option";
|
|
56
|
+
import * as Pipeable from "effect/Pipeable";
|
|
57
|
+
import * as Record from "effect/Record";
|
|
4
58
|
import { Event, Trigger } from "@dxos/async";
|
|
5
59
|
import { todo } from "@dxos/debug";
|
|
6
60
|
import { invariant } from "@dxos/invariant";
|
|
7
61
|
import { log } from "@dxos/log";
|
|
8
62
|
import { isNonNullable } from "@dxos/util";
|
|
63
|
+
|
|
64
|
+
// src/node.ts
|
|
65
|
+
var node_exports = {};
|
|
66
|
+
__export(node_exports, {
|
|
67
|
+
ActionGroupType: () => ActionGroupType,
|
|
68
|
+
ActionType: () => ActionType,
|
|
69
|
+
RootId: () => RootId,
|
|
70
|
+
RootType: () => RootType,
|
|
71
|
+
actionGroupSymbol: () => actionGroupSymbol,
|
|
72
|
+
isAction: () => isAction,
|
|
73
|
+
isActionGroup: () => isActionGroup,
|
|
74
|
+
isActionLike: () => isActionLike,
|
|
75
|
+
isGraphNode: () => isGraphNode
|
|
76
|
+
});
|
|
77
|
+
var RootId = "root";
|
|
78
|
+
var RootType = "dxos.org/type/GraphRoot";
|
|
79
|
+
var ActionType = "dxos.org/type/GraphAction";
|
|
80
|
+
var ActionGroupType = "dxos.org/type/GraphActionGroup";
|
|
81
|
+
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
82
|
+
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ActionType : false;
|
|
83
|
+
var actionGroupSymbol = Symbol("ActionGroup");
|
|
84
|
+
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ActionGroupType : false;
|
|
85
|
+
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
86
|
+
|
|
87
|
+
// src/graph.ts
|
|
9
88
|
var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
10
89
|
var graphSymbol = Symbol("graph");
|
|
11
90
|
var getGraph = (node) => {
|
|
12
91
|
const graph = node[graphSymbol];
|
|
13
92
|
invariant(graph, "Node is not associated with a graph.", {
|
|
14
93
|
F: __dxlog_file,
|
|
15
|
-
L:
|
|
94
|
+
L: 32,
|
|
16
95
|
S: void 0,
|
|
17
96
|
A: [
|
|
18
97
|
"graph",
|
|
@@ -21,95 +100,103 @@ var getGraph = (node) => {
|
|
|
21
100
|
});
|
|
22
101
|
return graph;
|
|
23
102
|
};
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
103
|
+
var GraphTypeId = Symbol.for("@dxos/app-graph/Graph");
|
|
104
|
+
var GraphKind = Symbol.for("@dxos/app-graph/GraphKind");
|
|
105
|
+
var GraphImpl = class {
|
|
106
|
+
[GraphTypeId] = GraphTypeId;
|
|
107
|
+
[GraphKind] = "writable";
|
|
108
|
+
pipe() {
|
|
109
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
110
|
+
}
|
|
111
|
+
onNodeChanged = new Event();
|
|
112
|
+
_onExpand;
|
|
113
|
+
_onInitialize;
|
|
114
|
+
_onRemoveNode;
|
|
115
|
+
_registry;
|
|
116
|
+
_expanded = Record.empty();
|
|
117
|
+
_initialized = Record.empty();
|
|
118
|
+
_initialEdges = Record.empty();
|
|
119
|
+
_initialNodes = Record.fromEntries([
|
|
120
|
+
[
|
|
121
|
+
RootId,
|
|
122
|
+
this._constructNode({
|
|
123
|
+
id: RootId,
|
|
124
|
+
type: RootType,
|
|
125
|
+
data: null,
|
|
126
|
+
properties: {}
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
]);
|
|
130
|
+
/** @internal */
|
|
131
|
+
_node = Atom2.family((id) => {
|
|
132
|
+
const initial = Option.flatten(Record.get(this._initialNodes, id));
|
|
133
|
+
return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:node:${id}`));
|
|
134
|
+
});
|
|
135
|
+
_nodeOrThrow = Atom2.family((id) => {
|
|
136
|
+
return Atom2.make((get2) => {
|
|
137
|
+
const node = get2(this._node(id));
|
|
138
|
+
invariant(Option.isSome(node), `Node not available: ${id}`, {
|
|
139
|
+
F: __dxlog_file,
|
|
140
|
+
L: 174,
|
|
141
|
+
S: this,
|
|
142
|
+
A: [
|
|
143
|
+
"Option.isSome(node)",
|
|
144
|
+
"`Node not available: ${id}`"
|
|
145
|
+
]
|
|
63
146
|
});
|
|
147
|
+
return node.value;
|
|
64
148
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (node.properties.label) {
|
|
95
|
-
obj.label = node.properties.label;
|
|
96
|
-
}
|
|
97
|
-
if (nodes.length) {
|
|
98
|
-
obj.nodes = nodes.map((n) => {
|
|
99
|
-
const nextSeen = [
|
|
100
|
-
...seen,
|
|
101
|
-
node.id
|
|
102
|
-
];
|
|
103
|
-
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
104
|
-
}).filter(isNonNullable);
|
|
105
|
-
}
|
|
106
|
-
return obj;
|
|
149
|
+
});
|
|
150
|
+
_edges = Atom2.family((id) => {
|
|
151
|
+
const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
|
|
152
|
+
inbound: [],
|
|
153
|
+
outbound: []
|
|
154
|
+
})));
|
|
155
|
+
return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:edges:${id}`));
|
|
156
|
+
});
|
|
157
|
+
// NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
|
|
158
|
+
// TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
|
|
159
|
+
_connections = Atom2.family((key) => {
|
|
160
|
+
return Atom2.make((get2) => {
|
|
161
|
+
const [id, relation] = key.split("$");
|
|
162
|
+
const edges = get2(this._edges(id));
|
|
163
|
+
return edges[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
|
|
164
|
+
}).pipe(Atom2.withLabel(`graph:connections:${key}`));
|
|
165
|
+
});
|
|
166
|
+
_actions = Atom2.family((id) => {
|
|
167
|
+
return Atom2.make((get2) => {
|
|
168
|
+
return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ActionType || node.type === ActionGroupType);
|
|
169
|
+
}).pipe(Atom2.withLabel(`graph:actions:${id}`));
|
|
170
|
+
});
|
|
171
|
+
_json = Atom2.family((id) => {
|
|
172
|
+
return Atom2.make((get2) => {
|
|
173
|
+
const toJSON2 = (node, seen = []) => {
|
|
174
|
+
const nodes = get2(this._connections(`${node.id}$outbound`));
|
|
175
|
+
const obj = {
|
|
176
|
+
id: node.id,
|
|
177
|
+
type: node.type
|
|
107
178
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
179
|
+
if (node.properties.label) {
|
|
180
|
+
obj.label = node.properties.label;
|
|
181
|
+
}
|
|
182
|
+
if (nodes.length) {
|
|
183
|
+
obj.nodes = nodes.map((n) => {
|
|
184
|
+
const nextSeen = [
|
|
185
|
+
...seen,
|
|
186
|
+
node.id
|
|
187
|
+
];
|
|
188
|
+
return nextSeen.includes(n.id) ? void 0 : toJSON2(n, nextSeen);
|
|
189
|
+
}).filter(isNonNullable);
|
|
190
|
+
}
|
|
191
|
+
return obj;
|
|
192
|
+
};
|
|
193
|
+
const root = get2(this._nodeOrThrow(id));
|
|
194
|
+
return toJSON2(root);
|
|
195
|
+
}).pipe(Atom2.withLabel(`graph:json:${id}`));
|
|
196
|
+
});
|
|
197
|
+
constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
|
|
112
198
|
this._registry = registry ?? Registry.make();
|
|
199
|
+
this._onInitialize = onInitialize;
|
|
113
200
|
this._onExpand = onExpand;
|
|
114
201
|
this._onRemoveNode = onRemoveNode;
|
|
115
202
|
if (nodes) {
|
|
@@ -123,500 +210,705 @@ var Graph = class {
|
|
|
123
210
|
});
|
|
124
211
|
}
|
|
125
212
|
}
|
|
126
|
-
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
json(id = ROOT_ID) {
|
|
130
|
-
return this._json(id);
|
|
213
|
+
json(id = RootId) {
|
|
214
|
+
return jsonImpl(this, id);
|
|
131
215
|
}
|
|
132
216
|
node(id) {
|
|
133
|
-
return this
|
|
217
|
+
return nodeImpl(this, id);
|
|
134
218
|
}
|
|
135
219
|
nodeOrThrow(id) {
|
|
136
|
-
return this
|
|
220
|
+
return nodeOrThrowImpl(this, id);
|
|
137
221
|
}
|
|
138
222
|
connections(id, relation = "outbound") {
|
|
139
|
-
return this
|
|
223
|
+
return connectionsImpl(this, id, relation);
|
|
140
224
|
}
|
|
141
225
|
actions(id) {
|
|
142
|
-
return this
|
|
226
|
+
return actionsImpl(this, id);
|
|
143
227
|
}
|
|
144
228
|
edges(id) {
|
|
145
|
-
return this
|
|
146
|
-
}
|
|
147
|
-
get root() {
|
|
148
|
-
return this.getNodeOrThrow(ROOT_ID);
|
|
149
|
-
}
|
|
150
|
-
getNode(id) {
|
|
151
|
-
return this._registry.get(this.node(id));
|
|
152
|
-
}
|
|
153
|
-
getNodeOrThrow(id) {
|
|
154
|
-
return this._registry.get(this.nodeOrThrow(id));
|
|
155
|
-
}
|
|
156
|
-
getConnections(id, relation = "outbound") {
|
|
157
|
-
return this._registry.get(this.connections(id, relation));
|
|
158
|
-
}
|
|
159
|
-
getActions(id) {
|
|
160
|
-
return this._registry.get(this.actions(id));
|
|
161
|
-
}
|
|
162
|
-
getEdges(id) {
|
|
163
|
-
return this._registry.get(this.edges(id));
|
|
164
|
-
}
|
|
165
|
-
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
166
|
-
// async initialize(id: string) {
|
|
167
|
-
// const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
|
|
168
|
-
// log('initialize', { id, initialized });
|
|
169
|
-
// if (!initialized) {
|
|
170
|
-
// await this._onInitialize?.(id);
|
|
171
|
-
// Record.set(this._initialized, id, true);
|
|
172
|
-
// }
|
|
173
|
-
// }
|
|
174
|
-
expand(id, relation = "outbound") {
|
|
175
|
-
const key = `${id}$${relation}`;
|
|
176
|
-
const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
|
|
177
|
-
log("expand", {
|
|
178
|
-
key,
|
|
179
|
-
expanded
|
|
180
|
-
}, {
|
|
181
|
-
F: __dxlog_file,
|
|
182
|
-
L: 395,
|
|
183
|
-
S: this,
|
|
184
|
-
C: (f, a) => f(...a)
|
|
185
|
-
});
|
|
186
|
-
if (!expanded) {
|
|
187
|
-
this._onExpand?.(id, relation);
|
|
188
|
-
Record.set(this._expanded, key, true);
|
|
189
|
-
}
|
|
229
|
+
return edgesImpl(this, id);
|
|
190
230
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
231
|
+
/** @internal */
|
|
232
|
+
_constructNode(node) {
|
|
233
|
+
return Option.some({
|
|
234
|
+
[graphSymbol]: this,
|
|
235
|
+
data: null,
|
|
236
|
+
properties: {},
|
|
237
|
+
...node
|
|
194
238
|
});
|
|
195
239
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
240
|
+
};
|
|
241
|
+
var getInternal = (graph) => {
|
|
242
|
+
return graph;
|
|
243
|
+
};
|
|
244
|
+
var toJSON = (graph, id = RootId) => {
|
|
245
|
+
const internal = getInternal(graph);
|
|
246
|
+
return internal._registry.get(internal._json(id));
|
|
247
|
+
};
|
|
248
|
+
var jsonImpl = (graph, id = RootId) => {
|
|
249
|
+
const internal = getInternal(graph);
|
|
250
|
+
return internal._json(id);
|
|
251
|
+
};
|
|
252
|
+
var nodeImpl = (graph, id) => {
|
|
253
|
+
const internal = getInternal(graph);
|
|
254
|
+
return internal._node(id);
|
|
255
|
+
};
|
|
256
|
+
var nodeOrThrowImpl = (graph, id) => {
|
|
257
|
+
const internal = getInternal(graph);
|
|
258
|
+
return internal._nodeOrThrow(id);
|
|
259
|
+
};
|
|
260
|
+
var connectionsImpl = (graph, id, relation = "outbound") => {
|
|
261
|
+
const internal = getInternal(graph);
|
|
262
|
+
return internal._connections(`${id}$${relation}`);
|
|
263
|
+
};
|
|
264
|
+
var actionsImpl = (graph, id) => {
|
|
265
|
+
const internal = getInternal(graph);
|
|
266
|
+
return internal._actions(id);
|
|
267
|
+
};
|
|
268
|
+
var edgesImpl = (graph, id) => {
|
|
269
|
+
const internal = getInternal(graph);
|
|
270
|
+
return internal._edges(id);
|
|
271
|
+
};
|
|
272
|
+
var getNodeImpl = (graph, id) => {
|
|
273
|
+
const internal = getInternal(graph);
|
|
274
|
+
return internal._registry.get(nodeImpl(graph, id));
|
|
275
|
+
};
|
|
276
|
+
function getNode(graphOrId, id) {
|
|
277
|
+
if (typeof graphOrId === "string") {
|
|
278
|
+
const id2 = graphOrId;
|
|
279
|
+
return (graph) => getNodeImpl(graph, id2);
|
|
280
|
+
} else {
|
|
281
|
+
const graph = graphOrId;
|
|
282
|
+
return getNodeImpl(graph, id);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
var getNodeOrThrowImpl = (graph, id) => {
|
|
286
|
+
const internal = getInternal(graph);
|
|
287
|
+
return internal._registry.get(nodeOrThrowImpl(graph, id));
|
|
288
|
+
};
|
|
289
|
+
function getNodeOrThrow(graphOrId, id) {
|
|
290
|
+
if (typeof graphOrId === "string") {
|
|
291
|
+
const id2 = graphOrId;
|
|
292
|
+
return (graph) => getNodeOrThrowImpl(graph, id2);
|
|
293
|
+
} else {
|
|
294
|
+
const graph = graphOrId;
|
|
295
|
+
return getNodeOrThrowImpl(graph, id);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function getRoot(graph) {
|
|
299
|
+
return getNodeOrThrowImpl(graph, RootId);
|
|
300
|
+
}
|
|
301
|
+
var getConnectionsImpl = (graph, id, relation = "outbound") => {
|
|
302
|
+
const internal = getInternal(graph);
|
|
303
|
+
return internal._registry.get(connectionsImpl(graph, id, relation));
|
|
304
|
+
};
|
|
305
|
+
function getConnections(graphOrId, idOrRelation, relation) {
|
|
306
|
+
if (typeof graphOrId === "string") {
|
|
307
|
+
const id = graphOrId;
|
|
308
|
+
const rel = (typeof idOrRelation === "string" ? "outbound" : idOrRelation) ?? "outbound";
|
|
309
|
+
return (graph) => getConnectionsImpl(graph, id, rel);
|
|
310
|
+
} else {
|
|
311
|
+
const graph = graphOrId;
|
|
312
|
+
const id = idOrRelation;
|
|
313
|
+
const rel = relation ?? "outbound";
|
|
314
|
+
return getConnectionsImpl(graph, id, rel);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
var getActionsImpl = (graph, id) => {
|
|
318
|
+
const internal = getInternal(graph);
|
|
319
|
+
return internal._registry.get(actionsImpl(graph, id));
|
|
320
|
+
};
|
|
321
|
+
function getActions(graphOrId, id) {
|
|
322
|
+
if (typeof graphOrId === "string") {
|
|
323
|
+
const id2 = graphOrId;
|
|
324
|
+
return (graph) => getActionsImpl(graph, id2);
|
|
325
|
+
} else {
|
|
326
|
+
const graph = graphOrId;
|
|
327
|
+
return getActionsImpl(graph, id);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
var getEdgesImpl = (graph, id) => {
|
|
331
|
+
const internal = getInternal(graph);
|
|
332
|
+
return internal._registry.get(edgesImpl(graph, id));
|
|
333
|
+
};
|
|
334
|
+
function getEdges(graphOrId, id) {
|
|
335
|
+
if (typeof graphOrId === "string") {
|
|
336
|
+
const id2 = graphOrId;
|
|
337
|
+
return (graph) => getEdgesImpl(graph, id2);
|
|
338
|
+
} else {
|
|
339
|
+
const graph = graphOrId;
|
|
340
|
+
return getEdgesImpl(graph, id);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
var traverseImpl = (graph, options, path = []) => {
|
|
344
|
+
const { visitor, source = RootId, relation = "outbound" } = options;
|
|
345
|
+
if (path.includes(source)) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const node = getNodeOrThrow(graph, source);
|
|
349
|
+
const shouldContinue = visitor(node, [
|
|
350
|
+
...path,
|
|
351
|
+
source
|
|
352
|
+
]);
|
|
353
|
+
if (shouldContinue === false) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
Object.values(getConnections(graph, source, relation)).forEach((child) => traverseImpl(graph, {
|
|
357
|
+
source: child.id,
|
|
358
|
+
relation,
|
|
359
|
+
visitor
|
|
360
|
+
}, [
|
|
361
|
+
...path,
|
|
362
|
+
source
|
|
363
|
+
]));
|
|
364
|
+
};
|
|
365
|
+
function traverse(graphOrOptions, optionsOrPath, path) {
|
|
366
|
+
if (typeof graphOrOptions === "object" && "visitor" in graphOrOptions) {
|
|
367
|
+
const options = graphOrOptions;
|
|
368
|
+
const pathArg = Array.isArray(optionsOrPath) ? optionsOrPath : void 0;
|
|
369
|
+
return (graph) => traverseImpl(graph, options, pathArg);
|
|
370
|
+
} else {
|
|
371
|
+
const graph = graphOrOptions;
|
|
372
|
+
const options = optionsOrPath;
|
|
373
|
+
const pathArg = path ?? (Array.isArray(optionsOrPath) ? optionsOrPath : void 0);
|
|
374
|
+
return traverseImpl(graph, options, pathArg);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
var getPathImpl = (graph, params) => {
|
|
378
|
+
return Function.pipe(getNode(graph, params.source ?? "root"), Option.flatMap((node) => {
|
|
379
|
+
let found = Option.none();
|
|
380
|
+
traverseImpl(graph, {
|
|
381
|
+
source: node.id,
|
|
382
|
+
visitor: (node2, path) => {
|
|
383
|
+
if (Option.isSome(found)) {
|
|
384
|
+
return false;
|
|
242
385
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
386
|
+
if (node2.id === params.target) {
|
|
387
|
+
found = Option.some(path);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
return found;
|
|
392
|
+
}));
|
|
393
|
+
};
|
|
394
|
+
function getPath(graphOrParams, params) {
|
|
395
|
+
if (params === void 0 && typeof graphOrParams === "object" && "target" in graphOrParams) {
|
|
396
|
+
const params2 = graphOrParams;
|
|
397
|
+
return (graph) => getPathImpl(graph, params2);
|
|
398
|
+
} else {
|
|
399
|
+
const graph = graphOrParams;
|
|
400
|
+
return getPathImpl(graph, params);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
var waitForPathImpl = (graph, params, options) => {
|
|
404
|
+
const { timeout = 5e3, interval = 500 } = options ?? {};
|
|
405
|
+
const path = getPathImpl(graph, params);
|
|
406
|
+
if (Option.isSome(path)) {
|
|
407
|
+
return Promise.resolve(path.value);
|
|
408
|
+
}
|
|
409
|
+
const trigger = new Trigger();
|
|
410
|
+
const i = setInterval(() => {
|
|
411
|
+
const path2 = getPathImpl(graph, params);
|
|
412
|
+
if (Option.isSome(path2)) {
|
|
413
|
+
trigger.wake(path2.value);
|
|
414
|
+
}
|
|
415
|
+
}, interval);
|
|
416
|
+
return trigger.wait({
|
|
417
|
+
timeout
|
|
418
|
+
}).finally(() => clearInterval(i));
|
|
419
|
+
};
|
|
420
|
+
function waitForPath(graphOrParams, paramsOrOptions, options) {
|
|
421
|
+
if (typeof graphOrParams === "object" && "target" in graphOrParams) {
|
|
422
|
+
const params = graphOrParams;
|
|
423
|
+
const opts = typeof paramsOrOptions === "object" && !("target" in paramsOrOptions) ? paramsOrOptions : void 0;
|
|
424
|
+
return (graph) => waitForPathImpl(graph, params, opts);
|
|
425
|
+
} else {
|
|
426
|
+
const graph = graphOrParams;
|
|
427
|
+
const params = paramsOrOptions;
|
|
428
|
+
return waitForPathImpl(graph, params, options);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
var initializeImpl = async (graph, id) => {
|
|
432
|
+
const internal = getInternal(graph);
|
|
433
|
+
const initialized = Record.get(internal._initialized, id).pipe(Option.getOrElse(() => false));
|
|
434
|
+
log("initialize", {
|
|
435
|
+
id,
|
|
436
|
+
initialized
|
|
437
|
+
}, {
|
|
438
|
+
F: __dxlog_file,
|
|
439
|
+
L: 661,
|
|
440
|
+
S: void 0,
|
|
441
|
+
C: (f, a) => f(...a)
|
|
442
|
+
});
|
|
443
|
+
if (!initialized) {
|
|
444
|
+
await internal._onInitialize?.(id);
|
|
445
|
+
Record.set(internal._initialized, id, true);
|
|
446
|
+
}
|
|
447
|
+
return graph;
|
|
448
|
+
};
|
|
449
|
+
function initialize(graphOrId, id) {
|
|
450
|
+
if (typeof graphOrId === "string") {
|
|
451
|
+
const id2 = graphOrId;
|
|
452
|
+
return (graph) => initializeImpl(graph, id2);
|
|
453
|
+
} else {
|
|
454
|
+
const graph = graphOrId;
|
|
455
|
+
return initializeImpl(graph, id);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
var expandImpl = (graph, id, relation = "outbound") => {
|
|
459
|
+
const internal = getInternal(graph);
|
|
460
|
+
const key = `${id}$${relation}`;
|
|
461
|
+
const expanded = Record.get(internal._expanded, key).pipe(Option.getOrElse(() => false));
|
|
462
|
+
log("expand", {
|
|
463
|
+
key,
|
|
464
|
+
expanded
|
|
465
|
+
}, {
|
|
466
|
+
F: __dxlog_file,
|
|
467
|
+
L: 702,
|
|
468
|
+
S: void 0,
|
|
469
|
+
C: (f, a) => f(...a)
|
|
470
|
+
});
|
|
471
|
+
if (!expanded) {
|
|
472
|
+
internal._onExpand?.(id, relation);
|
|
473
|
+
Record.set(internal._expanded, key, true);
|
|
474
|
+
}
|
|
475
|
+
return graph;
|
|
476
|
+
};
|
|
477
|
+
function expand(graphOrId, idOrRelation, relation) {
|
|
478
|
+
if (typeof graphOrId === "string") {
|
|
479
|
+
const id = graphOrId;
|
|
480
|
+
const rel = (typeof idOrRelation === "string" ? "outbound" : idOrRelation) ?? "outbound";
|
|
481
|
+
return (graph) => expandImpl(graph, id, rel);
|
|
482
|
+
} else {
|
|
483
|
+
const graph = graphOrId;
|
|
484
|
+
const id = idOrRelation;
|
|
485
|
+
const rel = relation ?? "outbound";
|
|
486
|
+
return expandImpl(graph, id, rel);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
var sortEdgesImpl = (graph, id, relation, order) => {
|
|
490
|
+
const internal = getInternal(graph);
|
|
491
|
+
const edgesAtom = internal._edges(id);
|
|
492
|
+
const edges = internal._registry.get(edgesAtom);
|
|
493
|
+
const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
|
|
494
|
+
const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
|
|
495
|
+
edges[relation].splice(0, edges[relation].length, ...[
|
|
496
|
+
...sorted,
|
|
497
|
+
...unsorted
|
|
498
|
+
]);
|
|
499
|
+
internal._registry.set(edgesAtom, edges);
|
|
500
|
+
return graph;
|
|
501
|
+
};
|
|
502
|
+
function sortEdges(graphOrId, idOrRelation, relationOrOrder, order) {
|
|
503
|
+
if (typeof graphOrId === "string") {
|
|
504
|
+
const id = graphOrId;
|
|
505
|
+
const relation = idOrRelation;
|
|
506
|
+
const order2 = relationOrOrder;
|
|
507
|
+
return (graph) => sortEdgesImpl(graph, id, relation, order2);
|
|
508
|
+
} else {
|
|
509
|
+
const graph = graphOrId;
|
|
510
|
+
const id = idOrRelation;
|
|
511
|
+
const relation = relationOrOrder;
|
|
512
|
+
return sortEdgesImpl(graph, id, relation, order);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
var addNodesImpl = (graph, nodes) => {
|
|
516
|
+
Atom2.batch(() => {
|
|
517
|
+
nodes.map((node) => addNodeImpl(graph, node));
|
|
518
|
+
});
|
|
519
|
+
return graph;
|
|
520
|
+
};
|
|
521
|
+
function addNodes(graphOrNodes, nodes) {
|
|
522
|
+
if (nodes === void 0) {
|
|
523
|
+
const nodes2 = graphOrNodes;
|
|
524
|
+
return (graph) => addNodesImpl(graph, nodes2);
|
|
525
|
+
} else {
|
|
526
|
+
const graph = graphOrNodes;
|
|
527
|
+
return addNodesImpl(graph, nodes);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
var addNodeImpl = (graph, nodeArg) => {
|
|
531
|
+
const internal = getInternal(graph);
|
|
532
|
+
const { nodes, edges, id, type, data = null, properties = {}, ...rest } = nodeArg;
|
|
533
|
+
const nodeAtom = internal._node(id);
|
|
534
|
+
const existingNode = internal._registry.get(nodeAtom);
|
|
535
|
+
Option.match(existingNode, {
|
|
536
|
+
onSome: (existing) => {
|
|
537
|
+
const typeChanged = existing.type !== type;
|
|
538
|
+
const dataChanged = existing.data !== data;
|
|
539
|
+
const propertiesChanged = Object.keys(properties).some((key) => existing.properties[key] !== properties[key]);
|
|
540
|
+
log("existing node", {
|
|
541
|
+
id,
|
|
542
|
+
typeChanged,
|
|
543
|
+
dataChanged,
|
|
544
|
+
propertiesChanged
|
|
545
|
+
}, {
|
|
546
|
+
F: __dxlog_file,
|
|
547
|
+
L: 847,
|
|
548
|
+
S: void 0,
|
|
549
|
+
C: (f, a) => f(...a)
|
|
550
|
+
});
|
|
551
|
+
if (typeChanged || dataChanged || propertiesChanged) {
|
|
552
|
+
log("updating node", {
|
|
246
553
|
id,
|
|
247
554
|
type,
|
|
248
555
|
data,
|
|
249
556
|
properties
|
|
250
557
|
}, {
|
|
251
558
|
F: __dxlog_file,
|
|
252
|
-
L:
|
|
253
|
-
S:
|
|
559
|
+
L: 854,
|
|
560
|
+
S: void 0,
|
|
254
561
|
C: (f, a) => f(...a)
|
|
255
562
|
});
|
|
256
|
-
const newNode =
|
|
257
|
-
|
|
563
|
+
const newNode = Option.some({
|
|
564
|
+
...existing,
|
|
565
|
+
...rest,
|
|
258
566
|
type,
|
|
259
567
|
data,
|
|
260
|
-
properties
|
|
568
|
+
properties: {
|
|
569
|
+
...existing.properties,
|
|
570
|
+
...properties
|
|
571
|
+
}
|
|
261
572
|
});
|
|
262
|
-
|
|
263
|
-
|
|
573
|
+
internal._registry.set(nodeAtom, newNode);
|
|
574
|
+
graph.onNodeChanged.emit({
|
|
264
575
|
id,
|
|
265
576
|
node: newNode
|
|
266
577
|
});
|
|
267
578
|
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
this.addEdges(_edges);
|
|
276
|
-
}
|
|
277
|
-
if (edges) {
|
|
278
|
-
todo();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
removeNodes(ids, edges = false) {
|
|
282
|
-
Rx.batch(() => {
|
|
283
|
-
ids.map((id) => this.removeNode(id, edges));
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
removeNode(id, edges = false) {
|
|
287
|
-
const nodeRx = this._node(id);
|
|
288
|
-
this._registry.set(nodeRx, Option.none());
|
|
289
|
-
this.onNodeChanged.emit({
|
|
290
|
-
id,
|
|
291
|
-
node: Option.none()
|
|
292
|
-
});
|
|
293
|
-
if (edges) {
|
|
294
|
-
const { inbound, outbound } = this._registry.get(this._edges(id));
|
|
295
|
-
const edges2 = [
|
|
296
|
-
...inbound.map((source) => ({
|
|
297
|
-
source,
|
|
298
|
-
target: id
|
|
299
|
-
})),
|
|
300
|
-
...outbound.map((target) => ({
|
|
301
|
-
source: id,
|
|
302
|
-
target
|
|
303
|
-
}))
|
|
304
|
-
];
|
|
305
|
-
this.removeEdges(edges2);
|
|
306
|
-
}
|
|
307
|
-
this._onRemoveNode?.(id);
|
|
308
|
-
}
|
|
309
|
-
addEdges(edges) {
|
|
310
|
-
Rx.batch(() => {
|
|
311
|
-
edges.map((edge) => this.addEdge(edge));
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
addEdge(edgeArg) {
|
|
315
|
-
const sourceRx = this._edges(edgeArg.source);
|
|
316
|
-
const source = this._registry.get(sourceRx);
|
|
317
|
-
if (!source.outbound.includes(edgeArg.target)) {
|
|
318
|
-
log("add outbound edge", {
|
|
319
|
-
source: edgeArg.source,
|
|
320
|
-
target: edgeArg.target
|
|
579
|
+
},
|
|
580
|
+
onNone: () => {
|
|
581
|
+
log("new node", {
|
|
582
|
+
id,
|
|
583
|
+
type,
|
|
584
|
+
data,
|
|
585
|
+
properties
|
|
321
586
|
}, {
|
|
322
587
|
F: __dxlog_file,
|
|
323
|
-
L:
|
|
324
|
-
S:
|
|
588
|
+
L: 867,
|
|
589
|
+
S: void 0,
|
|
325
590
|
C: (f, a) => f(...a)
|
|
326
591
|
});
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
const targetRx = this._edges(edgeArg.target);
|
|
336
|
-
const target = this._registry.get(targetRx);
|
|
337
|
-
if (!target.inbound.includes(edgeArg.source)) {
|
|
338
|
-
log("add inbound edge", {
|
|
339
|
-
source: edgeArg.source,
|
|
340
|
-
target: edgeArg.target
|
|
341
|
-
}, {
|
|
342
|
-
F: __dxlog_file,
|
|
343
|
-
L: 488,
|
|
344
|
-
S: this,
|
|
345
|
-
C: (f, a) => f(...a)
|
|
592
|
+
const newNode = internal._constructNode({
|
|
593
|
+
id,
|
|
594
|
+
type,
|
|
595
|
+
data,
|
|
596
|
+
properties,
|
|
597
|
+
...rest
|
|
346
598
|
});
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
],
|
|
352
|
-
outbound: target.outbound
|
|
599
|
+
internal._registry.set(nodeAtom, newNode);
|
|
600
|
+
graph.onNodeChanged.emit({
|
|
601
|
+
id,
|
|
602
|
+
node: newNode
|
|
353
603
|
});
|
|
354
604
|
}
|
|
605
|
+
});
|
|
606
|
+
if (nodes) {
|
|
607
|
+
addNodesImpl(graph, nodes);
|
|
608
|
+
const _edges = nodes.map((node) => ({
|
|
609
|
+
source: id,
|
|
610
|
+
target: node.id
|
|
611
|
+
}));
|
|
612
|
+
addEdgesImpl(graph, _edges);
|
|
613
|
+
}
|
|
614
|
+
if (edges) {
|
|
615
|
+
todo();
|
|
616
|
+
}
|
|
617
|
+
return graph;
|
|
618
|
+
};
|
|
619
|
+
function addNode(graphOrNodeArg, nodeArg) {
|
|
620
|
+
if (nodeArg === void 0) {
|
|
621
|
+
const nodeArg2 = graphOrNodeArg;
|
|
622
|
+
return (graph) => addNodeImpl(graph, nodeArg2);
|
|
623
|
+
} else {
|
|
624
|
+
const graph = graphOrNodeArg;
|
|
625
|
+
return addNodeImpl(graph, nodeArg);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
var removeNodesImpl = (graph, ids, edges = false) => {
|
|
629
|
+
Atom2.batch(() => {
|
|
630
|
+
ids.map((id) => removeNodeImpl(graph, id, edges));
|
|
631
|
+
});
|
|
632
|
+
return graph;
|
|
633
|
+
};
|
|
634
|
+
function removeNodes(graphOrIds, idsOrEdges, edges) {
|
|
635
|
+
if (Array.isArray(graphOrIds)) {
|
|
636
|
+
const ids = graphOrIds;
|
|
637
|
+
const edgesArg = typeof idsOrEdges === "boolean" ? idsOrEdges : false;
|
|
638
|
+
return (graph) => removeNodesImpl(graph, ids, edgesArg);
|
|
639
|
+
} else {
|
|
640
|
+
const graph = graphOrIds;
|
|
641
|
+
const ids = idsOrEdges;
|
|
642
|
+
const edgesArg = edges ?? false;
|
|
643
|
+
return removeNodesImpl(graph, ids, edgesArg);
|
|
355
644
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
645
|
+
}
|
|
646
|
+
var removeNodeImpl = (graph, id, edges = false) => {
|
|
647
|
+
const internal = getInternal(graph);
|
|
648
|
+
const nodeAtom = internal._node(id);
|
|
649
|
+
internal._registry.set(nodeAtom, Option.none());
|
|
650
|
+
graph.onNodeChanged.emit({
|
|
651
|
+
id,
|
|
652
|
+
node: Option.none()
|
|
653
|
+
});
|
|
654
|
+
if (edges) {
|
|
655
|
+
const { inbound, outbound } = internal._registry.get(internal._edges(id));
|
|
656
|
+
const edgesToRemove = [
|
|
657
|
+
...inbound.map((source) => ({
|
|
658
|
+
source,
|
|
659
|
+
target: id
|
|
660
|
+
})),
|
|
661
|
+
...outbound.map((target) => ({
|
|
662
|
+
source: id,
|
|
663
|
+
target
|
|
664
|
+
}))
|
|
665
|
+
];
|
|
666
|
+
removeEdgesImpl(graph, edgesToRemove);
|
|
667
|
+
}
|
|
668
|
+
internal._onRemoveNode?.(id);
|
|
669
|
+
return graph;
|
|
670
|
+
};
|
|
671
|
+
function removeNode(graphOrId, idOrEdges, edges) {
|
|
672
|
+
if (typeof graphOrId === "string") {
|
|
673
|
+
const id = graphOrId;
|
|
674
|
+
const edgesArg = typeof idOrEdges === "boolean" ? idOrEdges : false;
|
|
675
|
+
return (graph) => removeNodeImpl(graph, id, edgesArg);
|
|
676
|
+
} else {
|
|
677
|
+
const graph = graphOrId;
|
|
678
|
+
const id = idOrEdges;
|
|
679
|
+
const edgesArg = edges ?? false;
|
|
680
|
+
return removeNodeImpl(graph, id, edgesArg);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
var addEdgesImpl = (graph, edges) => {
|
|
684
|
+
Atom2.batch(() => {
|
|
685
|
+
edges.map((edge) => addEdgeImpl(graph, edge));
|
|
686
|
+
});
|
|
687
|
+
return graph;
|
|
688
|
+
};
|
|
689
|
+
function addEdges(graphOrEdges, edges) {
|
|
690
|
+
if (edges === void 0) {
|
|
691
|
+
const edges2 = graphOrEdges;
|
|
692
|
+
return (graph) => addEdgesImpl(graph, edges2);
|
|
693
|
+
} else {
|
|
694
|
+
const graph = graphOrEdges;
|
|
695
|
+
return addEdgesImpl(graph, edges);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
var addEdgeImpl = (graph, edgeArg) => {
|
|
699
|
+
const internal = getInternal(graph);
|
|
700
|
+
const sourceAtom = internal._edges(edgeArg.source);
|
|
701
|
+
const source = internal._registry.get(sourceAtom);
|
|
702
|
+
if (!source.outbound.includes(edgeArg.target)) {
|
|
703
|
+
log("add outbound edge", {
|
|
704
|
+
source: edgeArg.source,
|
|
705
|
+
target: edgeArg.target
|
|
706
|
+
}, {
|
|
707
|
+
F: __dxlog_file,
|
|
708
|
+
L: 1026,
|
|
709
|
+
S: void 0,
|
|
710
|
+
C: (f, a) => f(...a)
|
|
711
|
+
});
|
|
712
|
+
internal._registry.set(sourceAtom, {
|
|
713
|
+
inbound: source.inbound,
|
|
714
|
+
outbound: [
|
|
715
|
+
...source.outbound,
|
|
716
|
+
edgeArg.target
|
|
717
|
+
]
|
|
359
718
|
});
|
|
360
719
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const target2 = this._registry.get(targetRx);
|
|
381
|
-
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
|
|
382
|
-
this.removeNodes([
|
|
383
|
-
edgeArg.source
|
|
384
|
-
]);
|
|
385
|
-
}
|
|
386
|
-
if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== ROOT_ID) {
|
|
387
|
-
this.removeNodes([
|
|
388
|
-
edgeArg.target
|
|
389
|
-
]);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
720
|
+
const targetAtom = internal._edges(edgeArg.target);
|
|
721
|
+
const target = internal._registry.get(targetAtom);
|
|
722
|
+
if (!target.inbound.includes(edgeArg.source)) {
|
|
723
|
+
log("add inbound edge", {
|
|
724
|
+
source: edgeArg.source,
|
|
725
|
+
target: edgeArg.target
|
|
726
|
+
}, {
|
|
727
|
+
F: __dxlog_file,
|
|
728
|
+
L: 1039,
|
|
729
|
+
S: void 0,
|
|
730
|
+
C: (f, a) => f(...a)
|
|
731
|
+
});
|
|
732
|
+
internal._registry.set(targetAtom, {
|
|
733
|
+
inbound: [
|
|
734
|
+
...target.inbound,
|
|
735
|
+
edgeArg.source
|
|
736
|
+
],
|
|
737
|
+
outbound: target.outbound
|
|
738
|
+
});
|
|
392
739
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
this._registry.set(edgesRx, edges);
|
|
740
|
+
return graph;
|
|
741
|
+
};
|
|
742
|
+
function addEdge(graphOrEdgeArg, edgeArg) {
|
|
743
|
+
if (edgeArg === void 0) {
|
|
744
|
+
const edgeArg2 = graphOrEdgeArg;
|
|
745
|
+
return (graph) => addEdgeImpl(graph, edgeArg2);
|
|
746
|
+
} else {
|
|
747
|
+
const graph = graphOrEdgeArg;
|
|
748
|
+
return addEdgeImpl(graph, edgeArg);
|
|
403
749
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
...path,
|
|
422
|
-
source
|
|
423
|
-
]));
|
|
424
|
-
}
|
|
425
|
-
getPath({ source = "root", target }) {
|
|
426
|
-
return pipe(this.getNode(source), Option.flatMap((node) => {
|
|
427
|
-
let found = Option.none();
|
|
428
|
-
this.traverse({
|
|
429
|
-
source: node.id,
|
|
430
|
-
visitor: (node2, path) => {
|
|
431
|
-
if (Option.isSome(found)) {
|
|
432
|
-
return false;
|
|
433
|
-
}
|
|
434
|
-
if (node2.id === target) {
|
|
435
|
-
found = Option.some(path);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
});
|
|
439
|
-
return found;
|
|
440
|
-
}));
|
|
750
|
+
}
|
|
751
|
+
var removeEdgesImpl = (graph, edges, removeOrphans = false) => {
|
|
752
|
+
Atom2.batch(() => {
|
|
753
|
+
edges.map((edge) => removeEdgeImpl(graph, edge, removeOrphans));
|
|
754
|
+
});
|
|
755
|
+
return graph;
|
|
756
|
+
};
|
|
757
|
+
function removeEdges(graphOrEdges, edgesOrRemoveOrphans, removeOrphans) {
|
|
758
|
+
if (Array.isArray(graphOrEdges)) {
|
|
759
|
+
const edges = graphOrEdges;
|
|
760
|
+
const removeOrphansArg = typeof edgesOrRemoveOrphans === "boolean" ? edgesOrRemoveOrphans : false;
|
|
761
|
+
return (graph) => removeEdgesImpl(graph, edges, removeOrphansArg);
|
|
762
|
+
} else {
|
|
763
|
+
const graph = graphOrEdges;
|
|
764
|
+
const edges = edgesOrRemoveOrphans;
|
|
765
|
+
const removeOrphansArg = removeOrphans ?? false;
|
|
766
|
+
return removeEdgesImpl(graph, edges, removeOrphansArg);
|
|
441
767
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
453
|
-
}, interval);
|
|
454
|
-
return trigger.wait({
|
|
455
|
-
timeout
|
|
456
|
-
}).finally(() => clearInterval(i));
|
|
768
|
+
}
|
|
769
|
+
var removeEdgeImpl = (graph, edgeArg, removeOrphans = false) => {
|
|
770
|
+
const internal = getInternal(graph);
|
|
771
|
+
const sourceAtom = internal._edges(edgeArg.source);
|
|
772
|
+
const source = internal._registry.get(sourceAtom);
|
|
773
|
+
if (source.outbound.includes(edgeArg.target)) {
|
|
774
|
+
internal._registry.set(sourceAtom, {
|
|
775
|
+
inbound: source.inbound,
|
|
776
|
+
outbound: source.outbound.filter((id) => id !== edgeArg.target)
|
|
777
|
+
});
|
|
457
778
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
...node
|
|
779
|
+
const targetAtom = internal._edges(edgeArg.target);
|
|
780
|
+
const target = internal._registry.get(targetAtom);
|
|
781
|
+
if (target.inbound.includes(edgeArg.source)) {
|
|
782
|
+
internal._registry.set(targetAtom, {
|
|
783
|
+
inbound: target.inbound.filter((id) => id !== edgeArg.source),
|
|
784
|
+
outbound: target.outbound
|
|
465
785
|
});
|
|
466
786
|
}
|
|
787
|
+
if (removeOrphans) {
|
|
788
|
+
const source2 = internal._registry.get(sourceAtom);
|
|
789
|
+
const target2 = internal._registry.get(targetAtom);
|
|
790
|
+
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== RootId) {
|
|
791
|
+
removeNodesImpl(graph, [
|
|
792
|
+
edgeArg.source
|
|
793
|
+
]);
|
|
794
|
+
}
|
|
795
|
+
if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== RootId) {
|
|
796
|
+
removeNodesImpl(graph, [
|
|
797
|
+
edgeArg.target
|
|
798
|
+
]);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return graph;
|
|
802
|
+
};
|
|
803
|
+
function removeEdge(graphOrEdgeArg, edgeArgOrRemoveOrphans, removeOrphans) {
|
|
804
|
+
if (edgeArgOrRemoveOrphans === void 0 || typeof edgeArgOrRemoveOrphans === "boolean" || "source" in graphOrEdgeArg) {
|
|
805
|
+
const edgeArg = graphOrEdgeArg;
|
|
806
|
+
const removeOrphansArg = typeof edgeArgOrRemoveOrphans === "boolean" ? edgeArgOrRemoveOrphans : false;
|
|
807
|
+
return (graph) => removeEdgeImpl(graph, edgeArg, removeOrphansArg);
|
|
808
|
+
} else {
|
|
809
|
+
const graph = graphOrEdgeArg;
|
|
810
|
+
const edgeArg = edgeArgOrRemoveOrphans;
|
|
811
|
+
const removeOrphansArg = removeOrphans ?? false;
|
|
812
|
+
return removeEdgeImpl(graph, edgeArg, removeOrphansArg);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
var make = (params) => {
|
|
816
|
+
return new GraphImpl(params);
|
|
467
817
|
};
|
|
468
818
|
|
|
469
819
|
// src/graph-builder.ts
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
820
|
+
var graph_builder_exports = {};
|
|
821
|
+
__export(graph_builder_exports, {
|
|
822
|
+
GraphBuilderTypeId: () => GraphBuilderTypeId,
|
|
823
|
+
addExtension: () => addExtension,
|
|
824
|
+
createConnector: () => createConnector,
|
|
825
|
+
createExtension: () => createExtension,
|
|
826
|
+
createExtensionRaw: () => createExtensionRaw,
|
|
827
|
+
createTypeExtension: () => createTypeExtension,
|
|
828
|
+
destroy: () => destroy,
|
|
829
|
+
explore: () => explore,
|
|
830
|
+
flattenExtensions: () => flattenExtensions,
|
|
831
|
+
from: () => from,
|
|
832
|
+
make: () => make2,
|
|
833
|
+
removeExtension: () => removeExtension
|
|
834
|
+
});
|
|
835
|
+
import { Atom as Atom3, Registry as Registry2 } from "@effect-atom/atom-react";
|
|
836
|
+
import * as Array2 from "effect/Array";
|
|
837
|
+
import * as Effect from "effect/Effect";
|
|
838
|
+
import * as Function2 from "effect/Function";
|
|
839
|
+
import * as Option3 from "effect/Option";
|
|
840
|
+
import * as Pipeable2 from "effect/Pipeable";
|
|
841
|
+
import * as Record2 from "effect/Record";
|
|
473
842
|
import { log as log2 } from "@dxos/log";
|
|
474
843
|
import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
475
844
|
|
|
476
|
-
// src/node.ts
|
|
477
|
-
var
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
845
|
+
// src/node-matcher.ts
|
|
846
|
+
var node_matcher_exports = {};
|
|
847
|
+
__export(node_matcher_exports, {
|
|
848
|
+
whenAll: () => whenAll,
|
|
849
|
+
whenAny: () => whenAny,
|
|
850
|
+
whenEchoObject: () => whenEchoObject,
|
|
851
|
+
whenEchoObjectMatches: () => whenEchoObjectMatches,
|
|
852
|
+
whenEchoType: () => whenEchoType,
|
|
853
|
+
whenEchoTypeMatches: () => whenEchoTypeMatches,
|
|
854
|
+
whenId: () => whenId,
|
|
855
|
+
whenNodeType: () => whenNodeType,
|
|
856
|
+
whenNot: () => whenNot,
|
|
857
|
+
whenRoot: () => whenRoot
|
|
858
|
+
});
|
|
859
|
+
import * as Option2 from "effect/Option";
|
|
860
|
+
import { Obj } from "@dxos/echo";
|
|
861
|
+
var whenRoot = (node) => node.id === RootId ? Option2.some(node) : Option2.none();
|
|
862
|
+
var whenId = (id) => (node) => node.id === id ? Option2.some(node) : Option2.none();
|
|
863
|
+
var whenNodeType = (type) => (node) => node.type === type ? Option2.some(node) : Option2.none();
|
|
864
|
+
var whenEchoType = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node.data) : Option2.none();
|
|
865
|
+
var whenEchoObject = (node) => Obj.isObject(node.data) ? Option2.some(node.data) : Option2.none();
|
|
866
|
+
var whenAll = (...matchers) => (node) => {
|
|
867
|
+
for (const matcher of matchers) {
|
|
868
|
+
const result = matcher(node);
|
|
869
|
+
if (Option2.isNone(result)) {
|
|
870
|
+
return Option2.none();
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return Option2.some(node);
|
|
874
|
+
};
|
|
875
|
+
var whenAny = (...matchers) => (node) => {
|
|
876
|
+
for (const matcher of matchers) {
|
|
877
|
+
const result = matcher(node);
|
|
878
|
+
if (Option2.isSome(result)) {
|
|
879
|
+
return Option2.some(node);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return Option2.none();
|
|
883
|
+
};
|
|
884
|
+
var whenEchoTypeMatches = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node) : Option2.none();
|
|
885
|
+
var whenEchoObjectMatches = (node) => Obj.isObject(node.data) ? Option2.some(node) : Option2.none();
|
|
886
|
+
var whenNot = (matcher) => (node) => Option2.isNone(matcher(node)) ? Option2.some(node) : Option2.none();
|
|
482
887
|
|
|
483
888
|
// src/graph-builder.ts
|
|
484
889
|
var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
485
|
-
var
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const actions = _actions && Rx2.family((node) => _actions(node).pipe(Rx2.withLabel(`graph-builder:_actions:${id}`)));
|
|
491
|
-
return [
|
|
492
|
-
// resolver ? { id: getId('resolver'), position, resolver } : undefined,
|
|
493
|
-
connector ? {
|
|
494
|
-
id: getId("connector"),
|
|
495
|
-
position,
|
|
496
|
-
relation,
|
|
497
|
-
connector: Rx2.family((node) => Rx2.make((get) => {
|
|
498
|
-
try {
|
|
499
|
-
return get(connector(node));
|
|
500
|
-
} catch {
|
|
501
|
-
log2.warn("Error in connector", {
|
|
502
|
-
id: getId("connector"),
|
|
503
|
-
node
|
|
504
|
-
}, {
|
|
505
|
-
F: __dxlog_file2,
|
|
506
|
-
L: 101,
|
|
507
|
-
S: void 0,
|
|
508
|
-
C: (f, a) => f(...a)
|
|
509
|
-
});
|
|
510
|
-
return [];
|
|
511
|
-
}
|
|
512
|
-
}).pipe(Rx2.withLabel(`graph-builder:connector:${id}`)))
|
|
513
|
-
} : void 0,
|
|
514
|
-
actionGroups ? {
|
|
515
|
-
id: getId("actionGroups"),
|
|
516
|
-
position,
|
|
517
|
-
relation: "outbound",
|
|
518
|
-
connector: Rx2.family((node) => Rx2.make((get) => {
|
|
519
|
-
try {
|
|
520
|
-
return get(actionGroups(node)).map((arg) => ({
|
|
521
|
-
...arg,
|
|
522
|
-
data: actionGroupSymbol,
|
|
523
|
-
type: ACTION_GROUP_TYPE
|
|
524
|
-
}));
|
|
525
|
-
} catch {
|
|
526
|
-
log2.warn("Error in actionGroups", {
|
|
527
|
-
id: getId("actionGroups"),
|
|
528
|
-
node
|
|
529
|
-
}, {
|
|
530
|
-
F: __dxlog_file2,
|
|
531
|
-
L: 122,
|
|
532
|
-
S: void 0,
|
|
533
|
-
C: (f, a) => f(...a)
|
|
534
|
-
});
|
|
535
|
-
return [];
|
|
536
|
-
}
|
|
537
|
-
}).pipe(Rx2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
538
|
-
} : void 0,
|
|
539
|
-
actions ? {
|
|
540
|
-
id: getId("actions"),
|
|
541
|
-
position,
|
|
542
|
-
relation: "outbound",
|
|
543
|
-
connector: Rx2.family((node) => Rx2.make((get) => {
|
|
544
|
-
try {
|
|
545
|
-
return get(actions(node)).map((arg) => ({
|
|
546
|
-
...arg,
|
|
547
|
-
type: ACTION_TYPE
|
|
548
|
-
}));
|
|
549
|
-
} catch {
|
|
550
|
-
log2.warn("Error in actions", {
|
|
551
|
-
id: getId("actions"),
|
|
552
|
-
node
|
|
553
|
-
}, {
|
|
554
|
-
F: __dxlog_file2,
|
|
555
|
-
L: 139,
|
|
556
|
-
S: void 0,
|
|
557
|
-
C: (f, a) => f(...a)
|
|
558
|
-
});
|
|
559
|
-
return [];
|
|
560
|
-
}
|
|
561
|
-
}).pipe(Rx2.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
562
|
-
} : void 0
|
|
563
|
-
].filter(isNonNullable2);
|
|
564
|
-
};
|
|
565
|
-
var flattenExtensions = (extension, acc = []) => {
|
|
566
|
-
if (Array.isArray(extension)) {
|
|
567
|
-
return [
|
|
568
|
-
...acc,
|
|
569
|
-
...extension.flatMap((ext) => flattenExtensions(ext, acc))
|
|
570
|
-
];
|
|
571
|
-
} else {
|
|
572
|
-
return [
|
|
573
|
-
...acc,
|
|
574
|
-
extension
|
|
575
|
-
];
|
|
890
|
+
var GraphBuilderTypeId = Symbol.for("@dxos/app-graph/GraphBuilder");
|
|
891
|
+
var GraphBuilderImpl = class {
|
|
892
|
+
[GraphBuilderTypeId] = GraphBuilderTypeId;
|
|
893
|
+
pipe() {
|
|
894
|
+
return Pipeable2.pipeArguments(this, arguments);
|
|
576
895
|
}
|
|
577
|
-
|
|
578
|
-
|
|
896
|
+
// TODO(wittjosiah): Use Context.
|
|
897
|
+
_subscriptions = /* @__PURE__ */ new Map();
|
|
898
|
+
_extensions = Atom3.make(Record2.empty()).pipe(Atom3.keepAlive, Atom3.withLabel("graph-builder:extensions"));
|
|
899
|
+
_initialized = {};
|
|
900
|
+
_registry;
|
|
901
|
+
_graph;
|
|
579
902
|
constructor({ registry, ...params } = {}) {
|
|
580
|
-
// TODO(wittjosiah): Use Context.
|
|
581
|
-
this._connectorSubscriptions = /* @__PURE__ */ new Map();
|
|
582
|
-
this._extensions = Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions"));
|
|
583
|
-
this._connectors = Rx2.family((key) => {
|
|
584
|
-
return Rx2.make((get) => {
|
|
585
|
-
const [id, relation] = key.split("+");
|
|
586
|
-
const node = this._graph.node(id);
|
|
587
|
-
return pipe2(
|
|
588
|
-
get(this._extensions),
|
|
589
|
-
Record2.values,
|
|
590
|
-
// TODO(wittjosiah): Sort on write rather than read.
|
|
591
|
-
Array.sortBy(byPosition),
|
|
592
|
-
Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
593
|
-
Array.map(({ connector }) => connector?.(node)),
|
|
594
|
-
Array.filter(isNonNullable2),
|
|
595
|
-
Array.flatMap((result) => get(result))
|
|
596
|
-
);
|
|
597
|
-
}).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
|
|
598
|
-
});
|
|
599
903
|
this._registry = registry ?? Registry2.make();
|
|
600
|
-
|
|
904
|
+
const graph = make({
|
|
601
905
|
...params,
|
|
602
906
|
registry: this._registry,
|
|
603
907
|
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
604
|
-
|
|
908
|
+
onInitialize: (id) => this._onInitialize(id),
|
|
605
909
|
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
606
910
|
});
|
|
607
|
-
|
|
608
|
-
static from(pickle, registry) {
|
|
609
|
-
if (!pickle) {
|
|
610
|
-
return new _GraphBuilder({
|
|
611
|
-
registry
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
const { nodes, edges } = JSON.parse(pickle);
|
|
615
|
-
return new _GraphBuilder({
|
|
616
|
-
nodes,
|
|
617
|
-
edges,
|
|
618
|
-
registry
|
|
619
|
-
});
|
|
911
|
+
this._graph = graph;
|
|
620
912
|
}
|
|
621
913
|
get graph() {
|
|
622
914
|
return this._graph;
|
|
@@ -624,56 +916,27 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
624
916
|
get extensions() {
|
|
625
917
|
return this._extensions;
|
|
626
918
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
this._registry.set(this._extensions, Record2.set(extensions2, extension.id, extension));
|
|
919
|
+
_resolvers = Atom3.family((id) => {
|
|
920
|
+
return Atom3.make((get2) => {
|
|
921
|
+
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);
|
|
631
922
|
});
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
...path,
|
|
650
|
-
node.id
|
|
651
|
-
]);
|
|
652
|
-
if (shouldContinue === false) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
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))));
|
|
656
|
-
await Promise.all(nodes.map((nodeArg) => {
|
|
657
|
-
registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
|
|
658
|
-
return this.explore({
|
|
659
|
-
registry,
|
|
660
|
-
source: nodeArg.id,
|
|
661
|
-
relation,
|
|
662
|
-
visitor
|
|
663
|
-
}, [
|
|
664
|
-
...path,
|
|
665
|
-
node.id
|
|
666
|
-
]);
|
|
667
|
-
}));
|
|
668
|
-
if (registry !== this._registry) {
|
|
669
|
-
registry.reset();
|
|
670
|
-
registry.dispose();
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
destroy() {
|
|
674
|
-
this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
675
|
-
this._connectorSubscriptions.clear();
|
|
676
|
-
}
|
|
923
|
+
});
|
|
924
|
+
_connectors = Atom3.family((key) => {
|
|
925
|
+
return Atom3.make((get2) => {
|
|
926
|
+
const [id, relation] = key.split("+");
|
|
927
|
+
const node = this._graph.node(id);
|
|
928
|
+
return Function2.pipe(
|
|
929
|
+
get2(this._extensions),
|
|
930
|
+
Record2.values,
|
|
931
|
+
// TODO(wittjosiah): Sort on write rather than read.
|
|
932
|
+
Array2.sortBy(byPosition),
|
|
933
|
+
Array2.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
934
|
+
Array2.map(({ connector }) => connector?.(node)),
|
|
935
|
+
Array2.filter(isNonNullable2),
|
|
936
|
+
Array2.flatMap((result) => get2(result))
|
|
937
|
+
);
|
|
938
|
+
}).pipe(Atom3.withLabel(`graph-builder:connectors:${key}`));
|
|
939
|
+
});
|
|
677
940
|
_onExpand(id, relation) {
|
|
678
941
|
log2("onExpand", {
|
|
679
942
|
id,
|
|
@@ -681,7 +944,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
681
944
|
registry: getDebugName(this._registry)
|
|
682
945
|
}, {
|
|
683
946
|
F: __dxlog_file2,
|
|
684
|
-
L:
|
|
947
|
+
L: 176,
|
|
685
948
|
S: this,
|
|
686
949
|
C: (f, a) => f(...a)
|
|
687
950
|
});
|
|
@@ -698,25 +961,25 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
698
961
|
removed
|
|
699
962
|
}, {
|
|
700
963
|
F: __dxlog_file2,
|
|
701
|
-
L:
|
|
964
|
+
L: 187,
|
|
702
965
|
S: this,
|
|
703
966
|
C: (f, a) => f(...a)
|
|
704
967
|
});
|
|
705
968
|
const update = () => {
|
|
706
|
-
|
|
707
|
-
this._graph
|
|
969
|
+
Atom3.batch(() => {
|
|
970
|
+
removeEdges(this._graph, removed.map((target) => ({
|
|
708
971
|
source: id,
|
|
709
972
|
target
|
|
710
973
|
})), true);
|
|
711
|
-
this._graph
|
|
712
|
-
this._graph
|
|
974
|
+
addNodes(this._graph, nodes);
|
|
975
|
+
addEdges(this._graph, nodes.map((node) => relation === "outbound" ? {
|
|
713
976
|
source: id,
|
|
714
977
|
target: node.id
|
|
715
978
|
} : {
|
|
716
979
|
source: node.id,
|
|
717
980
|
target: id
|
|
718
981
|
}));
|
|
719
|
-
this._graph
|
|
982
|
+
sortEdges(this._graph, id, relation, nodes.map(({ id: id2 }) => id2));
|
|
720
983
|
});
|
|
721
984
|
};
|
|
722
985
|
if (typeof requestAnimationFrame === "function") {
|
|
@@ -727,52 +990,308 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
727
990
|
}, {
|
|
728
991
|
immediate: true
|
|
729
992
|
});
|
|
730
|
-
this.
|
|
993
|
+
this._subscriptions.set(id, cancel);
|
|
994
|
+
}
|
|
995
|
+
// TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
|
|
996
|
+
async _onInitialize(id) {
|
|
997
|
+
log2("onInitialize", {
|
|
998
|
+
id
|
|
999
|
+
}, {
|
|
1000
|
+
F: __dxlog_file2,
|
|
1001
|
+
L: 227,
|
|
1002
|
+
S: this,
|
|
1003
|
+
C: (f, a) => f(...a)
|
|
1004
|
+
});
|
|
1005
|
+
const resolver = this._resolvers(id);
|
|
1006
|
+
const cancel = this._registry.subscribe(resolver, (node) => {
|
|
1007
|
+
const trigger = this._initialized[id];
|
|
1008
|
+
Option3.match(node, {
|
|
1009
|
+
onSome: (node2) => {
|
|
1010
|
+
addNodes(this._graph, [
|
|
1011
|
+
node2
|
|
1012
|
+
]);
|
|
1013
|
+
trigger?.wake();
|
|
1014
|
+
},
|
|
1015
|
+
onNone: () => {
|
|
1016
|
+
trigger?.wake();
|
|
1017
|
+
removeNodes(this._graph, [
|
|
1018
|
+
id
|
|
1019
|
+
]);
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
}, {
|
|
1023
|
+
immediate: true
|
|
1024
|
+
});
|
|
1025
|
+
this._subscriptions.set(id, cancel);
|
|
731
1026
|
}
|
|
732
|
-
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
733
|
-
// private async _onInitialize(id: string) {
|
|
734
|
-
// log('onInitialize', { id });
|
|
735
|
-
// }
|
|
736
1027
|
_onRemoveNode(id) {
|
|
737
|
-
this.
|
|
738
|
-
this.
|
|
1028
|
+
this._subscriptions.get(id)?.();
|
|
1029
|
+
this._subscriptions.delete(id);
|
|
739
1030
|
}
|
|
740
1031
|
};
|
|
741
|
-
var
|
|
742
|
-
return
|
|
743
|
-
|
|
744
|
-
|
|
1032
|
+
var make2 = (params) => {
|
|
1033
|
+
return new GraphBuilderImpl(params);
|
|
1034
|
+
};
|
|
1035
|
+
var from = (pickle, registry) => {
|
|
1036
|
+
if (!pickle) {
|
|
1037
|
+
return make2({
|
|
1038
|
+
registry
|
|
745
1039
|
});
|
|
746
|
-
|
|
747
|
-
|
|
1040
|
+
}
|
|
1041
|
+
const { nodes, edges } = JSON.parse(pickle);
|
|
1042
|
+
return make2({
|
|
1043
|
+
nodes,
|
|
1044
|
+
edges,
|
|
1045
|
+
registry
|
|
748
1046
|
});
|
|
749
1047
|
};
|
|
750
|
-
var
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1048
|
+
var addExtensionImpl = (builder, extensions) => {
|
|
1049
|
+
const internal = builder;
|
|
1050
|
+
flattenExtensions(extensions).forEach((extension) => {
|
|
1051
|
+
const extensions2 = internal._registry.get(internal._extensions);
|
|
1052
|
+
internal._registry.set(internal._extensions, Record2.set(extensions2, extension.id, extension));
|
|
1053
|
+
});
|
|
1054
|
+
return builder;
|
|
1055
|
+
};
|
|
1056
|
+
function addExtension(builderOrExtensions, extensions) {
|
|
1057
|
+
if (extensions === void 0) {
|
|
1058
|
+
const extensions2 = builderOrExtensions;
|
|
1059
|
+
return (builder) => addExtensionImpl(builder, extensions2);
|
|
1060
|
+
} else {
|
|
1061
|
+
const builder = builderOrExtensions;
|
|
1062
|
+
return addExtensionImpl(builder, extensions);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
var removeExtensionImpl = (builder, id) => {
|
|
1066
|
+
const internal = builder;
|
|
1067
|
+
const extensions = internal._registry.get(internal._extensions);
|
|
1068
|
+
internal._registry.set(internal._extensions, Record2.remove(extensions, id));
|
|
1069
|
+
return builder;
|
|
1070
|
+
};
|
|
1071
|
+
function removeExtension(builderOrId, id) {
|
|
1072
|
+
if (typeof builderOrId === "string") {
|
|
1073
|
+
const id2 = builderOrId;
|
|
1074
|
+
return (builder) => removeExtensionImpl(builder, id2);
|
|
1075
|
+
} else {
|
|
1076
|
+
const builder = builderOrId;
|
|
1077
|
+
return removeExtensionImpl(builder, id);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
var exploreImpl = async (builder, options, path = []) => {
|
|
1081
|
+
const internal = builder;
|
|
1082
|
+
const { registry = Registry2.make(), source = RootId, relation = "outbound", visitor } = options;
|
|
1083
|
+
if (path.includes(source)) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
if (!isNode()) {
|
|
1087
|
+
const { yieldOrContinue } = await import("main-thread-scheduling");
|
|
1088
|
+
await yieldOrContinue("idle");
|
|
1089
|
+
}
|
|
1090
|
+
const node = registry.get(internal._graph.nodeOrThrow(source));
|
|
1091
|
+
const shouldContinue = await visitor(node, [
|
|
1092
|
+
...path,
|
|
1093
|
+
node.id
|
|
1094
|
+
]);
|
|
1095
|
+
if (shouldContinue === false) {
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
const nodes = Object.values(internal._registry.get(internal._extensions)).filter((extension) => relation === (extension.relation ?? "outbound")).map((extension) => extension.connector).filter(isNonNullable2).flatMap((connector) => registry.get(connector(internal._graph.node(source))));
|
|
1099
|
+
await Promise.all(nodes.map((nodeArg) => {
|
|
1100
|
+
registry.set(internal._graph._node(nodeArg.id), internal._graph._constructNode(nodeArg));
|
|
1101
|
+
return exploreImpl(builder, {
|
|
1102
|
+
registry,
|
|
1103
|
+
source: nodeArg.id,
|
|
1104
|
+
relation,
|
|
1105
|
+
visitor
|
|
1106
|
+
}, [
|
|
1107
|
+
...path,
|
|
1108
|
+
node.id
|
|
1109
|
+
]);
|
|
1110
|
+
}));
|
|
1111
|
+
if (registry !== internal._registry) {
|
|
1112
|
+
registry.reset();
|
|
1113
|
+
registry.dispose();
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
function explore(builderOrOptions, optionsOrPath, path) {
|
|
1117
|
+
if (typeof builderOrOptions === "object" && "visitor" in builderOrOptions) {
|
|
1118
|
+
const options = builderOrOptions;
|
|
1119
|
+
const path2 = Array2.isArray(optionsOrPath) ? optionsOrPath : void 0;
|
|
1120
|
+
return (builder) => exploreImpl(builder, options, path2);
|
|
1121
|
+
} else {
|
|
1122
|
+
const builder = builderOrOptions;
|
|
1123
|
+
const options = optionsOrPath;
|
|
1124
|
+
const pathArg = path ?? (Array2.isArray(optionsOrPath) ? optionsOrPath : void 0);
|
|
1125
|
+
return exploreImpl(builder, options, pathArg);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
var destroyImpl = (builder) => {
|
|
1129
|
+
const internal = builder;
|
|
1130
|
+
internal._subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
1131
|
+
internal._subscriptions.clear();
|
|
1132
|
+
};
|
|
1133
|
+
function destroy(builder) {
|
|
1134
|
+
if (builder === void 0) {
|
|
1135
|
+
return (builder2) => destroyImpl(builder2);
|
|
1136
|
+
} else {
|
|
1137
|
+
return destroyImpl(builder);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
var createExtensionRaw = (extension) => {
|
|
1141
|
+
const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
1142
|
+
const getId = (key) => `${id}/${key}`;
|
|
1143
|
+
const resolver = _resolver && Atom3.family((id2) => _resolver(id2).pipe(Atom3.withLabel(`graph-builder:_resolver:${id2}`)));
|
|
1144
|
+
const connector = _connector && Atom3.family((node) => _connector(node).pipe(Atom3.withLabel(`graph-builder:_connector:${id}`)));
|
|
1145
|
+
const actionGroups = _actionGroups && Atom3.family((node) => _actionGroups(node).pipe(Atom3.withLabel(`graph-builder:_actionGroups:${id}`)));
|
|
1146
|
+
const actions = _actions && Atom3.family((node) => _actions(node).pipe(Atom3.withLabel(`graph-builder:_actions:${id}`)));
|
|
1147
|
+
return [
|
|
1148
|
+
resolver ? {
|
|
1149
|
+
id: getId("resolver"),
|
|
1150
|
+
position,
|
|
1151
|
+
resolver
|
|
1152
|
+
} : void 0,
|
|
1153
|
+
connector ? {
|
|
1154
|
+
id: getId("connector"),
|
|
1155
|
+
position,
|
|
1156
|
+
relation,
|
|
1157
|
+
connector: Atom3.family((node) => Atom3.make((get2) => {
|
|
1158
|
+
try {
|
|
1159
|
+
return get2(connector(node));
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
log2.warn("Error in connector", {
|
|
1162
|
+
id: getId("connector"),
|
|
1163
|
+
node,
|
|
1164
|
+
error
|
|
1165
|
+
}, {
|
|
1166
|
+
F: __dxlog_file2,
|
|
1167
|
+
L: 509,
|
|
1168
|
+
S: void 0,
|
|
1169
|
+
C: (f, a) => f(...a)
|
|
1170
|
+
});
|
|
1171
|
+
return [];
|
|
1172
|
+
}
|
|
1173
|
+
}).pipe(Atom3.withLabel(`graph-builder:connector:${id}`)))
|
|
1174
|
+
} : void 0,
|
|
1175
|
+
actionGroups ? {
|
|
1176
|
+
id: getId("actionGroups"),
|
|
1177
|
+
position,
|
|
1178
|
+
relation: "outbound",
|
|
1179
|
+
connector: Atom3.family((node) => Atom3.make((get2) => {
|
|
1180
|
+
try {
|
|
1181
|
+
return get2(actionGroups(node)).map((arg) => ({
|
|
1182
|
+
...arg,
|
|
1183
|
+
data: actionGroupSymbol,
|
|
1184
|
+
type: ActionGroupType
|
|
1185
|
+
}));
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
log2.warn("Error in actionGroups", {
|
|
1188
|
+
id: getId("actionGroups"),
|
|
1189
|
+
node,
|
|
1190
|
+
error
|
|
1191
|
+
}, {
|
|
1192
|
+
F: __dxlog_file2,
|
|
1193
|
+
L: 530,
|
|
1194
|
+
S: void 0,
|
|
1195
|
+
C: (f, a) => f(...a)
|
|
1196
|
+
});
|
|
1197
|
+
return [];
|
|
1198
|
+
}
|
|
1199
|
+
}).pipe(Atom3.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
1200
|
+
} : void 0,
|
|
1201
|
+
actions ? {
|
|
1202
|
+
id: getId("actions"),
|
|
1203
|
+
position,
|
|
1204
|
+
relation: "outbound",
|
|
1205
|
+
connector: Atom3.family((node) => Atom3.make((get2) => {
|
|
1206
|
+
try {
|
|
1207
|
+
return get2(actions(node)).map((arg) => ({
|
|
1208
|
+
...arg,
|
|
1209
|
+
type: ActionType
|
|
1210
|
+
}));
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
log2.warn("Error in actions", {
|
|
1213
|
+
id: getId("actions"),
|
|
1214
|
+
node,
|
|
1215
|
+
error
|
|
1216
|
+
}, {
|
|
1217
|
+
F: __dxlog_file2,
|
|
1218
|
+
L: 547,
|
|
1219
|
+
S: void 0,
|
|
1220
|
+
C: (f, a) => f(...a)
|
|
1221
|
+
});
|
|
1222
|
+
return [];
|
|
1223
|
+
}
|
|
1224
|
+
}).pipe(Atom3.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
1225
|
+
} : void 0
|
|
1226
|
+
].filter(isNonNullable2);
|
|
1227
|
+
};
|
|
1228
|
+
var runEffectSyncWithFallback = (effect, context2, extensionId, fallback) => {
|
|
1229
|
+
return Effect.runSync(effect.pipe(Effect.provide(context2), Effect.catchAll((error) => {
|
|
1230
|
+
log2.warn("Extension failed", {
|
|
1231
|
+
extension: extensionId,
|
|
1232
|
+
error
|
|
1233
|
+
}, {
|
|
1234
|
+
F: __dxlog_file2,
|
|
1235
|
+
L: 590,
|
|
1236
|
+
S: void 0,
|
|
1237
|
+
C: (f, a) => f(...a)
|
|
1238
|
+
});
|
|
1239
|
+
return Effect.succeed(fallback);
|
|
1240
|
+
})));
|
|
1241
|
+
};
|
|
1242
|
+
var createExtension = (options) => Effect.map(Effect.context(), (context2) => {
|
|
1243
|
+
const { id, match: match3, actions, connector, resolver, relation, position } = options;
|
|
1244
|
+
const connectorExtension = connector ? createConnectorWithRuntime(id, match3, connector, context2) : void 0;
|
|
1245
|
+
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) => ({
|
|
1246
|
+
...action,
|
|
1247
|
+
// Attach captured context for action execution.
|
|
1248
|
+
_actionContext: context2
|
|
1249
|
+
}))), Option3.getOrElse(() => []))) : void 0;
|
|
1250
|
+
const resolverExtension = resolver ? (nodeId) => Atom3.make((get2) => runEffectSyncWithFallback(resolver(nodeId, get2), context2, id, null) ?? null) : void 0;
|
|
1251
|
+
return createExtensionRaw({
|
|
1252
|
+
id,
|
|
1253
|
+
relation,
|
|
1254
|
+
position,
|
|
1255
|
+
connector: connectorExtension,
|
|
1256
|
+
actions: actionsExtension,
|
|
1257
|
+
resolver: resolverExtension
|
|
755
1258
|
});
|
|
756
1259
|
});
|
|
757
|
-
var
|
|
758
|
-
return
|
|
1260
|
+
var createConnector = (matcher, factory) => {
|
|
1261
|
+
return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => factory(data, get2)), Option3.getOrElse(() => [])));
|
|
1262
|
+
};
|
|
1263
|
+
var createConnectorWithRuntime = (extensionId, matcher, factory, context2) => {
|
|
1264
|
+
return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => runEffectSyncWithFallback(factory(data, get2), context2, extensionId, [])), Option3.getOrElse(() => [])));
|
|
1265
|
+
};
|
|
1266
|
+
var createTypeExtension = (options) => {
|
|
1267
|
+
const { id, type, actions, connector, relation, position } = options;
|
|
1268
|
+
return createExtension({
|
|
1269
|
+
id,
|
|
1270
|
+
match: whenEchoType(type),
|
|
1271
|
+
actions,
|
|
1272
|
+
connector,
|
|
1273
|
+
relation,
|
|
1274
|
+
position
|
|
1275
|
+
});
|
|
1276
|
+
};
|
|
1277
|
+
var flattenExtensions = (extension, acc = []) => {
|
|
1278
|
+
if (Array2.isArray(extension)) {
|
|
1279
|
+
return [
|
|
1280
|
+
...acc,
|
|
1281
|
+
...extension.flatMap((ext) => flattenExtensions(ext, acc))
|
|
1282
|
+
];
|
|
1283
|
+
} else {
|
|
1284
|
+
return [
|
|
1285
|
+
...acc,
|
|
1286
|
+
extension
|
|
1287
|
+
];
|
|
1288
|
+
}
|
|
759
1289
|
};
|
|
760
1290
|
export {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
ROOT_TYPE,
|
|
767
|
-
actionGroupSymbol,
|
|
768
|
-
createExtension,
|
|
769
|
-
flattenExtensions,
|
|
770
|
-
getGraph,
|
|
771
|
-
isAction,
|
|
772
|
-
isActionGroup,
|
|
773
|
-
isActionLike,
|
|
774
|
-
isGraphNode,
|
|
775
|
-
rxFromObservable,
|
|
776
|
-
rxFromSignal
|
|
1291
|
+
atoms_exports as CreateAtom,
|
|
1292
|
+
graph_exports as Graph,
|
|
1293
|
+
graph_builder_exports as GraphBuilder,
|
|
1294
|
+
node_exports as Node,
|
|
1295
|
+
node_matcher_exports as NodeMatcher
|
|
777
1296
|
};
|
|
778
1297
|
//# sourceMappingURL=index.mjs.map
|