@typeonce/effect-machine 0.11.0 → 0.13.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 +89 -13
- package/dist/Machine.d.ts +396 -127
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +21 -19
- 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/cluster.js +2 -2
- package/dist/internal/machine/cluster.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 +12 -7
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +9 -5
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts +4 -3
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +68 -43
- 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 +18 -11
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +1 -2
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +21 -6
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +17 -2
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +137 -64
- 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 +7 -5
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/runtime.d.ts +29 -5
- 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 +13 -0
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +9 -0
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +3 -3
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +9 -0
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +9 -0
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +130 -20
- package/package.json +5 -5
- package/src/Machine.ts +548 -217
- package/src/internal/machine/atom.ts +26 -0
- package/src/internal/machine/cluster.ts +2 -2
- package/src/internal/machine/commandRuntime.ts +2 -7
- package/src/internal/machine/configuration.ts +38 -13
- package/src/internal/machine/executionPlan.ts +85 -52
- package/src/internal/machine/initialization.ts +73 -0
- package/src/internal/machine/inspectionRuntime.ts +102 -0
- package/src/internal/machine/invocation.ts +38 -13
- package/src/internal/machine/machine.ts +31 -6
- package/src/internal/machine/planner.ts +166 -66
- package/src/internal/machine/process.ts +7 -5
- package/src/internal/machine/runtime.ts +663 -91
- package/src/internal/machine/symbols.ts +3 -0
- package/src/internal/machine/topology.ts +27 -0
- package/src/internal/testing/machine/finiteModel.ts +8 -7
- package/src/unstable/reactivity/AtomMachine.ts +12 -0
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
import * as Cause from "effect/Cause"
|
|
8
8
|
import * as Effect from "effect/Effect"
|
|
9
9
|
import type * as Schema from "effect/Schema"
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
Enqueue,
|
|
12
|
+
InitialEvent as MachineInitialEvent,
|
|
13
|
+
Machine,
|
|
14
|
+
MachineReferences,
|
|
15
|
+
MachineTarget
|
|
16
|
+
} from "../../Machine.js"
|
|
11
17
|
import { getTargetBuilder, makeCollector, type RuntimeCommand } from "./command.js"
|
|
12
18
|
import {
|
|
13
19
|
type ActiveConfiguration,
|
|
@@ -16,6 +22,7 @@ import {
|
|
|
16
22
|
completeConfigurationEffect,
|
|
17
23
|
completeConfigurationSync,
|
|
18
24
|
configurationFromHistoryRecord,
|
|
25
|
+
configurationFromInitialTargetSync,
|
|
19
26
|
getActiveLeafPathFrom,
|
|
20
27
|
getActiveLeafPaths,
|
|
21
28
|
getHistoryRecord,
|
|
@@ -38,13 +45,16 @@ import {
|
|
|
38
45
|
validateInitialConfiguration
|
|
39
46
|
} from "./configuration.js"
|
|
40
47
|
import { InfiniteTransitionError, MachineSchemaDecodeError, StartupError, StoppedError } from "./errors.js"
|
|
48
|
+
import { getStateInitializeValues, makeStateInitializeBuilder } from "./initialization.js"
|
|
41
49
|
import * as InvocationEvent from "./invocationEvent.js"
|
|
42
50
|
import { decodeEventSync, decodeInputSync, decodeStateValueSync } from "./protocol.js"
|
|
43
51
|
import { InitialEventTypeId } from "./symbols.js"
|
|
44
52
|
import {
|
|
45
53
|
getNode,
|
|
54
|
+
type InitialTarget as InitialTargetInstruction,
|
|
46
55
|
isChoiceTarget,
|
|
47
56
|
isHistoryTarget,
|
|
57
|
+
isInitialTarget,
|
|
48
58
|
isNoTarget,
|
|
49
59
|
isSnapshot,
|
|
50
60
|
isTarget,
|
|
@@ -94,35 +104,35 @@ export type TransitionHandler<States extends Machine.StateSchemas, E, R, Context
|
|
|
94
104
|
enqueue: Enqueue<any, any>
|
|
95
105
|
) => Machine.HandlerResult<States, E, R>
|
|
96
106
|
|
|
97
|
-
const
|
|
98
|
-
const
|
|
107
|
+
const rootMachineReferences = new WeakMap<Machine.Any, MachineReferences<any, any>>()
|
|
108
|
+
const scopedMachineReferences = new WeakMap<Machine.Any, MachineReferences<any, any>>()
|
|
99
109
|
|
|
100
|
-
export const
|
|
110
|
+
export const withMachineReferences = (
|
|
101
111
|
machine: Machine.Any,
|
|
102
|
-
|
|
112
|
+
machineReferences: MachineReferences<any, any>
|
|
103
113
|
): Machine.Any => {
|
|
104
114
|
const scoped = Object.create(machine) as Machine.Any
|
|
105
|
-
|
|
115
|
+
scopedMachineReferences.set(scoped, { self: machineReferences.self, parent: machineReferences.parent })
|
|
106
116
|
return scoped
|
|
107
117
|
}
|
|
108
118
|
|
|
109
|
-
const
|
|
119
|
+
const resolveMachineReferences = (
|
|
110
120
|
machine: Machine.Any,
|
|
111
121
|
configuration: ActiveConfiguration
|
|
112
|
-
):
|
|
113
|
-
const scope = configuration.
|
|
122
|
+
): MachineReferences<any, any> => {
|
|
123
|
+
const scope = configuration.machineReferences
|
|
114
124
|
if (scope !== undefined) return scope
|
|
115
|
-
const machineScope =
|
|
125
|
+
const machineScope = scopedMachineReferences.get(machine)
|
|
116
126
|
if (machineScope !== undefined) return machineScope
|
|
117
|
-
const cached =
|
|
127
|
+
const cached = rootMachineReferences.get(machine)
|
|
118
128
|
if (cached !== undefined) return cached
|
|
119
|
-
const self:
|
|
129
|
+
const self: MachineTarget<unknown> = {
|
|
120
130
|
id: machine.id ?? "Machine",
|
|
121
131
|
sessionId: "Machine.plan",
|
|
122
132
|
send: () => Effect.fail(new StoppedError())
|
|
123
133
|
}
|
|
124
134
|
const root = { self, parent: undefined }
|
|
125
|
-
|
|
135
|
+
rootMachineReferences.set(machine, root)
|
|
126
136
|
return root
|
|
127
137
|
}
|
|
128
138
|
|
|
@@ -224,6 +234,7 @@ const completeHistoryConfiguration = (
|
|
|
224
234
|
const commands: Array<RuntimeCommand> = []
|
|
225
235
|
const raisedEvents: Array<unknown> = []
|
|
226
236
|
const emittedEvents: Array<unknown> = []
|
|
237
|
+
const transitions: Array<ResolvedChoiceTransition> = []
|
|
227
238
|
|
|
228
239
|
let changed = true
|
|
229
240
|
while (changed) {
|
|
@@ -240,22 +251,62 @@ const completeHistoryConfiguration = (
|
|
|
240
251
|
values,
|
|
241
252
|
outputs: configuration.outputs,
|
|
242
253
|
history: configuration.history,
|
|
243
|
-
|
|
254
|
+
machineReferences: configuration.machineReferences
|
|
244
255
|
} as ActiveConfiguration
|
|
256
|
+
if (child.type === "choice") {
|
|
257
|
+
const choice = resolveChoiceTarget(
|
|
258
|
+
machine,
|
|
259
|
+
current,
|
|
260
|
+
makeChoiceTarget(child.path, path, Object.fromEntries(values)),
|
|
261
|
+
event
|
|
262
|
+
)
|
|
263
|
+
let next = current
|
|
264
|
+
for (const routed of [choice.target, ...choice.additionalTargets]) {
|
|
265
|
+
if (routed === undefined || isHistoryTarget(routed)) {
|
|
266
|
+
throw new Error(`Machine initial choice "${child.path}" must resolve to an active state target`)
|
|
267
|
+
}
|
|
268
|
+
const resolved = isInitialTarget(routed)
|
|
269
|
+
? resolveInitialTarget(machine, next, routed, event)
|
|
270
|
+
: undefined
|
|
271
|
+
next = normalizeTargetConfigurationSync(
|
|
272
|
+
machine,
|
|
273
|
+
next,
|
|
274
|
+
(resolved?.target ?? routed) as Machine.Snapshot<any> | Machine.Target<any, any>
|
|
275
|
+
)
|
|
276
|
+
if (resolved !== undefined) {
|
|
277
|
+
commands.push(...resolved.commands)
|
|
278
|
+
raisedEvents.push(...resolved.raisedEvents)
|
|
279
|
+
emittedEvents.push(...resolved.emittedEvents)
|
|
280
|
+
transitions.push(...resolved.transitions)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
active.clear()
|
|
284
|
+
values.clear()
|
|
285
|
+
for (const activePath of next.active) active.add(activePath)
|
|
286
|
+
for (const [valuePath, stateValue] of next.values) values.set(valuePath, stateValue)
|
|
287
|
+
commands.push(...choice.commands)
|
|
288
|
+
raisedEvents.push(...choice.raisedEvents)
|
|
289
|
+
emittedEvents.push(...choice.emittedEvents)
|
|
290
|
+
transitions.push(...choice.transitions)
|
|
291
|
+
changed = true
|
|
292
|
+
continue
|
|
293
|
+
}
|
|
245
294
|
active.add(child.path)
|
|
246
295
|
if (child.schema !== undefined) {
|
|
247
|
-
const initializer = machine.handlers[path]?.
|
|
296
|
+
const initializer = machine.handlers[path]?.initialize
|
|
248
297
|
if (initializer === undefined) {
|
|
249
298
|
throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
|
|
250
299
|
}
|
|
251
300
|
const initialized = collectStateInitializer(machine, initializer, {
|
|
252
|
-
...
|
|
301
|
+
...resolveMachineReferences(machine, current),
|
|
253
302
|
state: current.values.get(path),
|
|
254
303
|
containingState: getParentValue(machine, current, path),
|
|
255
304
|
ancestors: getParentValues(machine, current, path),
|
|
256
|
-
event
|
|
305
|
+
event,
|
|
306
|
+
builder: makeStateInitializeBuilder(machine, path)
|
|
257
307
|
})
|
|
258
|
-
|
|
308
|
+
const initializedValues = getStateInitializeValues(path, initialized.value)
|
|
309
|
+
values.set(child.path, decodeStateValueSync(machine, child, initializedValues[child.key]))
|
|
259
310
|
commands.push(...initialized.commands)
|
|
260
311
|
raisedEvents.push(...initialized.raisedEvents)
|
|
261
312
|
emittedEvents.push(...initialized.emittedEvents)
|
|
@@ -271,35 +322,36 @@ const completeHistoryConfiguration = (
|
|
|
271
322
|
values,
|
|
272
323
|
outputs: configuration.outputs,
|
|
273
324
|
history: configuration.history,
|
|
274
|
-
|
|
325
|
+
machineReferences: configuration.machineReferences
|
|
275
326
|
} as ActiveConfiguration
|
|
276
|
-
const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.
|
|
327
|
+
const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.initialize
|
|
277
328
|
if (valuedMissing.length > 0 && initializer === undefined) {
|
|
278
329
|
throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
|
|
279
330
|
}
|
|
280
331
|
const initialized = initializer === undefined ? undefined : collectStateInitializer(machine, initializer, {
|
|
281
|
-
...
|
|
332
|
+
...resolveMachineReferences(machine, current),
|
|
282
333
|
state: current.values.get(path),
|
|
283
334
|
containingState: getParentValue(machine, current, path),
|
|
284
335
|
ancestors: getParentValues(machine, current, path),
|
|
285
|
-
event
|
|
336
|
+
event,
|
|
337
|
+
builder: makeStateInitializeBuilder(machine, path)
|
|
286
338
|
})
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
339
|
+
const initializedValues = initialized === undefined
|
|
340
|
+
? undefined
|
|
341
|
+
: getStateInitializeValues(path, initialized.value)
|
|
290
342
|
for (const childPath of missing) {
|
|
291
343
|
const child = getNode(machine, childPath)
|
|
292
344
|
active.add(child.path)
|
|
293
345
|
if (child.schema !== undefined) {
|
|
294
346
|
if (
|
|
295
347
|
initialized === undefined ||
|
|
296
|
-
!Object.prototype.hasOwnProperty.call(
|
|
348
|
+
initializedValues === undefined || !Object.prototype.hasOwnProperty.call(initializedValues, child.key)
|
|
297
349
|
) {
|
|
298
350
|
throw new Error(`Machine parallel state initializer for "${path}" must return region "${child.key}"`)
|
|
299
351
|
}
|
|
300
352
|
values.set(
|
|
301
353
|
child.path,
|
|
302
|
-
decodeStateValueSync(machine, child,
|
|
354
|
+
decodeStateValueSync(machine, child, initializedValues[child.key])
|
|
303
355
|
)
|
|
304
356
|
}
|
|
305
357
|
}
|
|
@@ -322,16 +374,38 @@ const completeHistoryConfiguration = (
|
|
|
322
374
|
} as ActiveConfiguration,
|
|
323
375
|
commands,
|
|
324
376
|
raisedEvents,
|
|
325
|
-
emittedEvents
|
|
377
|
+
emittedEvents,
|
|
378
|
+
transitions
|
|
326
379
|
}
|
|
327
380
|
}
|
|
328
381
|
|
|
329
|
-
|
|
382
|
+
export function resolveInitialTarget(
|
|
383
|
+
machine: Machine.Any,
|
|
384
|
+
configuration: ActiveConfiguration,
|
|
385
|
+
target: InitialTargetInstruction,
|
|
386
|
+
event: unknown
|
|
387
|
+
) {
|
|
388
|
+
const partial = configurationFromInitialTargetSync(machine, configuration, target)
|
|
389
|
+
const completed = completeHistoryConfiguration(machine, partial, event)
|
|
390
|
+
const snapshot = snapshotFromConfigurationAtPath(machine, completed.configuration, target.path)
|
|
391
|
+
return {
|
|
392
|
+
target: makeTarget(target.path as any, snapshot.value as any, {
|
|
393
|
+
snapshot: snapshot as any,
|
|
394
|
+
values: Object.fromEntries(completed.configuration.values) as any
|
|
395
|
+
}),
|
|
396
|
+
commands: completed.commands,
|
|
397
|
+
raisedEvents: completed.raisedEvents,
|
|
398
|
+
emittedEvents: completed.emittedEvents,
|
|
399
|
+
transitions: completed.transitions
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function resolveHistoryTarget(
|
|
330
404
|
machine: Machine.Any,
|
|
331
405
|
configuration: ActiveConfiguration,
|
|
332
406
|
target: { readonly path: string; readonly parent: string },
|
|
333
407
|
event: unknown
|
|
334
|
-
)
|
|
408
|
+
) {
|
|
335
409
|
const node = getNode(machine, target.path)
|
|
336
410
|
if (node.type !== "history" || node.parent !== target.parent) {
|
|
337
411
|
throw new Error(`Machine expected history target "${target.path}" to resolve to its declared parent`)
|
|
@@ -353,7 +427,7 @@ const resolveHistoryTarget = (
|
|
|
353
427
|
commands: completed.commands,
|
|
354
428
|
raisedEvents: completed.raisedEvents,
|
|
355
429
|
emittedEvents: completed.emittedEvents,
|
|
356
|
-
transitions:
|
|
430
|
+
transitions: completed.transitions
|
|
357
431
|
}
|
|
358
432
|
}
|
|
359
433
|
|
|
@@ -542,7 +616,7 @@ const makeStateActionContext = <
|
|
|
542
616
|
path: string,
|
|
543
617
|
event: Machine.LifecycleEvent<Events>
|
|
544
618
|
): Machine.StateActionContext<States, Events, Emits, StateId> => ({
|
|
545
|
-
...
|
|
619
|
+
...resolveMachineReferences(machine, configuration),
|
|
546
620
|
state: configuration.values.get(path) as Machine.StateByIdentifier<States, StateId>,
|
|
547
621
|
containingState: getParentValue(machine, configuration, path) as Machine.ParentStateValue<States, StateId>,
|
|
548
622
|
ancestors: getParentValues(machine, configuration, path) as Machine.ParentStateValues<States, StateId>,
|
|
@@ -562,7 +636,7 @@ const makeTransitionContext = <
|
|
|
562
636
|
event: Machine.EventByTag<Events, EventTag>,
|
|
563
637
|
snapshot: Machine.Snapshot<States>
|
|
564
638
|
): Machine.HandlerContext<States, Events, Emits, StateId, EventTag, any, any> => ({
|
|
565
|
-
...
|
|
639
|
+
...resolveMachineReferences(machine, configuration),
|
|
566
640
|
state: configuration.values.get(path) as Machine.StateByIdentifier<States, StateId>,
|
|
567
641
|
containingState: getParentValue(machine, configuration, path) as Machine.ParentStateValue<States, StateId>,
|
|
568
642
|
ancestors: getParentValues(machine, configuration, path) as Machine.ParentStateValues<States, StateId>,
|
|
@@ -584,7 +658,7 @@ const makeDoneContext = <
|
|
|
584
658
|
output: unknown,
|
|
585
659
|
snapshot: Machine.Snapshot<States>
|
|
586
660
|
): Machine.DoneContext<States, Events, Emits, StateId> => ({
|
|
587
|
-
...
|
|
661
|
+
...resolveMachineReferences(machine, configuration),
|
|
588
662
|
state: configuration.values.get(path) as Machine.StateByIdentifier<States, StateId>,
|
|
589
663
|
containingState: getParentValue(machine, configuration, path) as Machine.ParentStateValue<States, StateId>,
|
|
590
664
|
ancestors: getParentValues(machine, configuration, path) as Machine.ParentStateValues<States, StateId>,
|
|
@@ -679,7 +753,7 @@ const selectAlwaysTransitions = <
|
|
|
679
753
|
Machine.AlwaysContext<States, Events, Emits, Machine.StateIdentifier<States>>
|
|
680
754
|
>,
|
|
681
755
|
context: {
|
|
682
|
-
...
|
|
756
|
+
...resolveMachineReferences(machine, configuration),
|
|
683
757
|
state: configuration.values.get(path) as Machine.StateByIdentifier<
|
|
684
758
|
States,
|
|
685
759
|
Machine.StateIdentifier<States>
|
|
@@ -867,7 +941,7 @@ const selectInvocationTransition = <
|
|
|
867
941
|
if (transition === undefined) return []
|
|
868
942
|
const snapshot = snapshotFromConfiguration<States>(machine, configuration)
|
|
869
943
|
const context = {
|
|
870
|
-
...
|
|
944
|
+
...resolveMachineReferences(machine, configuration),
|
|
871
945
|
state: configuration.values.get(event.path),
|
|
872
946
|
containingState: getParentValue(machine, configuration, event.path),
|
|
873
947
|
ancestors: getParentValues(machine, configuration, event.path),
|
|
@@ -1059,12 +1133,12 @@ interface ResolvedChoiceTransition {
|
|
|
1059
1133
|
readonly resolvedTarget: string
|
|
1060
1134
|
}
|
|
1061
1135
|
|
|
1062
|
-
|
|
1136
|
+
function resolveChoiceTarget(
|
|
1063
1137
|
machine: Machine.Any,
|
|
1064
1138
|
configuration: ActiveConfiguration,
|
|
1065
1139
|
initialTarget: unknown,
|
|
1066
1140
|
event: unknown
|
|
1067
|
-
)
|
|
1141
|
+
) {
|
|
1068
1142
|
const pending: Array<unknown> = [initialTarget]
|
|
1069
1143
|
const resolvedTargets: Array<unknown> = []
|
|
1070
1144
|
const commands: Array<RuntimeCommand> = []
|
|
@@ -1107,10 +1181,10 @@ const resolveChoiceTarget = (
|
|
|
1107
1181
|
]),
|
|
1108
1182
|
outputs: configuration.outputs,
|
|
1109
1183
|
history: configuration.history,
|
|
1110
|
-
...(configuration.
|
|
1184
|
+
...(configuration.machineReferences === undefined ? {} : { machineReferences: configuration.machineReferences })
|
|
1111
1185
|
}
|
|
1112
1186
|
const collected = collectTransition(machine, choice.transition, {
|
|
1113
|
-
...
|
|
1187
|
+
...resolveMachineReferences(machine, provisional),
|
|
1114
1188
|
containingState: getParentValue(machine, provisional, node.path),
|
|
1115
1189
|
ancestors: getParentValues(machine, provisional, node.path),
|
|
1116
1190
|
event,
|
|
@@ -1135,7 +1209,7 @@ const resolveChoiceTarget = (
|
|
|
1135
1209
|
emittedEvents.push(...collected.emittedEvents)
|
|
1136
1210
|
}
|
|
1137
1211
|
|
|
1138
|
-
if (!isTarget(current) && !isSnapshot(current) && !isHistoryTarget(current)) {
|
|
1212
|
+
if (!isTarget(current) && !isSnapshot(current) && !isHistoryTarget(current) && !isInitialTarget(current)) {
|
|
1139
1213
|
throw new Error("Machine choice resolver must return a concrete typed target")
|
|
1140
1214
|
}
|
|
1141
1215
|
resolvedTargets.push(current)
|
|
@@ -1190,6 +1264,10 @@ const collectEvaluatedTransition = <
|
|
|
1190
1264
|
(selection.context as any).event
|
|
1191
1265
|
)
|
|
1192
1266
|
const choiceResolvedTarget = choiceResolution?.target ?? unresolvedTarget
|
|
1267
|
+
const initialResolution = choiceResolvedTarget !== undefined && isInitialTarget(choiceResolvedTarget)
|
|
1268
|
+
? resolveInitialTarget(machine, state, choiceResolvedTarget, (selection.context as any).event)
|
|
1269
|
+
: undefined
|
|
1270
|
+
const routedTarget = initialResolution?.target ?? choiceResolvedTarget
|
|
1193
1271
|
let historyResolution: {
|
|
1194
1272
|
readonly target: unknown
|
|
1195
1273
|
readonly commands: ReadonlyArray<RuntimeCommand>
|
|
@@ -1197,50 +1275,64 @@ const collectEvaluatedTransition = <
|
|
|
1197
1275
|
readonly emittedEvents: ReadonlyArray<unknown>
|
|
1198
1276
|
readonly transitions: ReadonlyArray<ResolvedChoiceTransition>
|
|
1199
1277
|
} | undefined
|
|
1200
|
-
const reenteredHistoryTarget = isHistoryTarget(
|
|
1201
|
-
state.active.has(
|
|
1202
|
-
?
|
|
1278
|
+
const reenteredHistoryTarget = isHistoryTarget(routedTarget) && selection.transition.reenter &&
|
|
1279
|
+
state.active.has(routedTarget.parent)
|
|
1280
|
+
? routedTarget
|
|
1203
1281
|
: undefined
|
|
1204
|
-
if (
|
|
1282
|
+
if (routedTarget !== undefined && isHistoryTarget(routedTarget)) {
|
|
1205
1283
|
// A reentering transition may exit the history node's own parent. SCXML
|
|
1206
1284
|
// history observes that same exit, so resolve against a provisional
|
|
1207
1285
|
// capture rather than an older record (or the default).
|
|
1208
1286
|
const provisionalBoundary = selection.transition.reenter
|
|
1209
1287
|
? getNode(machine, selection.sourcePath).parent
|
|
1210
|
-
: getLeastCommonAncestor(machine, stateIdentifier,
|
|
1288
|
+
: getLeastCommonAncestor(machine, stateIdentifier, routedTarget.parent)
|
|
1211
1289
|
const provisionalExitPaths = reenteredHistoryTarget !== undefined
|
|
1212
1290
|
? sortExitPaths(
|
|
1213
1291
|
machine,
|
|
1214
|
-
Array.from(state.active).filter((path) => isPathInSubtree(path,
|
|
1292
|
+
Array.from(state.active).filter((path) => isPathInSubtree(path, routedTarget.parent))
|
|
1215
1293
|
)
|
|
1216
1294
|
: getExitPaths(machine, state, provisionalBoundary)
|
|
1217
|
-
const stateAtHistoryResolution = provisionalExitPaths.includes(
|
|
1295
|
+
const stateAtHistoryResolution = provisionalExitPaths.includes(routedTarget.parent)
|
|
1218
1296
|
? captureHistory(machine, state, state, provisionalExitPaths)
|
|
1219
1297
|
: state
|
|
1220
1298
|
historyResolution = resolveHistoryTarget(
|
|
1221
1299
|
machine,
|
|
1222
1300
|
stateAtHistoryResolution,
|
|
1223
|
-
|
|
1301
|
+
routedTarget,
|
|
1224
1302
|
(selection.context as any).event
|
|
1225
1303
|
)
|
|
1226
1304
|
}
|
|
1227
1305
|
const target: Machine.Snapshot<States> | Machine.Target<States, Machine.StateIdentifier<States>> | undefined =
|
|
1228
1306
|
historyResolution === undefined
|
|
1229
|
-
?
|
|
1307
|
+
? routedTarget as
|
|
1230
1308
|
| Machine.Snapshot<States>
|
|
1231
1309
|
| Machine.Target<States, Machine.StateIdentifier<States>>
|
|
1232
1310
|
| undefined
|
|
1233
1311
|
: historyResolution.target as
|
|
1234
1312
|
| Machine.Snapshot<States>
|
|
1235
1313
|
| Machine.Target<States, Machine.StateIdentifier<States>>
|
|
1236
|
-
const
|
|
1237
|
-
const
|
|
1238
|
-
const
|
|
1239
|
-
const
|
|
1314
|
+
const additionalTargetActions: Array<RuntimeCommand> = []
|
|
1315
|
+
const additionalTargetRaisedEvents: Array<unknown> = []
|
|
1316
|
+
const additionalTargetEmittedEvents: Array<unknown> = []
|
|
1317
|
+
const additionalTargetChoiceTransitions: Array<ResolvedChoiceTransition> = []
|
|
1240
1318
|
const additionalChoiceTargets: Array<
|
|
1241
1319
|
Machine.Snapshot<States> | Machine.Target<States, Machine.StateIdentifier<States>>
|
|
1242
1320
|
> = []
|
|
1243
1321
|
for (const additionalTarget of choiceResolution?.additionalTargets ?? []) {
|
|
1322
|
+
if (isInitialTarget(additionalTarget)) {
|
|
1323
|
+
const resolved = resolveInitialTarget(
|
|
1324
|
+
machine,
|
|
1325
|
+
state,
|
|
1326
|
+
additionalTarget,
|
|
1327
|
+
(selection.context as any).event
|
|
1328
|
+
)
|
|
1329
|
+
additionalChoiceTargets.push(resolved.target as any)
|
|
1330
|
+
additionalTargetActions.push(...resolved.commands)
|
|
1331
|
+
additionalTargetRaisedEvents.push(...resolved.raisedEvents)
|
|
1332
|
+
additionalTargetEmittedEvents.push(...resolved.emittedEvents)
|
|
1333
|
+
additionalTargetChoiceTransitions.push(...resolved.transitions)
|
|
1334
|
+
continue
|
|
1335
|
+
}
|
|
1244
1336
|
if (!isHistoryTarget(additionalTarget)) {
|
|
1245
1337
|
additionalChoiceTargets.push(additionalTarget as any)
|
|
1246
1338
|
continue
|
|
@@ -1252,10 +1344,10 @@ const collectEvaluatedTransition = <
|
|
|
1252
1344
|
(selection.context as any).event
|
|
1253
1345
|
)
|
|
1254
1346
|
additionalChoiceTargets.push(resolved.target as any)
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1347
|
+
additionalTargetActions.push(...resolved.commands)
|
|
1348
|
+
additionalTargetRaisedEvents.push(...resolved.raisedEvents)
|
|
1349
|
+
additionalTargetEmittedEvents.push(...resolved.emittedEvents)
|
|
1350
|
+
additionalTargetChoiceTransitions.push(...resolved.transitions)
|
|
1259
1351
|
}
|
|
1260
1352
|
const targetPath = target === undefined
|
|
1261
1353
|
? undefined
|
|
@@ -1282,28 +1374,32 @@ const collectEvaluatedTransition = <
|
|
|
1282
1374
|
commands: [
|
|
1283
1375
|
...transitionResult.commands,
|
|
1284
1376
|
...(choiceResolution?.commands ?? []),
|
|
1377
|
+
...(initialResolution?.commands ?? []),
|
|
1285
1378
|
...(historyResolution?.commands ?? []),
|
|
1286
|
-
...
|
|
1379
|
+
...additionalTargetActions
|
|
1287
1380
|
],
|
|
1288
1381
|
raisedEvents: [
|
|
1289
1382
|
...transitionResult.raisedEvents,
|
|
1290
1383
|
...(choiceResolution?.raisedEvents ?? []),
|
|
1384
|
+
...(initialResolution?.raisedEvents ?? []),
|
|
1291
1385
|
...(historyResolution?.raisedEvents ?? []),
|
|
1292
|
-
...
|
|
1386
|
+
...additionalTargetRaisedEvents
|
|
1293
1387
|
],
|
|
1294
1388
|
emittedEvents: [
|
|
1295
1389
|
...transitionResult.emittedEvents,
|
|
1296
1390
|
...(choiceResolution?.emittedEvents ?? []),
|
|
1391
|
+
...(initialResolution?.emittedEvents ?? []),
|
|
1297
1392
|
...(historyResolution?.emittedEvents ?? []),
|
|
1298
|
-
...
|
|
1393
|
+
...additionalTargetEmittedEvents
|
|
1299
1394
|
],
|
|
1300
1395
|
changed,
|
|
1301
1396
|
exitPaths: [],
|
|
1302
1397
|
entryPaths: [],
|
|
1303
1398
|
choiceTransitions: [
|
|
1304
1399
|
...(choiceResolution?.transitions ?? []),
|
|
1400
|
+
...(initialResolution?.transitions ?? []),
|
|
1305
1401
|
...(historyResolution?.transitions ?? []),
|
|
1306
|
-
...
|
|
1402
|
+
...additionalTargetChoiceTransitions
|
|
1307
1403
|
]
|
|
1308
1404
|
} as EvaluatedTransition<States, Event, E, R, Context>
|
|
1309
1405
|
}
|
|
@@ -1323,20 +1419,23 @@ const collectEvaluatedTransition = <
|
|
|
1323
1419
|
commands: [
|
|
1324
1420
|
...transitionResult.commands,
|
|
1325
1421
|
...(choiceResolution?.commands ?? []),
|
|
1422
|
+
...(initialResolution?.commands ?? []),
|
|
1326
1423
|
...(historyResolution?.commands ?? []),
|
|
1327
|
-
...
|
|
1424
|
+
...additionalTargetActions
|
|
1328
1425
|
],
|
|
1329
1426
|
raisedEvents: [
|
|
1330
1427
|
...transitionResult.raisedEvents,
|
|
1331
1428
|
...(choiceResolution?.raisedEvents ?? []),
|
|
1429
|
+
...(initialResolution?.raisedEvents ?? []),
|
|
1332
1430
|
...(historyResolution?.raisedEvents ?? []),
|
|
1333
|
-
...
|
|
1431
|
+
...additionalTargetRaisedEvents
|
|
1334
1432
|
],
|
|
1335
1433
|
emittedEvents: [
|
|
1336
1434
|
...transitionResult.emittedEvents,
|
|
1337
1435
|
...(choiceResolution?.emittedEvents ?? []),
|
|
1436
|
+
...(initialResolution?.emittedEvents ?? []),
|
|
1338
1437
|
...(historyResolution?.emittedEvents ?? []),
|
|
1339
|
-
...
|
|
1438
|
+
...additionalTargetEmittedEvents
|
|
1340
1439
|
],
|
|
1341
1440
|
changed,
|
|
1342
1441
|
exitPaths: reenteredHistoryTarget !== undefined
|
|
@@ -1353,8 +1452,9 @@ const collectEvaluatedTransition = <
|
|
|
1353
1452
|
: getEntryPaths(machine, stateAfterTransition, boundary),
|
|
1354
1453
|
choiceTransitions: [
|
|
1355
1454
|
...(choiceResolution?.transitions ?? []),
|
|
1455
|
+
...(initialResolution?.transitions ?? []),
|
|
1356
1456
|
...(historyResolution?.transitions ?? []),
|
|
1357
|
-
...
|
|
1457
|
+
...additionalTargetChoiceTransitions
|
|
1358
1458
|
]
|
|
1359
1459
|
} as EvaluatedTransition<States, Event, E, R, Context>
|
|
1360
1460
|
}
|
|
@@ -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,
|
|
@@ -459,8 +459,9 @@ const makeProcessLogic: <
|
|
|
459
459
|
) =>
|
|
460
460
|
compiledInitial === undefined
|
|
461
461
|
? internalRuntime.provideMachineRuntime(
|
|
462
|
-
internalPlanner.planInitial(internalPlanner.
|
|
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,
|
|
@@ -540,7 +542,7 @@ const makeProcessLogic: <
|
|
|
540
542
|
try {
|
|
541
543
|
planned = internalPlanner.planConfiguration(
|
|
542
544
|
machine,
|
|
543
|
-
Configuration.
|
|
545
|
+
Configuration.withMachineReferences(
|
|
544
546
|
configuration ?? Configuration.normalizeConfigurationSync(machine, current),
|
|
545
547
|
context
|
|
546
548
|
),
|
|
@@ -651,7 +653,7 @@ const makeProcessLogic: <
|
|
|
651
653
|
try {
|
|
652
654
|
planned = internalPlanner.planConfiguration(
|
|
653
655
|
machine,
|
|
654
|
-
Configuration.
|
|
656
|
+
Configuration.withMachineReferences(
|
|
655
657
|
configuration ?? Configuration.normalizeConfigurationSync(machine, current),
|
|
656
658
|
context
|
|
657
659
|
),
|