@typeonce/effect-machine 0.3.0 → 0.4.0
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/README.md +203 -16
- package/dist/Machine.d.ts +784 -289
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +158 -528
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/activities.d.ts +57 -0
- package/dist/internal/machine/activities.d.ts.map +1 -0
- package/dist/internal/machine/activities.js +49 -0
- package/dist/internal/machine/activities.js.map +1 -0
- package/dist/internal/machine/atom.d.ts +69 -0
- package/dist/internal/machine/atom.d.ts.map +1 -0
- package/dist/{AtomMachine.js → internal/machine/atom.js} +19 -94
- package/dist/internal/machine/atom.js.map +1 -0
- package/dist/internal/machine/cluster.d.ts +63 -0
- package/dist/internal/machine/cluster.d.ts.map +1 -0
- package/dist/{ClusterMachine.js → internal/machine/cluster.js} +14 -118
- package/dist/internal/machine/cluster.js.map +1 -0
- package/dist/internal/machine/command.d.ts +16 -0
- package/dist/internal/machine/command.d.ts.map +1 -0
- package/dist/internal/machine/command.js +45 -0
- package/dist/internal/machine/command.js.map +1 -0
- package/dist/internal/machine/commandRuntime.d.ts +13 -0
- package/dist/internal/machine/commandRuntime.d.ts.map +1 -0
- package/dist/internal/machine/commandRuntime.js +16 -0
- package/dist/internal/machine/commandRuntime.js.map +1 -0
- package/dist/internal/{machineModel.d.ts → machine/configuration.d.ts} +11 -60
- package/dist/internal/machine/configuration.d.ts.map +1 -0
- package/dist/internal/{machineModel.js → machine/configuration.js} +249 -544
- package/dist/internal/machine/configuration.js.map +1 -0
- package/dist/internal/{machineErrors.d.ts → machine/errors.d.ts} +1 -1
- package/dist/internal/machine/errors.d.ts.map +1 -0
- package/dist/internal/{machineErrors.js → machine/errors.js} +1 -1
- package/dist/internal/machine/errors.js.map +1 -0
- package/dist/internal/machine/executionPlan.d.ts +49 -0
- package/dist/internal/machine/executionPlan.d.ts.map +1 -0
- package/dist/internal/machine/executionPlan.js +667 -0
- package/dist/internal/machine/executionPlan.js.map +1 -0
- package/dist/internal/machine/invocation.d.ts +23 -0
- package/dist/internal/machine/invocation.d.ts.map +1 -0
- package/dist/internal/machine/invocation.js +77 -0
- package/dist/internal/machine/invocation.js.map +1 -0
- package/dist/internal/machine/machine.d.ts +183 -0
- package/dist/internal/machine/machine.d.ts.map +1 -0
- package/dist/internal/machine/machine.js +552 -0
- package/dist/internal/machine/machine.js.map +1 -0
- package/dist/internal/machine/planner.d.ts +182 -0
- package/dist/internal/machine/planner.d.ts.map +1 -0
- package/dist/internal/machine/planner.js +1082 -0
- package/dist/internal/machine/planner.js.map +1 -0
- package/dist/internal/{machineProcess.d.ts → machine/process.d.ts} +10 -4
- package/dist/internal/machine/process.d.ts.map +1 -0
- package/dist/internal/machine/process.js +446 -0
- package/dist/internal/machine/process.js.map +1 -0
- package/dist/internal/machine/protocol.d.ts +34 -0
- package/dist/internal/machine/protocol.d.ts.map +1 -0
- package/dist/internal/machine/protocol.js +182 -0
- package/dist/internal/machine/protocol.js.map +1 -0
- package/dist/internal/machine/readiness.d.ts +4 -0
- package/dist/internal/machine/readiness.d.ts.map +1 -0
- package/dist/internal/machine/readiness.js +2 -0
- package/dist/internal/machine/readiness.js.map +1 -0
- package/dist/internal/{machineRuntime.d.ts → machine/runtime.d.ts} +104 -2
- package/dist/internal/machine/runtime.d.ts.map +1 -0
- package/dist/internal/machine/runtime.js +1381 -0
- package/dist/internal/machine/runtime.js.map +1 -0
- package/dist/internal/machine/serialization.d.ts +14 -0
- package/dist/internal/machine/serialization.d.ts.map +1 -0
- package/dist/internal/machine/serialization.js +338 -0
- package/dist/internal/machine/serialization.js.map +1 -0
- package/dist/internal/machine/stateDefinition.d.ts +15 -0
- package/dist/internal/machine/stateDefinition.d.ts.map +1 -0
- package/dist/internal/machine/stateDefinition.js +210 -0
- package/dist/internal/machine/stateDefinition.js.map +1 -0
- package/dist/internal/machine/symbols.d.ts +3 -0
- package/dist/internal/machine/symbols.d.ts.map +1 -0
- package/dist/internal/machine/symbols.js +3 -0
- package/dist/internal/machine/symbols.js.map +1 -0
- package/dist/internal/machine/topology.d.ts +98 -0
- package/dist/internal/machine/topology.d.ts.map +1 -0
- package/dist/internal/machine/topology.js +347 -0
- package/dist/internal/machine/topology.js.map +1 -0
- package/dist/internal/testing/machine/arbitrary.d.ts +36 -0
- package/dist/internal/testing/machine/arbitrary.d.ts.map +1 -0
- package/dist/internal/testing/machine/arbitrary.js +68 -0
- package/dist/internal/testing/machine/arbitrary.js.map +1 -0
- package/dist/internal/testing/machine/finiteModel.d.ts +322 -0
- package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -0
- package/dist/internal/testing/machine/finiteModel.js +976 -0
- package/dist/internal/testing/machine/finiteModel.js.map +1 -0
- package/dist/internal/testing/machine/referenceModel.d.ts +203 -0
- package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -0
- package/dist/internal/testing/machine/referenceModel.js +1012 -0
- package/dist/internal/testing/machine/referenceModel.js.map +1 -0
- package/dist/internal/testing/machine/runtime.d.ts +328 -0
- package/dist/internal/testing/machine/runtime.d.ts.map +1 -0
- package/dist/internal/testing/machine/runtime.js +437 -0
- package/dist/internal/testing/machine/runtime.js.map +1 -0
- package/dist/internal/testing/machine/verification.d.ts +33 -0
- package/dist/internal/testing/machine/verification.d.ts.map +1 -0
- package/dist/internal/testing/machine/verification.js +1446 -0
- package/dist/internal/testing/machine/verification.js.map +1 -0
- package/dist/testing/MachineTest.d.ts +606 -0
- package/dist/testing/MachineTest.d.ts.map +1 -0
- package/dist/testing/MachineTest.js +102 -0
- package/dist/testing/MachineTest.js.map +1 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/{ClusterMachine.d.ts → unstable/cluster/ClusterMachine.d.ts} +19 -27
- package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -0
- package/dist/unstable/cluster/ClusterMachine.js +126 -0
- package/dist/unstable/cluster/ClusterMachine.js.map +1 -0
- package/dist/{cluster.js → unstable/cluster/index.d.ts} +1 -1
- package/dist/unstable/cluster/index.d.ts.map +1 -0
- package/dist/{cluster.d.ts → unstable/cluster/index.js} +1 -1
- package/dist/unstable/cluster/index.js.map +1 -0
- package/dist/{AtomMachine.d.ts → unstable/reactivity/AtomMachine.d.ts} +35 -20
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -0
- package/dist/unstable/reactivity/AtomMachine.js +113 -0
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -0
- package/dist/{reactivity.js → unstable/reactivity/index.d.ts} +1 -1
- package/dist/unstable/reactivity/index.d.ts.map +1 -0
- package/dist/{reactivity.d.ts → unstable/reactivity/index.js} +1 -1
- package/dist/unstable/reactivity/index.js.map +1 -0
- package/docs/agent-guide.md +169 -31
- package/package.json +19 -10
- package/dist/AtomMachine.d.ts.map +0 -1
- package/dist/AtomMachine.js.map +0 -1
- package/dist/ClusterMachine.d.ts.map +0 -1
- package/dist/ClusterMachine.js.map +0 -1
- package/dist/cluster.d.ts.map +0 -1
- package/dist/cluster.js.map +0 -1
- package/dist/internal/machineErrors.d.ts.map +0 -1
- package/dist/internal/machineErrors.js.map +0 -1
- package/dist/internal/machineModel.d.ts.map +0 -1
- package/dist/internal/machineModel.js.map +0 -1
- package/dist/internal/machinePlanner.d.ts +0 -74
- package/dist/internal/machinePlanner.d.ts.map +0 -1
- package/dist/internal/machinePlanner.js +0 -797
- package/dist/internal/machinePlanner.js.map +0 -1
- package/dist/internal/machineProcess.d.ts.map +0 -1
- package/dist/internal/machineProcess.js +0 -181
- package/dist/internal/machineProcess.js.map +0 -1
- package/dist/internal/machineRuntime.d.ts.map +0 -1
- package/dist/internal/machineRuntime.js +0 -365
- package/dist/internal/machineRuntime.js.map +0 -1
- package/dist/reactivity.d.ts.map +0 -1
- package/dist/reactivity.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Internal
|
|
2
|
+
* Internal active-configuration, history, and completion helpers.
|
|
3
3
|
*
|
|
4
4
|
* @since 4.0.0
|
|
5
5
|
*/
|
|
@@ -7,14 +7,10 @@ import * as Cause from "effect/Cause";
|
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
8
8
|
import * as Option from "effect/Option";
|
|
9
9
|
import { hasProperty } from "effect/Predicate";
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
export const
|
|
14
|
-
export const StateInputTypeId = Symbol("effect/Machine/StateInput");
|
|
15
|
-
export const StateConstructionTypeId = Symbol("effect/Machine/StateConstruction");
|
|
16
|
-
export const HistoryTargetTypeId = Symbol("effect/Machine/HistoryTarget");
|
|
17
|
-
const validateHistoryRecordControl = (machine, record) => {
|
|
10
|
+
import { MachineSchemaDecodeError } from "./errors.js";
|
|
11
|
+
import { decodeBoundary, decodeOutputValue, decodeOutputValueSync, decodeStateValue, decodeStateValueSync } from "./protocol.js";
|
|
12
|
+
import { getNode, getStateNodeSchema, isSnapshot, isTarget, TargetSnapshotTypeId } from "./topology.js";
|
|
13
|
+
export const validateHistoryRecordControl = (machine, record) => {
|
|
18
14
|
const ancestry = new Set(getPathToRoot(machine, record.parent));
|
|
19
15
|
const visit = (path) => {
|
|
20
16
|
const node = getNode(machine, path);
|
|
@@ -62,14 +58,13 @@ const historyFromSnapshot = (machine, snapshot) => {
|
|
|
62
58
|
throw new Error(`Machine snapshot contains invalid remembered state "${activePath}"`);
|
|
63
59
|
}
|
|
64
60
|
const node = getNode(machine, activePath);
|
|
65
|
-
if (node.type === "history" ||
|
|
61
|
+
if (node.type === "history" || node.type === "choice" ||
|
|
66
62
|
!(isPathInSubtree(activePath, historyNode.parent) ||
|
|
67
|
-
getPathToRoot(machine, historyNode.parent).includes(activePath))
|
|
68
|
-
!Schema.is(getStateNodeSchema(node))(entry.values[activePath])) {
|
|
63
|
+
getPathToRoot(machine, historyNode.parent).includes(activePath))) {
|
|
69
64
|
throw new Error(`Machine snapshot contains invalid remembered value for "${activePath}"`);
|
|
70
65
|
}
|
|
71
66
|
active.add(activePath);
|
|
72
|
-
values.set(activePath, entry.values[activePath]);
|
|
67
|
+
values.set(activePath, decodeStateValueSync(machine, node, entry.values[activePath]));
|
|
73
68
|
}
|
|
74
69
|
if (!active.has(historyNode.parent) || Object.keys(entry.values).length !== active.size) {
|
|
75
70
|
throw new Error(`Machine snapshot contains incomplete history record "${path}"`);
|
|
@@ -101,7 +96,7 @@ const historyFromSnapshotEffect = Effect.fnUntraced(function* (machine, snapshot
|
|
|
101
96
|
const values = new Map();
|
|
102
97
|
for (const activePath of entry.active) {
|
|
103
98
|
const node = machine.stateNodes.byPath.get(activePath);
|
|
104
|
-
if (active.has(activePath) || node === undefined || node.type === "history" ||
|
|
99
|
+
if (active.has(activePath) || node === undefined || node.type === "history" || node.type === "choice" ||
|
|
105
100
|
!Object.prototype.hasOwnProperty.call(entry.values, activePath) ||
|
|
106
101
|
!(isPathInSubtree(activePath, historyNode.parent) ||
|
|
107
102
|
getPathToRoot(machine, historyNode.parent).includes(activePath))) {
|
|
@@ -146,251 +141,39 @@ const historyFromSnapshotEffect = Effect.fnUntraced(function* (machine, snapshot
|
|
|
146
141
|
}
|
|
147
142
|
return history;
|
|
148
143
|
});
|
|
149
|
-
const historyToSnapshot = (history) => {
|
|
144
|
+
const historyToSnapshot = (machine, history) => {
|
|
150
145
|
const entries = {};
|
|
151
146
|
for (const [path, record] of history) {
|
|
147
|
+
const active = Array.from(record.active).sort((left, right) => compareDocumentOrder(machine, left, right));
|
|
152
148
|
entries[path] = {
|
|
153
149
|
mode: record.mode,
|
|
154
|
-
active
|
|
155
|
-
values: Object.fromEntries(record.values)
|
|
150
|
+
active,
|
|
151
|
+
values: Object.fromEntries(active.map((path) => [path, record.values.get(path)]))
|
|
156
152
|
};
|
|
157
153
|
}
|
|
158
154
|
return entries;
|
|
159
155
|
};
|
|
160
|
-
|
|
161
|
-
[HistoryTargetTypeId]: HistoryTargetTypeId,
|
|
162
|
-
path,
|
|
163
|
-
parent
|
|
164
|
-
});
|
|
165
|
-
export const isHistoryTarget = (u) => hasProperty(u, HistoryTargetTypeId);
|
|
166
|
-
export const getStateNodeDefinition = (path, definition) => {
|
|
167
|
-
if (!Schema.isSchema(definition) && definition.type === "history") {
|
|
168
|
-
return {
|
|
169
|
-
schema: undefined,
|
|
170
|
-
output: undefined,
|
|
171
|
-
type: "history",
|
|
172
|
-
initial: undefined,
|
|
173
|
-
states: undefined
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
if (Schema.isSchema(definition)) {
|
|
177
|
-
return {
|
|
178
|
-
schema: definition,
|
|
179
|
-
output: undefined,
|
|
180
|
-
type: "atomic",
|
|
181
|
-
initial: undefined,
|
|
182
|
-
states: undefined
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
if (!hasProperty(definition, "schema") || !Schema.isSchema(definition.schema)) {
|
|
186
|
-
throw new Error(`Machine.make expected state "${path}" to be a tagged schema or state node config`);
|
|
187
|
-
}
|
|
188
|
-
if (definition.type === "parallel" && !hasProperty(definition, "states")) {
|
|
189
|
-
throw new Error(`Machine.make expected parallel state "${path}" to declare child regions`);
|
|
190
|
-
}
|
|
191
|
-
if (hasProperty(definition, "states")) {
|
|
192
|
-
if (definition.type === "final") {
|
|
193
|
-
throw new Error(`Machine.make expected compound state "${path}" to be active`);
|
|
194
|
-
}
|
|
195
|
-
if (definition.type === "parallel") {
|
|
196
|
-
return {
|
|
197
|
-
schema: definition.schema,
|
|
198
|
-
output: Schema.isSchema(definition.output) ? definition.output : undefined,
|
|
199
|
-
type: "parallel",
|
|
200
|
-
initial: undefined,
|
|
201
|
-
states: definition.states
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
if (typeof definition.initial !== "string") {
|
|
205
|
-
throw new Error(`Machine.make expected compound state "${path}" to declare an initial child`);
|
|
206
|
-
}
|
|
207
|
-
return {
|
|
208
|
-
schema: definition.schema,
|
|
209
|
-
output: undefined,
|
|
210
|
-
type: "compound",
|
|
211
|
-
initial: definition.initial,
|
|
212
|
-
states: definition.states
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
schema: definition.schema,
|
|
217
|
-
output: Schema.isSchema(definition.output) ? definition.output : undefined,
|
|
218
|
-
type: definition.type === "final" ? "final" : "atomic",
|
|
219
|
-
initial: undefined,
|
|
220
|
-
states: undefined
|
|
221
|
-
};
|
|
222
|
-
};
|
|
223
|
-
export const compileStateNodes = (states) => {
|
|
224
|
-
const byPath = new Map();
|
|
225
|
-
let order = 0;
|
|
226
|
-
const compile = (tree, parent) => {
|
|
227
|
-
const paths = [];
|
|
228
|
-
for (const key of Object.keys(tree)) {
|
|
229
|
-
if (key.includes(".")) {
|
|
230
|
-
throw new Error(`Machine state keys cannot contain ".": "${key}"`);
|
|
231
|
-
}
|
|
232
|
-
const path = parent === undefined ? key : `${parent}.${key}`;
|
|
233
|
-
const definition = getStateNodeDefinition(path, tree[key]);
|
|
234
|
-
const node = {
|
|
235
|
-
path,
|
|
236
|
-
key,
|
|
237
|
-
schema: definition.schema,
|
|
238
|
-
output: definition.output,
|
|
239
|
-
type: definition.type,
|
|
240
|
-
parent,
|
|
241
|
-
children: [],
|
|
242
|
-
initial: definition.initial === undefined ? undefined : `${path}.${definition.initial}`,
|
|
243
|
-
history: definition.type === "history"
|
|
244
|
-
? (tree[key].history === "deep" ? "deep" : "shallow")
|
|
245
|
-
: undefined,
|
|
246
|
-
order
|
|
247
|
-
};
|
|
248
|
-
byPath.set(path, node);
|
|
249
|
-
order += 1;
|
|
250
|
-
if (definition.type === "history") {
|
|
251
|
-
if (parent === undefined) {
|
|
252
|
-
throw new Error(`Machine history state "${path}" must belong to a parent state`);
|
|
253
|
-
}
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
paths.push(path);
|
|
257
|
-
if (definition.states !== undefined) {
|
|
258
|
-
const children = compile(definition.states, path);
|
|
259
|
-
if (node.type === "compound" && (node.initial === undefined || !children.includes(node.initial))) {
|
|
260
|
-
throw new Error(`Machine.make expected compound state "${path}" initial child to exist`);
|
|
261
|
-
}
|
|
262
|
-
;
|
|
263
|
-
node.children = children;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return paths;
|
|
267
|
-
};
|
|
268
|
-
return {
|
|
269
|
-
byPath,
|
|
270
|
-
roots: compile(states, undefined)
|
|
271
|
-
};
|
|
272
|
-
};
|
|
273
|
-
export const makeTarget = (path, value, options) => ({
|
|
274
|
-
[TargetTypeId]: TargetTypeId,
|
|
275
|
-
[TargetSnapshotTypeId]: options?.snapshot,
|
|
276
|
-
path,
|
|
277
|
-
value,
|
|
278
|
-
values: options?.values
|
|
279
|
-
});
|
|
280
|
-
export const isTarget = (u) => hasProperty(u, TargetTypeId);
|
|
281
|
-
export const makeStateInput = (input) => ({
|
|
282
|
-
[StateInputTypeId]: StateInputTypeId,
|
|
283
|
-
input
|
|
284
|
-
});
|
|
285
|
-
const isStateInput = (u) => hasProperty(u, StateInputTypeId);
|
|
286
|
-
export const markStateConstruction = (value) => {
|
|
287
|
-
if ((typeof value === "object" && value !== null) || typeof value === "function") {
|
|
288
|
-
Object.defineProperty(value, StateConstructionTypeId, {
|
|
289
|
-
value: StateConstructionTypeId,
|
|
290
|
-
enumerable: false
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
return value;
|
|
294
|
-
};
|
|
295
|
-
export const isStateConstruction = (u) => hasProperty(u, StateConstructionTypeId);
|
|
296
|
-
export const isSnapshot = (u) => hasProperty(u, "path") && hasProperty(u, "value");
|
|
297
|
-
export const getSnapshotByPath = (snapshot, path, parents) => {
|
|
298
|
-
if (snapshot.path === path) {
|
|
299
|
-
return Option.some(snapshot);
|
|
300
|
-
}
|
|
301
|
-
if (!path.startsWith(`${snapshot.path}.`)) {
|
|
302
|
-
return Option.none();
|
|
303
|
-
}
|
|
304
|
-
if (parents !== undefined) {
|
|
305
|
-
parents[snapshot.path] = snapshot.value;
|
|
306
|
-
}
|
|
307
|
-
if (hasProperty(snapshot, "state") && isSnapshot(snapshot.state)) {
|
|
308
|
-
return getSnapshotByPath(snapshot.state, path, parents);
|
|
309
|
-
}
|
|
310
|
-
if (hasProperty(snapshot, "states") && typeof snapshot.states === "object" && snapshot.states !== null) {
|
|
311
|
-
for (const child of Object.values(snapshot.states)) {
|
|
312
|
-
if (isSnapshot(child)) {
|
|
313
|
-
const result = getSnapshotByPath(child, path, parents);
|
|
314
|
-
if (Option.isSome(result)) {
|
|
315
|
-
return result;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return Option.none();
|
|
321
|
-
};
|
|
322
|
-
const MachineProtocolTypeId = Symbol.for("effect/Machine/protocol");
|
|
323
|
-
const getProtocolSchemas = (machine) => {
|
|
324
|
-
const protocol = machine[MachineProtocolTypeId];
|
|
325
|
-
if (protocol === undefined) {
|
|
326
|
-
throw new Error("Machine protocol is unavailable");
|
|
327
|
-
}
|
|
328
|
-
return protocol;
|
|
329
|
-
};
|
|
330
|
-
const setProtocolSchemas = (machine, protocol) => {
|
|
331
|
-
Object.defineProperty(machine, MachineProtocolTypeId, {
|
|
332
|
-
value: protocol,
|
|
333
|
-
enumerable: false
|
|
334
|
-
});
|
|
335
|
-
};
|
|
336
|
-
export const setProtocol = (machine) => {
|
|
337
|
-
setProtocolSchemas(machine, {
|
|
338
|
-
event: Schema.Union([...machine.events, ...machine.internalEvents]),
|
|
339
|
-
emit: Schema.Union(machine.emits)
|
|
340
|
-
});
|
|
341
|
-
};
|
|
342
|
-
export const copyProtocol = (source, target) => setProtocolSchemas(target, getProtocolSchemas(source));
|
|
343
|
-
export const getEventName = (event) => hasProperty(event, "_tag") ? String(event._tag) : undefined;
|
|
344
|
-
export const decodeBoundary = (machine, schema, value, options) => Schema.decodeUnknownEffect(Schema.toType(schema))(value).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
|
|
345
|
-
machineId: machine.id,
|
|
346
|
-
boundary: options.boundary,
|
|
347
|
-
cause,
|
|
348
|
-
...(options.state === undefined ? {} : { state: options.state }),
|
|
349
|
-
...(options.event === undefined ? {} : { event: options.event })
|
|
350
|
-
})));
|
|
351
|
-
export const decodeInput = (machine, schema, value) => decodeBoundary(machine, schema, value, { boundary: "input" });
|
|
352
|
-
export const decodeEvent = (machine, event) => {
|
|
353
|
-
const eventName = getEventName(event);
|
|
354
|
-
return decodeBoundary(machine, getProtocolSchemas(machine).event, event, eventName === undefined ? { boundary: "event" } : { boundary: "event", event: eventName });
|
|
355
|
-
};
|
|
356
|
-
export const decodeEmit = (machine, event) => {
|
|
357
|
-
const eventName = getEventName(event);
|
|
358
|
-
return decodeBoundary(machine, getProtocolSchemas(machine).emit, event, eventName === undefined ? { boundary: "emit" } : { boundary: "emit", event: eventName });
|
|
359
|
-
};
|
|
360
|
-
export const decodeStateValue = (machine, node, value) => isStateInput(value)
|
|
361
|
-
? getStateNodeSchema(node).makeEffect(value.input).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
|
|
362
|
-
machineId: machine.id,
|
|
363
|
-
boundary: "state",
|
|
364
|
-
state: node.path,
|
|
365
|
-
cause
|
|
366
|
-
})))
|
|
367
|
-
: decodeBoundary(machine, getStateNodeSchema(node), value, { boundary: "state", state: node.path });
|
|
368
|
-
export const decodeOutputValue = (machine, node, value) => node.output === undefined
|
|
369
|
-
? Effect.succeed(value)
|
|
370
|
-
: decodeBoundary(machine, node.output, value, { boundary: "output", state: node.path });
|
|
371
|
-
export const getNode = (machine, path) => {
|
|
372
|
-
const node = machine.stateNodes.byPath.get(path);
|
|
373
|
-
if (node === undefined) {
|
|
374
|
-
throw new Error(`Machine expected state path "${path}" to exist`);
|
|
375
|
-
}
|
|
376
|
-
return node;
|
|
377
|
-
};
|
|
378
|
-
export const getStateNodeSchema = (node) => {
|
|
379
|
-
if (node.schema === undefined || node.type === "history") {
|
|
380
|
-
throw new Error(`Machine history state "${node.path}" has no active value schema`);
|
|
381
|
-
}
|
|
382
|
-
return node.schema;
|
|
383
|
-
};
|
|
156
|
+
const pathToRootCache = new WeakMap();
|
|
384
157
|
export const hasOwn = (u, key) => Object.prototype.hasOwnProperty.call(u, key);
|
|
385
158
|
export const isDescendantOf = (path, ancestor) => path.startsWith(`${ancestor}.`);
|
|
386
159
|
export const isPathInSubtree = (path, ancestor) => path === ancestor || isDescendantOf(path, ancestor);
|
|
387
160
|
export const getPathToRoot = (machine, path) => {
|
|
161
|
+
let pathsByLeaf = pathToRootCache.get(machine.stateNodes);
|
|
162
|
+
if (pathsByLeaf === undefined) {
|
|
163
|
+
pathsByLeaf = new Map();
|
|
164
|
+
pathToRootCache.set(machine.stateNodes, pathsByLeaf);
|
|
165
|
+
}
|
|
166
|
+
const cached = pathsByLeaf.get(path);
|
|
167
|
+
if (cached !== undefined) {
|
|
168
|
+
return cached;
|
|
169
|
+
}
|
|
388
170
|
const paths = [];
|
|
389
171
|
let current = path;
|
|
390
172
|
while (current !== undefined) {
|
|
391
173
|
paths.unshift(current);
|
|
392
174
|
current = getNode(machine, current).parent;
|
|
393
175
|
}
|
|
176
|
+
pathsByLeaf.set(path, paths);
|
|
394
177
|
return paths;
|
|
395
178
|
};
|
|
396
179
|
export const pathDepth = (machine, path) => getPathToRoot(machine, path).length;
|
|
@@ -489,7 +272,7 @@ export const snapshotFromConfiguration = (machine, configuration) => {
|
|
|
489
272
|
snapshot.completed = completed;
|
|
490
273
|
}
|
|
491
274
|
if (configuration.history.size > 0) {
|
|
492
|
-
Object.assign(snapshot, { history: historyToSnapshot(configuration.history) });
|
|
275
|
+
Object.assign(snapshot, { history: historyToSnapshot(machine, configuration.history) });
|
|
493
276
|
}
|
|
494
277
|
return snapshot;
|
|
495
278
|
};
|
|
@@ -499,7 +282,7 @@ export const snapshotFromConfiguration = (machine, configuration) => {
|
|
|
499
282
|
export const snapshotFromConfigurationAtPath = (machine, configuration, path) => {
|
|
500
283
|
const snapshot = snapshotFromPath(machine, configuration, path);
|
|
501
284
|
if (configuration.history.size > 0) {
|
|
502
|
-
Object.assign(snapshot, { history: historyToSnapshot(configuration.history) });
|
|
285
|
+
Object.assign(snapshot, { history: historyToSnapshot(machine, configuration.history) });
|
|
503
286
|
}
|
|
504
287
|
return snapshot;
|
|
505
288
|
};
|
|
@@ -509,11 +292,9 @@ export const configurationFromSnapshot = (machine, snapshot) => {
|
|
|
509
292
|
const snapshotOutputs = snapshot.completed;
|
|
510
293
|
const visit = (current) => {
|
|
511
294
|
const node = getNode(machine, String(current.path));
|
|
512
|
-
|
|
513
|
-
throw new Error(`Machine expected snapshot for "${node.path}" to match its schema`);
|
|
514
|
-
}
|
|
295
|
+
const value = decodeStateValueSync(machine, node, current.value);
|
|
515
296
|
active.add(node.path);
|
|
516
|
-
values.set(node.path,
|
|
297
|
+
values.set(node.path, value);
|
|
517
298
|
if (node.type === "compound") {
|
|
518
299
|
if (!hasProperty(current, "state") || !isSnapshot(current.state)) {
|
|
519
300
|
throw new Error(`Machine expected compound snapshot "${node.path}" to include an active child state`);
|
|
@@ -555,6 +336,21 @@ export const configurationFromSnapshot = (machine, snapshot) => {
|
|
|
555
336
|
return { active, values, outputs, history: historyFromSnapshot(machine, snapshot) };
|
|
556
337
|
};
|
|
557
338
|
export const normalizeConfiguration = (machine, state) => configurationFromSnapshot(machine, state);
|
|
339
|
+
export const normalizeConfigurationSync = (machine, state) => {
|
|
340
|
+
try {
|
|
341
|
+
return configurationFromSnapshot(machine, state);
|
|
342
|
+
}
|
|
343
|
+
catch (cause) {
|
|
344
|
+
if (cause instanceof MachineSchemaDecodeError) {
|
|
345
|
+
throw cause;
|
|
346
|
+
}
|
|
347
|
+
throw new MachineSchemaDecodeError({
|
|
348
|
+
machineId: machine.id,
|
|
349
|
+
boundary: "configuration",
|
|
350
|
+
cause: Cause.die(cause)
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
};
|
|
558
354
|
export const configurationFromSnapshotEffect = Effect.fnUntraced(function* (machine, snapshot) {
|
|
559
355
|
const active = new Set();
|
|
560
356
|
const values = new Map();
|
|
@@ -624,7 +420,8 @@ export const validateInitialConfiguration = (machine, configuration) => {
|
|
|
624
420
|
const node = getNode(machine, path);
|
|
625
421
|
if (node.type === "compound") {
|
|
626
422
|
const child = node.children.find((child) => configuration.active.has(child));
|
|
627
|
-
|
|
423
|
+
const initialNode = node.initial === undefined ? undefined : getNode(machine, node.initial);
|
|
424
|
+
if (initialNode?.type === "choice" ? child === undefined : child !== node.initial) {
|
|
628
425
|
throw new Error(`Machine initial state "${node.path}" must enter initial child "${node.initial}"`);
|
|
629
426
|
}
|
|
630
427
|
}
|
|
@@ -794,19 +591,30 @@ export const configurationFromTargetSnapshotEffect = Effect.fnUntraced(function*
|
|
|
794
591
|
const ancestorNode = getNode(machine, ancestor);
|
|
795
592
|
if (ancestorNode.type === "parallel") {
|
|
796
593
|
for (const child of ancestorNode.children) {
|
|
797
|
-
if (pathSet.has(child)
|
|
594
|
+
if (pathSet.has(child))
|
|
798
595
|
continue;
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
596
|
+
if (current.active.has(child)) {
|
|
597
|
+
for (const activePath of current.active) {
|
|
598
|
+
if (isPathInSubtree(activePath, child)) {
|
|
599
|
+
active.add(activePath);
|
|
600
|
+
if (current.values.has(activePath)) {
|
|
601
|
+
values.set(activePath, current.values.get(activePath));
|
|
602
|
+
}
|
|
603
|
+
if (current.outputs.has(activePath)) {
|
|
604
|
+
outputs.set(activePath, current.outputs.get(activePath));
|
|
605
|
+
}
|
|
808
606
|
}
|
|
809
607
|
}
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
if (providedValues !== undefined && hasOwn(providedValues, child)) {
|
|
611
|
+
for (const [providedPath, providedValue] of Object.entries(providedValues)) {
|
|
612
|
+
if (!isPathInSubtree(providedPath, child))
|
|
613
|
+
continue;
|
|
614
|
+
const providedNode = getNode(machine, providedPath);
|
|
615
|
+
active.add(providedPath);
|
|
616
|
+
values.set(providedPath, yield* decodeStateValue(machine, providedNode, providedValue));
|
|
617
|
+
}
|
|
810
618
|
}
|
|
811
619
|
}
|
|
812
620
|
}
|
|
@@ -837,6 +645,126 @@ export const normalizeTargetConfigurationEffect = (machine, current, target) =>
|
|
|
837
645
|
}
|
|
838
646
|
throw new Error("Machine expected transition target to be a snapshot or target builder result");
|
|
839
647
|
};
|
|
648
|
+
const configurationFromTargetPathSync = (machine, current, path, value, providedValues) => {
|
|
649
|
+
const node = getNode(machine, path);
|
|
650
|
+
const active = new Set();
|
|
651
|
+
const values = new Map();
|
|
652
|
+
const outputs = new Map();
|
|
653
|
+
const paths = getPathToRoot(machine, node.path);
|
|
654
|
+
const pathSet = new Set(paths);
|
|
655
|
+
for (const currentPath of paths) {
|
|
656
|
+
const currentNode = getNode(machine, currentPath);
|
|
657
|
+
active.add(currentPath);
|
|
658
|
+
if (currentPath === node.path) {
|
|
659
|
+
values.set(currentPath, decodeStateValueSync(machine, currentNode, value));
|
|
660
|
+
}
|
|
661
|
+
else if (providedValues !== undefined && hasOwn(providedValues, currentPath)) {
|
|
662
|
+
values.set(currentPath, decodeStateValueSync(machine, currentNode, providedValues[currentPath]));
|
|
663
|
+
}
|
|
664
|
+
else if (current.values.has(currentPath)) {
|
|
665
|
+
values.set(currentPath, current.values.get(currentPath));
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
throw new Error(`Machine target "${node.path}" requires a value for ancestor state "${currentPath}"`);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
for (const ancestor of paths) {
|
|
672
|
+
const ancestorNode = getNode(machine, ancestor);
|
|
673
|
+
if (ancestorNode.type !== "parallel")
|
|
674
|
+
continue;
|
|
675
|
+
for (const child of ancestorNode.children) {
|
|
676
|
+
if (pathSet.has(child) || !current.active.has(child))
|
|
677
|
+
continue;
|
|
678
|
+
for (const activePath of current.active) {
|
|
679
|
+
if (!isPathInSubtree(activePath, child))
|
|
680
|
+
continue;
|
|
681
|
+
active.add(activePath);
|
|
682
|
+
if (current.values.has(activePath))
|
|
683
|
+
values.set(activePath, current.values.get(activePath));
|
|
684
|
+
if (current.outputs.has(activePath))
|
|
685
|
+
outputs.set(activePath, current.outputs.get(activePath));
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if (node.type === "compound" || node.type === "parallel") {
|
|
690
|
+
throw new Error(`Machine target "${node.path}" must include an active child state`);
|
|
691
|
+
}
|
|
692
|
+
return { active, values, outputs, history: current.history };
|
|
693
|
+
};
|
|
694
|
+
const configurationFromTargetSnapshotSync = (machine, current, snapshot, providedValues) => {
|
|
695
|
+
const subtree = configurationFromSnapshot(machine, snapshot);
|
|
696
|
+
const active = new Set(subtree.active);
|
|
697
|
+
const values = new Map(subtree.values);
|
|
698
|
+
const outputs = new Map(subtree.outputs);
|
|
699
|
+
const paths = getPathToRoot(machine, String(snapshot.path));
|
|
700
|
+
const pathSet = new Set(paths);
|
|
701
|
+
for (const ancestor of paths.slice(0, -1)) {
|
|
702
|
+
const node = getNode(machine, ancestor);
|
|
703
|
+
active.add(ancestor);
|
|
704
|
+
if (providedValues !== undefined && hasOwn(providedValues, ancestor)) {
|
|
705
|
+
values.set(ancestor, decodeStateValueSync(machine, node, providedValues[ancestor]));
|
|
706
|
+
}
|
|
707
|
+
else if (current.values.has(ancestor)) {
|
|
708
|
+
values.set(ancestor, current.values.get(ancestor));
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
throw new Error(`Machine target "${snapshot.path}" requires a value for ancestor state "${ancestor}"`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
for (const ancestor of paths.slice(0, -1)) {
|
|
715
|
+
const ancestorNode = getNode(machine, ancestor);
|
|
716
|
+
if (ancestorNode.type !== "parallel")
|
|
717
|
+
continue;
|
|
718
|
+
for (const child of ancestorNode.children) {
|
|
719
|
+
if (pathSet.has(child))
|
|
720
|
+
continue;
|
|
721
|
+
if (current.active.has(child)) {
|
|
722
|
+
for (const activePath of current.active) {
|
|
723
|
+
if (!isPathInSubtree(activePath, child))
|
|
724
|
+
continue;
|
|
725
|
+
active.add(activePath);
|
|
726
|
+
if (current.values.has(activePath))
|
|
727
|
+
values.set(activePath, current.values.get(activePath));
|
|
728
|
+
if (current.outputs.has(activePath))
|
|
729
|
+
outputs.set(activePath, current.outputs.get(activePath));
|
|
730
|
+
}
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (providedValues !== undefined && hasOwn(providedValues, child)) {
|
|
734
|
+
for (const [providedPath, providedValue] of Object.entries(providedValues)) {
|
|
735
|
+
if (!isPathInSubtree(providedPath, child))
|
|
736
|
+
continue;
|
|
737
|
+
const providedNode = getNode(machine, providedPath);
|
|
738
|
+
active.add(providedPath);
|
|
739
|
+
values.set(providedPath, decodeStateValueSync(machine, providedNode, providedValue));
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return {
|
|
745
|
+
active,
|
|
746
|
+
values,
|
|
747
|
+
outputs,
|
|
748
|
+
history: new Map([...current.history, ...subtree.history])
|
|
749
|
+
};
|
|
750
|
+
};
|
|
751
|
+
export const normalizeTargetConfigurationSync = (machine, current, target) => {
|
|
752
|
+
if (isTarget(target)) {
|
|
753
|
+
const snapshot = target[TargetSnapshotTypeId];
|
|
754
|
+
if (snapshot !== undefined) {
|
|
755
|
+
if (String(snapshot.path) !== String(target.path)) {
|
|
756
|
+
throw new Error(`Machine expected target snapshot path to be "${target.path}"`);
|
|
757
|
+
}
|
|
758
|
+
return configurationFromTargetSnapshotSync(machine, current, snapshot, target.values);
|
|
759
|
+
}
|
|
760
|
+
return configurationFromTargetPathSync(machine, current, target.path, target.value, target.values);
|
|
761
|
+
}
|
|
762
|
+
if (isSnapshot(target)) {
|
|
763
|
+
const configuration = normalizeConfigurationSync(machine, target);
|
|
764
|
+
return { ...configuration, history: new Map([...current.history, ...configuration.history]) };
|
|
765
|
+
}
|
|
766
|
+
throw new Error("Machine expected transition target to be a snapshot or target builder result");
|
|
767
|
+
};
|
|
840
768
|
export const getStateConfigByPath = (machine, path) => machine.handlers[path];
|
|
841
769
|
export const getActiveChildPath = (machine, configuration, path) => getNode(machine, path).children.find((child) => configuration.active.has(child));
|
|
842
770
|
export const isDirectFinalPath = (machine, path) => getNode(machine, path).type === "final";
|
|
@@ -964,297 +892,74 @@ export const completeConfigurationEffect = Effect.fnUntraced(function* (machine,
|
|
|
964
892
|
}
|
|
965
893
|
return { configuration: completed, completions };
|
|
966
894
|
});
|
|
967
|
-
const
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
983
|
-
const encodeBoundary = (machine, schema, value, options) => Schema.encodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new MachineSchemaEncodeError({
|
|
984
|
-
machineId: machine.id,
|
|
985
|
-
boundary: options.boundary,
|
|
986
|
-
state: options.state,
|
|
987
|
-
cause
|
|
988
|
-
})));
|
|
989
|
-
const decodeEncodedBoundary = (machine, schema, value, options) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
|
|
990
|
-
machineId: machine.id,
|
|
991
|
-
boundary: options.boundary,
|
|
992
|
-
state: options.state,
|
|
993
|
-
cause
|
|
994
|
-
})));
|
|
995
|
-
const getCompletionSchema = (machine, configuration, path) => {
|
|
895
|
+
const resolveFinalOutputSync = (machine, configuration, path, event, outputs) => {
|
|
896
|
+
const node = getNode(machine, path);
|
|
897
|
+
const output = getStateConfigByPath(machine, path)?.output?.({
|
|
898
|
+
state: getActiveValue(configuration, path),
|
|
899
|
+
parent: getParentValue(machine, configuration, path),
|
|
900
|
+
parents: getParentValues(machine, configuration, path),
|
|
901
|
+
event,
|
|
902
|
+
outputs
|
|
903
|
+
});
|
|
904
|
+
return decodeOutputValueSync(machine, node, output);
|
|
905
|
+
};
|
|
906
|
+
const completeActiveFinalNodeSync = (machine, configuration, path, event, outputs, completions) => {
|
|
907
|
+
if (!configuration.active.has(path))
|
|
908
|
+
return undefined;
|
|
909
|
+
if (outputs.has(path))
|
|
910
|
+
return { path, output: outputs.get(path), isNew: false };
|
|
996
911
|
const node = getNode(machine, path);
|
|
997
912
|
if (node.type === "compound") {
|
|
998
913
|
const child = getActiveChildPath(machine, configuration, path);
|
|
999
|
-
if (child === undefined)
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
const normalized = configurationFromSnapshot(machine, snapshot);
|
|
1009
|
-
if (normalized.active.size !== configuration.active.size ||
|
|
1010
|
-
Array.from(configuration.active).some((path) => !normalized.active.has(path))) {
|
|
1011
|
-
throw new Error("Machine encoded snapshot contains states outside its active configuration");
|
|
1012
|
-
}
|
|
1013
|
-
return snapshot;
|
|
1014
|
-
};
|
|
1015
|
-
const failEncodeCause = (machine, cause) => {
|
|
1016
|
-
const error = Cause.findErrorOption(cause);
|
|
1017
|
-
return Option.isSome(error) && error.value instanceof MachineSchemaEncodeError
|
|
1018
|
-
? Effect.fail(error.value)
|
|
1019
|
-
: Effect.fail(new MachineSchemaEncodeError({
|
|
1020
|
-
machineId: machine.id,
|
|
1021
|
-
boundary: "configuration",
|
|
1022
|
-
cause
|
|
1023
|
-
}));
|
|
1024
|
-
};
|
|
1025
|
-
const failDecodeCause = (machine, cause) => {
|
|
1026
|
-
const error = Cause.findErrorOption(cause);
|
|
1027
|
-
return Option.isSome(error) && error.value instanceof MachineSchemaDecodeError
|
|
1028
|
-
? Effect.fail(error.value)
|
|
1029
|
-
: Effect.fail(new MachineSchemaDecodeError({
|
|
1030
|
-
machineId: machine.id,
|
|
1031
|
-
boundary: "configuration",
|
|
1032
|
-
cause
|
|
1033
|
-
}));
|
|
1034
|
-
};
|
|
1035
|
-
export const encodeSnapshot = (machine, snapshot) => Effect.gen(function* () {
|
|
1036
|
-
const configuration = yield* normalizeConfigurationEffect(machine, snapshot).pipe(Effect.mapError((error) => new MachineSchemaEncodeError({
|
|
1037
|
-
machineId: machine.id,
|
|
1038
|
-
boundary: error.boundary === "state" || error.boundary === "history" ? error.boundary : "configuration",
|
|
1039
|
-
...(error.state === undefined ? {} : { state: error.state }),
|
|
1040
|
-
cause: error.cause
|
|
1041
|
-
})));
|
|
1042
|
-
const completionPaths = new Set();
|
|
1043
|
-
for (const completion of snapshot.completed ?? []) {
|
|
1044
|
-
if (completionPaths.has(completion.path)) {
|
|
1045
|
-
throw new Error(`Machine snapshot contains duplicate completion "${completion.path}"`);
|
|
1046
|
-
}
|
|
1047
|
-
if (!configuration.active.has(completion.path) || !isActiveFinalNode(machine, configuration, completion.path)) {
|
|
1048
|
-
throw new Error(`Machine snapshot contains invalid completion "${completion.path}"`);
|
|
1049
|
-
}
|
|
1050
|
-
completionPaths.add(completion.path);
|
|
1051
|
-
}
|
|
1052
|
-
const active = [];
|
|
1053
|
-
for (const path of Array.from(configuration.active).sort((left, right) => compareDocumentOrder(machine, left, right))) {
|
|
1054
|
-
const node = getNode(machine, path);
|
|
1055
|
-
active.push({
|
|
1056
|
-
path,
|
|
1057
|
-
value: yield* encodeBoundary(machine, getStateNodeSchema(node), getActiveValue(configuration, path), {
|
|
1058
|
-
boundary: "state",
|
|
1059
|
-
state: path
|
|
1060
|
-
})
|
|
1061
|
-
});
|
|
1062
|
-
}
|
|
1063
|
-
const completed = [];
|
|
1064
|
-
for (const [path, output] of Array.from(configuration.outputs).sort(([left], [right]) => compareDocumentOrder(machine, left, right))) {
|
|
1065
|
-
if (!configuration.active.has(path) || !isActiveFinalNode(machine, configuration, path)) {
|
|
1066
|
-
throw new Error(`Machine encoded snapshot contains invalid completion "${path}"`);
|
|
1067
|
-
}
|
|
1068
|
-
const encodedOutput = yield* encodeBoundary(machine, getCompletionSchema(machine, configuration, path), output, {
|
|
1069
|
-
boundary: "output",
|
|
1070
|
-
state: path
|
|
1071
|
-
});
|
|
1072
|
-
completed.push({
|
|
1073
|
-
path,
|
|
1074
|
-
...(encodedOutput === undefined ? {} : { output: encodedOutput })
|
|
1075
|
-
});
|
|
1076
|
-
}
|
|
1077
|
-
const history = {};
|
|
1078
|
-
for (const [historyPath, record] of Array.from(configuration.history).sort(([left], [right]) => left.localeCompare(right))) {
|
|
1079
|
-
const historyNode = machine.stateNodes.byPath.get(historyPath);
|
|
1080
|
-
if (historyNode === undefined || historyNode.type !== "history" || historyNode.parent !== record.parent ||
|
|
1081
|
-
historyNode.history !== record.mode) {
|
|
1082
|
-
return yield* Effect.fail(new MachineSchemaEncodeError({
|
|
1083
|
-
machineId: machine.id,
|
|
1084
|
-
boundary: "history",
|
|
1085
|
-
state: historyPath,
|
|
1086
|
-
cause: Cause.die(new Error(`Machine snapshot contains invalid history record "${historyPath}"`))
|
|
1087
|
-
}));
|
|
1088
|
-
}
|
|
1089
|
-
try {
|
|
1090
|
-
validateHistoryRecordControl(machine, record);
|
|
1091
|
-
}
|
|
1092
|
-
catch (cause) {
|
|
1093
|
-
return yield* Effect.fail(new MachineSchemaEncodeError({
|
|
1094
|
-
machineId: machine.id,
|
|
1095
|
-
boundary: "history",
|
|
1096
|
-
state: historyPath,
|
|
1097
|
-
cause: Cause.die(cause)
|
|
1098
|
-
}));
|
|
1099
|
-
}
|
|
1100
|
-
const encodedValues = {};
|
|
1101
|
-
for (const path of record.active) {
|
|
1102
|
-
const stateNode = machine.stateNodes.byPath.get(path);
|
|
1103
|
-
if (stateNode === undefined || stateNode.type === "history" || !record.values.has(path) ||
|
|
1104
|
-
!(isPathInSubtree(path, record.parent) || getPathToRoot(machine, record.parent).includes(path))) {
|
|
1105
|
-
return yield* Effect.fail(new MachineSchemaEncodeError({
|
|
1106
|
-
machineId: machine.id,
|
|
1107
|
-
boundary: "history",
|
|
1108
|
-
state: path,
|
|
1109
|
-
cause: Cause.die(new Error(`Machine snapshot contains invalid remembered state "${path}"`))
|
|
1110
|
-
}));
|
|
1111
|
-
}
|
|
1112
|
-
encodedValues[path] = yield* encodeBoundary(machine, getStateNodeSchema(stateNode), record.values.get(path), { boundary: "history", state: path });
|
|
1113
|
-
}
|
|
1114
|
-
if (record.values.size !== record.active.size) {
|
|
1115
|
-
return yield* Effect.fail(new MachineSchemaEncodeError({
|
|
1116
|
-
machineId: machine.id,
|
|
1117
|
-
boundary: "history",
|
|
1118
|
-
state: historyPath,
|
|
1119
|
-
cause: Cause.die(new Error(`Machine history record "${historyPath}" contains values outside its paths`))
|
|
1120
|
-
}));
|
|
1121
|
-
}
|
|
1122
|
-
history[historyPath] = {
|
|
1123
|
-
mode: record.mode,
|
|
1124
|
-
active: Array.from(record.active).sort((left, right) => compareDocumentOrder(machine, left, right)),
|
|
1125
|
-
values: encodedValues
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
return {
|
|
1129
|
-
_tag: "MachineSnapshot",
|
|
1130
|
-
active,
|
|
1131
|
-
...(completed.length === 0 ? {} : { completed }),
|
|
1132
|
-
...(Object.keys(history).length === 0 ? {} : { history })
|
|
1133
|
-
};
|
|
1134
|
-
}).pipe(Effect.catchCause((cause) => failEncodeCause(machine, cause)));
|
|
1135
|
-
export const decodeSnapshot = (machine, encoded) => Effect.gen(function* () {
|
|
1136
|
-
const decoded = yield* Schema.decodeUnknownEffect(EncodedSnapshotSchema)(encoded).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
|
|
1137
|
-
machineId: machine.id,
|
|
1138
|
-
boundary: "configuration",
|
|
1139
|
-
cause
|
|
1140
|
-
})));
|
|
1141
|
-
const active = new Set();
|
|
1142
|
-
const values = new Map();
|
|
1143
|
-
for (const entry of decoded.active) {
|
|
1144
|
-
if (active.has(entry.path)) {
|
|
1145
|
-
throw new Error(`Machine encoded snapshot contains duplicate state "${entry.path}"`);
|
|
1146
|
-
}
|
|
1147
|
-
const node = getNode(machine, entry.path);
|
|
1148
|
-
active.add(entry.path);
|
|
1149
|
-
values.set(entry.path, yield* decodeEncodedBoundary(machine, getStateNodeSchema(node), entry.value, {
|
|
1150
|
-
boundary: "state",
|
|
1151
|
-
state: entry.path
|
|
1152
|
-
}));
|
|
914
|
+
if (child === undefined || !isDirectFinalPath(machine, child))
|
|
915
|
+
return undefined;
|
|
916
|
+
const childCompletion = completeActiveFinalNodeSync(machine, configuration, child, event, outputs, completions);
|
|
917
|
+
if (childCompletion === undefined)
|
|
918
|
+
return undefined;
|
|
919
|
+
const completion = setCompletedOutput(outputs, path, childCompletion.output);
|
|
920
|
+
if (completion.isNew)
|
|
921
|
+
completions.push(completion);
|
|
922
|
+
return completion;
|
|
1153
923
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
cause: Cause.die(new Error(`Machine encoded snapshot contains invalid history record "${historyPath}"`))
|
|
1164
|
-
}));
|
|
1165
|
-
}
|
|
1166
|
-
const rememberedActive = new Set();
|
|
1167
|
-
const rememberedValues = new Map();
|
|
1168
|
-
for (const path of encodedRecord.active) {
|
|
1169
|
-
if (rememberedActive.has(path)) {
|
|
1170
|
-
return yield* Effect.fail(new MachineSchemaDecodeError({
|
|
1171
|
-
machineId: machine.id,
|
|
1172
|
-
boundary: "history",
|
|
1173
|
-
state: path,
|
|
1174
|
-
cause: Cause.die(new Error(`Machine encoded history contains duplicate state "${path}"`))
|
|
1175
|
-
}));
|
|
1176
|
-
}
|
|
1177
|
-
const stateNode = machine.stateNodes.byPath.get(path);
|
|
1178
|
-
if (stateNode === undefined || stateNode.type === "history" ||
|
|
1179
|
-
!Object.prototype.hasOwnProperty.call(encodedRecord.values, path) ||
|
|
1180
|
-
!(isPathInSubtree(path, historyNode.parent) || getPathToRoot(machine, historyNode.parent).includes(path))) {
|
|
1181
|
-
return yield* Effect.fail(new MachineSchemaDecodeError({
|
|
1182
|
-
machineId: machine.id,
|
|
1183
|
-
boundary: "history",
|
|
1184
|
-
state: path,
|
|
1185
|
-
cause: Cause.die(new Error(`Machine encoded snapshot contains invalid remembered state "${path}"`))
|
|
1186
|
-
}));
|
|
1187
|
-
}
|
|
1188
|
-
rememberedActive.add(path);
|
|
1189
|
-
rememberedValues.set(path, yield* decodeEncodedBoundary(machine, getStateNodeSchema(stateNode), encodedRecord.values[path], {
|
|
1190
|
-
boundary: "history",
|
|
1191
|
-
state: path
|
|
1192
|
-
}));
|
|
1193
|
-
}
|
|
1194
|
-
if (Object.keys(encodedRecord.values).length !== rememberedActive.size) {
|
|
1195
|
-
return yield* Effect.fail(new MachineSchemaDecodeError({
|
|
1196
|
-
machineId: machine.id,
|
|
1197
|
-
boundary: "history",
|
|
1198
|
-
state: historyPath,
|
|
1199
|
-
cause: Cause.die(new Error(`Machine encoded history "${historyPath}" contains values outside its paths`))
|
|
1200
|
-
}));
|
|
1201
|
-
}
|
|
1202
|
-
if (!rememberedActive.has(historyNode.parent)) {
|
|
1203
|
-
return yield* Effect.fail(new MachineSchemaDecodeError({
|
|
1204
|
-
machineId: machine.id,
|
|
1205
|
-
boundary: "history",
|
|
1206
|
-
state: historyPath,
|
|
1207
|
-
cause: Cause.die(new Error(`Machine encoded history "${historyPath}" does not contain its parent state`))
|
|
1208
|
-
}));
|
|
1209
|
-
}
|
|
1210
|
-
const record = {
|
|
1211
|
-
mode: encodedRecord.mode,
|
|
1212
|
-
parent: historyNode.parent,
|
|
1213
|
-
active: rememberedActive,
|
|
1214
|
-
values: rememberedValues
|
|
1215
|
-
};
|
|
1216
|
-
try {
|
|
1217
|
-
validateHistoryRecordControl(machine, record);
|
|
1218
|
-
}
|
|
1219
|
-
catch (cause) {
|
|
1220
|
-
return yield* Effect.fail(new MachineSchemaDecodeError({
|
|
1221
|
-
machineId: machine.id,
|
|
1222
|
-
boundary: "history",
|
|
1223
|
-
state: historyPath,
|
|
1224
|
-
cause: Cause.die(cause)
|
|
1225
|
-
}));
|
|
924
|
+
if (node.type === "parallel") {
|
|
925
|
+
const regionOutputs = {};
|
|
926
|
+
let completed = true;
|
|
927
|
+
for (const child of node.children) {
|
|
928
|
+
const childCompletion = completeActiveFinalNodeSync(machine, configuration, child, event, outputs, completions);
|
|
929
|
+
if (childCompletion === undefined)
|
|
930
|
+
completed = false;
|
|
931
|
+
else
|
|
932
|
+
regionOutputs[getNode(machine, child).key] = childCompletion.output;
|
|
1226
933
|
}
|
|
1227
|
-
|
|
934
|
+
if (!completed)
|
|
935
|
+
return undefined;
|
|
936
|
+
const completion = setCompletedOutput(outputs, path, resolveFinalOutputSync(machine, configuration, path, event, regionOutputs));
|
|
937
|
+
if (completion.isNew)
|
|
938
|
+
completions.push(completion);
|
|
939
|
+
return completion;
|
|
1228
940
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
941
|
+
if (!isDirectFinalPath(machine, path))
|
|
942
|
+
return undefined;
|
|
943
|
+
const completion = setCompletedOutput(outputs, path, resolveFinalOutputSync(machine, configuration, path, event));
|
|
944
|
+
if (completion.isNew)
|
|
945
|
+
completions.push(completion);
|
|
946
|
+
return completion;
|
|
947
|
+
};
|
|
948
|
+
export const completeConfigurationSync = (machine, configuration, event) => {
|
|
949
|
+
const outputs = new Map(configuration.outputs);
|
|
1236
950
|
const completions = [];
|
|
1237
|
-
const
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
output: yield* decodeEncodedBoundary(machine, getCompletionSchema(machine, configuration, completion.path), completion.output, {
|
|
1249
|
-
boundary: "output",
|
|
1250
|
-
state: completion.path
|
|
1251
|
-
})
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
if (completions.length > 0) {
|
|
1255
|
-
;
|
|
1256
|
-
snapshot.completed = completions;
|
|
951
|
+
const completed = {
|
|
952
|
+
active: configuration.active,
|
|
953
|
+
values: configuration.values,
|
|
954
|
+
outputs,
|
|
955
|
+
history: configuration.history
|
|
956
|
+
};
|
|
957
|
+
for (const path of Array.from(completed.active).sort((left, right) => {
|
|
958
|
+
const depth = pathDepth(machine, right) - pathDepth(machine, left);
|
|
959
|
+
return depth === 0 ? compareDocumentOrder(machine, left, right) : depth;
|
|
960
|
+
})) {
|
|
961
|
+
completeActiveFinalNodeSync(machine, completed, path, event, outputs, completions);
|
|
1257
962
|
}
|
|
1258
|
-
return
|
|
1259
|
-
}
|
|
1260
|
-
//# sourceMappingURL=
|
|
963
|
+
return { configuration: completed, completions };
|
|
964
|
+
};
|
|
965
|
+
//# sourceMappingURL=configuration.js.map
|