@typeonce/effect-machine 0.2.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.
Files changed (150) hide show
  1. package/README.md +345 -42
  2. package/dist/Machine.d.ts +1273 -347
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +161 -426
  5. package/dist/Machine.js.map +1 -1
  6. package/dist/internal/machine/activities.d.ts +57 -0
  7. package/dist/internal/machine/activities.d.ts.map +1 -0
  8. package/dist/internal/machine/activities.js +49 -0
  9. package/dist/internal/machine/activities.js.map +1 -0
  10. package/dist/internal/machine/atom.d.ts +69 -0
  11. package/dist/internal/machine/atom.d.ts.map +1 -0
  12. package/dist/{AtomMachine.js → internal/machine/atom.js} +19 -94
  13. package/dist/internal/machine/atom.js.map +1 -0
  14. package/dist/internal/machine/cluster.d.ts +63 -0
  15. package/dist/internal/machine/cluster.d.ts.map +1 -0
  16. package/dist/{ClusterMachine.js → internal/machine/cluster.js} +15 -119
  17. package/dist/internal/machine/cluster.js.map +1 -0
  18. package/dist/internal/machine/command.d.ts +16 -0
  19. package/dist/internal/machine/command.d.ts.map +1 -0
  20. package/dist/internal/machine/command.js +45 -0
  21. package/dist/internal/machine/command.js.map +1 -0
  22. package/dist/internal/machine/commandRuntime.d.ts +13 -0
  23. package/dist/internal/machine/commandRuntime.d.ts.map +1 -0
  24. package/dist/internal/machine/commandRuntime.js +16 -0
  25. package/dist/internal/machine/commandRuntime.js.map +1 -0
  26. package/dist/internal/{machineModel.d.ts → machine/configuration.d.ts} +32 -38
  27. package/dist/internal/machine/configuration.d.ts.map +1 -0
  28. package/dist/internal/machine/configuration.js +965 -0
  29. package/dist/internal/machine/configuration.js.map +1 -0
  30. package/dist/internal/{machineErrors.d.ts → machine/errors.d.ts} +3 -3
  31. package/dist/internal/machine/errors.d.ts.map +1 -0
  32. package/dist/internal/{machineErrors.js → machine/errors.js} +1 -1
  33. package/dist/internal/machine/errors.js.map +1 -0
  34. package/dist/internal/machine/executionPlan.d.ts +49 -0
  35. package/dist/internal/machine/executionPlan.d.ts.map +1 -0
  36. package/dist/internal/machine/executionPlan.js +667 -0
  37. package/dist/internal/machine/executionPlan.js.map +1 -0
  38. package/dist/internal/machine/invocation.d.ts +23 -0
  39. package/dist/internal/machine/invocation.d.ts.map +1 -0
  40. package/dist/internal/machine/invocation.js +77 -0
  41. package/dist/internal/machine/invocation.js.map +1 -0
  42. package/dist/internal/machine/machine.d.ts +183 -0
  43. package/dist/internal/machine/machine.d.ts.map +1 -0
  44. package/dist/internal/machine/machine.js +552 -0
  45. package/dist/internal/machine/machine.js.map +1 -0
  46. package/dist/internal/machine/planner.d.ts +182 -0
  47. package/dist/internal/machine/planner.d.ts.map +1 -0
  48. package/dist/internal/machine/planner.js +1082 -0
  49. package/dist/internal/machine/planner.js.map +1 -0
  50. package/dist/internal/{machineProcess.d.ts → machine/process.d.ts} +10 -4
  51. package/dist/internal/machine/process.d.ts.map +1 -0
  52. package/dist/internal/machine/process.js +446 -0
  53. package/dist/internal/machine/process.js.map +1 -0
  54. package/dist/internal/machine/protocol.d.ts +34 -0
  55. package/dist/internal/machine/protocol.d.ts.map +1 -0
  56. package/dist/internal/machine/protocol.js +182 -0
  57. package/dist/internal/machine/protocol.js.map +1 -0
  58. package/dist/internal/machine/readiness.d.ts +4 -0
  59. package/dist/internal/machine/readiness.d.ts.map +1 -0
  60. package/dist/internal/machine/readiness.js +2 -0
  61. package/dist/internal/machine/readiness.js.map +1 -0
  62. package/dist/internal/{machineRuntime.d.ts → machine/runtime.d.ts} +104 -2
  63. package/dist/internal/machine/runtime.d.ts.map +1 -0
  64. package/dist/internal/machine/runtime.js +1381 -0
  65. package/dist/internal/machine/runtime.js.map +1 -0
  66. package/dist/internal/machine/serialization.d.ts +14 -0
  67. package/dist/internal/machine/serialization.d.ts.map +1 -0
  68. package/dist/internal/machine/serialization.js +338 -0
  69. package/dist/internal/machine/serialization.js.map +1 -0
  70. package/dist/internal/machine/stateDefinition.d.ts +15 -0
  71. package/dist/internal/machine/stateDefinition.d.ts.map +1 -0
  72. package/dist/internal/machine/stateDefinition.js +210 -0
  73. package/dist/internal/machine/stateDefinition.js.map +1 -0
  74. package/dist/internal/machine/symbols.d.ts +3 -0
  75. package/dist/internal/machine/symbols.d.ts.map +1 -0
  76. package/dist/internal/machine/symbols.js +3 -0
  77. package/dist/internal/machine/symbols.js.map +1 -0
  78. package/dist/internal/machine/topology.d.ts +98 -0
  79. package/dist/internal/machine/topology.d.ts.map +1 -0
  80. package/dist/internal/machine/topology.js +347 -0
  81. package/dist/internal/machine/topology.js.map +1 -0
  82. package/dist/internal/testing/machine/arbitrary.d.ts +36 -0
  83. package/dist/internal/testing/machine/arbitrary.d.ts.map +1 -0
  84. package/dist/internal/testing/machine/arbitrary.js +68 -0
  85. package/dist/internal/testing/machine/arbitrary.js.map +1 -0
  86. package/dist/internal/testing/machine/finiteModel.d.ts +322 -0
  87. package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -0
  88. package/dist/internal/testing/machine/finiteModel.js +976 -0
  89. package/dist/internal/testing/machine/finiteModel.js.map +1 -0
  90. package/dist/internal/testing/machine/referenceModel.d.ts +203 -0
  91. package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -0
  92. package/dist/internal/testing/machine/referenceModel.js +1012 -0
  93. package/dist/internal/testing/machine/referenceModel.js.map +1 -0
  94. package/dist/internal/testing/machine/runtime.d.ts +328 -0
  95. package/dist/internal/testing/machine/runtime.d.ts.map +1 -0
  96. package/dist/internal/testing/machine/runtime.js +437 -0
  97. package/dist/internal/testing/machine/runtime.js.map +1 -0
  98. package/dist/internal/testing/machine/verification.d.ts +33 -0
  99. package/dist/internal/testing/machine/verification.d.ts.map +1 -0
  100. package/dist/internal/testing/machine/verification.js +1446 -0
  101. package/dist/internal/testing/machine/verification.js.map +1 -0
  102. package/dist/testing/MachineTest.d.ts +606 -0
  103. package/dist/testing/MachineTest.d.ts.map +1 -0
  104. package/dist/testing/MachineTest.js +102 -0
  105. package/dist/testing/MachineTest.js.map +1 -0
  106. package/dist/testing/index.d.ts +7 -0
  107. package/dist/testing/index.d.ts.map +1 -0
  108. package/dist/testing/index.js +7 -0
  109. package/dist/testing/index.js.map +1 -0
  110. package/dist/{ClusterMachine.d.ts → unstable/cluster/ClusterMachine.d.ts} +22 -30
  111. package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -0
  112. package/dist/unstable/cluster/ClusterMachine.js +126 -0
  113. package/dist/unstable/cluster/ClusterMachine.js.map +1 -0
  114. package/dist/{cluster.js → unstable/cluster/index.d.ts} +1 -1
  115. package/dist/unstable/cluster/index.d.ts.map +1 -0
  116. package/dist/{cluster.d.ts → unstable/cluster/index.js} +1 -1
  117. package/dist/unstable/cluster/index.js.map +1 -0
  118. package/dist/{AtomMachine.d.ts → unstable/reactivity/AtomMachine.d.ts} +40 -23
  119. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -0
  120. package/dist/unstable/reactivity/AtomMachine.js +113 -0
  121. package/dist/unstable/reactivity/AtomMachine.js.map +1 -0
  122. package/dist/{reactivity.js → unstable/reactivity/index.d.ts} +1 -1
  123. package/dist/unstable/reactivity/index.d.ts.map +1 -0
  124. package/dist/{reactivity.d.ts → unstable/reactivity/index.js} +1 -1
  125. package/dist/unstable/reactivity/index.js.map +1 -0
  126. package/docs/agent-guide.md +271 -38
  127. package/package.json +23 -13
  128. package/dist/AtomMachine.d.ts.map +0 -1
  129. package/dist/AtomMachine.js.map +0 -1
  130. package/dist/ClusterMachine.d.ts.map +0 -1
  131. package/dist/ClusterMachine.js.map +0 -1
  132. package/dist/cluster.d.ts.map +0 -1
  133. package/dist/cluster.js.map +0 -1
  134. package/dist/internal/machineErrors.d.ts.map +0 -1
  135. package/dist/internal/machineErrors.js.map +0 -1
  136. package/dist/internal/machineModel.d.ts.map +0 -1
  137. package/dist/internal/machineModel.js +0 -766
  138. package/dist/internal/machineModel.js.map +0 -1
  139. package/dist/internal/machinePlanner.d.ts +0 -74
  140. package/dist/internal/machinePlanner.d.ts.map +0 -1
  141. package/dist/internal/machinePlanner.js +0 -621
  142. package/dist/internal/machinePlanner.js.map +0 -1
  143. package/dist/internal/machineProcess.d.ts.map +0 -1
  144. package/dist/internal/machineProcess.js +0 -181
  145. package/dist/internal/machineProcess.js.map +0 -1
  146. package/dist/internal/machineRuntime.d.ts.map +0 -1
  147. package/dist/internal/machineRuntime.js +0 -365
  148. package/dist/internal/machineRuntime.js.map +0 -1
  149. package/dist/reactivity.d.ts.map +0 -1
  150. package/dist/reactivity.js.map +0 -1
