@dxos/app-graph 0.8.2-main.f11618f → 0.8.2-main.fbd8ed0
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 +541 -789
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +533 -780
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +541 -789
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/experimental/graph-projections.test.d.ts +25 -0
- package/dist/types/src/experimental/graph-projections.test.d.ts.map +1 -0
- package/dist/types/src/graph-builder.d.ts +48 -91
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +191 -98
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +2 -2
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/signals-integration.test.d.ts +2 -0
- package/dist/types/src/signals-integration.test.d.ts.map +1 -0
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/src/testing.d.ts +5 -0
- package/dist/types/src/testing.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -16
- package/src/experimental/graph-projections.test.ts +56 -0
- package/src/graph-builder.test.ts +293 -310
- package/src/graph-builder.ts +209 -317
- package/src/graph.test.ts +314 -463
- package/src/graph.ts +452 -458
- package/src/node.ts +2 -2
- package/src/signals-integration.test.ts +218 -0
- package/src/stories/EchoGraph.stories.tsx +56 -77
- package/src/testing.ts +20 -0
package/dist/lib/node/index.cjs
CHANGED
|
@@ -35,7 +35,6 @@ __export(node_exports, {
|
|
|
35
35
|
ROOT_ID: () => ROOT_ID,
|
|
36
36
|
ROOT_TYPE: () => ROOT_TYPE,
|
|
37
37
|
actionGroupSymbol: () => actionGroupSymbol,
|
|
38
|
-
cleanup: () => cleanup,
|
|
39
38
|
createExtension: () => createExtension,
|
|
40
39
|
flattenExtensions: () => flattenExtensions,
|
|
41
40
|
getGraph: () => getGraph,
|
|
@@ -43,34 +42,29 @@ __export(node_exports, {
|
|
|
43
42
|
isActionGroup: () => isActionGroup,
|
|
44
43
|
isActionLike: () => isActionLike,
|
|
45
44
|
isGraphNode: () => isGraphNode,
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
rxFromObservable: () => rxFromObservable,
|
|
46
|
+
rxFromSignal: () => rxFromSignal
|
|
48
47
|
});
|
|
49
48
|
module.exports = __toCommonJS(node_exports);
|
|
50
|
-
var
|
|
49
|
+
var import_rx_react = require("@effect-rx/rx-react");
|
|
50
|
+
var import_effect = require("effect");
|
|
51
51
|
var import_async = require("@dxos/async");
|
|
52
|
+
var import_debug = require("@dxos/debug");
|
|
52
53
|
var import_invariant = require("@dxos/invariant");
|
|
53
|
-
var import_live_object = require("@dxos/live-object");
|
|
54
54
|
var import_log = require("@dxos/log");
|
|
55
55
|
var import_util = require("@dxos/util");
|
|
56
|
-
var
|
|
57
|
-
var
|
|
58
|
-
var
|
|
59
|
-
var import_live_object2 = require("@dxos/live-object");
|
|
56
|
+
var import_rx_react2 = require("@effect-rx/rx-react");
|
|
57
|
+
var import_signals_core = require("@preact/signals-core");
|
|
58
|
+
var import_effect2 = require("effect");
|
|
60
59
|
var import_log2 = require("@dxos/log");
|
|
61
60
|
var import_util2 = require("@dxos/util");
|
|
62
|
-
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
63
|
-
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
|
|
64
|
-
var actionGroupSymbol = Symbol("ActionGroup");
|
|
65
|
-
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
|
|
66
|
-
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
67
61
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
|
|
68
62
|
var graphSymbol = Symbol("graph");
|
|
69
63
|
var getGraph = (node) => {
|
|
70
64
|
const graph = node[graphSymbol];
|
|
71
65
|
(0, import_invariant.invariant)(graph, "Node is not associated with a graph.", {
|
|
72
66
|
F: __dxlog_file,
|
|
73
|
-
L:
|
|
67
|
+
L: 25,
|
|
74
68
|
S: void 0,
|
|
75
69
|
A: [
|
|
76
70
|
"graph",
|
|
@@ -83,637 +77,484 @@ var ROOT_ID = "root";
|
|
|
83
77
|
var ROOT_TYPE = "dxos.org/type/GraphRoot";
|
|
84
78
|
var ACTION_TYPE = "dxos.org/type/GraphAction";
|
|
85
79
|
var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
|
|
86
|
-
var
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.
|
|
90
|
-
this._initialized =
|
|
91
|
-
this.
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
80
|
+
var Graph = class {
|
|
81
|
+
constructor({ registry, nodes, edges, onExpand, onRemoveNode } = {}) {
|
|
82
|
+
this.onNodeChanged = new import_async.Event();
|
|
83
|
+
this._expanded = import_effect.Record.empty();
|
|
84
|
+
this._initialized = import_effect.Record.empty();
|
|
85
|
+
this._initialEdges = import_effect.Record.empty();
|
|
86
|
+
this._initialNodes = import_effect.Record.fromEntries([
|
|
87
|
+
[
|
|
88
|
+
ROOT_ID,
|
|
89
|
+
this._constructNode({
|
|
90
|
+
id: ROOT_ID,
|
|
91
|
+
type: ROOT_TYPE,
|
|
92
|
+
data: null,
|
|
93
|
+
properties: {}
|
|
94
|
+
})
|
|
95
|
+
]
|
|
96
|
+
]);
|
|
97
|
+
this._node = import_rx_react.Rx.family((id) => {
|
|
98
|
+
const initial = import_effect.Option.flatten(import_effect.Record.get(this._initialNodes, id));
|
|
99
|
+
return import_rx_react.Rx.make(initial).pipe(import_rx_react.Rx.keepAlive, import_rx_react.Rx.withLabel(`graph:node:${id}`));
|
|
100
|
+
});
|
|
101
|
+
this._nodeOrThrow = import_rx_react.Rx.family((id) => {
|
|
102
|
+
return import_rx_react.Rx.make((get) => {
|
|
103
|
+
const node = get(this._node(id));
|
|
104
|
+
(0, import_invariant.invariant)(import_effect.Option.isSome(node), `Node not available: ${id}`, {
|
|
105
|
+
F: __dxlog_file,
|
|
106
|
+
L: 253,
|
|
107
|
+
S: this,
|
|
108
|
+
A: [
|
|
109
|
+
"Option.isSome(node)",
|
|
110
|
+
"`Node not available: ${id}`"
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
return node.value;
|
|
97
114
|
});
|
|
98
|
-
};
|
|
99
|
-
this._onInitialNode = onInitialNode;
|
|
100
|
-
this._onInitialNodes = onInitialNodes;
|
|
101
|
-
this._onRemoveNode = onRemoveNode;
|
|
102
|
-
this._nodes[ROOT_ID] = this._constructNode({
|
|
103
|
-
id: ROOT_ID,
|
|
104
|
-
type: ROOT_TYPE,
|
|
105
|
-
cacheable: [],
|
|
106
|
-
properties: {},
|
|
107
|
-
data: null
|
|
108
115
|
});
|
|
116
|
+
this._edges = import_rx_react.Rx.family((id) => {
|
|
117
|
+
const initial = import_effect.Record.get(this._initialEdges, id).pipe(import_effect.Option.getOrElse(() => ({
|
|
118
|
+
inbound: [],
|
|
119
|
+
outbound: []
|
|
120
|
+
})));
|
|
121
|
+
return import_rx_react.Rx.make(initial).pipe(import_rx_react.Rx.keepAlive, import_rx_react.Rx.withLabel(`graph:edges:${id}`));
|
|
122
|
+
});
|
|
123
|
+
this._connections = import_rx_react.Rx.family((key) => {
|
|
124
|
+
return import_rx_react.Rx.make((get) => {
|
|
125
|
+
const [id, relation] = key.split("$");
|
|
126
|
+
const edges2 = get(this._edges(id));
|
|
127
|
+
return edges2[relation].map((id2) => get(this._node(id2))).filter(import_effect.Option.isSome).map((o) => o.value);
|
|
128
|
+
}).pipe(import_rx_react.Rx.withLabel(`graph:connections:${key}`));
|
|
129
|
+
});
|
|
130
|
+
this._actions = import_rx_react.Rx.family((id) => {
|
|
131
|
+
return import_rx_react.Rx.make((get) => {
|
|
132
|
+
return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
|
|
133
|
+
}).pipe(import_rx_react.Rx.withLabel(`graph:actions:${id}`));
|
|
134
|
+
});
|
|
135
|
+
this._json = import_rx_react.Rx.family((id) => {
|
|
136
|
+
return import_rx_react.Rx.make((get) => {
|
|
137
|
+
const toJSON = (node, seen = []) => {
|
|
138
|
+
const nodes2 = get(this.connections(node.id));
|
|
139
|
+
const obj = {
|
|
140
|
+
id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
|
|
141
|
+
type: node.type
|
|
142
|
+
};
|
|
143
|
+
if (node.properties.label) {
|
|
144
|
+
obj.label = node.properties.label;
|
|
145
|
+
}
|
|
146
|
+
if (nodes2.length) {
|
|
147
|
+
obj.nodes = nodes2.map((n) => {
|
|
148
|
+
const nextSeen = [
|
|
149
|
+
...seen,
|
|
150
|
+
node.id
|
|
151
|
+
];
|
|
152
|
+
return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
|
|
153
|
+
}).filter(import_util.isNonNullable);
|
|
154
|
+
}
|
|
155
|
+
return obj;
|
|
156
|
+
};
|
|
157
|
+
const root = get(this.nodeOrThrow(id));
|
|
158
|
+
return toJSON(root);
|
|
159
|
+
}).pipe(import_rx_react.Rx.withLabel(`graph:json:${id}`));
|
|
160
|
+
});
|
|
161
|
+
this._registry = registry ?? import_rx_react.Registry.make();
|
|
162
|
+
this._onExpand = onExpand;
|
|
163
|
+
this._onRemoveNode = onRemoveNode;
|
|
109
164
|
if (nodes) {
|
|
110
165
|
nodes.forEach((node) => {
|
|
111
|
-
|
|
112
|
-
if (node.type === ACTION_TYPE) {
|
|
113
|
-
this._addNode({
|
|
114
|
-
cacheable,
|
|
115
|
-
data: () => import_log.log.warn("Pickled action invocation", void 0, {
|
|
116
|
-
F: __dxlog_file,
|
|
117
|
-
L: 113,
|
|
118
|
-
S: this,
|
|
119
|
-
C: (f, a) => f(...a)
|
|
120
|
-
}),
|
|
121
|
-
...node
|
|
122
|
-
});
|
|
123
|
-
} else if (node.type === ACTION_GROUP_TYPE) {
|
|
124
|
-
this._addNode({
|
|
125
|
-
cacheable,
|
|
126
|
-
data: actionGroupSymbol,
|
|
127
|
-
...node
|
|
128
|
-
});
|
|
129
|
-
} else {
|
|
130
|
-
this._addNode({
|
|
131
|
-
cacheable,
|
|
132
|
-
...node
|
|
133
|
-
});
|
|
134
|
-
}
|
|
166
|
+
import_effect.Record.set(this._initialNodes, node.id, this._constructNode(node));
|
|
135
167
|
});
|
|
136
168
|
}
|
|
137
|
-
this._edges[ROOT_ID] = (0, import_live_object.live)({
|
|
138
|
-
inbound: [],
|
|
139
|
-
outbound: []
|
|
140
|
-
});
|
|
141
169
|
if (edges) {
|
|
142
170
|
Object.entries(edges).forEach(([source, edges2]) => {
|
|
143
|
-
|
|
144
|
-
this._addEdge({
|
|
145
|
-
source,
|
|
146
|
-
target
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
this._sortEdges(source, "outbound", edges2);
|
|
171
|
+
import_effect.Record.set(this._initialEdges, source, edges2);
|
|
150
172
|
});
|
|
151
173
|
}
|
|
152
174
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
175
|
+
toJSON(id = ROOT_ID) {
|
|
176
|
+
return this._registry.get(this._json(id));
|
|
177
|
+
}
|
|
178
|
+
json(id = ROOT_ID) {
|
|
179
|
+
return this._json(id);
|
|
180
|
+
}
|
|
181
|
+
node(id) {
|
|
182
|
+
return this._node(id);
|
|
183
|
+
}
|
|
184
|
+
nodeOrThrow(id) {
|
|
185
|
+
return this._nodeOrThrow(id);
|
|
186
|
+
}
|
|
187
|
+
connections(id, relation = "outbound") {
|
|
188
|
+
return this._connections(`${id}$${relation}`);
|
|
189
|
+
}
|
|
190
|
+
actions(id) {
|
|
191
|
+
return this._actions(id);
|
|
192
|
+
}
|
|
193
|
+
edges(id) {
|
|
194
|
+
return this._edges(id);
|
|
160
195
|
}
|
|
161
|
-
/**
|
|
162
|
-
* Alias for `findNode('root')`.
|
|
163
|
-
*/
|
|
164
196
|
get root() {
|
|
165
|
-
return this.
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
197
|
+
return this.getNodeOrThrow(ROOT_ID);
|
|
198
|
+
}
|
|
199
|
+
getNode(id) {
|
|
200
|
+
return this._registry.get(this.node(id));
|
|
201
|
+
}
|
|
202
|
+
getNodeOrThrow(id) {
|
|
203
|
+
return this._registry.get(this.nodeOrThrow(id));
|
|
204
|
+
}
|
|
205
|
+
getConnections(id, relation = "outbound") {
|
|
206
|
+
return this._registry.get(this.connections(id, relation));
|
|
207
|
+
}
|
|
208
|
+
getActions(id) {
|
|
209
|
+
return this._registry.get(this.actions(id));
|
|
210
|
+
}
|
|
211
|
+
getEdges(id) {
|
|
212
|
+
return this._registry.get(this.edges(id));
|
|
213
|
+
}
|
|
214
|
+
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
215
|
+
// async initialize(id: string) {
|
|
216
|
+
// const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
|
|
217
|
+
// log('initialize', { id, initialized });
|
|
218
|
+
// if (!initialized) {
|
|
219
|
+
// await this._onInitialize?.(id);
|
|
220
|
+
// Record.set(this._initialized, id, true);
|
|
221
|
+
// }
|
|
222
|
+
// }
|
|
223
|
+
expand(id, relation = "outbound") {
|
|
224
|
+
const key = `${id}$${relation}`;
|
|
225
|
+
const expanded = import_effect.Record.get(this._expanded, key).pipe(import_effect.Option.getOrElse(() => false));
|
|
226
|
+
(0, import_log.log)("expand", {
|
|
227
|
+
key,
|
|
228
|
+
expanded
|
|
229
|
+
}, {
|
|
193
230
|
F: __dxlog_file,
|
|
194
|
-
L:
|
|
231
|
+
L: 395,
|
|
195
232
|
S: this,
|
|
196
|
-
|
|
197
|
-
"root",
|
|
198
|
-
"`Node not found: ${id}`"
|
|
199
|
-
]
|
|
233
|
+
C: (f, a) => f(...a)
|
|
200
234
|
});
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
};
|
|
235
|
+
if (!expanded) {
|
|
236
|
+
this._onExpand?.(id, relation);
|
|
237
|
+
import_effect.Record.set(this._expanded, key, true);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
addNodes(nodes) {
|
|
241
|
+
import_rx_react.Rx.batch(() => {
|
|
242
|
+
nodes.map((node) => this.addNode(node));
|
|
210
243
|
});
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
244
|
+
}
|
|
245
|
+
addNode({ nodes, edges, ...nodeArg }) {
|
|
246
|
+
const { id, type, data = null, properties = {} } = nodeArg;
|
|
247
|
+
const nodeRx = this._node(id);
|
|
248
|
+
const node = this._registry.get(nodeRx);
|
|
249
|
+
import_effect.Option.match(node, {
|
|
250
|
+
onSome: (node2) => {
|
|
251
|
+
const typeChanged = node2.type !== type;
|
|
252
|
+
const dataChanged = node2.data !== data;
|
|
253
|
+
const propertiesChanged = Object.keys(properties).some((key) => node2.properties[key] !== properties[key]);
|
|
254
|
+
(0, import_log.log)("existing node", {
|
|
255
|
+
typeChanged,
|
|
256
|
+
dataChanged,
|
|
257
|
+
propertiesChanged
|
|
258
|
+
}, {
|
|
259
|
+
F: __dxlog_file,
|
|
260
|
+
L: 417,
|
|
261
|
+
S: this,
|
|
262
|
+
C: (f, a) => f(...a)
|
|
263
|
+
});
|
|
264
|
+
if (typeChanged || dataChanged || propertiesChanged) {
|
|
265
|
+
(0, import_log.log)("updating node", {
|
|
266
|
+
id,
|
|
267
|
+
type,
|
|
268
|
+
data,
|
|
269
|
+
properties
|
|
270
|
+
}, {
|
|
271
|
+
F: __dxlog_file,
|
|
272
|
+
L: 419,
|
|
273
|
+
S: this,
|
|
274
|
+
C: (f, a) => f(...a)
|
|
275
|
+
});
|
|
276
|
+
const newNode = import_effect.Option.some({
|
|
277
|
+
...node2,
|
|
278
|
+
type,
|
|
279
|
+
data,
|
|
280
|
+
properties: {
|
|
281
|
+
...node2.properties,
|
|
282
|
+
...properties
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
this._registry.set(nodeRx, newNode);
|
|
286
|
+
this.onNodeChanged.emit({
|
|
287
|
+
id,
|
|
288
|
+
node: newNode
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
onNone: () => {
|
|
293
|
+
(0, import_log.log)("new node", {
|
|
294
|
+
id,
|
|
295
|
+
type,
|
|
296
|
+
data,
|
|
297
|
+
properties
|
|
298
|
+
}, {
|
|
299
|
+
F: __dxlog_file,
|
|
300
|
+
L: 426,
|
|
301
|
+
S: this,
|
|
302
|
+
C: (f, a) => f(...a)
|
|
303
|
+
});
|
|
304
|
+
const newNode = this._constructNode({
|
|
305
|
+
id,
|
|
306
|
+
type,
|
|
307
|
+
data,
|
|
308
|
+
properties
|
|
309
|
+
});
|
|
310
|
+
this._registry.set(nodeRx, newNode);
|
|
311
|
+
this.onNodeChanged.emit({
|
|
312
|
+
id,
|
|
313
|
+
node: newNode
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
if (nodes) {
|
|
318
|
+
this.addNodes(nodes);
|
|
319
|
+
const _edges = nodes.map((node2) => ({
|
|
320
|
+
source: id,
|
|
321
|
+
target: node2.id
|
|
322
|
+
}));
|
|
323
|
+
this.addEdges(_edges);
|
|
324
|
+
}
|
|
325
|
+
if (edges) {
|
|
326
|
+
(0, import_debug.todo)();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
removeNodes(ids, edges = false) {
|
|
330
|
+
import_rx_react.Rx.batch(() => {
|
|
331
|
+
ids.map((id) => this.removeNode(id, edges));
|
|
219
332
|
});
|
|
220
333
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
334
|
+
removeNode(id, edges = false) {
|
|
335
|
+
const nodeRx = this._node(id);
|
|
336
|
+
this._registry.set(nodeRx, import_effect.Option.none());
|
|
337
|
+
this.onNodeChanged.emit({
|
|
338
|
+
id,
|
|
339
|
+
node: import_effect.Option.none()
|
|
340
|
+
});
|
|
341
|
+
if (edges) {
|
|
342
|
+
const { inbound, outbound } = this._registry.get(this._edges(id));
|
|
343
|
+
const edges2 = [
|
|
344
|
+
...inbound.map((source) => ({
|
|
345
|
+
source,
|
|
346
|
+
target: id
|
|
347
|
+
})),
|
|
348
|
+
...outbound.map((target) => ({
|
|
349
|
+
source: id,
|
|
350
|
+
target
|
|
351
|
+
}))
|
|
352
|
+
];
|
|
353
|
+
this.removeEdges(edges2);
|
|
231
354
|
}
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
355
|
+
this._onRemoveNode?.(id);
|
|
356
|
+
}
|
|
357
|
+
addEdges(edges) {
|
|
358
|
+
import_rx_react.Rx.batch(() => {
|
|
359
|
+
edges.map((edge) => this.addEdge(edge));
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
addEdge(edgeArg) {
|
|
363
|
+
const sourceRx = this._edges(edgeArg.source);
|
|
364
|
+
const source = this._registry.get(sourceRx);
|
|
365
|
+
if (!source.outbound.includes(edgeArg.target)) {
|
|
366
|
+
(0, import_log.log)("add outbound edge", {
|
|
367
|
+
source: edgeArg.source,
|
|
368
|
+
target: edgeArg.target
|
|
369
|
+
}, {
|
|
370
|
+
F: __dxlog_file,
|
|
371
|
+
L: 481,
|
|
372
|
+
S: this,
|
|
373
|
+
C: (f, a) => f(...a)
|
|
374
|
+
});
|
|
375
|
+
this._registry.set(sourceRx, {
|
|
376
|
+
inbound: source.inbound,
|
|
377
|
+
outbound: [
|
|
378
|
+
...source.outbound,
|
|
379
|
+
edgeArg.target
|
|
380
|
+
]
|
|
381
|
+
});
|
|
248
382
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
383
|
+
const targetRx = this._edges(edgeArg.target);
|
|
384
|
+
const target = this._registry.get(targetRx);
|
|
385
|
+
if (!target.inbound.includes(edgeArg.source)) {
|
|
386
|
+
(0, import_log.log)("add inbound edge", {
|
|
387
|
+
source: edgeArg.source,
|
|
388
|
+
target: edgeArg.target
|
|
389
|
+
}, {
|
|
390
|
+
F: __dxlog_file,
|
|
391
|
+
L: 488,
|
|
392
|
+
S: this,
|
|
393
|
+
C: (f, a) => f(...a)
|
|
394
|
+
});
|
|
395
|
+
this._registry.set(targetRx, {
|
|
396
|
+
inbound: [
|
|
397
|
+
...target.inbound,
|
|
398
|
+
edgeArg.source
|
|
399
|
+
],
|
|
400
|
+
outbound: target.outbound
|
|
401
|
+
});
|
|
253
402
|
}
|
|
254
403
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
nodes(node, options = {}) {
|
|
259
|
-
const { relation, expansion, filter = DEFAULT_FILTER, type } = options;
|
|
260
|
-
const nodes = this._getNodes({
|
|
261
|
-
node,
|
|
262
|
-
relation,
|
|
263
|
-
expansion,
|
|
264
|
-
type
|
|
404
|
+
removeEdges(edges, removeOrphans = false) {
|
|
405
|
+
import_rx_react.Rx.batch(() => {
|
|
406
|
+
edges.map((edge) => this.removeEdge(edge, removeOrphans));
|
|
265
407
|
});
|
|
266
|
-
return nodes.filter((n) => filter(n, node));
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Edges that this node is connected to in default order.
|
|
270
|
-
*/
|
|
271
|
-
edges(node, { relation = "outbound" } = {}) {
|
|
272
|
-
return this._edges[node.id]?.[relation] ?? [];
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Actions or action groups that this node is connected to in default order.
|
|
276
|
-
*/
|
|
277
|
-
actions(node, { expansion } = {}) {
|
|
278
|
-
return [
|
|
279
|
-
...this._getNodes({
|
|
280
|
-
node,
|
|
281
|
-
expansion,
|
|
282
|
-
type: ACTION_GROUP_TYPE
|
|
283
|
-
}),
|
|
284
|
-
...this._getNodes({
|
|
285
|
-
node,
|
|
286
|
-
expansion,
|
|
287
|
-
type: ACTION_TYPE
|
|
288
|
-
})
|
|
289
|
-
];
|
|
290
408
|
}
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
|
|
409
|
+
removeEdge(edgeArg, removeOrphans = false) {
|
|
410
|
+
const sourceRx = this._edges(edgeArg.source);
|
|
411
|
+
const source = this._registry.get(sourceRx);
|
|
412
|
+
if (source.outbound.includes(edgeArg.target)) {
|
|
413
|
+
this._registry.set(sourceRx, {
|
|
414
|
+
inbound: source.inbound,
|
|
415
|
+
outbound: source.outbound.filter((id) => id !== edgeArg.target)
|
|
416
|
+
});
|
|
297
417
|
}
|
|
418
|
+
const targetRx = this._edges(edgeArg.target);
|
|
419
|
+
const target = this._registry.get(targetRx);
|
|
420
|
+
if (target.inbound.includes(edgeArg.source)) {
|
|
421
|
+
this._registry.set(targetRx, {
|
|
422
|
+
inbound: target.inbound.filter((id) => id !== edgeArg.source),
|
|
423
|
+
outbound: target.outbound
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
if (removeOrphans) {
|
|
427
|
+
const source2 = this._registry.get(sourceRx);
|
|
428
|
+
const target2 = this._registry.get(targetRx);
|
|
429
|
+
if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
|
|
430
|
+
this.removeNodes([
|
|
431
|
+
edgeArg.source
|
|
432
|
+
]);
|
|
433
|
+
}
|
|
434
|
+
if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== ROOT_ID) {
|
|
435
|
+
this.removeNodes([
|
|
436
|
+
edgeArg.target
|
|
437
|
+
]);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
sortEdges(id, relation, order) {
|
|
442
|
+
const edgesRx = this._edges(id);
|
|
443
|
+
const edges = this._registry.get(edgesRx);
|
|
444
|
+
const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
|
|
445
|
+
const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
|
|
446
|
+
edges[relation].splice(0, edges[relation].length, ...[
|
|
447
|
+
...sorted,
|
|
448
|
+
...unsorted
|
|
449
|
+
]);
|
|
450
|
+
this._registry.set(edgesRx, edges);
|
|
298
451
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Recursive depth-first traversal of the graph.
|
|
304
|
-
*
|
|
305
|
-
* @param options.node The node to start traversing from.
|
|
306
|
-
* @param options.relation The relation to traverse graph edges.
|
|
307
|
-
* @param options.visitor A callback which is called for each node visited during traversal.
|
|
308
|
-
*/
|
|
309
|
-
traverse({ visitor, node = this.root, relation = "outbound", expansion }, path = []) {
|
|
310
|
-
if (path.includes(node.id)) {
|
|
452
|
+
traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
|
|
453
|
+
if (path.includes(source)) {
|
|
311
454
|
return;
|
|
312
455
|
}
|
|
456
|
+
const node = this.getNodeOrThrow(source);
|
|
313
457
|
const shouldContinue = visitor(node, [
|
|
314
458
|
...path,
|
|
315
|
-
|
|
459
|
+
source
|
|
316
460
|
]);
|
|
317
461
|
if (shouldContinue === false) {
|
|
318
462
|
return;
|
|
319
463
|
}
|
|
320
|
-
Object.values(this.
|
|
321
|
-
|
|
322
|
-
relation,
|
|
323
|
-
expansion
|
|
324
|
-
})).forEach((child) => this.traverse({
|
|
325
|
-
node: child,
|
|
464
|
+
Object.values(this.getConnections(source, relation)).forEach((child) => this.traverse({
|
|
465
|
+
source: child.id,
|
|
326
466
|
relation,
|
|
327
|
-
visitor
|
|
328
|
-
expansion
|
|
467
|
+
visitor
|
|
329
468
|
}, [
|
|
330
469
|
...path,
|
|
331
|
-
|
|
470
|
+
source
|
|
332
471
|
]));
|
|
333
472
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Recursive depth-first traversal of the graph wrapping each visitor call in an effect.
|
|
336
|
-
*
|
|
337
|
-
* @param options.node The node to start traversing from.
|
|
338
|
-
* @param options.relation The relation to traverse graph edges.
|
|
339
|
-
* @param options.visitor A callback which is called for each node visited during traversal.
|
|
340
|
-
*/
|
|
341
|
-
subscribeTraverse({ visitor, node = this.root, relation = "outbound", expansion }, currentPath = []) {
|
|
342
|
-
return (0, import_signals_core.effect)(() => {
|
|
343
|
-
const path = [
|
|
344
|
-
...currentPath,
|
|
345
|
-
node.id
|
|
346
|
-
];
|
|
347
|
-
const result = visitor(node, path);
|
|
348
|
-
if (result === false) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
const nodes = this._getNodes({
|
|
352
|
-
node,
|
|
353
|
-
relation,
|
|
354
|
-
expansion
|
|
355
|
-
});
|
|
356
|
-
const nodeSubscriptions = nodes.map((n) => this.subscribeTraverse({
|
|
357
|
-
node: n,
|
|
358
|
-
visitor,
|
|
359
|
-
expansion
|
|
360
|
-
}, path));
|
|
361
|
-
return () => {
|
|
362
|
-
nodeSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
363
|
-
};
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Get the path between two nodes in the graph.
|
|
368
|
-
*/
|
|
369
473
|
getPath({ source = "root", target }) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (node.id === target) {
|
|
382
|
-
found = path;
|
|
474
|
+
return (0, import_effect.pipe)(this.getNode(source), import_effect.Option.flatMap((node) => {
|
|
475
|
+
let found = import_effect.Option.none();
|
|
476
|
+
this.traverse({
|
|
477
|
+
source: node.id,
|
|
478
|
+
visitor: (node2, path) => {
|
|
479
|
+
if (import_effect.Option.isSome(found)) {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
if (node2.id === target) {
|
|
483
|
+
found = import_effect.Option.some(path);
|
|
484
|
+
}
|
|
383
485
|
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
486
|
+
});
|
|
487
|
+
return found;
|
|
488
|
+
}));
|
|
387
489
|
}
|
|
388
|
-
/**
|
|
389
|
-
* Wait for the path between two nodes in the graph to be established.
|
|
390
|
-
*/
|
|
391
490
|
async waitForPath(params, { timeout = 5e3, interval = 500 } = {}) {
|
|
392
491
|
const path = this.getPath(params);
|
|
393
|
-
if (path) {
|
|
394
|
-
return path;
|
|
492
|
+
if (import_effect.Option.isSome(path)) {
|
|
493
|
+
return path.value;
|
|
395
494
|
}
|
|
396
495
|
const trigger = new import_async.Trigger();
|
|
397
496
|
const i = setInterval(() => {
|
|
398
497
|
const path2 = this.getPath(params);
|
|
399
|
-
if (path2) {
|
|
400
|
-
trigger.wake(path2);
|
|
498
|
+
if (import_effect.Option.isSome(path2)) {
|
|
499
|
+
trigger.wake(path2.value);
|
|
401
500
|
}
|
|
402
501
|
}, interval);
|
|
403
502
|
return trigger.wait({
|
|
404
503
|
timeout
|
|
405
504
|
}).finally(() => clearInterval(i));
|
|
406
505
|
}
|
|
407
|
-
/**
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
_addNode({ nodes, edges, ..._node }) {
|
|
416
|
-
return (0, import_signals_core.untracked)(() => {
|
|
417
|
-
const existingNode = this._nodes[_node.id];
|
|
418
|
-
const node = existingNode ?? this._constructNode({
|
|
419
|
-
data: null,
|
|
420
|
-
properties: {},
|
|
421
|
-
..._node
|
|
422
|
-
});
|
|
423
|
-
if (existingNode) {
|
|
424
|
-
const { data = null, properties, type } = _node;
|
|
425
|
-
if (data !== node.data) {
|
|
426
|
-
node.data = data;
|
|
427
|
-
}
|
|
428
|
-
if (type !== node.type) {
|
|
429
|
-
node.type = type;
|
|
430
|
-
}
|
|
431
|
-
for (const key in properties) {
|
|
432
|
-
if (properties[key] !== node.properties[key]) {
|
|
433
|
-
node.properties[key] = properties[key];
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
} else {
|
|
437
|
-
this._nodes[node.id] = node;
|
|
438
|
-
this._edges[node.id] = (0, import_live_object.live)({
|
|
439
|
-
inbound: [],
|
|
440
|
-
outbound: []
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
const trigger = this._waitingForNodes[node.id];
|
|
444
|
-
if (trigger) {
|
|
445
|
-
trigger.wake(node);
|
|
446
|
-
delete this._waitingForNodes[node.id];
|
|
447
|
-
}
|
|
448
|
-
if (nodes) {
|
|
449
|
-
nodes.forEach((subNode) => {
|
|
450
|
-
this._addNode(subNode);
|
|
451
|
-
this._addEdge({
|
|
452
|
-
source: node.id,
|
|
453
|
-
target: subNode.id
|
|
454
|
-
});
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
if (edges) {
|
|
458
|
-
edges.forEach(([id, relation]) => relation === "outbound" ? this._addEdge({
|
|
459
|
-
source: node.id,
|
|
460
|
-
target: id
|
|
461
|
-
}) : this._addEdge({
|
|
462
|
-
source: id,
|
|
463
|
-
target: node.id
|
|
464
|
-
}));
|
|
465
|
-
}
|
|
466
|
-
return node;
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Remove nodes from the graph.
|
|
471
|
-
*
|
|
472
|
-
* @param ids The id of the node to remove.
|
|
473
|
-
* @param edges Whether to remove edges connected to the node from the graph as well.
|
|
474
|
-
* @internal
|
|
475
|
-
*/
|
|
476
|
-
_removeNodes(ids, edges = false) {
|
|
477
|
-
(0, import_signals_core.batch)(() => ids.forEach((id) => this._removeNode(id, edges)));
|
|
478
|
-
}
|
|
479
|
-
_removeNode(id, edges = false) {
|
|
480
|
-
(0, import_signals_core.untracked)(() => {
|
|
481
|
-
const node = this.findNode(id, false);
|
|
482
|
-
if (!node) {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
if (edges) {
|
|
486
|
-
this._getNodes({
|
|
487
|
-
node
|
|
488
|
-
}).forEach((node2) => {
|
|
489
|
-
this._removeEdge({
|
|
490
|
-
source: id,
|
|
491
|
-
target: node2.id
|
|
492
|
-
});
|
|
493
|
-
});
|
|
494
|
-
this._getNodes({
|
|
495
|
-
node,
|
|
496
|
-
relation: "inbound"
|
|
497
|
-
}).forEach((node2) => {
|
|
498
|
-
this._removeEdge({
|
|
499
|
-
source: node2.id,
|
|
500
|
-
target: id
|
|
501
|
-
});
|
|
502
|
-
});
|
|
503
|
-
delete this._edges[id];
|
|
504
|
-
}
|
|
505
|
-
delete this._nodes[id];
|
|
506
|
-
Object.keys(this._initialized).filter((key) => key.startsWith(id)).forEach((key) => {
|
|
507
|
-
delete this._initialized[key];
|
|
508
|
-
});
|
|
509
|
-
void this._onRemoveNode?.(id);
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* Add edges to the graph.
|
|
514
|
-
*
|
|
515
|
-
* @internal
|
|
516
|
-
*/
|
|
517
|
-
_addEdges(edges) {
|
|
518
|
-
(0, import_signals_core.batch)(() => edges.forEach((edge) => this._addEdge(edge)));
|
|
519
|
-
}
|
|
520
|
-
_addEdge({ source, target }) {
|
|
521
|
-
(0, import_signals_core.untracked)(() => {
|
|
522
|
-
if (!this._edges[source]) {
|
|
523
|
-
this._edges[source] = (0, import_live_object.live)({
|
|
524
|
-
inbound: [],
|
|
525
|
-
outbound: []
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
if (!this._edges[target]) {
|
|
529
|
-
this._edges[target] = (0, import_live_object.live)({
|
|
530
|
-
inbound: [],
|
|
531
|
-
outbound: []
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
const sourceEdges = this._edges[source];
|
|
535
|
-
if (!sourceEdges.outbound.includes(target)) {
|
|
536
|
-
sourceEdges.outbound.push(target);
|
|
537
|
-
}
|
|
538
|
-
const targetEdges = this._edges[target];
|
|
539
|
-
if (!targetEdges.inbound.includes(source)) {
|
|
540
|
-
targetEdges.inbound.push(source);
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Remove edges from the graph.
|
|
546
|
-
* @internal
|
|
547
|
-
*/
|
|
548
|
-
_removeEdges(edges, removeOrphans = false) {
|
|
549
|
-
(0, import_signals_core.batch)(() => edges.forEach((edge) => this._removeEdge(edge, removeOrphans)));
|
|
550
|
-
}
|
|
551
|
-
_removeEdge({ source, target }, removeOrphans = false) {
|
|
552
|
-
(0, import_signals_core.untracked)(() => {
|
|
553
|
-
(0, import_signals_core.batch)(() => {
|
|
554
|
-
const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);
|
|
555
|
-
if (outboundIndex !== void 0 && outboundIndex !== -1) {
|
|
556
|
-
this._edges[source].outbound.splice(outboundIndex, 1);
|
|
557
|
-
}
|
|
558
|
-
const inboundIndex = this._edges[target]?.inbound.findIndex((id) => id === source);
|
|
559
|
-
if (inboundIndex !== void 0 && inboundIndex !== -1) {
|
|
560
|
-
this._edges[target].inbound.splice(inboundIndex, 1);
|
|
561
|
-
}
|
|
562
|
-
if (removeOrphans) {
|
|
563
|
-
if (this._edges[source]?.outbound.length === 0 && this._edges[source]?.inbound.length === 0 && source !== ROOT_ID) {
|
|
564
|
-
this._removeNode(source, true);
|
|
565
|
-
}
|
|
566
|
-
if (this._edges[target]?.outbound.length === 0 && this._edges[target]?.inbound.length === 0 && target !== ROOT_ID) {
|
|
567
|
-
this._removeNode(target, true);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Sort edges for a node.
|
|
575
|
-
*
|
|
576
|
-
* Edges not included in the sorted list are appended to the end of the list.
|
|
577
|
-
*
|
|
578
|
-
* @param nodeId The id of the node to sort edges for.
|
|
579
|
-
* @param relation The relation of the edges from the node to sort.
|
|
580
|
-
* @param edges The ordered list of edges.
|
|
581
|
-
* @ignore
|
|
582
|
-
*/
|
|
583
|
-
_sortEdges(nodeId, relation, edges) {
|
|
584
|
-
(0, import_signals_core.untracked)(() => {
|
|
585
|
-
(0, import_signals_core.batch)(() => {
|
|
586
|
-
const current = this._edges[nodeId];
|
|
587
|
-
if (current) {
|
|
588
|
-
const unsorted = current[relation].filter((id) => !edges.includes(id)) ?? [];
|
|
589
|
-
const sorted = edges.filter((id) => current[relation].includes(id)) ?? [];
|
|
590
|
-
current[relation].splice(0, current[relation].length, ...[
|
|
591
|
-
...sorted,
|
|
592
|
-
...unsorted
|
|
593
|
-
]);
|
|
594
|
-
}
|
|
595
|
-
});
|
|
506
|
+
/** @internal */
|
|
507
|
+
_constructNode(node) {
|
|
508
|
+
return import_effect.Option.some({
|
|
509
|
+
[graphSymbol]: this,
|
|
510
|
+
data: null,
|
|
511
|
+
properties: {},
|
|
512
|
+
...node
|
|
596
513
|
});
|
|
597
514
|
}
|
|
598
|
-
_getNodes({ node, relation = "outbound", type, expansion }) {
|
|
599
|
-
if (expansion) {
|
|
600
|
-
void this.expand(node, relation, type);
|
|
601
|
-
}
|
|
602
|
-
const edges = this._edges[node.id];
|
|
603
|
-
if (!edges) {
|
|
604
|
-
return [];
|
|
605
|
-
} else {
|
|
606
|
-
return edges[relation].map((id) => this._nodes[id]).filter(import_util.isNonNullable).filter((n) => !type || n.type === type);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
515
|
};
|
|
516
|
+
var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
|
|
517
|
+
var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
|
|
518
|
+
var actionGroupSymbol = Symbol("ActionGroup");
|
|
519
|
+
var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
|
|
520
|
+
var isActionLike = (data) => isAction(data) || isActionGroup(data);
|
|
610
521
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
|
|
611
|
-
var NODE_RESOLVER_TIMEOUT = 1e3;
|
|
612
522
|
var createExtension = (extension) => {
|
|
613
|
-
const { id, position = "static",
|
|
523
|
+
const { id, position = "static", relation = "outbound", connector, actions: _actions, actionGroups: _actionGroups } = extension;
|
|
614
524
|
const getId = (key) => `${id}/${key}`;
|
|
525
|
+
const actionGroups = _actionGroups && import_rx_react2.Rx.family((node) => _actionGroups(node).pipe(import_rx_react2.Rx.withLabel(`graph-builder:actionGroups:${id}`)));
|
|
526
|
+
const actions = _actions && import_rx_react2.Rx.family((node) => _actions(node).pipe(import_rx_react2.Rx.withLabel(`graph-builder:actions:${id}`)));
|
|
615
527
|
return [
|
|
616
|
-
resolver ? {
|
|
617
|
-
id: getId("resolver"),
|
|
618
|
-
position,
|
|
619
|
-
resolver
|
|
620
|
-
} : void 0,
|
|
528
|
+
// resolver ? { id: getId('resolver'), position, resolver } : undefined,
|
|
621
529
|
connector ? {
|
|
622
|
-
...rest,
|
|
623
530
|
id: getId("connector"),
|
|
624
531
|
position,
|
|
625
|
-
|
|
532
|
+
relation,
|
|
533
|
+
connector: import_rx_react2.Rx.family((key) => connector(key).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connector:${id}`)))
|
|
626
534
|
} : void 0,
|
|
627
535
|
actionGroups ? {
|
|
628
|
-
...rest,
|
|
629
536
|
id: getId("actionGroups"),
|
|
630
537
|
position,
|
|
631
|
-
type: ACTION_GROUP_TYPE,
|
|
632
538
|
relation: "outbound",
|
|
633
|
-
connector: (
|
|
634
|
-
node
|
|
635
|
-
})?.map((arg) => ({
|
|
539
|
+
connector: import_rx_react2.Rx.family((node) => import_rx_react2.Rx.make((get) => get(actionGroups(node)).map((arg) => ({
|
|
636
540
|
...arg,
|
|
637
541
|
data: actionGroupSymbol,
|
|
638
542
|
type: ACTION_GROUP_TYPE
|
|
639
|
-
}))
|
|
543
|
+
}))).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connector:actionGroups:${id}`)))
|
|
640
544
|
} : void 0,
|
|
641
545
|
actions ? {
|
|
642
|
-
...rest,
|
|
643
546
|
id: getId("actions"),
|
|
644
547
|
position,
|
|
645
|
-
type: ACTION_TYPE,
|
|
646
548
|
relation: "outbound",
|
|
647
|
-
connector: (
|
|
648
|
-
node
|
|
649
|
-
})?.map((arg) => ({
|
|
549
|
+
connector: import_rx_react2.Rx.family((node) => import_rx_react2.Rx.make((get) => get(actions(node)).map((arg) => ({
|
|
650
550
|
...arg,
|
|
651
551
|
type: ACTION_TYPE
|
|
652
|
-
}))
|
|
552
|
+
}))).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connector:actions:${id}`)))
|
|
653
553
|
} : void 0
|
|
654
554
|
].filter(import_util2.isNonNullable);
|
|
655
555
|
};
|
|
656
|
-
var Dispatcher = class {
|
|
657
|
-
constructor() {
|
|
658
|
-
this.stateIndex = 0;
|
|
659
|
-
this.state = {};
|
|
660
|
-
this.cleanup = [];
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
|
-
var BuilderInternal = class {
|
|
664
|
-
};
|
|
665
|
-
var memoize = (fn, key = "result") => {
|
|
666
|
-
const dispatcher = BuilderInternal.currentDispatcher;
|
|
667
|
-
(0, import_invariant2.invariant)(dispatcher?.currentExtension, "memoize must be called within an extension", {
|
|
668
|
-
F: __dxlog_file2,
|
|
669
|
-
L: 135,
|
|
670
|
-
S: void 0,
|
|
671
|
-
A: [
|
|
672
|
-
"dispatcher?.currentExtension",
|
|
673
|
-
"'memoize must be called within an extension'"
|
|
674
|
-
]
|
|
675
|
-
});
|
|
676
|
-
const all = dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] ?? {};
|
|
677
|
-
const current = all[key];
|
|
678
|
-
const result = current ? current.result : fn();
|
|
679
|
-
dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] = {
|
|
680
|
-
...all,
|
|
681
|
-
[key]: {
|
|
682
|
-
result
|
|
683
|
-
}
|
|
684
|
-
};
|
|
685
|
-
dispatcher.stateIndex++;
|
|
686
|
-
return result;
|
|
687
|
-
};
|
|
688
|
-
var cleanup = (fn) => {
|
|
689
|
-
memoize(() => {
|
|
690
|
-
const dispatcher = BuilderInternal.currentDispatcher;
|
|
691
|
-
(0, import_invariant2.invariant)(dispatcher, "cleanup must be called within an extension", {
|
|
692
|
-
F: __dxlog_file2,
|
|
693
|
-
L: 150,
|
|
694
|
-
S: void 0,
|
|
695
|
-
A: [
|
|
696
|
-
"dispatcher",
|
|
697
|
-
"'cleanup must be called within an extension'"
|
|
698
|
-
]
|
|
699
|
-
});
|
|
700
|
-
dispatcher.cleanup.push(fn);
|
|
701
|
-
});
|
|
702
|
-
};
|
|
703
|
-
var toSignal = (subscribe, get, key) => {
|
|
704
|
-
const thisSignal = memoize(() => {
|
|
705
|
-
return (0, import_signals_core2.signal)(get());
|
|
706
|
-
}, key);
|
|
707
|
-
const unsubscribe = memoize(() => {
|
|
708
|
-
return subscribe(() => thisSignal.value = get());
|
|
709
|
-
}, key);
|
|
710
|
-
cleanup(() => {
|
|
711
|
-
unsubscribe();
|
|
712
|
-
});
|
|
713
|
-
return thisSignal.value;
|
|
714
|
-
};
|
|
715
556
|
var flattenExtensions = (extension, acc = []) => {
|
|
716
|
-
if (Array.isArray(extension)) {
|
|
557
|
+
if (import_effect2.Array.isArray(extension)) {
|
|
717
558
|
return [
|
|
718
559
|
...acc,
|
|
719
560
|
...extension.flatMap((ext) => flattenExtensions(ext, acc))
|
|
@@ -726,107 +567,74 @@ var flattenExtensions = (extension, acc = []) => {
|
|
|
726
567
|
}
|
|
727
568
|
};
|
|
728
569
|
var GraphBuilder = class _GraphBuilder {
|
|
729
|
-
constructor(params = {}) {
|
|
730
|
-
this._dispatcher = new Dispatcher();
|
|
731
|
-
this._extensions = (0, import_live_object2.live)({});
|
|
732
|
-
this._resolverSubscriptions = /* @__PURE__ */ new Map();
|
|
570
|
+
constructor({ registry, ...params } = {}) {
|
|
733
571
|
this._connectorSubscriptions = /* @__PURE__ */ new Map();
|
|
734
|
-
this.
|
|
735
|
-
this.
|
|
572
|
+
this._extensions = import_rx_react2.Rx.make(import_effect2.Record.empty()).pipe(import_rx_react2.Rx.keepAlive, import_rx_react2.Rx.withLabel("graph-builder:extensions"));
|
|
573
|
+
this._connectors = import_rx_react2.Rx.family((key) => {
|
|
574
|
+
return import_rx_react2.Rx.make((get) => {
|
|
575
|
+
const [id, relation] = key.split("+");
|
|
576
|
+
const node = this._graph.node(id);
|
|
577
|
+
return (0, import_effect2.pipe)(
|
|
578
|
+
get(this._extensions),
|
|
579
|
+
import_effect2.Record.values,
|
|
580
|
+
// TODO(wittjosiah): Sort on write rather than read.
|
|
581
|
+
import_effect2.Array.sortBy(import_util2.byPosition),
|
|
582
|
+
import_effect2.Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
|
|
583
|
+
import_effect2.Array.map(({ connector }) => connector?.(node)),
|
|
584
|
+
import_effect2.Array.filter(import_util2.isNonNullable),
|
|
585
|
+
import_effect2.Array.flatMap((result) => get(result))
|
|
586
|
+
);
|
|
587
|
+
}).pipe(import_rx_react2.Rx.withLabel(`graph-builder:connectors:${key}`));
|
|
588
|
+
});
|
|
589
|
+
this._registry = registry ?? import_rx_react2.Registry.make();
|
|
736
590
|
this._graph = new Graph({
|
|
737
591
|
...params,
|
|
738
|
-
|
|
739
|
-
|
|
592
|
+
registry: this._registry,
|
|
593
|
+
onExpand: (id, relation) => this._onExpand(id, relation),
|
|
594
|
+
// onInitialize: (id) => this._onInitialize(id),
|
|
740
595
|
onRemoveNode: (id) => this._onRemoveNode(id)
|
|
741
596
|
});
|
|
742
597
|
}
|
|
743
|
-
static from(pickle) {
|
|
598
|
+
static from(pickle, registry) {
|
|
744
599
|
if (!pickle) {
|
|
745
|
-
return new _GraphBuilder(
|
|
600
|
+
return new _GraphBuilder({
|
|
601
|
+
registry
|
|
602
|
+
});
|
|
746
603
|
}
|
|
747
604
|
const { nodes, edges } = JSON.parse(pickle);
|
|
748
605
|
return new _GraphBuilder({
|
|
749
606
|
nodes,
|
|
750
|
-
edges
|
|
607
|
+
edges,
|
|
608
|
+
registry
|
|
751
609
|
});
|
|
752
610
|
}
|
|
753
|
-
/**
|
|
754
|
-
* If graph is being restored from a pickle, the data will be null.
|
|
755
|
-
* Initialize the data of each node by calling resolvers.
|
|
756
|
-
* Wait until all of the initial nodes have resolved.
|
|
757
|
-
*/
|
|
758
|
-
async initialize() {
|
|
759
|
-
Object.keys(this._graph._nodes).filter((id) => id !== ROOT_ID).forEach((id) => this._initialized[id] = new import_async2.Trigger());
|
|
760
|
-
Object.keys(this._graph._nodes).forEach((id) => this._onInitialNode(id));
|
|
761
|
-
await Promise.all(Object.entries(this._initialized).map(async ([id, trigger]) => {
|
|
762
|
-
try {
|
|
763
|
-
await trigger.wait({
|
|
764
|
-
timeout: NODE_RESOLVER_TIMEOUT
|
|
765
|
-
});
|
|
766
|
-
} catch {
|
|
767
|
-
import_log2.log.error("node resolver timeout", {
|
|
768
|
-
id
|
|
769
|
-
}, {
|
|
770
|
-
F: __dxlog_file2,
|
|
771
|
-
L: 244,
|
|
772
|
-
S: this,
|
|
773
|
-
C: (f, a) => f(...a)
|
|
774
|
-
});
|
|
775
|
-
this.graph._removeNodes([
|
|
776
|
-
id
|
|
777
|
-
]);
|
|
778
|
-
}
|
|
779
|
-
}));
|
|
780
|
-
}
|
|
781
611
|
get graph() {
|
|
782
612
|
return this._graph;
|
|
783
613
|
}
|
|
784
|
-
/**
|
|
785
|
-
* @reactive
|
|
786
|
-
*/
|
|
787
614
|
get extensions() {
|
|
788
|
-
return
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
const extensions = flattenExtensions(extension);
|
|
795
|
-
(0, import_signals_core2.untracked)(() => {
|
|
796
|
-
extensions.forEach((extension2) => {
|
|
797
|
-
this._dispatcher.state[extension2.id] = [];
|
|
798
|
-
this._extensions[extension2.id] = extension2;
|
|
799
|
-
});
|
|
615
|
+
return this._extensions;
|
|
616
|
+
}
|
|
617
|
+
addExtension(extensions) {
|
|
618
|
+
flattenExtensions(extensions).forEach((extension) => {
|
|
619
|
+
const extensions2 = this._registry.get(this._extensions);
|
|
620
|
+
this._registry.set(this._extensions, import_effect2.Record.set(extensions2, extension.id, extension));
|
|
800
621
|
});
|
|
801
622
|
return this;
|
|
802
623
|
}
|
|
803
|
-
/**
|
|
804
|
-
* Remove a node builder from the graph builder.
|
|
805
|
-
*/
|
|
806
624
|
removeExtension(id) {
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
});
|
|
625
|
+
const extensions = this._registry.get(this._extensions);
|
|
626
|
+
this._registry.set(this._extensions, import_effect2.Record.remove(extensions, id));
|
|
810
627
|
return this;
|
|
811
628
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
this._resolverSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
815
|
-
this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
816
|
-
this._resolverSubscriptions.clear();
|
|
817
|
-
this._connectorSubscriptions.clear();
|
|
818
|
-
}
|
|
819
|
-
/**
|
|
820
|
-
* A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.
|
|
821
|
-
*/
|
|
822
|
-
async explore({ node = this._graph.root, relation = "outbound", visitor }, path = []) {
|
|
823
|
-
if (path.includes(node.id)) {
|
|
629
|
+
async explore({ registry = import_rx_react2.Registry.make(), source = ROOT_ID, relation = "outbound", visitor }, path = []) {
|
|
630
|
+
if (path.includes(source)) {
|
|
824
631
|
return;
|
|
825
632
|
}
|
|
826
633
|
if (!(0, import_util2.isNode)()) {
|
|
827
634
|
const { yieldOrContinue } = await import("main-thread-scheduling");
|
|
828
635
|
await yieldOrContinue("idle");
|
|
829
636
|
}
|
|
637
|
+
const node = registry.get(this._graph.nodeOrThrow(source));
|
|
830
638
|
const shouldContinue = await visitor(node, [
|
|
831
639
|
...path,
|
|
832
640
|
node.id
|
|
@@ -834,158 +642,104 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
834
642
|
if (shouldContinue === false) {
|
|
835
643
|
return;
|
|
836
644
|
}
|
|
837
|
-
const nodes = Object.values(this._extensions).filter((extension) => relation === (extension.relation ?? "outbound")).
|
|
838
|
-
|
|
839
|
-
this.
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
cacheable: arg.cacheable,
|
|
850
|
-
data: arg.data ?? null,
|
|
851
|
-
properties: arg.properties ?? {}
|
|
852
|
-
}));
|
|
853
|
-
await Promise.all(nodes.map((n) => this.explore({
|
|
854
|
-
node: n,
|
|
855
|
-
relation,
|
|
856
|
-
visitor
|
|
857
|
-
}, [
|
|
858
|
-
...path,
|
|
859
|
-
node.id
|
|
860
|
-
])));
|
|
861
|
-
}
|
|
862
|
-
_onInitialNode(nodeId) {
|
|
863
|
-
this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? (0, import_signals_core2.signal)({});
|
|
864
|
-
this._resolverSubscriptions.set(nodeId, (0, import_signals_core2.effect)(() => {
|
|
865
|
-
const extensions = Object.values(this._extensions).toSorted(import_util2.byPosition);
|
|
866
|
-
for (const { id, resolver } of extensions) {
|
|
867
|
-
if (!resolver) {
|
|
868
|
-
continue;
|
|
869
|
-
}
|
|
870
|
-
this._dispatcher.currentExtension = id;
|
|
871
|
-
this._dispatcher.stateIndex = 0;
|
|
872
|
-
BuilderInternal.currentDispatcher = this._dispatcher;
|
|
873
|
-
let node;
|
|
874
|
-
try {
|
|
875
|
-
node = resolver({
|
|
876
|
-
id: nodeId
|
|
877
|
-
});
|
|
878
|
-
} catch (err) {
|
|
879
|
-
import_log2.log.catch(err, {
|
|
880
|
-
extension: id
|
|
881
|
-
}, {
|
|
882
|
-
F: __dxlog_file2,
|
|
883
|
-
L: 359,
|
|
884
|
-
S: this,
|
|
885
|
-
C: (f, a) => f(...a)
|
|
886
|
-
});
|
|
887
|
-
import_log2.log.error(`Previous error occurred in extension: ${id}`, void 0, {
|
|
888
|
-
F: __dxlog_file2,
|
|
889
|
-
L: 360,
|
|
890
|
-
S: this,
|
|
891
|
-
C: (f, a) => f(...a)
|
|
892
|
-
});
|
|
893
|
-
} finally {
|
|
894
|
-
BuilderInternal.currentDispatcher = void 0;
|
|
895
|
-
}
|
|
896
|
-
const trigger = this._initialized[nodeId];
|
|
897
|
-
if (node) {
|
|
898
|
-
this.graph._addNodes([
|
|
899
|
-
node
|
|
900
|
-
]);
|
|
901
|
-
trigger?.wake();
|
|
902
|
-
if (this._nodeChanged[node.id]) {
|
|
903
|
-
this._nodeChanged[node.id].value = {};
|
|
904
|
-
}
|
|
905
|
-
break;
|
|
906
|
-
} else if (node === false) {
|
|
907
|
-
this.graph._removeNodes([
|
|
908
|
-
nodeId
|
|
909
|
-
]);
|
|
910
|
-
trigger?.wake();
|
|
911
|
-
break;
|
|
912
|
-
}
|
|
913
|
-
}
|
|
645
|
+
const nodes = Object.values(this._registry.get(this._extensions)).filter((extension) => relation === (extension.relation ?? "outbound")).map((extension) => extension.connector).filter(import_util2.isNonNullable).flatMap((connector) => registry.get(connector(this._graph.node(source))));
|
|
646
|
+
await Promise.all(nodes.map((nodeArg) => {
|
|
647
|
+
registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
|
|
648
|
+
return this.explore({
|
|
649
|
+
registry,
|
|
650
|
+
source: nodeArg.id,
|
|
651
|
+
relation,
|
|
652
|
+
visitor
|
|
653
|
+
}, [
|
|
654
|
+
...path,
|
|
655
|
+
node.id
|
|
656
|
+
]);
|
|
914
657
|
}));
|
|
658
|
+
if (registry !== this._registry) {
|
|
659
|
+
registry.reset();
|
|
660
|
+
registry.dispose();
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
destroy() {
|
|
664
|
+
this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
665
|
+
this._connectorSubscriptions.clear();
|
|
915
666
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
667
|
+
_onExpand(id, relation) {
|
|
668
|
+
(0, import_log2.log)("onExpand", {
|
|
669
|
+
id,
|
|
670
|
+
relation,
|
|
671
|
+
registry: (0, import_util2.getDebugName)(this._registry)
|
|
672
|
+
}, {
|
|
673
|
+
F: __dxlog_file2,
|
|
674
|
+
L: 276,
|
|
675
|
+
S: this,
|
|
676
|
+
C: (f, a) => f(...a)
|
|
677
|
+
});
|
|
678
|
+
const connectors = this._connectors(`${id}+${relation}`);
|
|
919
679
|
let previous = [];
|
|
920
|
-
this.
|
|
921
|
-
if (!first && !this._connectorSubscriptions.has(node.id)) {
|
|
922
|
-
return;
|
|
923
|
-
}
|
|
924
|
-
first = false;
|
|
925
|
-
Object.keys(this._extensions);
|
|
926
|
-
this._nodeChanged[node.id].value;
|
|
927
|
-
const nodes = [];
|
|
928
|
-
const extensions = Object.values(this._extensions).toSorted(import_util2.byPosition);
|
|
929
|
-
for (const { id, connector, filter, type, relation = "outbound" } of extensions) {
|
|
930
|
-
if (!connector || relation !== nodesRelation || nodesType && type !== nodesType || filter && !filter(node)) {
|
|
931
|
-
continue;
|
|
932
|
-
}
|
|
933
|
-
this._dispatcher.currentExtension = id;
|
|
934
|
-
this._dispatcher.stateIndex = 0;
|
|
935
|
-
BuilderInternal.currentDispatcher = this._dispatcher;
|
|
936
|
-
try {
|
|
937
|
-
nodes.push(...connector({
|
|
938
|
-
node
|
|
939
|
-
}) ?? []);
|
|
940
|
-
} catch (err) {
|
|
941
|
-
import_log2.log.catch(err, {
|
|
942
|
-
extension: id
|
|
943
|
-
}, {
|
|
944
|
-
F: __dxlog_file2,
|
|
945
|
-
L: 421,
|
|
946
|
-
S: this,
|
|
947
|
-
C: (f, a) => f(...a)
|
|
948
|
-
});
|
|
949
|
-
import_log2.log.error(`Previous error occurred in extension: ${id}`, void 0, {
|
|
950
|
-
F: __dxlog_file2,
|
|
951
|
-
L: 422,
|
|
952
|
-
S: this,
|
|
953
|
-
C: (f, a) => f(...a)
|
|
954
|
-
});
|
|
955
|
-
} finally {
|
|
956
|
-
BuilderInternal.currentDispatcher = void 0;
|
|
957
|
-
}
|
|
958
|
-
}
|
|
680
|
+
const cancel = this._registry.subscribe(connectors, (nodes) => {
|
|
959
681
|
const ids = nodes.map((n) => n.id);
|
|
960
|
-
const removed = previous.filter((
|
|
682
|
+
const removed = previous.filter((id2) => !ids.includes(id2));
|
|
961
683
|
previous = ids;
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
target: node.id
|
|
973
|
-
}));
|
|
974
|
-
this.graph._sortEdges(node.id, nodesRelation, nodes.map(({ id }) => id));
|
|
975
|
-
nodes.forEach((n) => {
|
|
976
|
-
if (this._nodeChanged[n.id]) {
|
|
977
|
-
this._nodeChanged[n.id].value = {};
|
|
978
|
-
}
|
|
684
|
+
(0, import_log2.log)("update", {
|
|
685
|
+
id,
|
|
686
|
+
relation,
|
|
687
|
+
ids,
|
|
688
|
+
removed
|
|
689
|
+
}, {
|
|
690
|
+
F: __dxlog_file2,
|
|
691
|
+
L: 287,
|
|
692
|
+
S: this,
|
|
693
|
+
C: (f, a) => f(...a)
|
|
979
694
|
});
|
|
980
|
-
|
|
695
|
+
import_rx_react2.Rx.batch(() => {
|
|
696
|
+
this._graph.removeEdges(removed.map((target) => ({
|
|
697
|
+
source: id,
|
|
698
|
+
target
|
|
699
|
+
})), true);
|
|
700
|
+
this._graph.addNodes(nodes);
|
|
701
|
+
this._graph.addEdges(nodes.map((node) => relation === "outbound" ? {
|
|
702
|
+
source: id,
|
|
703
|
+
target: node.id
|
|
704
|
+
} : {
|
|
705
|
+
source: node.id,
|
|
706
|
+
target: id
|
|
707
|
+
}));
|
|
708
|
+
this._graph.sortEdges(id, relation, nodes.map(({ id: id2 }) => id2));
|
|
709
|
+
});
|
|
710
|
+
}, {
|
|
711
|
+
immediate: true
|
|
712
|
+
});
|
|
713
|
+
this._connectorSubscriptions.set(id, cancel);
|
|
981
714
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
715
|
+
// TODO(wittjosiah): On initialize to restore state from cache.
|
|
716
|
+
// private async _onInitialize(id: string) {
|
|
717
|
+
// log('onInitialize', { id });
|
|
718
|
+
// }
|
|
719
|
+
_onRemoveNode(id) {
|
|
720
|
+
this._connectorSubscriptions.get(id)?.();
|
|
721
|
+
this._connectorSubscriptions.delete(id);
|
|
987
722
|
}
|
|
988
723
|
};
|
|
724
|
+
var rxFromSignal = (cb) => {
|
|
725
|
+
return import_rx_react2.Rx.make((get) => {
|
|
726
|
+
const dispose = (0, import_signals_core.effect)(() => {
|
|
727
|
+
get.setSelf(cb());
|
|
728
|
+
});
|
|
729
|
+
get.addFinalizer(() => dispose());
|
|
730
|
+
return cb();
|
|
731
|
+
});
|
|
732
|
+
};
|
|
733
|
+
var observableFamily = import_rx_react2.Rx.family((observable) => {
|
|
734
|
+
return import_rx_react2.Rx.make((get) => {
|
|
735
|
+
const subscription = observable.subscribe((value) => get.setSelf(value));
|
|
736
|
+
get.addFinalizer(() => subscription.unsubscribe());
|
|
737
|
+
return observable.get();
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
var rxFromObservable = (observable) => {
|
|
741
|
+
return observableFamily(observable);
|
|
742
|
+
};
|
|
989
743
|
// Annotate the CommonJS export names for ESM import in node:
|
|
990
744
|
0 && (module.exports = {
|
|
991
745
|
ACTION_GROUP_TYPE,
|
|
@@ -995,7 +749,6 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
995
749
|
ROOT_ID,
|
|
996
750
|
ROOT_TYPE,
|
|
997
751
|
actionGroupSymbol,
|
|
998
|
-
cleanup,
|
|
999
752
|
createExtension,
|
|
1000
753
|
flattenExtensions,
|
|
1001
754
|
getGraph,
|
|
@@ -1003,7 +756,7 @@ var GraphBuilder = class _GraphBuilder {
|
|
|
1003
756
|
isActionGroup,
|
|
1004
757
|
isActionLike,
|
|
1005
758
|
isGraphNode,
|
|
1006
|
-
|
|
1007
|
-
|
|
759
|
+
rxFromObservable,
|
|
760
|
+
rxFromSignal
|
|
1008
761
|
});
|
|
1009
762
|
//# sourceMappingURL=index.cjs.map
|