@typeonce/effect-machine 0.3.0 → 0.5.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 +410 -17
- package/dist/Machine.d.ts +1191 -510
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +371 -565
- 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} +20 -95
- 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} +15 -119
- 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} +12 -61
- package/dist/internal/machine/configuration.d.ts.map +1 -0
- package/dist/internal/{machineModel.js → machine/configuration.js} +250 -545
- package/dist/internal/machine/configuration.js.map +1 -0
- package/dist/internal/{machineErrors.d.ts → machine/errors.d.ts} +8 -8
- package/dist/internal/machine/errors.d.ts.map +1 -0
- package/dist/internal/{machineErrors.js → machine/errors.js} +8 -8
- 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 +676 -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} +11 -5
- package/dist/internal/machine/process.d.ts.map +1 -0
- package/dist/internal/machine/process.js +498 -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/machine/runtime.d.ts +255 -0
- package/dist/internal/machine/runtime.d.ts.map +1 -0
- package/dist/internal/machine/runtime.js +1489 -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/exploration.d.ts +30 -0
- package/dist/internal/testing/machine/exploration.d.ts.map +1 -0
- package/dist/internal/testing/machine/exploration.js +237 -0
- package/dist/internal/testing/machine/exploration.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/invariant.d.ts +31 -0
- package/dist/internal/testing/machine/invariant.d.ts.map +1 -0
- package/dist/internal/testing/machine/invariant.js +214 -0
- package/dist/internal/testing/machine/invariant.js.map +1 -0
- package/dist/internal/testing/machine/probe.d.ts +26 -0
- package/dist/internal/testing/machine/probe.d.ts.map +1 -0
- package/dist/internal/testing/machine/probe.js +45 -0
- package/dist/internal/testing/machine/probe.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 +631 -0
- package/dist/internal/testing/machine/runtime.d.ts.map +1 -0
- package/dist/internal/testing/machine/runtime.js +726 -0
- package/dist/internal/testing/machine/runtime.js.map +1 -0
- package/dist/internal/testing/machine/runtimeInvariant.d.ts +32 -0
- package/dist/internal/testing/machine/runtimeInvariant.d.ts.map +1 -0
- package/dist/internal/testing/machine/runtimeInvariant.js +334 -0
- package/dist/internal/testing/machine/runtimeInvariant.js.map +1 -0
- package/dist/internal/testing/machine/trace.d.ts +17 -0
- package/dist/internal/testing/machine/trace.d.ts.map +1 -0
- package/dist/internal/testing/machine/trace.js +94 -0
- package/dist/internal/testing/machine/trace.js.map +1 -0
- package/dist/internal/testing/machine/verification.d.ts +36 -0
- package/dist/internal/testing/machine/verification.d.ts.map +1 -0
- package/dist/internal/testing/machine/verification.js +1375 -0
- package/dist/internal/testing/machine/verification.js.map +1 -0
- package/dist/testing/MachineTest.d.ts +1588 -0
- package/dist/testing/MachineTest.d.ts.map +1 -0
- package/dist/testing/MachineTest.js +406 -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} +56 -45
- package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -0
- package/dist/unstable/cluster/ClusterMachine.js +144 -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} +116 -50
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -0
- package/dist/unstable/reactivity/AtomMachine.js +164 -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 +316 -31
- package/package.json +28 -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 +0 -125
- 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,797 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal machine planning helpers.
|
|
3
|
-
*
|
|
4
|
-
* @since 4.0.0
|
|
5
|
-
*/
|
|
6
|
-
import * as Cause from "effect/Cause";
|
|
7
|
-
import * as Context from "effect/Context";
|
|
8
|
-
import * as Effect from "effect/Effect";
|
|
9
|
-
import * as Option from "effect/Option";
|
|
10
|
-
import { InfiniteTransitionError, MachineSchemaDecodeError, StartupError } from "./machineErrors.js";
|
|
11
|
-
import { captureHistory, compareDocumentOrder, completeConfigurationEffect, configurationFromHistoryRecord, decodeEmit, decodeEvent, decodeInput, decodeStateValue, getActiveLeafPathFrom, getActiveLeafPaths, getActiveValue, getHistoryRecord, getInitialEntryPaths, getLeafPath, getNode, getParentValue, getParentValues, getPathToRoot, getRootPath, isActiveFinalConfiguration, isDescendantOf, isHistoryTarget, isPathInSubtree, isSnapshot, isTarget, makeTarget, normalizeConfiguration, normalizeConfigurationEffect, normalizeTargetConfigurationEffect, pathDepth, snapshotFromConfiguration, snapshotFromConfigurationAtPath, validateInitialConfiguration } from "./machineModel.js";
|
|
12
|
-
class DeferredActions extends Context.Service()("effect/Machine/DeferredActions") {
|
|
13
|
-
}
|
|
14
|
-
class DeferredRaisedEvents extends Context.Service()("effect/Machine/DeferredRaisedEvents") {
|
|
15
|
-
}
|
|
16
|
-
class RuntimeContext extends Context.Service()("effect/Machine/Runtime") {
|
|
17
|
-
}
|
|
18
|
-
const makeDeferredQueue = () => Effect.sync(() => {
|
|
19
|
-
const values = [];
|
|
20
|
-
return {
|
|
21
|
-
read: Effect.sync(() => values),
|
|
22
|
-
add: (value) => Effect.sync(() => {
|
|
23
|
-
values.push(value);
|
|
24
|
-
})
|
|
25
|
-
};
|
|
26
|
-
});
|
|
27
|
-
const makeDeferredActions = Effect.map(makeDeferredQueue(), (queue) => DeferredActions.of({
|
|
28
|
-
read: queue.read,
|
|
29
|
-
add: (effect) => queue.add(effect)
|
|
30
|
-
}));
|
|
31
|
-
const makeDeferredRaisedEvents = Effect.gen(function* () {
|
|
32
|
-
const raised = yield* makeDeferredQueue();
|
|
33
|
-
const emitted = yield* makeDeferredQueue();
|
|
34
|
-
return (DeferredRaisedEvents.of({
|
|
35
|
-
read: raised.read,
|
|
36
|
-
readEmitted: emitted.read,
|
|
37
|
-
add: (event) => raised.add(event),
|
|
38
|
-
addEmitted: (event) => emitted.add(event)
|
|
39
|
-
}));
|
|
40
|
-
});
|
|
41
|
-
const provideDeferredServices = (effect, machine, deferredActions, deferredRaisedEvents) => effect.pipe(Effect.provideService(DeferredActions, deferredActions), Effect.provideService(DeferredRaisedEvents, deferredRaisedEvents), Effect.provideService(RuntimeContext, makePlanningRuntime(machine, deferredRaisedEvents)));
|
|
42
|
-
const provideRuntimeContext = (effect, runtime) => Effect.provideService(effect, RuntimeContext, runtime);
|
|
43
|
-
const makePlanningRuntime = (machine, deferredRaisedEvents) => RuntimeContext.of({
|
|
44
|
-
raise: (event) => decodeEvent(machine, event).pipe(Effect.flatMap((event) => deferredRaisedEvents.add(event))),
|
|
45
|
-
sendParent: (event) => decodeEmit(machine, event).pipe(Effect.flatMap((event) => deferredRaisedEvents.addEmitted(event)))
|
|
46
|
-
});
|
|
47
|
-
export const makeLiveRuntime = (machine, scope) => RuntimeContext.of({
|
|
48
|
-
raise: (event) => decodeEvent(machine, event).pipe(Effect.flatMap((event) => scope.self.send(event))),
|
|
49
|
-
sendParent: (event) => decodeEmit(machine, event).pipe(Effect.flatMap((event) => scope.sendParent(event)))
|
|
50
|
-
});
|
|
51
|
-
export const runActions = (actions, runtime) => Effect.all(Array.from(actions, (action) => provideRuntimeContext(action, runtime)), { discard: true });
|
|
52
|
-
export const runEmittedEvents = (events, runtime) => Effect.all(Array.from(events, (event) => runtime.sendParent(event)), { discard: true });
|
|
53
|
-
export const runtimeFor = () => runtime();
|
|
54
|
-
const normalizeEventTransition = (transition) => {
|
|
55
|
-
if (transition === undefined) {
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
return typeof transition === "function"
|
|
59
|
-
? { reenter: false, transition }
|
|
60
|
-
: { reenter: transition.reenter === true, transition: transition.transition };
|
|
61
|
-
};
|
|
62
|
-
const collectStateAction = Effect.fnUntraced(function* (machine, handler, context) {
|
|
63
|
-
const deferredActions = yield* makeDeferredActions;
|
|
64
|
-
const deferredRaisedEvents = yield* makeDeferredRaisedEvents;
|
|
65
|
-
if (handler !== undefined) {
|
|
66
|
-
const result = handler(context);
|
|
67
|
-
if (Effect.isEffect(result)) {
|
|
68
|
-
yield* provideDeferredServices(result, machine, deferredActions, deferredRaisedEvents);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
const actions = yield* deferredActions.read;
|
|
72
|
-
const raisedEvents = yield* deferredRaisedEvents.read;
|
|
73
|
-
const emittedEvents = yield* deferredRaisedEvents.readEmitted;
|
|
74
|
-
return {
|
|
75
|
-
actions: actions,
|
|
76
|
-
raisedEvents: raisedEvents,
|
|
77
|
-
emittedEvents
|
|
78
|
-
};
|
|
79
|
-
});
|
|
80
|
-
const collectTransition = Effect.fnUntraced(function* (machine, transition, context) {
|
|
81
|
-
const deferredActions = yield* makeDeferredActions;
|
|
82
|
-
const deferredRaisedEvents = yield* makeDeferredRaisedEvents;
|
|
83
|
-
const result = transition(context);
|
|
84
|
-
const state = Effect.isEffect(result)
|
|
85
|
-
? yield* provideDeferredServices(result, machine, deferredActions, deferredRaisedEvents)
|
|
86
|
-
: result;
|
|
87
|
-
const actions = yield* deferredActions.read;
|
|
88
|
-
const raisedEvents = yield* deferredRaisedEvents.read;
|
|
89
|
-
const emittedEvents = yield* deferredRaisedEvents.readEmitted;
|
|
90
|
-
return {
|
|
91
|
-
state,
|
|
92
|
-
actions: actions,
|
|
93
|
-
raisedEvents: raisedEvents,
|
|
94
|
-
emittedEvents
|
|
95
|
-
};
|
|
96
|
-
});
|
|
97
|
-
const collectStateInitializer = Effect.fnUntraced(function* (machine, handler, context) {
|
|
98
|
-
const deferredActions = yield* makeDeferredActions;
|
|
99
|
-
const deferredRaisedEvents = yield* makeDeferredRaisedEvents;
|
|
100
|
-
const result = handler(context);
|
|
101
|
-
const value = Effect.isEffect(result)
|
|
102
|
-
? yield* provideDeferredServices(result, machine, deferredActions, deferredRaisedEvents)
|
|
103
|
-
: result;
|
|
104
|
-
return {
|
|
105
|
-
value,
|
|
106
|
-
actions: yield* deferredActions.read,
|
|
107
|
-
raisedEvents: yield* deferredRaisedEvents.read,
|
|
108
|
-
emittedEvents: yield* deferredRaisedEvents.readEmitted
|
|
109
|
-
};
|
|
110
|
-
});
|
|
111
|
-
/** Completes the intentionally partial configuration held by shallow history.
|
|
112
|
-
* Only a compound node with no remembered child invokes an initializer; deep
|
|
113
|
-
* history never reaches this path. */
|
|
114
|
-
const completeHistoryConfiguration = Effect.fnUntraced(function* (machine, configuration, event) {
|
|
115
|
-
const active = new Set(configuration.active);
|
|
116
|
-
const values = new Map(configuration.values);
|
|
117
|
-
const actions = [];
|
|
118
|
-
const raisedEvents = [];
|
|
119
|
-
const emittedEvents = [];
|
|
120
|
-
let changed = true;
|
|
121
|
-
while (changed) {
|
|
122
|
-
changed = false;
|
|
123
|
-
for (const path of Array.from(active).sort((left, right) => compareDocumentOrder(machine, left, right))) {
|
|
124
|
-
const node = getNode(machine, path);
|
|
125
|
-
if (node.type === "compound" && !node.children.some((child) => active.has(child))) {
|
|
126
|
-
if (node.initial === undefined) {
|
|
127
|
-
throw new Error(`Machine shallow history expected compound state "${path}" to have an initial child`);
|
|
128
|
-
}
|
|
129
|
-
const initializer = machine.handlers[path]?.initial;
|
|
130
|
-
if (initializer === undefined) {
|
|
131
|
-
throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`);
|
|
132
|
-
}
|
|
133
|
-
const current = {
|
|
134
|
-
active,
|
|
135
|
-
values,
|
|
136
|
-
outputs: configuration.outputs,
|
|
137
|
-
history: configuration.history
|
|
138
|
-
};
|
|
139
|
-
const initialized = yield* collectStateInitializer(machine, initializer, {
|
|
140
|
-
state: getActiveValue(current, path),
|
|
141
|
-
parent: getParentValue(machine, current, path),
|
|
142
|
-
parents: getParentValues(machine, current, path),
|
|
143
|
-
event,
|
|
144
|
-
...makePlanningCapabilities()
|
|
145
|
-
});
|
|
146
|
-
const child = getNode(machine, node.initial);
|
|
147
|
-
active.add(child.path);
|
|
148
|
-
values.set(child.path, yield* decodeStateValue(machine, child, initialized.value));
|
|
149
|
-
actions.push(...initialized.actions);
|
|
150
|
-
raisedEvents.push(...initialized.raisedEvents);
|
|
151
|
-
emittedEvents.push(...initialized.emittedEvents);
|
|
152
|
-
changed = true;
|
|
153
|
-
}
|
|
154
|
-
if (node.type === "parallel") {
|
|
155
|
-
const missing = node.children.filter((childPath) => !active.has(childPath));
|
|
156
|
-
if (missing.length > 0) {
|
|
157
|
-
const initializer = machine.handlers[path]?.initial;
|
|
158
|
-
if (initializer === undefined) {
|
|
159
|
-
throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`);
|
|
160
|
-
}
|
|
161
|
-
const current = {
|
|
162
|
-
active,
|
|
163
|
-
values,
|
|
164
|
-
outputs: configuration.outputs,
|
|
165
|
-
history: configuration.history
|
|
166
|
-
};
|
|
167
|
-
const initialized = yield* collectStateInitializer(machine, initializer, {
|
|
168
|
-
state: getActiveValue(current, path),
|
|
169
|
-
parent: getParentValue(machine, current, path),
|
|
170
|
-
parents: getParentValues(machine, current, path),
|
|
171
|
-
event,
|
|
172
|
-
...makePlanningCapabilities()
|
|
173
|
-
});
|
|
174
|
-
if (typeof initialized.value !== "object" || initialized.value === null) {
|
|
175
|
-
throw new Error(`Machine parallel state initializer for "${path}" must return its region values`);
|
|
176
|
-
}
|
|
177
|
-
for (const childPath of missing) {
|
|
178
|
-
const child = getNode(machine, childPath);
|
|
179
|
-
if (!Object.prototype.hasOwnProperty.call(initialized.value, child.key)) {
|
|
180
|
-
throw new Error(`Machine parallel state initializer for "${path}" must return region "${child.key}"`);
|
|
181
|
-
}
|
|
182
|
-
active.add(child.path);
|
|
183
|
-
values.set(child.path, yield* decodeStateValue(machine, child, initialized.value[child.key]));
|
|
184
|
-
}
|
|
185
|
-
actions.push(...initialized.actions);
|
|
186
|
-
raisedEvents.push(...initialized.raisedEvents);
|
|
187
|
-
emittedEvents.push(...initialized.emittedEvents);
|
|
188
|
-
changed = true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
configuration: {
|
|
195
|
-
active,
|
|
196
|
-
values,
|
|
197
|
-
outputs: new Map(),
|
|
198
|
-
history: configuration.history
|
|
199
|
-
},
|
|
200
|
-
actions,
|
|
201
|
-
raisedEvents,
|
|
202
|
-
emittedEvents
|
|
203
|
-
};
|
|
204
|
-
});
|
|
205
|
-
const resolveHistoryTarget = Effect.fnUntraced(function* (machine, configuration, target, event) {
|
|
206
|
-
const node = getNode(machine, target.path);
|
|
207
|
-
if (node.type !== "history" || node.parent !== target.parent) {
|
|
208
|
-
throw new Error(`Machine expected history target "${target.path}" to resolve to its declared parent`);
|
|
209
|
-
}
|
|
210
|
-
const record = getHistoryRecord(configuration, target.path);
|
|
211
|
-
if (record !== undefined) {
|
|
212
|
-
const restored = configurationFromHistoryRecord(machine, configuration, record);
|
|
213
|
-
// Deep records are already complete below the history parent. This pass is
|
|
214
|
-
// still required for parallel ancestors outside that parent whose other
|
|
215
|
-
// regions must be initialized when the ancestor is re-entered.
|
|
216
|
-
const completed = yield* completeHistoryConfiguration(machine, restored, event);
|
|
217
|
-
const snapshot = snapshotFromConfigurationAtPath(machine, completed.configuration, target.parent);
|
|
218
|
-
return {
|
|
219
|
-
target: makeTarget(target.parent, snapshot.value, { snapshot: snapshot }),
|
|
220
|
-
actions: completed.actions,
|
|
221
|
-
raisedEvents: completed.raisedEvents,
|
|
222
|
-
emittedEvents: completed.emittedEvents
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
const key = node.key;
|
|
226
|
-
const fallback = machine.handlers[target.parent]?.history?.[key]?.default;
|
|
227
|
-
if (fallback === undefined) {
|
|
228
|
-
throw new Error(`Machine history state "${target.path}" requires a default implementation`);
|
|
229
|
-
}
|
|
230
|
-
const collected = yield* collectTransition(machine, fallback, {
|
|
231
|
-
event,
|
|
232
|
-
...makePlanningCapabilities(),
|
|
233
|
-
target: machine.makeTargetBuilder(target.parent).full,
|
|
234
|
-
parent: target.parent
|
|
235
|
-
});
|
|
236
|
-
if (collected.state === undefined || isHistoryTarget(collected.state) || !isSnapshot(collected.state)) {
|
|
237
|
-
throw new Error(`Machine history default for "${target.path}" must return a concrete parent snapshot`);
|
|
238
|
-
}
|
|
239
|
-
if (String(collected.state.path) !== target.parent) {
|
|
240
|
-
throw new Error(`Machine history default for "${target.path}" must return state "${target.parent}"`);
|
|
241
|
-
}
|
|
242
|
-
return {
|
|
243
|
-
target: makeTarget(target.parent, collected.state.value, { snapshot: collected.state }),
|
|
244
|
-
actions: collected.actions,
|
|
245
|
-
raisedEvents: collected.raisedEvents,
|
|
246
|
-
emittedEvents: collected.emittedEvents
|
|
247
|
-
};
|
|
248
|
-
});
|
|
249
|
-
const getCandidatePaths = (machine, configuration) => Array.from(configuration.active)
|
|
250
|
-
.sort((left, right) => {
|
|
251
|
-
const depth = pathDepth(machine, right) - pathDepth(machine, left);
|
|
252
|
-
return depth === 0 ? compareDocumentOrder(machine, left, right) : depth;
|
|
253
|
-
});
|
|
254
|
-
const getLeafCandidatePaths = (machine, leaf) => [...getPathToRoot(machine, leaf)].reverse();
|
|
255
|
-
const getLeastCommonAncestor = (machine, left, right) => {
|
|
256
|
-
const leftPath = getPathToRoot(machine, left);
|
|
257
|
-
const rightPath = getPathToRoot(machine, right);
|
|
258
|
-
let ancestor = undefined;
|
|
259
|
-
const length = Math.min(leftPath.length, rightPath.length);
|
|
260
|
-
for (let index = 0; index < length; index++) {
|
|
261
|
-
if (leftPath[index] !== rightPath[index]) {
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
ancestor = leftPath[index];
|
|
265
|
-
}
|
|
266
|
-
return ancestor;
|
|
267
|
-
};
|
|
268
|
-
const getExitPaths = (machine, configuration, boundary) => sortExitPaths(machine, Array.from(configuration.active)
|
|
269
|
-
.filter((path) => boundary === undefined || isDescendantOf(path, boundary)));
|
|
270
|
-
const getEntryPaths = (machine, configuration, boundary) => sortEntryPaths(machine, Array.from(configuration.active).filter((path) => boundary === undefined || isDescendantOf(path, boundary)));
|
|
271
|
-
const hasSameActivePaths = (left, right) => left.active.size === right.active.size && Array.from(left.active).every((path) => right.active.has(path));
|
|
272
|
-
export const sortExitPaths = (machine, paths) => Array.from(new Set(paths))
|
|
273
|
-
.sort((left, right) => {
|
|
274
|
-
const depth = getPathToRoot(machine, right).length - getPathToRoot(machine, left).length;
|
|
275
|
-
return depth === 0 ? getNode(machine, right).order - getNode(machine, left).order : depth;
|
|
276
|
-
});
|
|
277
|
-
export const sortEntryPaths = (machine, paths) => Array.from(new Set(paths))
|
|
278
|
-
.sort((left, right) => {
|
|
279
|
-
const depth = getPathToRoot(machine, left).length - getPathToRoot(machine, right).length;
|
|
280
|
-
return depth === 0 ? compareDocumentOrder(machine, left, right) : depth;
|
|
281
|
-
});
|
|
282
|
-
const makePlanningCapabilities = () => {
|
|
283
|
-
const runtimeEffect = runtimeFor();
|
|
284
|
-
return {
|
|
285
|
-
runtime: runtimeEffect,
|
|
286
|
-
raise: (event) => Effect.flatMap(runtimeEffect, (runtime) => runtime.raise(event)),
|
|
287
|
-
emit: (event) => Effect.flatMap(runtimeEffect, (runtime) => runtime.sendParent(event))
|
|
288
|
-
};
|
|
289
|
-
};
|
|
290
|
-
const makeStateActionContext = (machine, configuration, path, event) => ({
|
|
291
|
-
state: getActiveValue(configuration, path),
|
|
292
|
-
parent: getParentValue(machine, configuration, path),
|
|
293
|
-
parents: getParentValues(machine, configuration, path),
|
|
294
|
-
event,
|
|
295
|
-
...makePlanningCapabilities()
|
|
296
|
-
});
|
|
297
|
-
const makeTransitionContext = (machine, configuration, path, event) => ({
|
|
298
|
-
state: getActiveValue(configuration, path),
|
|
299
|
-
parent: getParentValue(machine, configuration, path),
|
|
300
|
-
parents: getParentValues(machine, configuration, path),
|
|
301
|
-
event,
|
|
302
|
-
...makePlanningCapabilities(),
|
|
303
|
-
target: machine.makeTargetBuilder(path)
|
|
304
|
-
});
|
|
305
|
-
const makeDoneContext = (machine, configuration, path, event, output) => ({
|
|
306
|
-
state: getActiveValue(configuration, path),
|
|
307
|
-
parent: getParentValue(machine, configuration, path),
|
|
308
|
-
parents: getParentValues(machine, configuration, path),
|
|
309
|
-
event,
|
|
310
|
-
output: output,
|
|
311
|
-
...makePlanningCapabilities(),
|
|
312
|
-
target: machine.makeTargetBuilder(path)
|
|
313
|
-
});
|
|
314
|
-
const collectStateActions = Effect.fnUntraced(function* (machine, configuration, paths, event, key) {
|
|
315
|
-
const actions = [];
|
|
316
|
-
const raisedEvents = [];
|
|
317
|
-
const emittedEvents = [];
|
|
318
|
-
for (const path of paths) {
|
|
319
|
-
const collected = yield* collectStateAction(machine, machine.handlers[path]?.[key], makeStateActionContext(machine, configuration, path, event));
|
|
320
|
-
actions.push(...collected.actions);
|
|
321
|
-
raisedEvents.push(...collected.raisedEvents);
|
|
322
|
-
emittedEvents.push(...collected.emittedEvents);
|
|
323
|
-
}
|
|
324
|
-
return { actions, emittedEvents, raisedEvents };
|
|
325
|
-
});
|
|
326
|
-
const selectAlwaysTransitions = (machine, configuration, event) => {
|
|
327
|
-
const selected = [];
|
|
328
|
-
const selectedSources = new Set();
|
|
329
|
-
for (const leaf of getActiveLeafPaths(machine, configuration)) {
|
|
330
|
-
for (const path of getLeafCandidatePaths(machine, leaf)) {
|
|
331
|
-
const always = machine.handlers[path]?.always;
|
|
332
|
-
if (always !== undefined) {
|
|
333
|
-
if (!selectedSources.has(path)) {
|
|
334
|
-
selectedSources.add(path);
|
|
335
|
-
selected.push({
|
|
336
|
-
sourcePath: path,
|
|
337
|
-
leafPath: leaf,
|
|
338
|
-
transition: { reenter: false, transition: always },
|
|
339
|
-
context: {
|
|
340
|
-
state: getActiveValue(configuration, path),
|
|
341
|
-
parent: getParentValue(machine, configuration, path),
|
|
342
|
-
parents: getParentValues(machine, configuration, path),
|
|
343
|
-
event,
|
|
344
|
-
...makePlanningCapabilities(),
|
|
345
|
-
target: machine.makeTargetBuilder(path)
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
break;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return selected;
|
|
354
|
-
};
|
|
355
|
-
const selectDoneTransitions = (machine, configuration, event, completions) => {
|
|
356
|
-
const selected = [];
|
|
357
|
-
const selectedSources = new Set();
|
|
358
|
-
for (const completion of completions) {
|
|
359
|
-
const onDone = machine.handlers[completion.path]?.onDone;
|
|
360
|
-
if (onDone !== undefined && !selectedSources.has(completion.path)) {
|
|
361
|
-
selectedSources.add(completion.path);
|
|
362
|
-
selected.push({
|
|
363
|
-
sourcePath: completion.path,
|
|
364
|
-
leafPath: getActiveLeafPathFrom(machine, configuration, completion.path),
|
|
365
|
-
transition: { reenter: false, transition: onDone },
|
|
366
|
-
context: makeDoneContext(machine, configuration, completion.path, event, completion.output)
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return selected;
|
|
371
|
-
};
|
|
372
|
-
const selectEventTransitions = (machine, configuration, event) => {
|
|
373
|
-
const selected = [];
|
|
374
|
-
const selectedSources = new Set();
|
|
375
|
-
for (const leaf of getActiveLeafPaths(machine, configuration)) {
|
|
376
|
-
for (const path of getLeafCandidatePaths(machine, leaf)) {
|
|
377
|
-
const transition = normalizeEventTransition(machine.handlers[path]?.on?.[event._tag]);
|
|
378
|
-
if (transition !== undefined) {
|
|
379
|
-
if (!selectedSources.has(path)) {
|
|
380
|
-
selectedSources.add(path);
|
|
381
|
-
selected.push({
|
|
382
|
-
sourcePath: path,
|
|
383
|
-
leafPath: leaf,
|
|
384
|
-
transition: transition,
|
|
385
|
-
context: makeTransitionContext(machine, configuration, path, event)
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
break;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return selected;
|
|
393
|
-
};
|
|
394
|
-
const getTargetNodePath = (target) => {
|
|
395
|
-
if (isTarget(target)) {
|
|
396
|
-
return String(target.path);
|
|
397
|
-
}
|
|
398
|
-
if (isSnapshot(target)) {
|
|
399
|
-
return String(target.path);
|
|
400
|
-
}
|
|
401
|
-
throw new Error("Machine expected transition target to be a snapshot or target builder result");
|
|
402
|
-
};
|
|
403
|
-
const hasPathIntersection = (left, right) => {
|
|
404
|
-
for (const path of left) {
|
|
405
|
-
if (right.includes(path)) {
|
|
406
|
-
return true;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return false;
|
|
410
|
-
};
|
|
411
|
-
const sortEvaluatedTransitions = (machine, transitions) => Array.from(transitions)
|
|
412
|
-
.sort((left, right) => compareDocumentOrder(machine, left.selection.sourcePath, right.selection.sourcePath));
|
|
413
|
-
const removePreemptedAncestorSelections = (selections) => selections.filter((selection) => !selections.some((other) => other.sourcePath !== selection.sourcePath && isDescendantOf(other.sourcePath, selection.sourcePath)));
|
|
414
|
-
const removeConflictingTransitions = (machine, transitions) => {
|
|
415
|
-
const filtered = [];
|
|
416
|
-
for (const transition of sortEvaluatedTransitions(machine, transitions)) {
|
|
417
|
-
let preempted = false;
|
|
418
|
-
const transitionsToRemove = new Set();
|
|
419
|
-
for (const selected of filtered) {
|
|
420
|
-
if (hasPathIntersection(transition.exitPaths, selected.exitPaths)) {
|
|
421
|
-
if (isDescendantOf(transition.selection.sourcePath, selected.selection.sourcePath)) {
|
|
422
|
-
transitionsToRemove.add(selected);
|
|
423
|
-
}
|
|
424
|
-
else {
|
|
425
|
-
preempted = true;
|
|
426
|
-
break;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
if (!preempted) {
|
|
431
|
-
for (const removed of transitionsToRemove) {
|
|
432
|
-
const index = filtered.indexOf(removed);
|
|
433
|
-
if (index >= 0) {
|
|
434
|
-
filtered.splice(index, 1);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
filtered.push(transition);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
return filtered;
|
|
441
|
-
};
|
|
442
|
-
const collectEvaluatedTransition = Effect.fnUntraced(function* (machine, state, selection) {
|
|
443
|
-
const stateIdentifier = selection.leafPath;
|
|
444
|
-
const transitionResult = yield* collectTransition(machine, selection.transition.transition, selection.context);
|
|
445
|
-
const unresolvedTarget = transitionResult.state === undefined
|
|
446
|
-
? undefined
|
|
447
|
-
: transitionResult.state;
|
|
448
|
-
let historyResolution;
|
|
449
|
-
const reenteredHistoryParent = unresolvedTarget !== undefined && isHistoryTarget(unresolvedTarget) &&
|
|
450
|
-
selection.transition.reenter && state.active.has(unresolvedTarget.parent);
|
|
451
|
-
if (unresolvedTarget !== undefined && isHistoryTarget(unresolvedTarget)) {
|
|
452
|
-
// A reentering transition may exit the history node's own parent. SCXML
|
|
453
|
-
// history observes that same exit, so resolve against a provisional
|
|
454
|
-
// capture rather than an older record (or the default).
|
|
455
|
-
const provisionalBoundary = selection.transition.reenter
|
|
456
|
-
? getNode(machine, selection.sourcePath).parent
|
|
457
|
-
: getLeastCommonAncestor(machine, stateIdentifier, unresolvedTarget.parent);
|
|
458
|
-
const provisionalExitPaths = reenteredHistoryParent
|
|
459
|
-
? sortExitPaths(machine, Array.from(state.active).filter((path) => isPathInSubtree(path, unresolvedTarget.parent)))
|
|
460
|
-
: getExitPaths(machine, state, provisionalBoundary);
|
|
461
|
-
const stateAtHistoryResolution = provisionalExitPaths.includes(unresolvedTarget.parent)
|
|
462
|
-
? captureHistory(machine, state, state, provisionalExitPaths)
|
|
463
|
-
: state;
|
|
464
|
-
historyResolution = yield* resolveHistoryTarget(machine, stateAtHistoryResolution, unresolvedTarget, selection.context.event);
|
|
465
|
-
}
|
|
466
|
-
const target = historyResolution === undefined ? unresolvedTarget : historyResolution.target;
|
|
467
|
-
const targetPath = target === undefined ? undefined : getTargetNodePath(target);
|
|
468
|
-
const stateAfterTransition = target === undefined
|
|
469
|
-
? state
|
|
470
|
-
: yield* normalizeTargetConfigurationEffect(machine, state, target);
|
|
471
|
-
const changed = selection.transition.reenter || !hasSameActivePaths(state, stateAfterTransition);
|
|
472
|
-
if (!changed) {
|
|
473
|
-
return {
|
|
474
|
-
selection,
|
|
475
|
-
target,
|
|
476
|
-
actions: [...transitionResult.actions, ...(historyResolution?.actions ?? [])],
|
|
477
|
-
raisedEvents: [...transitionResult.raisedEvents, ...(historyResolution?.raisedEvents ?? [])],
|
|
478
|
-
emittedEvents: [...transitionResult.emittedEvents, ...(historyResolution?.emittedEvents ?? [])],
|
|
479
|
-
changed,
|
|
480
|
-
exitPaths: [],
|
|
481
|
-
entryPaths: []
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
const boundary = selection.transition.reenter
|
|
485
|
-
? getNode(machine, selection.sourcePath).parent
|
|
486
|
-
: getLeastCommonAncestor(machine, stateIdentifier, targetPath);
|
|
487
|
-
return {
|
|
488
|
-
selection,
|
|
489
|
-
target,
|
|
490
|
-
actions: [...transitionResult.actions, ...(historyResolution?.actions ?? [])],
|
|
491
|
-
raisedEvents: [...transitionResult.raisedEvents, ...(historyResolution?.raisedEvents ?? [])],
|
|
492
|
-
emittedEvents: [...transitionResult.emittedEvents, ...(historyResolution?.emittedEvents ?? [])],
|
|
493
|
-
changed,
|
|
494
|
-
exitPaths: reenteredHistoryParent
|
|
495
|
-
? sortExitPaths(machine, Array.from(state.active).filter((path) => isPathInSubtree(path, unresolvedTarget.parent)))
|
|
496
|
-
: getExitPaths(machine, state, boundary),
|
|
497
|
-
entryPaths: reenteredHistoryParent
|
|
498
|
-
? sortEntryPaths(machine, Array.from(stateAfterTransition.active).filter((path) => isPathInSubtree(path, unresolvedTarget.parent)))
|
|
499
|
-
: getEntryPaths(machine, stateAfterTransition, boundary)
|
|
500
|
-
};
|
|
501
|
-
});
|
|
502
|
-
const MaxMacrostepIterations = 1000;
|
|
503
|
-
export const InitialEventTypeId = Symbol("effect/Machine/InitialEvent");
|
|
504
|
-
export const InitialEvent = { _tag: InitialEventTypeId };
|
|
505
|
-
const catchStartup = (effect) => Effect.catchCause(effect, (cause) => {
|
|
506
|
-
if (Cause.hasDies(cause)) {
|
|
507
|
-
return Effect.fail(new StartupError({ cause }));
|
|
508
|
-
}
|
|
509
|
-
return Effect.failCause(cause);
|
|
510
|
-
});
|
|
511
|
-
export const isFinalState = (machine, state) => isActiveFinalConfiguration(machine, normalizeConfiguration(machine, state));
|
|
512
|
-
export const getFinalOutputEffect = (machine, state, event) => normalizeConfigurationEffect(machine, state).pipe(Effect.flatMap((configuration) => completeConfigurationEffect(machine, configuration, event)), Effect.flatMap((completed) => {
|
|
513
|
-
const root = getRootPath(machine, completed.configuration);
|
|
514
|
-
if (!isActiveFinalConfiguration(machine, completed.configuration)
|
|
515
|
-
|| !completed.configuration.outputs.has(root)) {
|
|
516
|
-
return Effect.die(new Error("Machine attempted to read terminal output from a non-terminal configuration"));
|
|
517
|
-
}
|
|
518
|
-
return Effect.succeed(completed.configuration.outputs.get(root));
|
|
519
|
-
}));
|
|
520
|
-
export const isFinal = (machine, state) => isFinalState(machine, state);
|
|
521
|
-
export const planInitial = Effect.fnUntraced(function* (machine, ...args) {
|
|
522
|
-
return yield* catchStartup(Effect.gen(function* () {
|
|
523
|
-
const deferredActions = yield* makeDeferredActions;
|
|
524
|
-
const deferredRaisedEvents = yield* makeDeferredRaisedEvents;
|
|
525
|
-
const inputArgs = machine.input === undefined
|
|
526
|
-
? args
|
|
527
|
-
: args.length === 0
|
|
528
|
-
? (yield* decodeInput(machine, machine.input, undefined), args)
|
|
529
|
-
: [yield* decodeInput(machine, machine.input, args[0])];
|
|
530
|
-
const result = machine.initial(...inputArgs);
|
|
531
|
-
const state = Effect.isEffect(result)
|
|
532
|
-
? yield* provideDeferredServices(result, machine, deferredActions, deferredRaisedEvents)
|
|
533
|
-
: result;
|
|
534
|
-
const configuration = yield* normalizeConfigurationEffect(machine, state);
|
|
535
|
-
validateInitialConfiguration(machine, configuration);
|
|
536
|
-
const actions = yield* deferredActions.read;
|
|
537
|
-
const raisedEvents = yield* deferredRaisedEvents.read;
|
|
538
|
-
const emittedEvents = yield* deferredRaisedEvents.readEmitted;
|
|
539
|
-
const settled = yield* Effect.gen(function* () {
|
|
540
|
-
const entry = yield* collectStateActions(machine, configuration, getInitialEntryPaths(machine, configuration), InitialEvent, "entry");
|
|
541
|
-
return yield* settle(machine, configuration, InitialEvent, [...entry.actions], [...raisedEvents, ...entry.raisedEvents], [...emittedEvents, ...entry.emittedEvents], []);
|
|
542
|
-
});
|
|
543
|
-
const planned = {
|
|
544
|
-
state: snapshotFromConfiguration(machine, settled.next),
|
|
545
|
-
actions: [
|
|
546
|
-
...actions,
|
|
547
|
-
...settled.actions
|
|
548
|
-
],
|
|
549
|
-
emittedEvents: settled.emittedEvents
|
|
550
|
-
};
|
|
551
|
-
return settled.done
|
|
552
|
-
? { ...planned, done: true, output: settled.output }
|
|
553
|
-
: { ...planned, done: false, output: undefined };
|
|
554
|
-
}));
|
|
555
|
-
});
|
|
556
|
-
export const enabled = (machine, state) => {
|
|
557
|
-
if (isFinalState(machine, state)) {
|
|
558
|
-
return [];
|
|
559
|
-
}
|
|
560
|
-
const configuration = normalizeConfiguration(machine, state);
|
|
561
|
-
const tags = [];
|
|
562
|
-
const seen = new Set();
|
|
563
|
-
for (const path of getCandidatePaths(machine, configuration)) {
|
|
564
|
-
for (const tag of Reflect.ownKeys(machine.handlers[path]?.on ?? {})) {
|
|
565
|
-
if (!seen.has(tag)) {
|
|
566
|
-
seen.add(tag);
|
|
567
|
-
tags.push(tag);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return tags;
|
|
572
|
-
};
|
|
573
|
-
const microstep = Effect.fnUntraced(function* (machine, state, event, selections) {
|
|
574
|
-
if (selections.length === 0) {
|
|
575
|
-
return {
|
|
576
|
-
next: state,
|
|
577
|
-
event,
|
|
578
|
-
actions: [],
|
|
579
|
-
raisedEvents: [],
|
|
580
|
-
emittedEvents: [],
|
|
581
|
-
exitPaths: [],
|
|
582
|
-
entryPaths: [],
|
|
583
|
-
changed: false
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
const activeSelections = removePreemptedAncestorSelections(selections);
|
|
587
|
-
const evaluatedTransitions = [];
|
|
588
|
-
for (const selection of activeSelections) {
|
|
589
|
-
evaluatedTransitions.push(yield* collectEvaluatedTransition(machine, state, selection));
|
|
590
|
-
}
|
|
591
|
-
const transitions = removeConflictingTransitions(machine, evaluatedTransitions);
|
|
592
|
-
const sortedTransitions = sortEvaluatedTransitions(machine, transitions);
|
|
593
|
-
let stateAfterTransition = state;
|
|
594
|
-
for (const transition of sortedTransitions) {
|
|
595
|
-
if (transition.target !== undefined) {
|
|
596
|
-
stateAfterTransition = yield* normalizeTargetConfigurationEffect(machine, stateAfterTransition, transition.target);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
const changed = transitions.some((transition) => transition.changed);
|
|
600
|
-
const transitionActions = sortedTransitions
|
|
601
|
-
.flatMap((transition) => transition.actions);
|
|
602
|
-
const transitionRaisedEvents = sortedTransitions
|
|
603
|
-
.flatMap((transition) => transition.raisedEvents);
|
|
604
|
-
const transitionEmittedEvents = sortedTransitions
|
|
605
|
-
.flatMap((transition) => transition.emittedEvents);
|
|
606
|
-
if (!changed) {
|
|
607
|
-
return {
|
|
608
|
-
next: stateAfterTransition,
|
|
609
|
-
event,
|
|
610
|
-
actions: transitionActions,
|
|
611
|
-
raisedEvents: transitionRaisedEvents,
|
|
612
|
-
emittedEvents: transitionEmittedEvents,
|
|
613
|
-
exitPaths: [],
|
|
614
|
-
entryPaths: [],
|
|
615
|
-
changed: false
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
const exitPaths = sortExitPaths(machine, sortedTransitions.flatMap((transition) => transition.exitPaths));
|
|
619
|
-
const entryPaths = sortEntryPaths(machine, sortedTransitions.flatMap((transition) => transition.entryPaths));
|
|
620
|
-
stateAfterTransition = captureHistory(machine, state, stateAfterTransition, exitPaths);
|
|
621
|
-
const exit = yield* collectStateActions(machine, state, exitPaths, event, "exit");
|
|
622
|
-
const entry = yield* collectStateActions(machine, stateAfterTransition, entryPaths, event, "entry");
|
|
623
|
-
return {
|
|
624
|
-
next: stateAfterTransition,
|
|
625
|
-
event,
|
|
626
|
-
actions: [...exit.actions, ...transitionActions, ...entry.actions],
|
|
627
|
-
raisedEvents: [...exit.raisedEvents, ...transitionRaisedEvents, ...entry.raisedEvents],
|
|
628
|
-
emittedEvents: [...exit.emittedEvents, ...transitionEmittedEvents, ...entry.emittedEvents],
|
|
629
|
-
exitPaths,
|
|
630
|
-
entryPaths,
|
|
631
|
-
changed: true
|
|
632
|
-
};
|
|
633
|
-
});
|
|
634
|
-
const settle = Effect.fnUntraced(function* (machine, state, event, actions, raisedEvents, emittedEvents, microsteps) {
|
|
635
|
-
let currentState = state;
|
|
636
|
-
let currentEvent = event;
|
|
637
|
-
let shouldRunAlways = true;
|
|
638
|
-
let iterations = 0;
|
|
639
|
-
let raisedEventIndex = 0;
|
|
640
|
-
let completedTerminal = false;
|
|
641
|
-
let finalOutput = undefined;
|
|
642
|
-
const pendingCompletions = [];
|
|
643
|
-
while (true) {
|
|
644
|
-
iterations += 1;
|
|
645
|
-
if (iterations > MaxMacrostepIterations) {
|
|
646
|
-
return yield* new InfiniteTransitionError({
|
|
647
|
-
machineId: machine.id,
|
|
648
|
-
state: String(getLeafPath(machine, currentState)),
|
|
649
|
-
maxIterations: MaxMacrostepIterations
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
const completed = yield* completeConfigurationEffect(machine, currentState, currentEvent);
|
|
653
|
-
currentState = completed.configuration;
|
|
654
|
-
pendingCompletions.push(...completed.completions.filter((completion) => machine.handlers[completion.path]?.onDone !== undefined));
|
|
655
|
-
while (pendingCompletions.length > 0 && !currentState.active.has(pendingCompletions[0].path)) {
|
|
656
|
-
pendingCompletions.shift();
|
|
657
|
-
}
|
|
658
|
-
const done = selectDoneTransitions(machine, currentState, currentEvent, pendingCompletions.length === 0 ? [] : [pendingCompletions.shift()]);
|
|
659
|
-
if (done.length > 0) {
|
|
660
|
-
const doneStep = yield* microstep(machine, currentState, currentEvent, done);
|
|
661
|
-
actions.push(...doneStep.actions);
|
|
662
|
-
raisedEvents.push(...doneStep.raisedEvents);
|
|
663
|
-
emittedEvents.push(...doneStep.emittedEvents);
|
|
664
|
-
microsteps.push(doneStep);
|
|
665
|
-
currentState = doneStep.next;
|
|
666
|
-
shouldRunAlways = doneStep.changed;
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
if (isActiveFinalConfiguration(machine, currentState)) {
|
|
670
|
-
const root = getRootPath(machine, currentState);
|
|
671
|
-
if (!currentState.outputs.has(root)) {
|
|
672
|
-
return yield* Effect.die(new Error("Machine reached a terminal configuration without a completed root output"));
|
|
673
|
-
}
|
|
674
|
-
completedTerminal = true;
|
|
675
|
-
finalOutput = currentState.outputs.get(root);
|
|
676
|
-
break;
|
|
677
|
-
}
|
|
678
|
-
const always = shouldRunAlways
|
|
679
|
-
? selectAlwaysTransitions(machine, currentState, currentEvent)
|
|
680
|
-
: [];
|
|
681
|
-
if (always.length > 0) {
|
|
682
|
-
const alwaysStep = yield* microstep(machine, currentState, currentEvent, always);
|
|
683
|
-
actions.push(...alwaysStep.actions);
|
|
684
|
-
raisedEvents.push(...alwaysStep.raisedEvents);
|
|
685
|
-
emittedEvents.push(...alwaysStep.emittedEvents);
|
|
686
|
-
microsteps.push(alwaysStep);
|
|
687
|
-
currentState = alwaysStep.next;
|
|
688
|
-
shouldRunAlways = alwaysStep.changed;
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
691
|
-
const raisedEventValue = raisedEvents[raisedEventIndex];
|
|
692
|
-
if (raisedEventValue === undefined) {
|
|
693
|
-
break;
|
|
694
|
-
}
|
|
695
|
-
raisedEventIndex += 1;
|
|
696
|
-
// Planning runtime validates and normalizes every event before it enters this
|
|
697
|
-
// internal queue, so decoding it again here only repeats schema work.
|
|
698
|
-
const raisedEvent = raisedEventValue;
|
|
699
|
-
currentEvent = raisedEvent;
|
|
700
|
-
const raisedSelections = selectEventTransitions(machine, currentState, raisedEvent);
|
|
701
|
-
if (raisedSelections.length === 0) {
|
|
702
|
-
shouldRunAlways = true;
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
const raisedStep = yield* microstep(machine, currentState, raisedEvent, raisedSelections);
|
|
706
|
-
actions.push(...raisedStep.actions);
|
|
707
|
-
raisedEvents.push(...raisedStep.raisedEvents);
|
|
708
|
-
emittedEvents.push(...raisedStep.emittedEvents);
|
|
709
|
-
microsteps.push(raisedStep);
|
|
710
|
-
currentState = raisedStep.next;
|
|
711
|
-
shouldRunAlways = true;
|
|
712
|
-
}
|
|
713
|
-
const result = {
|
|
714
|
-
next: currentState,
|
|
715
|
-
actions,
|
|
716
|
-
emittedEvents,
|
|
717
|
-
microsteps
|
|
718
|
-
};
|
|
719
|
-
return completedTerminal
|
|
720
|
-
? { ...result, done: true, output: finalOutput }
|
|
721
|
-
: { ...result, done: false, output: undefined };
|
|
722
|
-
});
|
|
723
|
-
const macrostep = Effect.fnUntraced(function* (machine, state, event) {
|
|
724
|
-
const configuration = yield* normalizeConfigurationEffect(machine, state);
|
|
725
|
-
const snapshot = snapshotFromConfiguration(machine, configuration);
|
|
726
|
-
const decodedEvent = yield* decodeEvent(machine, event);
|
|
727
|
-
if (isActiveFinalConfiguration(machine, configuration)) {
|
|
728
|
-
const completed = yield* completeConfigurationEffect(machine, configuration, decodedEvent);
|
|
729
|
-
const root = getRootPath(machine, completed.configuration);
|
|
730
|
-
if (!completed.configuration.outputs.has(root)) {
|
|
731
|
-
return yield* Effect.die(new Error("Machine reached a terminal configuration without a completed root output"));
|
|
732
|
-
}
|
|
733
|
-
return {
|
|
734
|
-
next: snapshotFromConfiguration(machine, completed.configuration),
|
|
735
|
-
actions: [],
|
|
736
|
-
emittedEvents: [],
|
|
737
|
-
microsteps: [],
|
|
738
|
-
done: true,
|
|
739
|
-
output: completed.configuration.outputs.get(root)
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
const selections = selectEventTransitions(machine, configuration, decodedEvent);
|
|
743
|
-
if (selections.length === 0) {
|
|
744
|
-
return {
|
|
745
|
-
next: snapshot,
|
|
746
|
-
actions: [],
|
|
747
|
-
emittedEvents: [],
|
|
748
|
-
microsteps: [],
|
|
749
|
-
done: false,
|
|
750
|
-
output: undefined
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
const step = yield* microstep(machine, configuration, decodedEvent, selections);
|
|
754
|
-
const actions = [...step.actions];
|
|
755
|
-
const raisedEvents = [...step.raisedEvents];
|
|
756
|
-
const emittedEvents = [...step.emittedEvents];
|
|
757
|
-
const microsteps = [step];
|
|
758
|
-
const settled = yield* settle(machine, step.next, decodedEvent, actions, raisedEvents, emittedEvents, microsteps);
|
|
759
|
-
const planned = {
|
|
760
|
-
next: snapshotFromConfiguration(machine, settled.next),
|
|
761
|
-
actions: settled.actions,
|
|
762
|
-
emittedEvents: settled.emittedEvents,
|
|
763
|
-
microsteps: settled.microsteps.map((step) => ({
|
|
764
|
-
next: snapshotFromConfiguration(machine, step.next),
|
|
765
|
-
event: step.event,
|
|
766
|
-
actions: step.actions,
|
|
767
|
-
raisedEvents: step.raisedEvents,
|
|
768
|
-
emittedEvents: step.emittedEvents,
|
|
769
|
-
exitPaths: step.exitPaths,
|
|
770
|
-
entryPaths: step.entryPaths,
|
|
771
|
-
changed: step.changed
|
|
772
|
-
}))
|
|
773
|
-
};
|
|
774
|
-
return settled.done
|
|
775
|
-
? { ...planned, done: true, output: settled.output }
|
|
776
|
-
: { ...planned, done: false, output: undefined };
|
|
777
|
-
});
|
|
778
|
-
export const plan = macrostep;
|
|
779
|
-
const actionUnsafe = Effect.fnUntraced(function* (effect) {
|
|
780
|
-
const actions = yield* DeferredActions;
|
|
781
|
-
yield* actions.add(effect);
|
|
782
|
-
});
|
|
783
|
-
/**
|
|
784
|
-
* Defers an effectful action until the current machine step is planned.
|
|
785
|
-
*
|
|
786
|
-
* @category combinators
|
|
787
|
-
* @since 4.0.0
|
|
788
|
-
*/
|
|
789
|
-
export const action = (effect) => actionUnsafe(effect);
|
|
790
|
-
/**
|
|
791
|
-
* Returns the typed runtime capability for the current machine.
|
|
792
|
-
*
|
|
793
|
-
* @category combinators
|
|
794
|
-
* @since 4.0.0
|
|
795
|
-
*/
|
|
796
|
-
export const runtime = () => RuntimeContext;
|
|
797
|
-
//# sourceMappingURL=machinePlanner.js.map
|