@typeonce/effect-machine 0.12.0 → 0.14.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 +130 -30
- package/dist/Machine.d.ts +722 -262
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +130 -62
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +1 -0
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js +23 -0
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/commandRuntime.d.ts.map +1 -1
- package/dist/internal/machine/commandRuntime.js +2 -5
- package/dist/internal/machine/commandRuntime.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts +5 -0
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +6 -2
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts +1 -0
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +57 -24
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/initialization.d.ts +5 -0
- package/dist/internal/machine/initialization.d.ts.map +1 -0
- package/dist/internal/machine/initialization.js +61 -0
- package/dist/internal/machine/initialization.js.map +1 -0
- package/dist/internal/machine/inspectionRuntime.d.ts +25 -0
- package/dist/internal/machine/inspectionRuntime.d.ts.map +1 -0
- package/dist/internal/machine/inspectionRuntime.js +79 -0
- package/dist/internal/machine/inspectionRuntime.js.map +1 -0
- package/dist/internal/machine/invocation.d.ts +2 -1
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +17 -10
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +4 -3
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +327 -32
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +28 -0
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +132 -51
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/process.d.ts.map +1 -1
- package/dist/internal/machine/process.js +4 -2
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/runtime.d.ts +27 -3
- package/dist/internal/machine/runtime.d.ts.map +1 -1
- package/dist/internal/machine/runtime.js +440 -64
- package/dist/internal/machine/runtime.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 +25 -0
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +26 -10
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/exploration.d.ts.map +1 -1
- package/dist/internal/testing/machine/exploration.js +11 -2
- package/dist/internal/testing/machine/exploration.js.map +1 -1
- package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +75 -69
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/internal/testing/machine/transitionCoverage.d.ts +20 -0
- package/dist/internal/testing/machine/transitionCoverage.d.ts.map +1 -0
- package/dist/internal/testing/machine/transitionCoverage.js +80 -0
- package/dist/internal/testing/machine/transitionCoverage.js.map +1 -0
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +171 -33
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +97 -22
- package/dist/testing/MachineTest.d.ts.map +1 -1
- package/dist/testing/MachineTest.js +58 -16
- package/dist/testing/MachineTest.js.map +1 -1
- package/dist/unstable/cluster/ClusterMachine.d.ts +4 -1
- package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterMachine.js +4 -1
- package/dist/unstable/cluster/ClusterMachine.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +21 -3
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +21 -3
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +240 -65
- package/package.json +5 -5
- package/src/Machine.ts +1240 -495
- package/src/internal/machine/atom.ts +26 -0
- package/src/internal/machine/commandRuntime.ts +2 -9
- package/src/internal/machine/configuration.ts +28 -3
- package/src/internal/machine/executionPlan.ts +72 -24
- package/src/internal/machine/initialization.ts +73 -0
- package/src/internal/machine/inspectionRuntime.ts +102 -0
- package/src/internal/machine/invocation.ts +37 -12
- package/src/internal/machine/machine.ts +438 -39
- package/src/internal/machine/planner.ts +180 -55
- package/src/internal/machine/process.ts +4 -2
- package/src/internal/machine/runtime.ts +661 -89
- package/src/internal/machine/symbols.ts +3 -0
- package/src/internal/machine/topology.ts +65 -12
- package/src/internal/testing/machine/exploration.ts +10 -2
- package/src/internal/testing/machine/finiteModel.ts +114 -80
- package/src/internal/testing/machine/transitionCoverage.ts +116 -0
- package/src/internal/testing/machine/verification.ts +216 -58
- package/src/testing/MachineTest.ts +118 -28
- package/src/unstable/cluster/ClusterMachine.ts +4 -1
- package/src/unstable/reactivity/AtomMachine.ts +24 -3
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
completeConfigurationEffect,
|
|
23
23
|
completeConfigurationSync,
|
|
24
24
|
configurationFromHistoryRecord,
|
|
25
|
+
configurationFromInitialTargetSync,
|
|
25
26
|
getActiveLeafPathFrom,
|
|
26
27
|
getActiveLeafPaths,
|
|
27
28
|
getHistoryRecord,
|
|
@@ -44,13 +45,16 @@ import {
|
|
|
44
45
|
validateInitialConfiguration
|
|
45
46
|
} from "./configuration.js"
|
|
46
47
|
import { InfiniteTransitionError, MachineSchemaDecodeError, StartupError, StoppedError } from "./errors.js"
|
|
48
|
+
import { getStateInitializeValues, makeStateInitializeBuilder } from "./initialization.js"
|
|
47
49
|
import * as InvocationEvent from "./invocationEvent.js"
|
|
48
50
|
import { decodeEventSync, decodeInputSync, decodeStateValueSync } from "./protocol.js"
|
|
49
51
|
import { InitialEventTypeId } from "./symbols.js"
|
|
50
52
|
import {
|
|
51
53
|
getNode,
|
|
54
|
+
type InitialTarget as InitialTargetInstruction,
|
|
52
55
|
isChoiceTarget,
|
|
53
56
|
isHistoryTarget,
|
|
57
|
+
isInitialTarget,
|
|
54
58
|
isNoTarget,
|
|
55
59
|
isSnapshot,
|
|
56
60
|
isTarget,
|
|
@@ -66,6 +70,7 @@ export type MicrostepPlan<State, Event, E, R> = {
|
|
|
66
70
|
readonly source: string
|
|
67
71
|
readonly trigger: Machine.TransitionTrigger
|
|
68
72
|
readonly reenter: boolean
|
|
73
|
+
readonly branchIndex: number
|
|
69
74
|
readonly target: string | undefined
|
|
70
75
|
readonly resolvedTarget: string | undefined
|
|
71
76
|
}>
|
|
@@ -100,6 +105,16 @@ export type TransitionHandler<States extends Machine.StateSchemas, E, R, Context
|
|
|
100
105
|
enqueue: Enqueue<any, any>
|
|
101
106
|
) => Machine.HandlerResult<States, E, R>
|
|
102
107
|
|
|
108
|
+
type TransitionEvaluation<States extends Machine.StateSchemas, E, R> = {
|
|
109
|
+
readonly result: Machine.HandlerResult<States, E, R>
|
|
110
|
+
readonly branchIndex: number
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
type TransitionEvaluator<States extends Machine.StateSchemas, E, R, Context> = (
|
|
114
|
+
context: Context,
|
|
115
|
+
enqueue: Enqueue<any, any>
|
|
116
|
+
) => TransitionEvaluation<States, E, R>
|
|
117
|
+
|
|
103
118
|
const rootMachineReferences = new WeakMap<Machine.Any, MachineReferences<any, any>>()
|
|
104
119
|
const scopedMachineReferences = new WeakMap<Machine.Any, MachineReferences<any, any>>()
|
|
105
120
|
|
|
@@ -138,12 +153,14 @@ type EventTransition<States extends Machine.StateSchemas, E, R, Context> =
|
|
|
138
153
|
readonly reenter?: boolean
|
|
139
154
|
readonly targets?: ReadonlyArray<string>
|
|
140
155
|
readonly transition: TransitionHandler<States, E, R, Context>
|
|
156
|
+
readonly evaluate?: TransitionEvaluator<States, E, R, Context>
|
|
141
157
|
}
|
|
142
158
|
|
|
143
159
|
export type MicrostepTransition<States extends Machine.StateSchemas, E, R, Context> = {
|
|
144
160
|
readonly reenter: boolean
|
|
145
161
|
readonly targets: ReadonlyArray<string> | undefined
|
|
146
162
|
readonly transition: TransitionHandler<States, E, R, Context>
|
|
163
|
+
readonly evaluate: TransitionEvaluator<States, E, R, Context> | undefined
|
|
147
164
|
}
|
|
148
165
|
|
|
149
166
|
export const normalizeTransition = <States extends Machine.StateSchemas, E, R, Context>(
|
|
@@ -153,11 +170,12 @@ export const normalizeTransition = <States extends Machine.StateSchemas, E, R, C
|
|
|
153
170
|
return undefined
|
|
154
171
|
}
|
|
155
172
|
return typeof transition === "function"
|
|
156
|
-
? { reenter: false, targets: undefined, transition }
|
|
173
|
+
? { reenter: false, targets: undefined, transition, evaluate: undefined }
|
|
157
174
|
: {
|
|
158
175
|
reenter: transition.reenter === true,
|
|
159
176
|
targets: transition.targets,
|
|
160
|
-
transition: transition.transition
|
|
177
|
+
transition: transition.transition,
|
|
178
|
+
evaluate: transition.evaluate
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
181
|
|
|
@@ -191,12 +209,16 @@ const collectTransition = <
|
|
|
191
209
|
>(
|
|
192
210
|
machine: Machine.Any,
|
|
193
211
|
transition: TransitionHandler<States, E, R, Context>,
|
|
194
|
-
context: Context
|
|
212
|
+
context: Context,
|
|
213
|
+
evaluate?: TransitionEvaluator<States, E, R, Context>
|
|
195
214
|
) => {
|
|
196
215
|
const collected = makeCollector<Event>(machine)
|
|
197
|
-
const
|
|
216
|
+
const evaluated = evaluate === undefined
|
|
217
|
+
? { result: transition(context, collected.enqueue), branchIndex: 0 }
|
|
218
|
+
: evaluate(context, collected.enqueue)
|
|
198
219
|
return {
|
|
199
|
-
state: isNoTarget(result) ? undefined : result,
|
|
220
|
+
state: isNoTarget(evaluated.result) ? undefined : evaluated.result,
|
|
221
|
+
branchIndex: evaluated.branchIndex,
|
|
200
222
|
commands: collected.commands,
|
|
201
223
|
raisedEvents: collected.raisedEvents,
|
|
202
224
|
emittedEvents: collected.emittedEvents
|
|
@@ -230,6 +252,7 @@ const completeHistoryConfiguration = (
|
|
|
230
252
|
const commands: Array<RuntimeCommand> = []
|
|
231
253
|
const raisedEvents: Array<unknown> = []
|
|
232
254
|
const emittedEvents: Array<unknown> = []
|
|
255
|
+
const transitions: Array<ResolvedChoiceTransition> = []
|
|
233
256
|
|
|
234
257
|
let changed = true
|
|
235
258
|
while (changed) {
|
|
@@ -248,9 +271,47 @@ const completeHistoryConfiguration = (
|
|
|
248
271
|
history: configuration.history,
|
|
249
272
|
machineReferences: configuration.machineReferences
|
|
250
273
|
} as ActiveConfiguration
|
|
274
|
+
if (child.type === "choice") {
|
|
275
|
+
const choice = resolveChoiceTarget(
|
|
276
|
+
machine,
|
|
277
|
+
current,
|
|
278
|
+
makeChoiceTarget(child.path, path, Object.fromEntries(values)),
|
|
279
|
+
event
|
|
280
|
+
)
|
|
281
|
+
let next = current
|
|
282
|
+
for (const routed of [choice.target, ...choice.additionalTargets]) {
|
|
283
|
+
if (routed === undefined || isHistoryTarget(routed)) {
|
|
284
|
+
throw new Error(`Machine initial choice "${child.path}" must resolve to an active state target`)
|
|
285
|
+
}
|
|
286
|
+
const resolved = isInitialTarget(routed)
|
|
287
|
+
? resolveInitialTarget(machine, next, routed, event)
|
|
288
|
+
: undefined
|
|
289
|
+
next = normalizeTargetConfigurationSync(
|
|
290
|
+
machine,
|
|
291
|
+
next,
|
|
292
|
+
(resolved?.target ?? routed) as Machine.Snapshot<any> | Machine.Target<any, any>
|
|
293
|
+
)
|
|
294
|
+
if (resolved !== undefined) {
|
|
295
|
+
commands.push(...resolved.commands)
|
|
296
|
+
raisedEvents.push(...resolved.raisedEvents)
|
|
297
|
+
emittedEvents.push(...resolved.emittedEvents)
|
|
298
|
+
transitions.push(...resolved.transitions)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
active.clear()
|
|
302
|
+
values.clear()
|
|
303
|
+
for (const activePath of next.active) active.add(activePath)
|
|
304
|
+
for (const [valuePath, stateValue] of next.values) values.set(valuePath, stateValue)
|
|
305
|
+
commands.push(...choice.commands)
|
|
306
|
+
raisedEvents.push(...choice.raisedEvents)
|
|
307
|
+
emittedEvents.push(...choice.emittedEvents)
|
|
308
|
+
transitions.push(...choice.transitions)
|
|
309
|
+
changed = true
|
|
310
|
+
continue
|
|
311
|
+
}
|
|
251
312
|
active.add(child.path)
|
|
252
313
|
if (child.schema !== undefined) {
|
|
253
|
-
const initializer = machine.handlers[path]?.
|
|
314
|
+
const initializer = machine.handlers[path]?.initialize
|
|
254
315
|
if (initializer === undefined) {
|
|
255
316
|
throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
|
|
256
317
|
}
|
|
@@ -259,9 +320,11 @@ const completeHistoryConfiguration = (
|
|
|
259
320
|
state: current.values.get(path),
|
|
260
321
|
containingState: getParentValue(machine, current, path),
|
|
261
322
|
ancestors: getParentValues(machine, current, path),
|
|
262
|
-
event
|
|
323
|
+
event,
|
|
324
|
+
builder: makeStateInitializeBuilder(machine, path)
|
|
263
325
|
})
|
|
264
|
-
|
|
326
|
+
const initializedValues = getStateInitializeValues(path, initialized.value)
|
|
327
|
+
values.set(child.path, decodeStateValueSync(machine, child, initializedValues[child.key]))
|
|
265
328
|
commands.push(...initialized.commands)
|
|
266
329
|
raisedEvents.push(...initialized.raisedEvents)
|
|
267
330
|
emittedEvents.push(...initialized.emittedEvents)
|
|
@@ -279,7 +342,7 @@ const completeHistoryConfiguration = (
|
|
|
279
342
|
history: configuration.history,
|
|
280
343
|
machineReferences: configuration.machineReferences
|
|
281
344
|
} as ActiveConfiguration
|
|
282
|
-
const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.
|
|
345
|
+
const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.initialize
|
|
283
346
|
if (valuedMissing.length > 0 && initializer === undefined) {
|
|
284
347
|
throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
|
|
285
348
|
}
|
|
@@ -288,24 +351,25 @@ const completeHistoryConfiguration = (
|
|
|
288
351
|
state: current.values.get(path),
|
|
289
352
|
containingState: getParentValue(machine, current, path),
|
|
290
353
|
ancestors: getParentValues(machine, current, path),
|
|
291
|
-
event
|
|
354
|
+
event,
|
|
355
|
+
builder: makeStateInitializeBuilder(machine, path)
|
|
292
356
|
})
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
357
|
+
const initializedValues = initialized === undefined
|
|
358
|
+
? undefined
|
|
359
|
+
: getStateInitializeValues(path, initialized.value)
|
|
296
360
|
for (const childPath of missing) {
|
|
297
361
|
const child = getNode(machine, childPath)
|
|
298
362
|
active.add(child.path)
|
|
299
363
|
if (child.schema !== undefined) {
|
|
300
364
|
if (
|
|
301
365
|
initialized === undefined ||
|
|
302
|
-
!Object.prototype.hasOwnProperty.call(
|
|
366
|
+
initializedValues === undefined || !Object.prototype.hasOwnProperty.call(initializedValues, child.key)
|
|
303
367
|
) {
|
|
304
368
|
throw new Error(`Machine parallel state initializer for "${path}" must return region "${child.key}"`)
|
|
305
369
|
}
|
|
306
370
|
values.set(
|
|
307
371
|
child.path,
|
|
308
|
-
decodeStateValueSync(machine, child,
|
|
372
|
+
decodeStateValueSync(machine, child, initializedValues[child.key])
|
|
309
373
|
)
|
|
310
374
|
}
|
|
311
375
|
}
|
|
@@ -328,16 +392,38 @@ const completeHistoryConfiguration = (
|
|
|
328
392
|
} as ActiveConfiguration,
|
|
329
393
|
commands,
|
|
330
394
|
raisedEvents,
|
|
331
|
-
emittedEvents
|
|
395
|
+
emittedEvents,
|
|
396
|
+
transitions
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function resolveInitialTarget(
|
|
401
|
+
machine: Machine.Any,
|
|
402
|
+
configuration: ActiveConfiguration,
|
|
403
|
+
target: InitialTargetInstruction,
|
|
404
|
+
event: unknown
|
|
405
|
+
) {
|
|
406
|
+
const partial = configurationFromInitialTargetSync(machine, configuration, target)
|
|
407
|
+
const completed = completeHistoryConfiguration(machine, partial, event)
|
|
408
|
+
const snapshot = snapshotFromConfigurationAtPath(machine, completed.configuration, target.path)
|
|
409
|
+
return {
|
|
410
|
+
target: makeTarget(target.path as any, snapshot.value as any, {
|
|
411
|
+
snapshot: snapshot as any,
|
|
412
|
+
values: Object.fromEntries(completed.configuration.values) as any
|
|
413
|
+
}),
|
|
414
|
+
commands: completed.commands,
|
|
415
|
+
raisedEvents: completed.raisedEvents,
|
|
416
|
+
emittedEvents: completed.emittedEvents,
|
|
417
|
+
transitions: completed.transitions
|
|
332
418
|
}
|
|
333
419
|
}
|
|
334
420
|
|
|
335
|
-
|
|
421
|
+
function resolveHistoryTarget(
|
|
336
422
|
machine: Machine.Any,
|
|
337
423
|
configuration: ActiveConfiguration,
|
|
338
424
|
target: { readonly path: string; readonly parent: string },
|
|
339
425
|
event: unknown
|
|
340
|
-
)
|
|
426
|
+
) {
|
|
341
427
|
const node = getNode(machine, target.path)
|
|
342
428
|
if (node.type !== "history" || node.parent !== target.parent) {
|
|
343
429
|
throw new Error(`Machine expected history target "${target.path}" to resolve to its declared parent`)
|
|
@@ -359,7 +445,7 @@ const resolveHistoryTarget = (
|
|
|
359
445
|
commands: completed.commands,
|
|
360
446
|
raisedEvents: completed.raisedEvents,
|
|
361
447
|
emittedEvents: completed.emittedEvents,
|
|
362
|
-
transitions:
|
|
448
|
+
transitions: completed.transitions
|
|
363
449
|
}
|
|
364
450
|
}
|
|
365
451
|
|
|
@@ -436,6 +522,7 @@ export type SelectedTransition<States extends Machine.StateSchemas, E, R, Contex
|
|
|
436
522
|
|
|
437
523
|
export type EvaluatedTransition<States extends Machine.StateSchemas, Event, E, R, Context> = {
|
|
438
524
|
readonly selection: SelectedTransition<States, E, R, Context>
|
|
525
|
+
readonly branchIndex: number
|
|
439
526
|
readonly unresolvedTarget:
|
|
440
527
|
| Machine.Snapshot<States>
|
|
441
528
|
| Machine.Target<States, Machine.StateIdentifier<States>>
|
|
@@ -456,6 +543,7 @@ export type EvaluatedTransition<States extends Machine.StateSchemas, Event, E, R
|
|
|
456
543
|
readonly source: string
|
|
457
544
|
readonly trigger: Machine.TransitionTrigger
|
|
458
545
|
readonly reenter: false
|
|
546
|
+
readonly branchIndex: number
|
|
459
547
|
readonly target: string
|
|
460
548
|
readonly resolvedTarget: string
|
|
461
549
|
}>
|
|
@@ -1061,16 +1149,17 @@ interface ResolvedChoiceTransition {
|
|
|
1061
1149
|
readonly source: string
|
|
1062
1150
|
readonly trigger: Machine.TransitionTrigger
|
|
1063
1151
|
readonly reenter: false
|
|
1152
|
+
readonly branchIndex: number
|
|
1064
1153
|
readonly target: string
|
|
1065
1154
|
readonly resolvedTarget: string
|
|
1066
1155
|
}
|
|
1067
1156
|
|
|
1068
|
-
|
|
1157
|
+
function resolveChoiceTarget(
|
|
1069
1158
|
machine: Machine.Any,
|
|
1070
1159
|
configuration: ActiveConfiguration,
|
|
1071
1160
|
initialTarget: unknown,
|
|
1072
1161
|
event: unknown
|
|
1073
|
-
)
|
|
1162
|
+
) {
|
|
1074
1163
|
const pending: Array<unknown> = [initialTarget]
|
|
1075
1164
|
const resolvedTargets: Array<unknown> = []
|
|
1076
1165
|
const commands: Array<RuntimeCommand> = []
|
|
@@ -1115,13 +1204,18 @@ const resolveChoiceTarget = (
|
|
|
1115
1204
|
history: configuration.history,
|
|
1116
1205
|
...(configuration.machineReferences === undefined ? {} : { machineReferences: configuration.machineReferences })
|
|
1117
1206
|
}
|
|
1118
|
-
const collected = collectTransition(
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1207
|
+
const collected = collectTransition(
|
|
1208
|
+
machine,
|
|
1209
|
+
choice.transition,
|
|
1210
|
+
{
|
|
1211
|
+
...resolveMachineReferences(machine, provisional),
|
|
1212
|
+
containingState: getParentValue(machine, provisional, node.path),
|
|
1213
|
+
ancestors: getParentValues(machine, provisional, node.path),
|
|
1214
|
+
event,
|
|
1215
|
+
target: getTargetBuilder(machine, node.path)
|
|
1216
|
+
},
|
|
1217
|
+
choice.evaluate
|
|
1218
|
+
)
|
|
1125
1219
|
if (collected.state === undefined) {
|
|
1126
1220
|
throw new Error(`Machine choice resolver for "${node.path}" must return a target`)
|
|
1127
1221
|
}
|
|
@@ -1133,6 +1227,7 @@ const resolveChoiceTarget = (
|
|
|
1133
1227
|
source: node.path,
|
|
1134
1228
|
trigger: { type: "choice" },
|
|
1135
1229
|
reenter: false,
|
|
1230
|
+
branchIndex: collected.branchIndex,
|
|
1136
1231
|
target: returnedPath,
|
|
1137
1232
|
resolvedTarget: nested?.target.path ?? returnedPath
|
|
1138
1233
|
})
|
|
@@ -1141,7 +1236,7 @@ const resolveChoiceTarget = (
|
|
|
1141
1236
|
emittedEvents.push(...collected.emittedEvents)
|
|
1142
1237
|
}
|
|
1143
1238
|
|
|
1144
|
-
if (!isTarget(current) && !isSnapshot(current) && !isHistoryTarget(current)) {
|
|
1239
|
+
if (!isTarget(current) && !isSnapshot(current) && !isHistoryTarget(current) && !isInitialTarget(current)) {
|
|
1145
1240
|
throw new Error("Machine choice resolver must return a concrete typed target")
|
|
1146
1241
|
}
|
|
1147
1242
|
resolvedTargets.push(current)
|
|
@@ -1172,7 +1267,8 @@ const collectEvaluatedTransition = <
|
|
|
1172
1267
|
const transitionResult = collectTransition<States, Event, E, R, Context>(
|
|
1173
1268
|
machine,
|
|
1174
1269
|
selection.transition.transition,
|
|
1175
|
-
selection.context
|
|
1270
|
+
selection.context,
|
|
1271
|
+
selection.transition.evaluate
|
|
1176
1272
|
)
|
|
1177
1273
|
const unresolvedTarget = transitionResult.state === undefined
|
|
1178
1274
|
? undefined
|
|
@@ -1196,6 +1292,10 @@ const collectEvaluatedTransition = <
|
|
|
1196
1292
|
(selection.context as any).event
|
|
1197
1293
|
)
|
|
1198
1294
|
const choiceResolvedTarget = choiceResolution?.target ?? unresolvedTarget
|
|
1295
|
+
const initialResolution = choiceResolvedTarget !== undefined && isInitialTarget(choiceResolvedTarget)
|
|
1296
|
+
? resolveInitialTarget(machine, state, choiceResolvedTarget, (selection.context as any).event)
|
|
1297
|
+
: undefined
|
|
1298
|
+
const routedTarget = initialResolution?.target ?? choiceResolvedTarget
|
|
1199
1299
|
let historyResolution: {
|
|
1200
1300
|
readonly target: unknown
|
|
1201
1301
|
readonly commands: ReadonlyArray<RuntimeCommand>
|
|
@@ -1203,50 +1303,64 @@ const collectEvaluatedTransition = <
|
|
|
1203
1303
|
readonly emittedEvents: ReadonlyArray<unknown>
|
|
1204
1304
|
readonly transitions: ReadonlyArray<ResolvedChoiceTransition>
|
|
1205
1305
|
} | undefined
|
|
1206
|
-
const reenteredHistoryTarget = isHistoryTarget(
|
|
1207
|
-
state.active.has(
|
|
1208
|
-
?
|
|
1306
|
+
const reenteredHistoryTarget = isHistoryTarget(routedTarget) && selection.transition.reenter &&
|
|
1307
|
+
state.active.has(routedTarget.parent)
|
|
1308
|
+
? routedTarget
|
|
1209
1309
|
: undefined
|
|
1210
|
-
if (
|
|
1310
|
+
if (routedTarget !== undefined && isHistoryTarget(routedTarget)) {
|
|
1211
1311
|
// A reentering transition may exit the history node's own parent. SCXML
|
|
1212
1312
|
// history observes that same exit, so resolve against a provisional
|
|
1213
1313
|
// capture rather than an older record (or the default).
|
|
1214
1314
|
const provisionalBoundary = selection.transition.reenter
|
|
1215
1315
|
? getNode(machine, selection.sourcePath).parent
|
|
1216
|
-
: getLeastCommonAncestor(machine, stateIdentifier,
|
|
1316
|
+
: getLeastCommonAncestor(machine, stateIdentifier, routedTarget.parent)
|
|
1217
1317
|
const provisionalExitPaths = reenteredHistoryTarget !== undefined
|
|
1218
1318
|
? sortExitPaths(
|
|
1219
1319
|
machine,
|
|
1220
|
-
Array.from(state.active).filter((path) => isPathInSubtree(path,
|
|
1320
|
+
Array.from(state.active).filter((path) => isPathInSubtree(path, routedTarget.parent))
|
|
1221
1321
|
)
|
|
1222
1322
|
: getExitPaths(machine, state, provisionalBoundary)
|
|
1223
|
-
const stateAtHistoryResolution = provisionalExitPaths.includes(
|
|
1323
|
+
const stateAtHistoryResolution = provisionalExitPaths.includes(routedTarget.parent)
|
|
1224
1324
|
? captureHistory(machine, state, state, provisionalExitPaths)
|
|
1225
1325
|
: state
|
|
1226
1326
|
historyResolution = resolveHistoryTarget(
|
|
1227
1327
|
machine,
|
|
1228
1328
|
stateAtHistoryResolution,
|
|
1229
|
-
|
|
1329
|
+
routedTarget,
|
|
1230
1330
|
(selection.context as any).event
|
|
1231
1331
|
)
|
|
1232
1332
|
}
|
|
1233
1333
|
const target: Machine.Snapshot<States> | Machine.Target<States, Machine.StateIdentifier<States>> | undefined =
|
|
1234
1334
|
historyResolution === undefined
|
|
1235
|
-
?
|
|
1335
|
+
? routedTarget as
|
|
1236
1336
|
| Machine.Snapshot<States>
|
|
1237
1337
|
| Machine.Target<States, Machine.StateIdentifier<States>>
|
|
1238
1338
|
| undefined
|
|
1239
1339
|
: historyResolution.target as
|
|
1240
1340
|
| Machine.Snapshot<States>
|
|
1241
1341
|
| Machine.Target<States, Machine.StateIdentifier<States>>
|
|
1242
|
-
const
|
|
1243
|
-
const
|
|
1244
|
-
const
|
|
1245
|
-
const
|
|
1342
|
+
const additionalTargetActions: Array<RuntimeCommand> = []
|
|
1343
|
+
const additionalTargetRaisedEvents: Array<unknown> = []
|
|
1344
|
+
const additionalTargetEmittedEvents: Array<unknown> = []
|
|
1345
|
+
const additionalTargetChoiceTransitions: Array<ResolvedChoiceTransition> = []
|
|
1246
1346
|
const additionalChoiceTargets: Array<
|
|
1247
1347
|
Machine.Snapshot<States> | Machine.Target<States, Machine.StateIdentifier<States>>
|
|
1248
1348
|
> = []
|
|
1249
1349
|
for (const additionalTarget of choiceResolution?.additionalTargets ?? []) {
|
|
1350
|
+
if (isInitialTarget(additionalTarget)) {
|
|
1351
|
+
const resolved = resolveInitialTarget(
|
|
1352
|
+
machine,
|
|
1353
|
+
state,
|
|
1354
|
+
additionalTarget,
|
|
1355
|
+
(selection.context as any).event
|
|
1356
|
+
)
|
|
1357
|
+
additionalChoiceTargets.push(resolved.target as any)
|
|
1358
|
+
additionalTargetActions.push(...resolved.commands)
|
|
1359
|
+
additionalTargetRaisedEvents.push(...resolved.raisedEvents)
|
|
1360
|
+
additionalTargetEmittedEvents.push(...resolved.emittedEvents)
|
|
1361
|
+
additionalTargetChoiceTransitions.push(...resolved.transitions)
|
|
1362
|
+
continue
|
|
1363
|
+
}
|
|
1250
1364
|
if (!isHistoryTarget(additionalTarget)) {
|
|
1251
1365
|
additionalChoiceTargets.push(additionalTarget as any)
|
|
1252
1366
|
continue
|
|
@@ -1258,10 +1372,10 @@ const collectEvaluatedTransition = <
|
|
|
1258
1372
|
(selection.context as any).event
|
|
1259
1373
|
)
|
|
1260
1374
|
additionalChoiceTargets.push(resolved.target as any)
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1375
|
+
additionalTargetActions.push(...resolved.commands)
|
|
1376
|
+
additionalTargetRaisedEvents.push(...resolved.raisedEvents)
|
|
1377
|
+
additionalTargetEmittedEvents.push(...resolved.emittedEvents)
|
|
1378
|
+
additionalTargetChoiceTransitions.push(...resolved.transitions)
|
|
1265
1379
|
}
|
|
1266
1380
|
const targetPath = target === undefined
|
|
1267
1381
|
? undefined
|
|
@@ -1283,33 +1397,38 @@ const collectEvaluatedTransition = <
|
|
|
1283
1397
|
if (!changed) {
|
|
1284
1398
|
return {
|
|
1285
1399
|
selection,
|
|
1400
|
+
branchIndex: transitionResult.branchIndex,
|
|
1286
1401
|
unresolvedTarget,
|
|
1287
1402
|
target,
|
|
1288
1403
|
commands: [
|
|
1289
1404
|
...transitionResult.commands,
|
|
1290
1405
|
...(choiceResolution?.commands ?? []),
|
|
1406
|
+
...(initialResolution?.commands ?? []),
|
|
1291
1407
|
...(historyResolution?.commands ?? []),
|
|
1292
|
-
...
|
|
1408
|
+
...additionalTargetActions
|
|
1293
1409
|
],
|
|
1294
1410
|
raisedEvents: [
|
|
1295
1411
|
...transitionResult.raisedEvents,
|
|
1296
1412
|
...(choiceResolution?.raisedEvents ?? []),
|
|
1413
|
+
...(initialResolution?.raisedEvents ?? []),
|
|
1297
1414
|
...(historyResolution?.raisedEvents ?? []),
|
|
1298
|
-
...
|
|
1415
|
+
...additionalTargetRaisedEvents
|
|
1299
1416
|
],
|
|
1300
1417
|
emittedEvents: [
|
|
1301
1418
|
...transitionResult.emittedEvents,
|
|
1302
1419
|
...(choiceResolution?.emittedEvents ?? []),
|
|
1420
|
+
...(initialResolution?.emittedEvents ?? []),
|
|
1303
1421
|
...(historyResolution?.emittedEvents ?? []),
|
|
1304
|
-
...
|
|
1422
|
+
...additionalTargetEmittedEvents
|
|
1305
1423
|
],
|
|
1306
1424
|
changed,
|
|
1307
1425
|
exitPaths: [],
|
|
1308
1426
|
entryPaths: [],
|
|
1309
1427
|
choiceTransitions: [
|
|
1310
1428
|
...(choiceResolution?.transitions ?? []),
|
|
1429
|
+
...(initialResolution?.transitions ?? []),
|
|
1311
1430
|
...(historyResolution?.transitions ?? []),
|
|
1312
|
-
...
|
|
1431
|
+
...additionalTargetChoiceTransitions
|
|
1313
1432
|
]
|
|
1314
1433
|
} as EvaluatedTransition<States, Event, E, R, Context>
|
|
1315
1434
|
}
|
|
@@ -1324,25 +1443,29 @@ const collectEvaluatedTransition = <
|
|
|
1324
1443
|
|
|
1325
1444
|
return {
|
|
1326
1445
|
selection,
|
|
1446
|
+
branchIndex: transitionResult.branchIndex,
|
|
1327
1447
|
unresolvedTarget,
|
|
1328
1448
|
target,
|
|
1329
1449
|
commands: [
|
|
1330
1450
|
...transitionResult.commands,
|
|
1331
1451
|
...(choiceResolution?.commands ?? []),
|
|
1452
|
+
...(initialResolution?.commands ?? []),
|
|
1332
1453
|
...(historyResolution?.commands ?? []),
|
|
1333
|
-
...
|
|
1454
|
+
...additionalTargetActions
|
|
1334
1455
|
],
|
|
1335
1456
|
raisedEvents: [
|
|
1336
1457
|
...transitionResult.raisedEvents,
|
|
1337
1458
|
...(choiceResolution?.raisedEvents ?? []),
|
|
1459
|
+
...(initialResolution?.raisedEvents ?? []),
|
|
1338
1460
|
...(historyResolution?.raisedEvents ?? []),
|
|
1339
|
-
...
|
|
1461
|
+
...additionalTargetRaisedEvents
|
|
1340
1462
|
],
|
|
1341
1463
|
emittedEvents: [
|
|
1342
1464
|
...transitionResult.emittedEvents,
|
|
1343
1465
|
...(choiceResolution?.emittedEvents ?? []),
|
|
1466
|
+
...(initialResolution?.emittedEvents ?? []),
|
|
1344
1467
|
...(historyResolution?.emittedEvents ?? []),
|
|
1345
|
-
...
|
|
1468
|
+
...additionalTargetEmittedEvents
|
|
1346
1469
|
],
|
|
1347
1470
|
changed,
|
|
1348
1471
|
exitPaths: reenteredHistoryTarget !== undefined
|
|
@@ -1359,8 +1482,9 @@ const collectEvaluatedTransition = <
|
|
|
1359
1482
|
: getEntryPaths(machine, stateAfterTransition, boundary),
|
|
1360
1483
|
choiceTransitions: [
|
|
1361
1484
|
...(choiceResolution?.transitions ?? []),
|
|
1485
|
+
...(initialResolution?.transitions ?? []),
|
|
1362
1486
|
...(historyResolution?.transitions ?? []),
|
|
1363
|
-
...
|
|
1487
|
+
...additionalTargetChoiceTransitions
|
|
1364
1488
|
]
|
|
1365
1489
|
} as EvaluatedTransition<States, Event, E, R, Context>
|
|
1366
1490
|
}
|
|
@@ -1674,6 +1798,7 @@ const microstep = <
|
|
|
1674
1798
|
source: transition.selection.sourcePath,
|
|
1675
1799
|
trigger: transition.selection.trigger,
|
|
1676
1800
|
reenter: transition.selection.transition.reenter,
|
|
1801
|
+
branchIndex: transition.branchIndex,
|
|
1677
1802
|
target: transition.unresolvedTarget === undefined ? undefined : getTargetNodePath(transition.unresolvedTarget),
|
|
1678
1803
|
resolvedTarget: transition.target === undefined ? undefined : getTargetNodePath(transition.target)
|
|
1679
1804
|
},
|
|
@@ -73,8 +73,7 @@ const acknowledgedPlan = (
|
|
|
73
73
|
commands: planned.commands,
|
|
74
74
|
emittedEvents: planned.emittedEvents,
|
|
75
75
|
microsteps: planned.microsteps.map((microstep) => {
|
|
76
|
-
|
|
77
|
-
return { ...evidence, next: snapshot(microstep.next) }
|
|
76
|
+
return { ...microstep, transitions: microstep.transitions ?? [], next: snapshot(microstep.next) }
|
|
78
77
|
}),
|
|
79
78
|
done: planned.done,
|
|
80
79
|
output: planned.output
|
|
@@ -433,6 +432,7 @@ const makeProcessLogic: <
|
|
|
433
432
|
) => {
|
|
434
433
|
try {
|
|
435
434
|
const planned = compiledInitial(initialArgs, scope)
|
|
435
|
+
scope.inspectInitial(planned.initialEntryPaths)
|
|
436
436
|
const result = {
|
|
437
437
|
state: planned.state as Machine.Snapshot<States>,
|
|
438
438
|
done: planned.done,
|
|
@@ -461,6 +461,7 @@ const makeProcessLogic: <
|
|
|
461
461
|
? internalRuntime.provideMachineRuntime(
|
|
462
462
|
internalPlanner.planInitial(internalPlanner.withMachineReferences(machine, scope), ...initialArgs).pipe(
|
|
463
463
|
Effect.flatMap((planned) => {
|
|
464
|
+
scope.inspectInitial(planned.initialEntryPaths, planned.microsteps)
|
|
464
465
|
const commands = planned.commands.length === 0
|
|
465
466
|
? undefined
|
|
466
467
|
: CommandRuntime.runCommands(planned.commands, scope)
|
|
@@ -486,6 +487,7 @@ const makeProcessLogic: <
|
|
|
486
487
|
)
|
|
487
488
|
: Effect.try({ try: () => makeCompiledInitial!(scope), catch: (error) => error as any })
|
|
488
489
|
return ({
|
|
490
|
+
inspection: { kind: "Machine", definition: machine },
|
|
489
491
|
execution: {
|
|
490
492
|
_tag: "Compiled",
|
|
491
493
|
childless: !hasInvokes,
|