@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.
Files changed (149) hide show
  1. package/README.md +203 -16
  2. package/dist/Machine.d.ts +784 -289
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +158 -528
  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} +14 -118
  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} +11 -60
  27. package/dist/internal/machine/configuration.d.ts.map +1 -0
  28. package/dist/internal/{machineModel.js → machine/configuration.js} +249 -544
  29. package/dist/internal/machine/configuration.js.map +1 -0
  30. package/dist/internal/{machineErrors.d.ts → machine/errors.d.ts} +1 -1
  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} +19 -27
  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} +35 -20
  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 +169 -31
  127. package/package.json +19 -10
  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.map +0 -1
  138. package/dist/internal/machinePlanner.d.ts +0 -74
  139. package/dist/internal/machinePlanner.d.ts.map +0 -1
  140. package/dist/internal/machinePlanner.js +0 -797
  141. package/dist/internal/machinePlanner.js.map +0 -1
  142. package/dist/internal/machineProcess.d.ts.map +0 -1
  143. package/dist/internal/machineProcess.js +0 -181
  144. package/dist/internal/machineProcess.js.map +0 -1
  145. package/dist/internal/machineRuntime.d.ts.map +0 -1
  146. package/dist/internal/machineRuntime.js +0 -365
  147. package/dist/internal/machineRuntime.js.map +0 -1
  148. package/dist/reactivity.d.ts.map +0 -1
  149. package/dist/reactivity.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Internal machine representation helpers.
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 * as Schema from "effect/Schema";
11
- import { MachineSchemaDecodeError, MachineSchemaEncodeError } from "./machineErrors.js";
12
- export const TargetTypeId = "~effect/Machine/Target";
13
- export const TargetSnapshotTypeId = Symbol("effect/Machine/TargetSnapshot");
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: Array.from(record.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
- export const makeHistoryTarget = (path, parent) => ({
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
- if (!Schema.is(getStateNodeSchema(node))(current.value)) {
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, current.value);
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
- if (child !== node.initial) {
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) || !current.active.has(child)) {
594
+ if (pathSet.has(child))
798
595
  continue;
799
- }
800
- for (const activePath of current.active) {
801
- if (isPathInSubtree(activePath, child)) {
802
- active.add(activePath);
803
- if (current.values.has(activePath)) {
804
- values.set(activePath, current.values.get(activePath));
805
- }
806
- if (current.outputs.has(activePath)) {
807
- outputs.set(activePath, current.outputs.get(activePath));
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 EncodedSnapshotSchema = Schema.Struct({
968
- _tag: Schema.Literal("MachineSnapshot"),
969
- active: Schema.Array(Schema.Struct({
970
- path: Schema.String,
971
- value: Schema.Unknown
972
- })),
973
- completed: Schema.optional(Schema.Array(Schema.Struct({
974
- path: Schema.String,
975
- output: Schema.optional(Schema.Unknown)
976
- }))),
977
- history: Schema.optional(Schema.Record(Schema.String, Schema.Struct({
978
- mode: Schema.Literals(["shallow", "deep"]),
979
- active: Schema.Array(Schema.String),
980
- values: Schema.Record(Schema.String, Schema.Unknown)
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
- throw new Error(`Machine expected completed state "${path}" to have an active child`);
1001
- }
1002
- return getCompletionSchema(machine, configuration, child);
1003
- }
1004
- return node.output ?? Schema.Void;
1005
- };
1006
- const validateEncodedConfiguration = (machine, configuration) => {
1007
- const snapshot = snapshotFromConfiguration(machine, configuration);
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
- const history = new Map();
1155
- for (const [historyPath, encodedRecord] of Object.entries(decoded.history ?? {})) {
1156
- const historyNode = machine.stateNodes.byPath.get(historyPath);
1157
- if (historyNode === undefined || historyNode.type !== "history" || historyNode.parent === undefined ||
1158
- historyNode.history !== encodedRecord.mode) {
1159
- return yield* Effect.fail(new MachineSchemaDecodeError({
1160
- machineId: machine.id,
1161
- boundary: "history",
1162
- state: historyPath,
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
- history.set(historyPath, record);
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
- const configuration = {
1230
- active,
1231
- values,
1232
- outputs: new Map(),
1233
- history
1234
- };
1235
- const snapshot = validateEncodedConfiguration(machine, configuration);
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 completionPaths = new Set();
1238
- for (const completion of decoded.completed ?? []) {
1239
- if (completionPaths.has(completion.path)) {
1240
- throw new Error(`Machine encoded snapshot contains duplicate completion "${completion.path}"`);
1241
- }
1242
- if (!active.has(completion.path) || !isActiveFinalNode(machine, configuration, completion.path)) {
1243
- throw new Error(`Machine encoded snapshot contains invalid completion "${completion.path}"`);
1244
- }
1245
- completionPaths.add(completion.path);
1246
- completions.push({
1247
- path: completion.path,
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 snapshot;
1259
- }).pipe(Effect.catchCause((cause) => failDecodeCause(machine, cause)));
1260
- //# sourceMappingURL=machineModel.js.map
963
+ return { configuration: completed, completions };
964
+ };
965
+ //# sourceMappingURL=configuration.js.map