@@ -0,0 +1,667 @@
1
+ /**
2
+ * Internal compiled machine execution plans.
3
+ *
4
+ * @since 4.0.0
5
+ */
6
+ import { getTargetBuilder } from "./command.js";
7
+ import { compareDocumentOrder, completeConfigurationSync, getInitialEntryPaths, getPathToRoot, getRootPath, isActiveFinalConfiguration, isDescendantOf, normalizeConfigurationSync, normalizeTargetConfigurationSync, snapshotFromConfiguration, validateInitialConfiguration } from "./configuration.js";
8
+ import { InfiniteTransitionError } from "./errors.js";
9
+ import { broadenTransitionBoundary, getEntryPaths, getExitPaths, getLeastCommonAncestor, getTargetNodePath, InitialEvent, MaxMacrostepIterations, normalizeTransition, planConfiguration, removeConflictingTransitions, sortEntryPaths, sortEvaluatedTransitions, sortExitPaths, validateDeclaredTransitionTarget } from "./planner.js";
10
+ import { decodeEmitSync, decodeEventSync, decodeInputSync, decodeStateValueSync } from "./protocol.js";
11
+ import { isSnapshot, isTarget, TargetSnapshotTypeId } from "./topology.js";
12
+ const indexedStateConfigKeys = new Set([
13
+ "initial",
14
+ "invoke",
15
+ "on",
16
+ "output"
17
+ ]);
18
+ // Fail closed so a newly introduced semantic field must explicitly opt into
19
+ // indexed execution instead of being accepted before the kernel supports it.
20
+ const supportsIndexedStateConfig = (config) => {
21
+ if (config === undefined) {
22
+ return true;
23
+ }
24
+ for (const key of Reflect.ownKeys(config)) {
25
+ if (!indexedStateConfigKeys.has(key)) {
26
+ return false;
27
+ }
28
+ }
29
+ return true;
30
+ };
31
+ const compileIndexedExecutionDescriptor = (machine) => {
32
+ const nodes = [];
33
+ const leafPaths = [];
34
+ const finalPaths = [];
35
+ const transitionsByPath = new Map();
36
+ for (const node of machine.stateNodes.byPath.values()) {
37
+ nodes.push(node);
38
+ if (node.type === "choice" || node.type === "history") {
39
+ return undefined;
40
+ }
41
+ if (node.type === "atomic" || node.type === "final") {
42
+ leafPaths.push(node.path);
43
+ }
44
+ if (node.type === "final") {
45
+ finalPaths.push(node.path);
46
+ }
47
+ const config = machine.handlers[node.path];
48
+ if (!supportsIndexedStateConfig(config)) {
49
+ return undefined;
50
+ }
51
+ if (config?.on === undefined) {
52
+ continue;
53
+ }
54
+ const byEvent = new Map();
55
+ for (const tag of Reflect.ownKeys(config.on)) {
56
+ const transition = normalizeTransition(config.on[tag]);
57
+ if (transition !== undefined) {
58
+ byEvent.set(tag, transition);
59
+ }
60
+ }
61
+ if (byEvent.size > 0) {
62
+ transitionsByPath.set(node.path, byEvent);
63
+ }
64
+ }
65
+ leafPaths.sort((left, right) => compareDocumentOrder(machine, left, right));
66
+ finalPaths.sort((left, right) => compareDocumentOrder(machine, left, right));
67
+ nodes.sort((left, right) => left.order - right.order);
68
+ const indexByPath = new Map(nodes.map((node, index) => [node.path, index]));
69
+ const indexOf = (path) => {
70
+ const index = indexByPath.get(path);
71
+ if (index === undefined) {
72
+ throw new Error(`Machine expected compiled state path "${path}"`);
73
+ }
74
+ return index;
75
+ };
76
+ const leafIndices = leafPaths.map(indexOf);
77
+ const parentIndices = nodes.map((node) => node.parent === undefined ? -1 : indexOf(node.parent));
78
+ const childIndices = nodes.map((node) => node.children.map(indexOf));
79
+ const ancestorIndices = nodes.map((node) => getPathToRoot(machine, node.path).slice(0, -1).map(indexOf));
80
+ const transitionsByIndex = nodes.map((node) => transitionsByPath.get(node.path));
81
+ const dispatchByLeaf = new Map();
82
+ for (const leafIndex of leafIndices) {
83
+ const dispatch = new Map();
84
+ const candidates = [leafIndex, ...ancestorIndices[leafIndex].slice().reverse()];
85
+ for (const sourceIndex of candidates) {
86
+ for (const [tag, transition] of transitionsByIndex[sourceIndex] ?? []) {
87
+ if (!dispatch.has(tag))
88
+ dispatch.set(tag, { sourceIndex, transition });
89
+ }
90
+ }
91
+ dispatchByLeaf.set(leafIndex, dispatch);
92
+ }
93
+ return {
94
+ flat: nodes.every((node) => node.parent === undefined && (node.type === "atomic" || node.type === "final")),
95
+ nodes,
96
+ indexByPath,
97
+ parentIndices,
98
+ childIndices,
99
+ ancestorIndices,
100
+ rootIndices: nodes.flatMap((node, index) => node.parent === undefined ? [index] : []),
101
+ leafIndices,
102
+ finalIndices: finalPaths.map(indexOf),
103
+ dispatchByLeaf
104
+ };
105
+ };
106
+ const updateOwnedIndexedValue = (state, index, value) => {
107
+ state.values[index] = value;
108
+ };
109
+ const ownedIndexedStateFromActive = (descriptor, configuration) => {
110
+ const active = new Uint8Array(descriptor.nodes.length);
111
+ const values = new Array(descriptor.nodes.length);
112
+ const completed = new Uint8Array(descriptor.nodes.length);
113
+ const outputs = new Array(descriptor.nodes.length);
114
+ const completedOrder = [];
115
+ for (const path of configuration.active) {
116
+ const index = descriptor.indexByPath.get(path);
117
+ if (index === undefined)
118
+ throw new Error(`Machine expected indexed active path "${path}"`);
119
+ active[index] = 1;
120
+ values[index] = configuration.values.get(path);
121
+ }
122
+ for (const [path, output] of configuration.outputs) {
123
+ const index = descriptor.indexByPath.get(path);
124
+ if (index === undefined)
125
+ throw new Error(`Machine expected indexed completed path "${path}"`);
126
+ completed[index] = 1;
127
+ outputs[index] = output;
128
+ completedOrder.push(index);
129
+ }
130
+ return {
131
+ active,
132
+ activeLeaves: descriptor.leafIndices.filter((index) => active[index] === 1),
133
+ values,
134
+ completed,
135
+ outputs,
136
+ completedOrder
137
+ };
138
+ };
139
+ const activeConfigurationFromIndexedState = (descriptor, configuration) => {
140
+ const active = new Set();
141
+ const values = new Map();
142
+ const outputs = new Map();
143
+ for (let index = 0; index < descriptor.nodes.length; index++) {
144
+ if (configuration.active[index] !== 1)
145
+ continue;
146
+ const path = descriptor.nodes[index].path;
147
+ active.add(path);
148
+ values.set(path, configuration.values[index]);
149
+ }
150
+ for (const index of configuration.completedOrder) {
151
+ if (configuration.completed[index] === 1) {
152
+ outputs.set(descriptor.nodes[index].path, configuration.outputs[index]);
153
+ }
154
+ }
155
+ return { active, values, outputs, history: new Map() };
156
+ };
157
+ const snapshotFromIndexedStateStatePath = (descriptor, configuration, index) => {
158
+ const node = descriptor.nodes[index];
159
+ const snapshot = {
160
+ path: node.path,
161
+ value: configuration.values[index]
162
+ };
163
+ if (node.type === "compound") {
164
+ const childIndex = descriptor.childIndices[index].find((childIndex) => configuration.active[childIndex] === 1);
165
+ if (childIndex === undefined) {
166
+ throw new Error(`Machine expected indexed compound state "${node.path}" to have an active child`);
167
+ }
168
+ snapshot.state = snapshotFromIndexedStateStatePath(descriptor, configuration, childIndex);
169
+ }
170
+ else if (node.type === "parallel") {
171
+ const states = {};
172
+ for (const childIndex of descriptor.childIndices[index]) {
173
+ if (configuration.active[childIndex] !== 1) {
174
+ throw new Error(`Machine expected indexed parallel state "${node.path}" to have active region "${descriptor.nodes[childIndex].path}"`);
175
+ }
176
+ states[descriptor.nodes[childIndex].key] = snapshotFromIndexedStateStatePath(descriptor, configuration, childIndex);
177
+ }
178
+ snapshot.states = states;
179
+ }
180
+ return snapshot;
181
+ };
182
+ const snapshotFromIndexedState = (descriptor, configuration) => {
183
+ const rootIndex = descriptor.rootIndices.find((index) => configuration.active[index] === 1);
184
+ if (rootIndex === undefined)
185
+ throw new Error("Machine expected an active indexed root state");
186
+ const snapshot = snapshotFromIndexedStateStatePath(descriptor, configuration, rootIndex);
187
+ if (configuration.completedOrder.length > 0) {
188
+ ;
189
+ snapshot.completed = configuration.completedOrder.map((index) => ({
190
+ path: descriptor.nodes[index].path,
191
+ output: configuration.outputs[index]
192
+ }));
193
+ }
194
+ return snapshot;
195
+ };
196
+ const makeIndexedTransitionContext = (machine, descriptor, configuration, sourceIndex, event) => {
197
+ const source = descriptor.nodes[sourceIndex];
198
+ const parentIndex = descriptor.parentIndices[sourceIndex];
199
+ const parents = {};
200
+ for (const ancestorIndex of descriptor.ancestorIndices[sourceIndex]) {
201
+ parents[descriptor.nodes[ancestorIndex].path] = configuration.values[ancestorIndex];
202
+ }
203
+ return {
204
+ state: configuration.values[sourceIndex],
205
+ parent: parentIndex < 0 ? undefined : configuration.values[parentIndex],
206
+ parents,
207
+ event,
208
+ snapshot: snapshotFromIndexedState(descriptor, configuration),
209
+ target: getTargetBuilder(machine, source.path)
210
+ };
211
+ };
212
+ const emptyExecutionValues = Object.freeze([]);
213
+ const collectIndexedTransition = (machine, transition, context) => {
214
+ let commands;
215
+ let raisedEvents;
216
+ let emittedEvents;
217
+ const state = transition(context, {
218
+ raise: (event) => {
219
+ ;
220
+ (raisedEvents ??= []).push(decodeEventSync(machine, event));
221
+ },
222
+ emit: (event) => {
223
+ ;
224
+ (emittedEvents ??= []).push(decodeEmitSync(machine, event));
225
+ },
226
+ sendTo: (child, event) => {
227
+ ;
228
+ (commands ??= []).push({ _tag: "SendTo", child: child, event });
229
+ },
230
+ stop: (child) => {
231
+ ;
232
+ (commands ??= []).push({ _tag: "Stop", child: child });
233
+ }
234
+ });
235
+ return {
236
+ state,
237
+ commands: commands ?? emptyExecutionValues,
238
+ raisedEvents: raisedEvents ?? emptyExecutionValues,
239
+ emittedEvents: emittedEvents ?? emptyExecutionValues
240
+ };
241
+ };
242
+ const selectIndexedEventTransitions = (machine, descriptor, configuration, event) => {
243
+ const selected = [];
244
+ for (const leafIndex of configuration.activeLeaves) {
245
+ const dispatched = descriptor.dispatchByLeaf.get(leafIndex).get(event._tag);
246
+ if (dispatched !== undefined) {
247
+ const { sourceIndex, transition } = dispatched;
248
+ if (!selected.some((selection) => selection.sourceIndex === sourceIndex)) {
249
+ const sourcePath = descriptor.nodes[sourceIndex].path;
250
+ selected.push({
251
+ sourceIndex,
252
+ leafIndex,
253
+ sourcePath,
254
+ leafPath: descriptor.nodes[leafIndex].path,
255
+ trigger: { type: "event", event: event._tag },
256
+ transition,
257
+ context: makeIndexedTransitionContext(machine, descriptor, configuration, sourceIndex, event)
258
+ });
259
+ }
260
+ }
261
+ }
262
+ return selected;
263
+ };
264
+ const hasSameIndexedActive = (left, right) => {
265
+ if (left.active === right.active)
266
+ return true;
267
+ for (let index = 0; index < left.active.length; index++) {
268
+ if (left.active[index] !== right.active[index])
269
+ return false;
270
+ }
271
+ return true;
272
+ };
273
+ const normalizeIndexedTargetStateSync = (machine, descriptor, current, target, activeLeafIndex) => {
274
+ const targetIndex = isTarget(target) ? descriptor.indexByPath.get(String(target.path)) : undefined;
275
+ if (targetIndex === activeLeafIndex && current.active[activeLeafIndex] === 1 && isTarget(target) &&
276
+ target[TargetSnapshotTypeId] === undefined && target.values === undefined && current.completedOrder.length === 0) {
277
+ const values = current.values.slice();
278
+ values[activeLeafIndex] = decodeStateValueSync(machine, descriptor.nodes[activeLeafIndex], target.value);
279
+ return { ...current, values };
280
+ }
281
+ return ownedIndexedStateFromActive(descriptor, normalizeTargetConfigurationSync(machine, activeConfigurationFromIndexedState(descriptor, current), target));
282
+ };
283
+ const collectIndexedEvaluatedTransition = (machine, descriptor, state, selection) => {
284
+ const transitionResult = collectIndexedTransition(machine, selection.transition.transition, selection.context);
285
+ const target = transitionResult.state;
286
+ validateDeclaredTransitionTarget(selection.sourcePath, selection.trigger, selection.transition.targets, target);
287
+ if (target !== undefined && !isTarget(target) && !isSnapshot(target)) {
288
+ throw new Error("Machine expected indexed transition target to be a snapshot or target builder result");
289
+ }
290
+ const next = target === undefined
291
+ ? state
292
+ : normalizeIndexedTargetStateSync(machine, descriptor, state, target, selection.leafIndex);
293
+ const changed = selection.transition.reenter || !hasSameIndexedActive(state, next);
294
+ if (!changed) {
295
+ return {
296
+ selection,
297
+ unresolvedTarget: target,
298
+ target: target,
299
+ next,
300
+ commands: transitionResult.commands,
301
+ raisedEvents: transitionResult.raisedEvents,
302
+ emittedEvents: transitionResult.emittedEvents,
303
+ changed: false,
304
+ exitPaths: [],
305
+ entryPaths: [],
306
+ choiceTransitions: []
307
+ };
308
+ }
309
+ const targetPath = target === undefined ? undefined : getTargetNodePath(target);
310
+ const naturalBoundary = targetPath === undefined
311
+ ? descriptor.nodes[selection.sourceIndex].parent
312
+ : getLeastCommonAncestor(machine, selection.leafPath, targetPath);
313
+ const reentryBoundary = descriptor.nodes[selection.sourceIndex].parent;
314
+ const boundary = selection.transition.reenter
315
+ ? broadenTransitionBoundary(naturalBoundary, reentryBoundary)
316
+ : naturalBoundary;
317
+ return {
318
+ selection,
319
+ unresolvedTarget: target,
320
+ target: target,
321
+ next,
322
+ commands: transitionResult.commands,
323
+ raisedEvents: transitionResult.raisedEvents,
324
+ emittedEvents: transitionResult.emittedEvents,
325
+ changed: true,
326
+ exitPaths: getExitPaths(machine, activeConfigurationFromIndexedState(descriptor, state), boundary),
327
+ entryPaths: getEntryPaths(machine, activeConfigurationFromIndexedState(descriptor, next), boundary),
328
+ choiceTransitions: []
329
+ };
330
+ };
331
+ const indexedMicrostep = (machine, descriptor, state, event, selections) => {
332
+ if (selections.length === 1) {
333
+ const transition = collectIndexedEvaluatedTransition(machine, descriptor, state, selections[0]);
334
+ return {
335
+ next: transition.next,
336
+ event,
337
+ commands: transition.commands,
338
+ raisedEvents: transition.raisedEvents,
339
+ emittedEvents: transition.emittedEvents,
340
+ exitPaths: transition.exitPaths,
341
+ entryPaths: transition.entryPaths,
342
+ changed: transition.changed
343
+ };
344
+ }
345
+ const activeSelections = selections.filter((selection) => !selections.some((other) => other.sourceIndex !== selection.sourceIndex &&
346
+ isDescendantOf(other.sourcePath, selection.sourcePath)));
347
+ const evaluated = activeSelections.map((selection) => collectIndexedEvaluatedTransition(machine, descriptor, state, selection));
348
+ const transitions = sortEvaluatedTransitions(machine, removeConflictingTransitions(machine, evaluated));
349
+ let next = state;
350
+ if (transitions.length === 1) {
351
+ next = transitions[0].next;
352
+ }
353
+ else {
354
+ const applicationOrder = [
355
+ ...transitions.filter((transition) => !transition.changed),
356
+ ...transitions.filter((transition) => transition.changed)
357
+ ];
358
+ for (const transition of applicationOrder) {
359
+ if (transition.target !== undefined) {
360
+ next = normalizeIndexedTargetStateSync(machine, descriptor, next, transition.target, transition.selection.leafIndex);
361
+ }
362
+ }
363
+ }
364
+ const commands = transitions.flatMap((transition) => transition.commands);
365
+ const raisedEvents = transitions.flatMap((transition) => transition.raisedEvents);
366
+ const emittedEvents = transitions.flatMap((transition) => transition.emittedEvents);
367
+ const changed = transitions.some((transition) => transition.changed);
368
+ return {
369
+ next,
370
+ event,
371
+ commands,
372
+ raisedEvents,
373
+ emittedEvents,
374
+ exitPaths: changed ? sortExitPaths(machine, transitions.flatMap((transition) => transition.exitPaths)) : [],
375
+ entryPaths: changed ? sortEntryPaths(machine, transitions.flatMap((transition) => transition.entryPaths)) : [],
376
+ changed
377
+ };
378
+ };
379
+ const planIndexedFlatState = (machine, descriptor, configuration, decoded) => {
380
+ let current = configuration;
381
+ let event = decoded;
382
+ let commands;
383
+ let raisedEvents;
384
+ let emittedEvents;
385
+ let microsteps;
386
+ let raisedIndex = 0;
387
+ let iterations = 0;
388
+ while (true) {
389
+ iterations += 1;
390
+ if (iterations > MaxMacrostepIterations) {
391
+ throw new InfiniteTransitionError({
392
+ machineId: machine.id,
393
+ state: descriptor.nodes[current.activeLeaves[0]].path,
394
+ maxIterations: MaxMacrostepIterations
395
+ });
396
+ }
397
+ const sourceIndex = current.activeLeaves[0];
398
+ if (sourceIndex === undefined) {
399
+ throw new Error("Machine expected an active indexed root state");
400
+ }
401
+ if (descriptor.nodes[sourceIndex].type === "final") {
402
+ const completed = completeConfigurationSync(machine, activeConfigurationFromIndexedState(descriptor, current), event).configuration;
403
+ const root = getRootPath(machine, completed);
404
+ if (!completed.outputs.has(root)) {
405
+ throw new Error("Machine reached a terminal indexed configuration without a completed root output");
406
+ }
407
+ return {
408
+ next: ownedIndexedStateFromActive(descriptor, completed),
409
+ commands: commands ?? emptyExecutionValues,
410
+ emittedEvents: emittedEvents ?? emptyExecutionValues,
411
+ microsteps: microsteps ?? emptyExecutionValues,
412
+ done: true,
413
+ output: completed.outputs.get(root)
414
+ };
415
+ }
416
+ const sourcePath = descriptor.nodes[sourceIndex].path;
417
+ const transition = normalizeTransition(machine.handlers[sourcePath]?.on?.[event._tag]);
418
+ if (transition !== undefined) {
419
+ const transitionResult = collectIndexedTransition(machine, transition.transition, {
420
+ state: current.values[sourceIndex],
421
+ parent: undefined,
422
+ parents: {},
423
+ event,
424
+ snapshot: snapshotFromIndexedState(descriptor, current),
425
+ target: getTargetBuilder(machine, sourcePath)
426
+ });
427
+ const target = transitionResult.state;
428
+ validateDeclaredTransitionTarget(sourcePath, { type: "event", event: event._tag }, transition.targets, target);
429
+ if (target !== undefined && !isTarget(target) && !isSnapshot(target)) {
430
+ throw new Error("Machine expected indexed transition target to be a snapshot or target builder result");
431
+ }
432
+ let next = current;
433
+ if (target !== undefined) {
434
+ const targetIndex = descriptor.indexByPath.get(String(target.path));
435
+ const isSimpleTarget = isTarget(target)
436
+ ? target[TargetSnapshotTypeId] === undefined && target.values === undefined
437
+ : !("state" in target) && !("states" in target) && !("completed" in target) && !("history" in target);
438
+ if (targetIndex === sourceIndex && isSimpleTarget && current.completedOrder.length === 0) {
439
+ updateOwnedIndexedValue(current, sourceIndex, decodeStateValueSync(machine, descriptor.nodes[sourceIndex], target.value));
440
+ }
441
+ else {
442
+ next = normalizeIndexedTargetStateSync(machine, descriptor, current, target, sourceIndex);
443
+ }
444
+ }
445
+ const changed = transition.reenter || !hasSameIndexedActive(current, next);
446
+ const nextIndex = next.activeLeaves[0];
447
+ if (nextIndex === undefined) {
448
+ throw new Error("Machine expected an active indexed transition target");
449
+ }
450
+ const step = {
451
+ next,
452
+ event,
453
+ commands: transitionResult.commands,
454
+ raisedEvents: transitionResult.raisedEvents,
455
+ emittedEvents: transitionResult.emittedEvents,
456
+ exitPaths: changed ? [sourcePath] : emptyExecutionValues,
457
+ entryPaths: changed ? [descriptor.nodes[nextIndex].path] : emptyExecutionValues,
458
+ changed
459
+ };
460
+ current = next;
461
+ (microsteps ??= []).push(step);
462
+ if (transitionResult.commands.length > 0) {
463
+ ;
464
+ (commands ??= []).push(...transitionResult.commands);
465
+ }
466
+ if (transitionResult.raisedEvents.length > 0) {
467
+ ;
468
+ (raisedEvents ??= []).push(...transitionResult.raisedEvents);
469
+ }
470
+ if (transitionResult.emittedEvents.length > 0) {
471
+ ;
472
+ (emittedEvents ??= []).push(...transitionResult.emittedEvents);
473
+ }
474
+ }
475
+ if (descriptor.nodes[current.activeLeaves[0]].type === "final") {
476
+ continue;
477
+ }
478
+ const raised = raisedEvents?.[raisedIndex];
479
+ if (raised === undefined) {
480
+ return {
481
+ next: current,
482
+ commands: commands ?? emptyExecutionValues,
483
+ emittedEvents: emittedEvents ?? emptyExecutionValues,
484
+ microsteps: microsteps ?? emptyExecutionValues,
485
+ done: false,
486
+ output: undefined
487
+ };
488
+ }
489
+ raisedIndex += 1;
490
+ event = raised;
491
+ }
492
+ };
493
+ const planIndexedState = (machine, descriptor, configuration, input) => {
494
+ const decoded = decodeEventSync(machine, input);
495
+ if (descriptor.flat) {
496
+ return planIndexedFlatState(machine, descriptor, configuration, decoded);
497
+ }
498
+ if (descriptor.finalIndices.some((index) => configuration.active[index] === 1)) {
499
+ const active = activeConfigurationFromIndexedState(descriptor, configuration);
500
+ if (isActiveFinalConfiguration(machine, active)) {
501
+ const completed = completeConfigurationSync(machine, active, decoded).configuration;
502
+ const root = getRootPath(machine, completed);
503
+ if (!completed.outputs.has(root)) {
504
+ throw new Error("Machine reached a terminal indexed configuration without a completed root output");
505
+ }
506
+ return {
507
+ next: ownedIndexedStateFromActive(descriptor, completed),
508
+ commands: [],
509
+ emittedEvents: [],
510
+ microsteps: [],
511
+ done: true,
512
+ output: completed.outputs.get(root)
513
+ };
514
+ }
515
+ }
516
+ const selections = selectIndexedEventTransitions(machine, descriptor, configuration, decoded);
517
+ if (selections.length === 0) {
518
+ return {
519
+ next: configuration,
520
+ commands: [],
521
+ emittedEvents: [],
522
+ microsteps: [],
523
+ done: false,
524
+ output: undefined
525
+ };
526
+ }
527
+ const first = indexedMicrostep(machine, descriptor, configuration, decoded, selections);
528
+ let current = first.next;
529
+ let currentEvent = decoded;
530
+ const commands = [...first.commands];
531
+ const raisedEvents = [...first.raisedEvents];
532
+ const emittedEvents = [...first.emittedEvents];
533
+ const microsteps = [first];
534
+ let raisedIndex = 0;
535
+ let iterations = 0;
536
+ while (true) {
537
+ iterations += 1;
538
+ if (iterations > MaxMacrostepIterations) {
539
+ throw new InfiniteTransitionError({
540
+ machineId: machine.id,
541
+ state: descriptor.nodes[descriptor.leafIndices.find((index) => current.active[index] === 1)].path,
542
+ maxIterations: MaxMacrostepIterations
543
+ });
544
+ }
545
+ if (descriptor.finalIndices.some((index) => current.active[index] === 1)) {
546
+ const completed = completeConfigurationSync(machine, activeConfigurationFromIndexedState(descriptor, current), currentEvent).configuration;
547
+ current = ownedIndexedStateFromActive(descriptor, completed);
548
+ if (isActiveFinalConfiguration(machine, completed)) {
549
+ const root = getRootPath(machine, completed);
550
+ if (!completed.outputs.has(root)) {
551
+ throw new Error("Machine reached a terminal indexed configuration without a completed root output");
552
+ }
553
+ return {
554
+ next: current,
555
+ commands,
556
+ emittedEvents,
557
+ microsteps,
558
+ done: true,
559
+ output: completed.outputs.get(root)
560
+ };
561
+ }
562
+ }
563
+ const raised = raisedEvents[raisedIndex];
564
+ if (raised === undefined) {
565
+ return {
566
+ next: current,
567
+ commands,
568
+ emittedEvents,
569
+ microsteps,
570
+ done: false,
571
+ output: undefined
572
+ };
573
+ }
574
+ raisedIndex += 1;
575
+ currentEvent = raised;
576
+ const raisedSelections = selectIndexedEventTransitions(machine, descriptor, current, raised);
577
+ if (raisedSelections.length === 0)
578
+ continue;
579
+ const step = indexedMicrostep(machine, descriptor, current, raised, raisedSelections);
580
+ current = step.next;
581
+ commands.push(...step.commands);
582
+ raisedEvents.push(...step.raisedEvents);
583
+ emittedEvents.push(...step.emittedEvents);
584
+ microsteps.push(step);
585
+ }
586
+ };
587
+ const executionPlanCache = new WeakMap();
588
+ const makeActiveExecutionPlan = (machine) => ({
589
+ fromConfiguration: (configuration) => configuration,
590
+ toConfiguration: (state) => state,
591
+ snapshot: (state) => snapshotFromConfiguration(machine, state),
592
+ plan: (state, event) => planConfiguration(machine, state, event)
593
+ });
594
+ const makeIndexedExecutionPlan = (machine, indexed) => ({
595
+ fromConfiguration: (configuration) => ownedIndexedStateFromActive(indexed, configuration),
596
+ toConfiguration: (state) => activeConfigurationFromIndexedState(indexed, state),
597
+ snapshot: (state) => snapshotFromIndexedState(indexed, state),
598
+ plan: (state, event) => planIndexedState(machine, indexed, state, event),
599
+ initial: (args) => {
600
+ const inputArgs = machine.input === undefined
601
+ ? args
602
+ : args.length === 0
603
+ ? (decodeInputSync(machine, machine.input, undefined), args)
604
+ : [decodeInputSync(machine, machine.input, args[0])];
605
+ const initial = machine.initial(...inputArgs);
606
+ const active = normalizeConfigurationSync(machine, initial);
607
+ validateInitialConfiguration(machine, active);
608
+ const completed = completeConfigurationSync(machine, active, InitialEvent).configuration;
609
+ const configuration = ownedIndexedStateFromActive(indexed, completed);
610
+ const state = snapshotFromIndexedState(indexed, configuration);
611
+ const done = isActiveFinalConfiguration(machine, completed);
612
+ if (!done) {
613
+ return {
614
+ state,
615
+ configuration,
616
+ activeConfiguration: completed,
617
+ initialEntryPaths: getInitialEntryPaths(machine, completed),
618
+ done: false,
619
+ output: undefined
620
+ };
621
+ }
622
+ const root = getRootPath(machine, completed);
623
+ if (!completed.outputs.has(root)) {
624
+ throw new Error("Machine reached a terminal configuration without a completed root output");
625
+ }
626
+ return {
627
+ state,
628
+ configuration,
629
+ activeConfiguration: completed,
630
+ initialEntryPaths: getInitialEntryPaths(machine, completed),
631
+ done: true,
632
+ output: completed.outputs.get(root)
633
+ };
634
+ }
635
+ });
636
+ const selectExecutionPlan = (machine, strategy) => {
637
+ if (strategy === "generic") {
638
+ return { strategy, plan: makeActiveExecutionPlan(machine) };
639
+ }
640
+ const indexed = compileIndexedExecutionDescriptor(machine);
641
+ if (indexed === undefined) {
642
+ if (strategy === "auto") {
643
+ return { strategy: "generic", plan: makeActiveExecutionPlan(machine) };
644
+ }
645
+ throw new Error(`Machine cannot compile the requested ${strategy} execution plan`);
646
+ }
647
+ const selected = indexed.flat ? "indexed-flat" : "indexed-hierarchical";
648
+ if (strategy !== "auto" && strategy !== selected) {
649
+ throw new Error(`Machine compiled ${selected}, not the requested ${strategy} execution plan`);
650
+ }
651
+ return { strategy: selected, plan: makeIndexedExecutionPlan(machine, indexed) };
652
+ };
653
+ /** @internal Test-only uncached strategy selection. */
654
+ export const selectExecutionPlanForTesting = (machine, strategy) => selectExecutionPlan(machine, strategy);
655
+ export const compileExecutionPlan = (machine) => {
656
+ const cached = executionPlanCache.get(machine);
657
+ if (cached !== undefined) {
658
+ return cached;
659
+ }
660
+ const indexed = compileIndexedExecutionDescriptor(machine);
661
+ const compiled = indexed === undefined
662
+ ? makeActiveExecutionPlan(machine)
663
+ : makeIndexedExecutionPlan(machine, indexed);
664
+ executionPlanCache.set(machine, compiled);
665
+ return compiled;
666
+ };
667
+ //# sourceMappingURL=executionPlan.js.map