@typeonce/effect-machine 0.7.0 → 0.9.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 +85 -24
- package/dist/Machine.d.ts +545 -444
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +69 -172
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/activities.d.ts +5 -12
- package/dist/internal/machine/activities.d.ts.map +1 -1
- package/dist/internal/machine/activities.js +47 -17
- package/dist/internal/machine/activities.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +10 -4
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +103 -20
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +31 -0
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/invocation.d.ts +10 -2
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +93 -34
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/invocationEvent.d.ts +39 -0
- package/dist/internal/machine/invocationEvent.d.ts.map +1 -0
- package/dist/internal/machine/invocationEvent.js +43 -0
- package/dist/internal/machine/invocationEvent.js.map +1 -0
- package/dist/internal/machine/machine.d.ts +6 -50
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +30 -81
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +12 -1
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +90 -37
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/protocol.d.ts +9 -0
- package/dist/internal/machine/protocol.d.ts.map +1 -1
- package/dist/internal/machine/protocol.js +114 -0
- package/dist/internal/machine/protocol.js.map +1 -1
- package/dist/internal/machine/serialization.d.ts.map +1 -1
- package/dist/internal/machine/serialization.js +53 -21
- package/dist/internal/machine/serialization.js.map +1 -1
- package/dist/internal/machine/stateDefinition.d.ts +4 -4
- package/dist/internal/machine/stateDefinition.d.ts.map +1 -1
- package/dist/internal/machine/stateDefinition.js +18 -11
- package/dist/internal/machine/stateDefinition.js.map +1 -1
- package/dist/internal/machine/symbols.d.ts +2 -0
- package/dist/internal/machine/symbols.d.ts.map +1 -1
- package/dist/internal/machine/symbols.js +2 -0
- package/dist/internal/machine/symbols.js.map +1 -1
- package/dist/internal/machine/topology.d.ts +5 -5
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +39 -13
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +10 -3
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +11 -5
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +174 -121
- package/package.json +3 -3
- package/src/Machine.ts +1336 -872
- package/src/internal/machine/activities.ts +48 -33
- package/src/internal/machine/atom.ts +13 -6
- package/src/internal/machine/configuration.ts +102 -23
- package/src/internal/machine/executionPlan.ts +35 -0
- package/src/internal/machine/invocation.ts +180 -49
- package/src/internal/machine/invocationEvent.ts +72 -0
- package/src/internal/machine/machine.ts +105 -403
- package/src/internal/machine/planner.ts +110 -48
- package/src/internal/machine/protocol.ts +149 -0
- package/src/internal/machine/serialization.ts +56 -31
- package/src/internal/machine/stateDefinition.ts +22 -11
- package/src/internal/machine/symbols.ts +3 -0
- package/src/internal/machine/topology.ts +44 -18
- package/src/internal/testing/machine/verification.ts +13 -3
- package/src/unstable/reactivity/AtomMachine.ts +12 -5
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* @since 0.4.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
export const ActivityMetadataTypeId: unique symbol = Symbol.for("effect/Machine/ActivityMetadata")
|
|
7
|
+
import * as Duration from "effect/Duration"
|
|
9
8
|
|
|
10
9
|
/** @internal */
|
|
11
10
|
export type StaticActivityMetadata =
|
|
@@ -21,8 +20,7 @@ export type StaticActivityMetadata =
|
|
|
21
20
|
}
|
|
22
21
|
| {
|
|
23
22
|
readonly type: "timer"
|
|
24
|
-
readonly duration: string
|
|
25
|
-
readonly event: string
|
|
23
|
+
readonly duration: string | "dynamic"
|
|
26
24
|
}
|
|
27
25
|
| {
|
|
28
26
|
readonly type: "machine"
|
|
@@ -33,20 +31,10 @@ export type StaticActivityMetadata =
|
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
/** @internal */
|
|
36
|
-
export type ActivityDefinition<Source extends string = string> =
|
|
37
|
-
|
|
38
|
-
readonly source: Source
|
|
39
|
-
readonly id: string
|
|
40
|
-
} & StaticActivityMetadata)
|
|
41
|
-
| {
|
|
42
|
-
readonly source: Source
|
|
43
|
-
readonly type: "dynamic"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
interface ActivityDescriptor {
|
|
34
|
+
export type ActivityDefinition<Source extends string = string> = {
|
|
35
|
+
readonly source: Source
|
|
47
36
|
readonly id: string
|
|
48
|
-
|
|
49
|
-
}
|
|
37
|
+
} & StaticActivityMetadata
|
|
50
38
|
|
|
51
39
|
interface InspectableMachine {
|
|
52
40
|
readonly handlers: unknown
|
|
@@ -62,31 +50,60 @@ const isObject = (value: unknown): value is object =>
|
|
|
62
50
|
|
|
63
51
|
const getProperty = (value: unknown, key: PropertyKey): unknown => isObject(value) ? Reflect.get(value, key) : undefined
|
|
64
52
|
|
|
65
|
-
const hasActivityMetadata = (value: unknown): value is ActivityDescriptor =>
|
|
66
|
-
isObject(value) && typeof getProperty(value, "id") === "string" &&
|
|
67
|
-
isObject(getProperty(value, ActivityMetadataTypeId))
|
|
68
|
-
|
|
69
53
|
const appendStaticDefinition = (
|
|
70
54
|
definitions: Array<ActivityDefinition>,
|
|
71
55
|
source: string,
|
|
72
56
|
descriptor: unknown
|
|
73
57
|
): void => {
|
|
74
|
-
if (!
|
|
58
|
+
if (!isObject(descriptor)) return
|
|
59
|
+
const child = getProperty(descriptor, "child")
|
|
60
|
+
if (isObject(child)) {
|
|
61
|
+
const id = getProperty(child, "id")
|
|
62
|
+
if (typeof id !== "string") return
|
|
63
|
+
const machine = getProperty(child, "machine")
|
|
64
|
+
const machineId = getProperty(machine, "id")
|
|
65
|
+
definitions.push({
|
|
66
|
+
source,
|
|
67
|
+
id,
|
|
68
|
+
type: "machine",
|
|
69
|
+
child: { id, machineId: typeof machineId === "string" ? machineId : null }
|
|
70
|
+
})
|
|
75
71
|
return
|
|
76
72
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
73
|
+
const id = getProperty(descriptor, "id")
|
|
74
|
+
if (typeof id !== "string") return
|
|
75
|
+
if (Reflect.has(descriptor, "effect")) {
|
|
76
|
+
definitions.push({
|
|
77
|
+
source,
|
|
78
|
+
id,
|
|
79
|
+
type: "effect",
|
|
80
|
+
outcomes: {
|
|
81
|
+
success: "dynamic",
|
|
82
|
+
failure: Reflect.has(descriptor, "onFailure") ? "dynamic" : "none"
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
if (Reflect.has(descriptor, "after")) {
|
|
88
|
+
const after = getProperty(descriptor, "after")
|
|
89
|
+
definitions.push({
|
|
90
|
+
source,
|
|
91
|
+
id,
|
|
92
|
+
type: "timer",
|
|
93
|
+
duration: typeof after === "function" ? "dynamic" : Duration.format(Duration.fromInputUnsafe(after as any))
|
|
94
|
+
})
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
if (Reflect.has(descriptor, "logic")) {
|
|
98
|
+
definitions.push({ source, id, type: "process" })
|
|
99
|
+
}
|
|
82
100
|
}
|
|
83
101
|
|
|
84
102
|
/**
|
|
85
103
|
* Collects state-owned activity descriptions without executing user code.
|
|
86
104
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* definition order and descriptor array order.
|
|
105
|
+
* Source factories are inspected without execution. Static descriptors are
|
|
106
|
+
* returned in state definition order and descriptor array order.
|
|
90
107
|
*
|
|
91
108
|
* @internal
|
|
92
109
|
*/
|
|
@@ -94,9 +111,7 @@ export const activityDefinitions = (machine: InspectableMachine): ReadonlyArray<
|
|
|
94
111
|
const definitions: Array<ActivityDefinition> = []
|
|
95
112
|
for (const node of machine.stateNodes.byPath.values()) {
|
|
96
113
|
const invoke = getProperty(getProperty(machine.handlers, node.path), "invoke")
|
|
97
|
-
if (
|
|
98
|
-
definitions.push({ source: node.path, type: "dynamic" })
|
|
99
|
-
} else if (Array.isArray(invoke)) {
|
|
114
|
+
if (Array.isArray(invoke)) {
|
|
100
115
|
for (const descriptor of invoke) {
|
|
101
116
|
appendStaticDefinition(definitions, node.path, descriptor)
|
|
102
117
|
}
|
|
@@ -120,7 +120,7 @@ const startMachineAtomEffect = <
|
|
|
120
120
|
): Effect.Effect<
|
|
121
121
|
Machine.MachineRef<
|
|
122
122
|
Machine.Machine.Snapshot<States>,
|
|
123
|
-
Machine.Machine.
|
|
123
|
+
Machine.Machine.EventInputOf<InputEvents>,
|
|
124
124
|
MachineRuntimeError<E, R>,
|
|
125
125
|
Output
|
|
126
126
|
>,
|
|
@@ -431,6 +431,13 @@ type SnapshotIdentifier<State> = SnapshotNode<State> extends infer Node ?
|
|
|
431
431
|
Node extends { readonly path: infer Path extends string } ? Path : never
|
|
432
432
|
: never
|
|
433
433
|
|
|
434
|
+
type ValuedSnapshotIdentifier<State> = SnapshotNode<State> extends infer Node ?
|
|
435
|
+
Node extends { readonly path: infer Path extends string; readonly value: infer Value } ?
|
|
436
|
+
[Value] extends [undefined] ? never
|
|
437
|
+
: Path
|
|
438
|
+
: never
|
|
439
|
+
: never
|
|
440
|
+
|
|
434
441
|
type SnapshotValueByIdentifier<State, Path extends SnapshotIdentifier<State>> = SnapshotNode<State> extends infer Node ?
|
|
435
442
|
Node extends { readonly path: Path; readonly value: infer Value } ? Value : never
|
|
436
443
|
: never
|
|
@@ -443,7 +450,7 @@ type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.Child
|
|
|
443
450
|
|
|
444
451
|
const selectValueByPath = <
|
|
445
452
|
State extends Machine.Machine.AtomicSnapshot<string, unknown>,
|
|
446
|
-
Path extends
|
|
453
|
+
Path extends ValuedSnapshotIdentifier<State>
|
|
447
454
|
>(
|
|
448
455
|
snapshot: State,
|
|
449
456
|
path: Path
|
|
@@ -467,7 +474,7 @@ export const select = <
|
|
|
467
474
|
Error,
|
|
468
475
|
Output,
|
|
469
476
|
StartError,
|
|
470
|
-
const Path extends
|
|
477
|
+
const Path extends ValuedSnapshotIdentifier<State>
|
|
471
478
|
>(
|
|
472
479
|
self: MachineAtom<State, Event, Error, Output, StartError>,
|
|
473
480
|
path: Path
|
|
@@ -498,7 +505,7 @@ export const selectSnapshot = <
|
|
|
498
505
|
export const selectChild = <
|
|
499
506
|
Child extends Machine.ChildMachine.Any,
|
|
500
507
|
StartError,
|
|
501
|
-
const Path extends
|
|
508
|
+
const Path extends ValuedSnapshotIdentifier<ChildState<Child>>
|
|
502
509
|
>(
|
|
503
510
|
self: ChildMachineAtom<Child, StartError>,
|
|
504
511
|
path: Path
|
|
@@ -578,7 +585,7 @@ type EnsureMachineExecutable<M extends Machine.Machine.Any> = IsAny<Machine.Mach
|
|
|
578
585
|
|
|
579
586
|
type ResumedMachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
|
|
580
587
|
Machine.Machine.Snapshot<Machine.Machine.States<M>>,
|
|
581
|
-
Machine.Machine.InputEvent<M
|
|
588
|
+
Machine.Machine.EventInput<Machine.Machine.InputEvent<M>>,
|
|
582
589
|
MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
|
|
583
590
|
Machine.Machine.Output<M>,
|
|
584
591
|
Machine.MachineSchemaDecodeError | RuntimeError
|
|
@@ -628,7 +635,7 @@ export const make: {
|
|
|
628
635
|
...args: [...Machine.Machine.InputArgs<Input>]
|
|
629
636
|
): MachineAtom<
|
|
630
637
|
Machine.Machine.Snapshot<States>,
|
|
631
|
-
Machine.Machine.
|
|
638
|
+
Machine.Machine.EventInputOf<InputEvents>,
|
|
632
639
|
MachineRuntimeError<E, R>,
|
|
633
640
|
Output,
|
|
634
641
|
MachineStartError<InitialE, E, InitialR, R>
|
|
@@ -84,7 +84,7 @@ const historyFromSnapshot = (
|
|
|
84
84
|
const active = new Set<string>()
|
|
85
85
|
const values = new Map<string, unknown>()
|
|
86
86
|
for (const activePath of entry.active) {
|
|
87
|
-
if (active.has(activePath)
|
|
87
|
+
if (active.has(activePath)) {
|
|
88
88
|
throw new Error(`Machine snapshot contains invalid remembered state "${activePath}"`)
|
|
89
89
|
}
|
|
90
90
|
const node = getNode(machine, activePath)
|
|
@@ -96,9 +96,15 @@ const historyFromSnapshot = (
|
|
|
96
96
|
throw new Error(`Machine snapshot contains invalid remembered value for "${activePath}"`)
|
|
97
97
|
}
|
|
98
98
|
active.add(activePath)
|
|
99
|
-
|
|
99
|
+
const hasValue = Object.prototype.hasOwnProperty.call(entry.values, activePath)
|
|
100
|
+
if (node.schema === undefined) {
|
|
101
|
+
if (hasValue) throw new Error(`Machine snapshot contains a value for structural state "${activePath}"`)
|
|
102
|
+
} else {
|
|
103
|
+
if (!hasValue) throw new Error(`Machine snapshot omits remembered value for "${activePath}"`)
|
|
104
|
+
values.set(activePath, decodeStateValueSync(machine, node, entry.values[activePath]))
|
|
105
|
+
}
|
|
100
106
|
}
|
|
101
|
-
if (!active.has(historyNode.parent) || Object.keys(entry.values).length !==
|
|
107
|
+
if (!active.has(historyNode.parent) || Object.keys(entry.values).length !== values.size) {
|
|
102
108
|
throw new Error(`Machine snapshot contains incomplete history record "${path}"`)
|
|
103
109
|
}
|
|
104
110
|
history.set(path, {
|
|
@@ -138,7 +144,6 @@ const historyFromSnapshotEffect = Effect.fnUntraced(function*(
|
|
|
138
144
|
const node = machine.stateNodes.byPath.get(activePath)
|
|
139
145
|
if (
|
|
140
146
|
active.has(activePath) || node === undefined || node.type === "history" || node.type === "choice" ||
|
|
141
|
-
!Object.prototype.hasOwnProperty.call(entry.values, activePath) ||
|
|
142
147
|
!(isPathInSubtree(activePath, historyNode.parent) ||
|
|
143
148
|
getPathToRoot(machine, historyNode.parent).includes(activePath))
|
|
144
149
|
) {
|
|
@@ -152,15 +157,39 @@ const historyFromSnapshotEffect = Effect.fnUntraced(function*(
|
|
|
152
157
|
)
|
|
153
158
|
}
|
|
154
159
|
active.add(activePath)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
const hasValue = Object.prototype.hasOwnProperty.call(entry.values, activePath)
|
|
161
|
+
if (node.schema === undefined) {
|
|
162
|
+
if (hasValue) {
|
|
163
|
+
return yield* Effect.fail(
|
|
164
|
+
new MachineSchemaDecodeError({
|
|
165
|
+
machineId: machine.id,
|
|
166
|
+
boundary: "history",
|
|
167
|
+
state: activePath,
|
|
168
|
+
cause: Cause.die(new Error(`Machine snapshot contains a value for structural state "${activePath}"`))
|
|
169
|
+
})
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
if (!hasValue) {
|
|
174
|
+
return yield* Effect.fail(
|
|
175
|
+
new MachineSchemaDecodeError({
|
|
176
|
+
machineId: machine.id,
|
|
177
|
+
boundary: "history",
|
|
178
|
+
state: activePath,
|
|
179
|
+
cause: Cause.die(new Error(`Machine snapshot omits remembered value for "${activePath}"`))
|
|
180
|
+
})
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
values.set(
|
|
184
|
+
activePath,
|
|
185
|
+
yield* decodeBoundary(machine, getStateNodeSchema(node), entry.values[activePath], {
|
|
186
|
+
boundary: "history",
|
|
187
|
+
state: activePath
|
|
188
|
+
})
|
|
189
|
+
)
|
|
190
|
+
}
|
|
162
191
|
}
|
|
163
|
-
if (!active.has(historyNode.parent) || Object.keys(entry.values).length !==
|
|
192
|
+
if (!active.has(historyNode.parent) || Object.keys(entry.values).length !== values.size) {
|
|
164
193
|
return yield* Effect.fail(
|
|
165
194
|
new MachineSchemaDecodeError({
|
|
166
195
|
machineId: machine.id,
|
|
@@ -212,7 +241,7 @@ const historyToSnapshot = (
|
|
|
212
241
|
entries[path] = {
|
|
213
242
|
mode: record.mode,
|
|
214
243
|
active,
|
|
215
|
-
values: Object.fromEntries(
|
|
244
|
+
values: Object.fromEntries(record.values)
|
|
216
245
|
}
|
|
217
246
|
}
|
|
218
247
|
return entries
|
|
@@ -329,7 +358,9 @@ export const getParentValues = (
|
|
|
329
358
|
const paths = getPathToRoot(machine, path)
|
|
330
359
|
for (let index = 0; index < paths.length - 1; index++) {
|
|
331
360
|
const parent = paths[index]!
|
|
332
|
-
|
|
361
|
+
if (configuration.values.has(parent)) {
|
|
362
|
+
parents[parent] = configuration.values.get(parent)
|
|
363
|
+
}
|
|
333
364
|
}
|
|
334
365
|
return parents
|
|
335
366
|
}
|
|
@@ -340,7 +371,7 @@ export const getParentValue = (
|
|
|
340
371
|
path: string
|
|
341
372
|
): unknown => {
|
|
342
373
|
const parent = getNode(machine, path).parent
|
|
343
|
-
return parent === undefined ? undefined :
|
|
374
|
+
return parent === undefined ? undefined : configuration.values.get(parent)
|
|
344
375
|
}
|
|
345
376
|
|
|
346
377
|
export const getInitialEntryPaths = (
|
|
@@ -368,7 +399,7 @@ export const snapshotFromPath = <const States extends Machine.StateSchemas>(
|
|
|
368
399
|
const node = getNode(machine, path)
|
|
369
400
|
const snapshot: Record<string, unknown> = {
|
|
370
401
|
path,
|
|
371
|
-
value:
|
|
402
|
+
value: configuration.values.get(path)
|
|
372
403
|
}
|
|
373
404
|
if (node.type === "compound") {
|
|
374
405
|
const child = node.children.find((child) => configuration.active.has(child))
|
|
@@ -438,9 +469,14 @@ export const configurationFromSnapshot = (
|
|
|
438
469
|
|
|
439
470
|
const visit = (current: Machine.AtomicSnapshot<string, unknown>): void => {
|
|
440
471
|
const node = getNode(machine, String(current.path))
|
|
441
|
-
const value = decodeStateValueSync(machine, node, current.value)
|
|
442
472
|
active.add(node.path)
|
|
443
|
-
|
|
473
|
+
if (node.schema === undefined) {
|
|
474
|
+
if (current.value !== undefined) {
|
|
475
|
+
throw new Error(`Machine structural snapshot "${node.path}" cannot contain a value`)
|
|
476
|
+
}
|
|
477
|
+
} else {
|
|
478
|
+
values.set(node.path, decodeStateValueSync(machine, node, current.value))
|
|
479
|
+
}
|
|
444
480
|
if (node.type === "compound") {
|
|
445
481
|
if (!hasProperty(current, "state") || !isSnapshot(current.state)) {
|
|
446
482
|
throw new Error(`Machine expected compound snapshot "${node.path}" to include an active child state`)
|
|
@@ -520,9 +556,14 @@ export const configurationFromSnapshotEffect = Effect.fnUntraced(function*(
|
|
|
520
556
|
current: Machine.AtomicSnapshot<string, unknown>
|
|
521
557
|
) {
|
|
522
558
|
const node = getNode(machine, String(current.path))
|
|
523
|
-
const value = yield* decodeStateValue(machine, node, current.value)
|
|
524
559
|
active.add(node.path)
|
|
525
|
-
|
|
560
|
+
if (node.schema === undefined) {
|
|
561
|
+
if (current.value !== undefined) {
|
|
562
|
+
throw new Error(`Machine structural snapshot "${node.path}" cannot contain a value`)
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
values.set(node.path, yield* decodeStateValue(machine, node, current.value))
|
|
566
|
+
}
|
|
526
567
|
if (node.type === "compound") {
|
|
527
568
|
if (!hasProperty(current, "state") || !isSnapshot(current.state)) {
|
|
528
569
|
throw new Error(`Machine expected compound snapshot "${node.path}" to include an active child state`)
|
|
@@ -645,7 +686,9 @@ export const captureHistory = (
|
|
|
645
686
|
}
|
|
646
687
|
const values = new Map<string, unknown>()
|
|
647
688
|
for (const path of active) {
|
|
648
|
-
values.
|
|
689
|
+
if (current.values.has(path)) {
|
|
690
|
+
values.set(path, current.values.get(path))
|
|
691
|
+
}
|
|
649
692
|
}
|
|
650
693
|
history.set(node.path, {
|
|
651
694
|
mode,
|
|
@@ -722,6 +765,15 @@ export const configurationFromTargetPathEffect = Effect.fnUntraced(function*(
|
|
|
722
765
|
for (const currentPath of paths) {
|
|
723
766
|
const currentNode = getNode(machine, currentPath)
|
|
724
767
|
active.add(currentPath)
|
|
768
|
+
if (currentNode.schema === undefined) {
|
|
769
|
+
const supplied = currentPath === node.path ?
|
|
770
|
+
value
|
|
771
|
+
: providedValues !== undefined && hasOwn(providedValues, currentPath) ?
|
|
772
|
+
providedValues[currentPath]
|
|
773
|
+
: undefined
|
|
774
|
+
if (supplied !== undefined) throw new Error(`Machine structural target "${currentPath}" cannot contain a value`)
|
|
775
|
+
continue
|
|
776
|
+
}
|
|
725
777
|
if (currentPath === node.path) {
|
|
726
778
|
values.set(currentPath, yield* decodeStateValue(machine, currentNode, value))
|
|
727
779
|
} else if (providedValues !== undefined && hasOwn(providedValues, currentPath)) {
|
|
@@ -783,6 +835,12 @@ export const configurationFromTargetSnapshotEffect = Effect.fnUntraced(function*
|
|
|
783
835
|
for (const ancestor of paths.slice(0, -1)) {
|
|
784
836
|
const node = getNode(machine, ancestor)
|
|
785
837
|
active.add(ancestor)
|
|
838
|
+
if (node.schema === undefined) {
|
|
839
|
+
if (providedValues !== undefined && hasOwn(providedValues, ancestor)) {
|
|
840
|
+
throw new Error(`Machine structural target "${ancestor}" cannot contain a value`)
|
|
841
|
+
}
|
|
842
|
+
continue
|
|
843
|
+
}
|
|
786
844
|
if (providedValues !== undefined && hasOwn(providedValues, ancestor)) {
|
|
787
845
|
values.set(ancestor, yield* decodeStateValue(machine, node, providedValues[ancestor]))
|
|
788
846
|
} else if (current.values.has(ancestor)) {
|
|
@@ -816,6 +874,9 @@ export const configurationFromTargetSnapshotEffect = Effect.fnUntraced(function*
|
|
|
816
874
|
if (!isPathInSubtree(providedPath, child)) continue
|
|
817
875
|
const providedNode = getNode(machine, providedPath)
|
|
818
876
|
active.add(providedPath)
|
|
877
|
+
if (providedNode.schema === undefined) {
|
|
878
|
+
throw new Error(`Machine structural target "${providedPath}" cannot contain a value`)
|
|
879
|
+
}
|
|
819
880
|
values.set(providedPath, yield* decodeStateValue(machine, providedNode, providedValue))
|
|
820
881
|
}
|
|
821
882
|
}
|
|
@@ -885,6 +946,15 @@ const configurationFromTargetPathSync = (
|
|
|
885
946
|
for (const currentPath of paths) {
|
|
886
947
|
const currentNode = getNode(machine, currentPath)
|
|
887
948
|
active.add(currentPath)
|
|
949
|
+
if (currentNode.schema === undefined) {
|
|
950
|
+
const supplied = currentPath === node.path ?
|
|
951
|
+
value
|
|
952
|
+
: providedValues !== undefined && hasOwn(providedValues, currentPath) ?
|
|
953
|
+
providedValues[currentPath]
|
|
954
|
+
: undefined
|
|
955
|
+
if (supplied !== undefined) throw new Error(`Machine structural target "${currentPath}" cannot contain a value`)
|
|
956
|
+
continue
|
|
957
|
+
}
|
|
888
958
|
if (currentPath === node.path) {
|
|
889
959
|
values.set(currentPath, decodeStateValueSync(machine, currentNode, value))
|
|
890
960
|
} else if (providedValues !== undefined && hasOwn(providedValues, currentPath)) {
|
|
@@ -932,6 +1002,12 @@ const configurationFromTargetSnapshotSync = (
|
|
|
932
1002
|
for (const ancestor of paths.slice(0, -1)) {
|
|
933
1003
|
const node = getNode(machine, ancestor)
|
|
934
1004
|
active.add(ancestor)
|
|
1005
|
+
if (node.schema === undefined) {
|
|
1006
|
+
if (providedValues !== undefined && hasOwn(providedValues, ancestor)) {
|
|
1007
|
+
throw new Error(`Machine structural target "${ancestor}" cannot contain a value`)
|
|
1008
|
+
}
|
|
1009
|
+
continue
|
|
1010
|
+
}
|
|
935
1011
|
if (providedValues !== undefined && hasOwn(providedValues, ancestor)) {
|
|
936
1012
|
values.set(ancestor, decodeStateValueSync(machine, node, providedValues[ancestor]))
|
|
937
1013
|
} else if (current.values.has(ancestor)) {
|
|
@@ -960,6 +1036,9 @@ const configurationFromTargetSnapshotSync = (
|
|
|
960
1036
|
if (!isPathInSubtree(providedPath, child)) continue
|
|
961
1037
|
const providedNode = getNode(machine, providedPath)
|
|
962
1038
|
active.add(providedPath)
|
|
1039
|
+
if (providedNode.schema === undefined) {
|
|
1040
|
+
throw new Error(`Machine structural target "${providedPath}" cannot contain a value`)
|
|
1041
|
+
}
|
|
963
1042
|
values.set(providedPath, decodeStateValueSync(machine, providedNode, providedValue))
|
|
964
1043
|
}
|
|
965
1044
|
}
|
|
@@ -1098,7 +1177,7 @@ export const resolveFinalOutputEffect: <
|
|
|
1098
1177
|
) {
|
|
1099
1178
|
const node = getNode(machine, path)
|
|
1100
1179
|
const output = getStateConfigByPath(machine, path)?.output?.({
|
|
1101
|
-
state:
|
|
1180
|
+
state: configuration.values.get(path),
|
|
1102
1181
|
parent: getParentValue(machine, configuration, path),
|
|
1103
1182
|
parents: getParentValues(machine, configuration, path),
|
|
1104
1183
|
event,
|
|
@@ -1251,7 +1330,7 @@ const resolveFinalOutputSync = <const Events extends ReadonlyArray<Machine.Tagge
|
|
|
1251
1330
|
): unknown => {
|
|
1252
1331
|
const node = getNode(machine, path)
|
|
1253
1332
|
const output = getStateConfigByPath(machine, path)?.output?.({
|
|
1254
|
-
state:
|
|
1333
|
+
state: configuration.values.get(path),
|
|
1255
1334
|
parent: getParentValue(machine, configuration, path),
|
|
1256
1335
|
parents: getParentValues(machine, configuration, path),
|
|
1257
1336
|
event,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
validateInitialConfiguration
|
|
22
22
|
} from "./configuration.js"
|
|
23
23
|
import { InfiniteTransitionError } from "./errors.js"
|
|
24
|
+
import * as InvocationEvent from "./invocationEvent.js"
|
|
24
25
|
import {
|
|
25
26
|
broadenTransitionBoundary,
|
|
26
27
|
type EvaluatedTransition,
|
|
@@ -100,6 +101,12 @@ const compileIndexedExecutionDescriptor = (
|
|
|
100
101
|
if (node.type === "choice" || node.type === "history") {
|
|
101
102
|
return undefined
|
|
102
103
|
}
|
|
104
|
+
// Structural active states deliberately use the generic semantic
|
|
105
|
+
// reference until the indexed value table represents absent values as an
|
|
106
|
+
// explicit capability rather than an `undefined` slot.
|
|
107
|
+
if (node.schema === undefined) {
|
|
108
|
+
return undefined
|
|
109
|
+
}
|
|
103
110
|
if (node.type === "atomic" || node.type === "final") {
|
|
104
111
|
leafPaths.push(node.path)
|
|
105
112
|
}
|
|
@@ -769,6 +776,34 @@ const planIndexedState = (
|
|
|
769
776
|
input: unknown,
|
|
770
777
|
retainMicrosteps: boolean
|
|
771
778
|
): ExecutionMacrostep<OwnedIndexedState> => {
|
|
779
|
+
if (InvocationEvent.isInvocationEvent(input)) {
|
|
780
|
+
// Invocation lifecycle transitions retain the generic planner as their
|
|
781
|
+
// semantic reference. Ordinary machine events and initialization stay on
|
|
782
|
+
// the indexed representation; only the private lifecycle macrostep crosses
|
|
783
|
+
// the representation boundary.
|
|
784
|
+
const planned = planConfiguration(
|
|
785
|
+
machine as any,
|
|
786
|
+
activeConfigurationFromIndexedState(descriptor, configuration),
|
|
787
|
+
input
|
|
788
|
+
)
|
|
789
|
+
return {
|
|
790
|
+
next: ownedIndexedStateFromActive(descriptor, planned.next),
|
|
791
|
+
commands: planned.commands,
|
|
792
|
+
emittedEvents: planned.emittedEvents,
|
|
793
|
+
microsteps: planned.microsteps.map((step) => ({
|
|
794
|
+
next: ownedIndexedStateFromActive(descriptor, step.next),
|
|
795
|
+
event: step.event,
|
|
796
|
+
commands: step.commands,
|
|
797
|
+
raisedEvents: step.raisedEvents,
|
|
798
|
+
emittedEvents: step.emittedEvents,
|
|
799
|
+
exitPaths: step.exitPaths,
|
|
800
|
+
entryPaths: step.entryPaths,
|
|
801
|
+
changed: step.changed
|
|
802
|
+
})),
|
|
803
|
+
done: planned.done,
|
|
804
|
+
output: planned.output
|
|
805
|
+
}
|
|
806
|
+
}
|
|
772
807
|
const decoded = decodeEventSync(machine, input)
|
|
773
808
|
if (descriptor.flat) {
|
|
774
809
|
return planIndexedFlatState(machine, descriptor, configuration, decoded, retainMicrosteps)
|