@typeonce/effect-machine 0.31.2 → 0.33.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 +168 -162
- package/dist/Machine.d.ts +495 -284
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +91 -111
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +3 -4
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js +0 -2
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/childRegistry.d.ts +52 -0
- package/dist/internal/machine/childRegistry.d.ts.map +1 -0
- package/dist/internal/machine/childRegistry.js +74 -0
- package/dist/internal/machine/childRegistry.js.map +1 -0
- package/dist/internal/machine/cluster.d.ts +2 -3
- package/dist/internal/machine/cluster.d.ts.map +1 -1
- package/dist/internal/machine/cluster.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +14 -4
- 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 +97 -53
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +4 -2
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/invocationDefinition.d.ts +35 -0
- package/dist/internal/machine/invocationDefinition.d.ts.map +1 -0
- package/dist/internal/machine/invocationDefinition.js +21 -0
- package/dist/internal/machine/invocationDefinition.js.map +1 -0
- package/dist/internal/machine/invocationEvent.d.ts +0 -2
- package/dist/internal/machine/invocationEvent.d.ts.map +1 -1
- package/dist/internal/machine/invocationEvent.js +0 -8
- package/dist/internal/machine/invocationEvent.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +21 -43
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +134 -403
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +13 -19
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +63 -35
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/process.d.ts +6 -8
- package/dist/internal/machine/process.d.ts.map +1 -1
- package/dist/internal/machine/process.js +1 -0
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/protocol.d.ts +2 -2
- package/dist/internal/machine/protocol.d.ts.map +1 -1
- package/dist/internal/machine/protocol.js +4 -18
- package/dist/internal/machine/protocol.js.map +1 -1
- package/dist/internal/machine/readiness.d.ts +1 -1
- package/dist/internal/machine/readiness.d.ts.map +1 -1
- package/dist/internal/machine/requirements.d.ts +4 -0
- package/dist/internal/machine/requirements.d.ts.map +1 -0
- package/dist/internal/machine/requirements.js +2 -0
- package/dist/internal/machine/requirements.js.map +1 -0
- package/dist/internal/machine/runtime.d.ts +4 -58
- package/dist/internal/machine/runtime.d.ts.map +1 -1
- package/dist/internal/machine/runtime.js +1 -69
- package/dist/internal/machine/runtime.js.map +1 -1
- package/dist/internal/machine/serialization.d.ts.map +1 -1
- package/dist/internal/machine/serialization.js +16 -0
- package/dist/internal/machine/serialization.js.map +1 -1
- package/dist/internal/machine/stateDefinition.d.ts +3 -1
- package/dist/internal/machine/stateDefinition.d.ts.map +1 -1
- package/dist/internal/machine/stateDefinition.js +36 -2
- package/dist/internal/machine/stateDefinition.js.map +1 -1
- package/dist/internal/machine/targetBuilder.d.ts +16 -0
- package/dist/internal/machine/targetBuilder.d.ts.map +1 -0
- package/dist/internal/machine/targetBuilder.js +333 -0
- package/dist/internal/machine/targetBuilder.js.map +1 -0
- package/dist/internal/machine/topology.js +3 -3
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/machine/transition.d.ts +16 -0
- package/dist/internal/machine/transition.d.ts.map +1 -0
- package/dist/internal/machine/transition.js +2 -0
- package/dist/internal/machine/transition.js.map +1 -0
- package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +11 -13
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/internal/testing/machine/format.d.ts +7 -0
- package/dist/internal/testing/machine/format.d.ts.map +1 -0
- package/dist/internal/testing/machine/format.js +104 -0
- package/dist/internal/testing/machine/format.js.map +1 -0
- package/dist/internal/testing/machine/probe.d.ts +1 -1
- package/dist/internal/testing/machine/probe.d.ts.map +1 -1
- package/dist/internal/testing/machine/probe.js +1 -1
- package/dist/internal/testing/machine/probe.js.map +1 -1
- package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/referenceModel.js +15 -19
- package/dist/internal/testing/machine/referenceModel.js.map +1 -1
- package/dist/internal/testing/machine/trace.d.ts +1 -1
- package/dist/internal/testing/machine/trace.d.ts.map +1 -1
- package/dist/internal/testing/machine/trace.js +3 -3
- package/dist/internal/testing/machine/trace.js.map +1 -1
- package/dist/internal/testing/machine/value.d.ts +8 -0
- package/dist/internal/testing/machine/value.d.ts.map +1 -0
- package/dist/internal/testing/machine/value.js +82 -0
- package/dist/internal/testing/machine/value.js.map +1 -0
- package/dist/internal/testing/machine/verification.d.ts +2 -13
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +21 -113
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +89 -104
- package/dist/testing/MachineTest.d.ts.map +1 -1
- package/dist/testing/MachineTest.js +70 -84
- package/dist/testing/MachineTest.js.map +1 -1
- package/dist/unstable/cluster/ClusterMachine.d.ts +10 -13
- package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterMachine.js +5 -8
- package/dist/unstable/cluster/ClusterMachine.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +26 -61
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +17 -26
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +45 -45
- package/docs/effect-atom-react.md +35 -63
- package/docs/machine-review.md +7 -7
- package/docs/root-api.md +259 -0
- package/package.json +1 -1
- package/src/Machine.ts +1053 -538
- package/src/internal/machine/atom.ts +3 -13
- package/src/internal/machine/childRegistry.ts +141 -0
- package/src/internal/machine/cluster.ts +5 -14
- package/src/internal/machine/configuration.ts +20 -4
- package/src/internal/machine/executionPlan.ts +109 -52
- package/src/internal/machine/invocation.ts +10 -6
- package/src/internal/machine/invocationDefinition.ts +52 -0
- package/src/internal/machine/invocationEvent.ts +0 -8
- package/src/internal/machine/machine.ts +222 -716
- package/src/internal/machine/planner.ts +74 -62
- package/src/internal/machine/process.ts +14 -21
- package/src/internal/machine/protocol.ts +9 -32
- package/src/internal/machine/readiness.ts +1 -0
- package/src/internal/machine/requirements.ts +11 -0
- package/src/internal/machine/runtime.ts +17 -186
- package/src/internal/machine/serialization.ts +22 -0
- package/src/internal/machine/stateDefinition.ts +36 -3
- package/src/internal/machine/targetBuilder.ts +525 -0
- package/src/internal/machine/topology.ts +3 -3
- package/src/internal/machine/transition.ts +26 -0
- package/src/internal/testing/machine/finiteModel.ts +23 -24
- package/src/internal/testing/machine/format.ts +120 -0
- package/src/internal/testing/machine/probe.ts +4 -4
- package/src/internal/testing/machine/referenceModel.ts +25 -17
- package/src/internal/testing/machine/trace.ts +4 -4
- package/src/internal/testing/machine/value.ts +77 -0
- package/src/internal/testing/machine/verification.ts +904 -1109
- package/src/testing/MachineTest.ts +103 -114
- package/src/unstable/cluster/ClusterMachine.ts +10 -20
- package/src/unstable/reactivity/AtomMachine.ts +42 -79
|
@@ -3,7 +3,7 @@ import * as Inspectable from "effect/Inspectable"
|
|
|
3
3
|
import * as Option from "effect/Option"
|
|
4
4
|
import { Prototype as PipeablePrototype } from "effect/Pipeable"
|
|
5
5
|
import { hasProperty } from "effect/Predicate"
|
|
6
|
-
import
|
|
6
|
+
import * as Schema from "effect/Schema"
|
|
7
7
|
import type * as Scope from "effect/Scope"
|
|
8
8
|
import type * as Stream from "effect/Stream"
|
|
9
9
|
import type {
|
|
@@ -21,22 +21,31 @@ import type {
|
|
|
21
21
|
MachineSchemaEncodeError,
|
|
22
22
|
Parent,
|
|
23
23
|
ParentMode,
|
|
24
|
-
Runtime,
|
|
25
24
|
RuntimeOutcome,
|
|
26
25
|
SpawnOptions,
|
|
26
|
+
State,
|
|
27
27
|
StoppedError
|
|
28
28
|
} from "../../Machine.js"
|
|
29
29
|
import * as Activities from "./activities.js"
|
|
30
30
|
import * as Configuration from "./configuration.js"
|
|
31
31
|
import type { ChildAlreadyExistsError, InfiniteTransitionError, StartupError } from "./errors.js"
|
|
32
|
+
import * as InvocationDefinition from "./invocationDefinition.js"
|
|
32
33
|
import * as internalPlanner from "./planner.js"
|
|
33
34
|
import * as internalProcess from "./process.js"
|
|
34
35
|
import * as Protocol from "./protocol.js"
|
|
35
36
|
import type { EnsureExecutable } from "./readiness.js"
|
|
37
|
+
import type { ExcludeCompatibleRuntime } from "./requirements.js"
|
|
36
38
|
import * as internalRuntime from "./runtime.js"
|
|
37
39
|
import * as Serialization from "./serialization.js"
|
|
38
40
|
import * as StateDefinition from "./stateDefinition.js"
|
|
39
|
-
import { ChildMachineLogicTypeId
|
|
41
|
+
import { ChildMachineLogicTypeId } from "./symbols.js"
|
|
42
|
+
import {
|
|
43
|
+
getLocalTargetScope,
|
|
44
|
+
getTargetBuilderNode,
|
|
45
|
+
makeSnapshotBuilder,
|
|
46
|
+
makeTargetBuilder,
|
|
47
|
+
withFrom
|
|
48
|
+
} from "./targetBuilder.js"
|
|
40
49
|
import * as Topology from "./topology.js"
|
|
41
50
|
|
|
42
51
|
export {
|
|
@@ -56,15 +65,8 @@ export const InvokeTypeId: unique symbol = Symbol.for("effect/Machine/Invoke")
|
|
|
56
65
|
export const TransitionTypeId: unique symbol = Symbol.for("effect/Machine/Transition")
|
|
57
66
|
const InvokeBuilderDescriptorTypeId: unique symbol = Symbol("effect/Machine/InvokeBuilderDescriptor")
|
|
58
67
|
const ChildMachineTypeId = "~effect/Machine/ChildMachine"
|
|
59
|
-
type IsAny<A> = 0 extends 1 & A ? true : false
|
|
60
68
|
type MachineRuntimeRequirement = internalRuntime.MachineRuntime
|
|
61
|
-
|
|
62
|
-
infer RequiredEvents,
|
|
63
|
-
infer RequiredEmits
|
|
64
|
-
> ? IsAny<Requirements> extends true ? Requirements
|
|
65
|
-
: [RequiredEvents] extends [Events] ? [RequiredEmits] extends [Emits] ? never : Requirements
|
|
66
|
-
: Requirements
|
|
67
|
-
: Requirements
|
|
69
|
+
|
|
68
70
|
type SpawnRequirements<Requirements> = Exclude<Requirements, Scope.Scope>
|
|
69
71
|
type SpawnIdError<Options extends SpawnOptions> = "id" extends keyof Options ? Options extends {
|
|
70
72
|
readonly id?: infer Id
|
|
@@ -77,34 +79,6 @@ type SpawnResult<State, Event, Error, Requirements, Output, SpawnError, InitialE
|
|
|
77
79
|
SpawnError | InitialError,
|
|
78
80
|
MachineRuntimeRequirement | SpawnRequirements<Requirements>
|
|
79
81
|
>
|
|
80
|
-
type DefineStateTreeInput<States extends Machine.StateSchemas> = States
|
|
81
|
-
type ValidateDefinedStates<States extends Machine.StateSchemas> = [States] extends
|
|
82
|
-
[Machine.ValidateStateSchemas<States>] ? []
|
|
83
|
-
: [validation: Machine.ValidateStateSchemas<States>]
|
|
84
|
-
type InvalidDefinedStateTreeInput<States extends Machine.StateSchemas> = [States] extends
|
|
85
|
-
[Machine.ValidateStateSchemas<States>] ? never
|
|
86
|
-
: States & Machine.ValidateStateSchemas<States>
|
|
87
|
-
type ReusableStateNodeConfig =
|
|
88
|
-
| Machine.AtomicStateNodeConfig
|
|
89
|
-
| Machine.CompoundStateNodeConfig
|
|
90
|
-
| Machine.ParallelStateNodeConfig
|
|
91
|
-
interface StateConstructor {
|
|
92
|
-
<const Node extends ReusableStateNodeConfig>(node: Node): Node
|
|
93
|
-
}
|
|
94
|
-
interface StatesConstructor {
|
|
95
|
-
<const States extends Machine.StateSchemas>(
|
|
96
|
-
states: States,
|
|
97
|
-
..._validation: ValidateDefinedStates<NoInfer<States>>
|
|
98
|
-
): Machine.DefinedStates<States>
|
|
99
|
-
<const States extends Machine.StateSchemas>(states: InvalidDefinedStateTreeInput<States>): never
|
|
100
|
-
}
|
|
101
|
-
type ValidateInputEventProtocol<InputEvents extends ReadonlyArray<Machine.TaggedSchema>> = InputEvents extends
|
|
102
|
-
ReadonlyArray<Machine.TaggedSchema> ? unknown : never
|
|
103
|
-
type ValidateInternalEventProtocol<
|
|
104
|
-
InputEvents extends ReadonlyArray<Machine.TaggedSchema>,
|
|
105
|
-
InternalEvents extends ReadonlyArray<Machine.TaggedSchema>
|
|
106
|
-
> = InputEvents | InternalEvents extends ReadonlyArray<Machine.TaggedSchema> ? unknown : never
|
|
107
|
-
|
|
108
82
|
const Proto = {
|
|
109
83
|
...Inspectable.BaseProto,
|
|
110
84
|
...PipeablePrototype,
|
|
@@ -122,6 +96,7 @@ const makeWithHandlers = (
|
|
|
122
96
|
): Machine.Any => {
|
|
123
97
|
const machine = Object.create(Proto)
|
|
124
98
|
machine.states = self.states
|
|
99
|
+
machine.root = self.root
|
|
125
100
|
machine.events = self.events
|
|
126
101
|
machine.internalEvents = self.internalEvents
|
|
127
102
|
machine.emittedEvents = self.emittedEvents
|
|
@@ -164,8 +139,8 @@ type DirectTransitionDescriptor = {
|
|
|
164
139
|
readonly [TransitionBuilderDescriptorTypeId]: typeof TransitionBuilderDescriptorTypeId
|
|
165
140
|
readonly type: "direct"
|
|
166
141
|
readonly selection: Topology.TargetSelection
|
|
167
|
-
readonly
|
|
168
|
-
readonly
|
|
142
|
+
readonly resolver?: (context: any, enqueue: unknown) => unknown
|
|
143
|
+
readonly reenterSource: boolean
|
|
169
144
|
readonly declinable: boolean
|
|
170
145
|
}
|
|
171
146
|
|
|
@@ -174,7 +149,7 @@ type BranchesTransitionDescriptor = {
|
|
|
174
149
|
readonly type: "branches"
|
|
175
150
|
readonly declarations: unknown
|
|
176
151
|
readonly resolve: (context: any, enqueue: unknown) => unknown
|
|
177
|
-
readonly
|
|
152
|
+
readonly reenterSource: boolean
|
|
178
153
|
readonly declinable: boolean
|
|
179
154
|
}
|
|
180
155
|
|
|
@@ -193,38 +168,95 @@ const plainTargetSelection = (selection: Topology.TargetSelection): Topology.Tar
|
|
|
193
168
|
? Topology.noneTargetSelection
|
|
194
169
|
: Topology.makeTargetSelection(selection.kind, selection.path, selection.scope, selection.updatePath)
|
|
195
170
|
|
|
196
|
-
const transitionOptions = (options: unknown): { readonly
|
|
171
|
+
const transitionOptions = (options: unknown): { readonly declinable: boolean } => {
|
|
197
172
|
const configuration = typeof options === "object" && options !== null
|
|
198
|
-
? options as { readonly
|
|
173
|
+
? options as { readonly declinable?: unknown }
|
|
199
174
|
: {}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
declinable: configuration.declinable === true
|
|
175
|
+
if (hasProperty(configuration, "reenter")) {
|
|
176
|
+
throw new Error("Use .reenter() before construction instead of the resolver reenter option")
|
|
203
177
|
}
|
|
178
|
+
return { declinable: configuration.declinable === true }
|
|
204
179
|
}
|
|
205
180
|
|
|
206
181
|
const makeDirectTransitionDescriptor = (
|
|
207
182
|
selection: Topology.TargetSelection,
|
|
208
183
|
resolve: ((context: any, enqueue: unknown) => unknown) | undefined,
|
|
209
|
-
options: unknown
|
|
184
|
+
options: unknown,
|
|
185
|
+
reenterSource = false
|
|
210
186
|
): DirectTransitionDescriptor => {
|
|
211
|
-
const shared: Omit<DirectTransitionDescriptor, "
|
|
187
|
+
const shared: Omit<DirectTransitionDescriptor, "resolver"> = {
|
|
212
188
|
[TransitionBuilderDescriptorTypeId]: TransitionBuilderDescriptorTypeId,
|
|
213
189
|
type: "direct",
|
|
214
190
|
selection: plainTargetSelection(selection),
|
|
191
|
+
reenterSource,
|
|
215
192
|
...transitionOptions(options)
|
|
216
193
|
}
|
|
217
194
|
return resolve === undefined
|
|
218
195
|
? Object.freeze(shared)
|
|
219
|
-
: Object.freeze({ ...shared, resolve })
|
|
196
|
+
: Object.freeze({ ...shared, resolver: resolve })
|
|
220
197
|
}
|
|
221
198
|
|
|
222
|
-
|
|
199
|
+
// The authored callback crosses an erased schema boundary here. Each builder
|
|
200
|
+
// retains its construction mode, and planning validates both resulting values.
|
|
201
|
+
const constructSelectionValue = (
|
|
202
|
+
selection: Topology.TargetSelection,
|
|
203
|
+
context: any,
|
|
204
|
+
method: "from" | "decoded",
|
|
205
|
+
value: unknown
|
|
206
|
+
): unknown => {
|
|
207
|
+
if (selection.kind === "update") return context.owner[method](value)
|
|
208
|
+
if (selection.updatePath === undefined) return context.target[method](value)
|
|
209
|
+
const values = value as { readonly target: unknown; readonly update: unknown }
|
|
210
|
+
return context.target[method](values.target).update(context.owner[method](values.update))
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const guardedSelection = (
|
|
214
|
+
selection: Topology.TargetSelection,
|
|
215
|
+
predicate: (context: any) => boolean,
|
|
216
|
+
reenterSource: boolean
|
|
217
|
+
): object => {
|
|
218
|
+
const wrap = (resolve: (context: any, enqueue: unknown) => unknown, options?: unknown) =>
|
|
219
|
+
makeDirectTransitionDescriptor(
|
|
220
|
+
selection,
|
|
221
|
+
(context, enqueue) => predicate(context) ? resolve(context, enqueue) : Topology.makeDeclined(),
|
|
222
|
+
{ ...transitionOptions(options), declinable: true },
|
|
223
|
+
reenterSource
|
|
224
|
+
)
|
|
225
|
+
return Object.freeze({
|
|
226
|
+
...wrap((context) => selection.kind === "none" ? undefined : constructSelectedTarget(context.target)),
|
|
227
|
+
from: (value: (context: any) => unknown) =>
|
|
228
|
+
wrap((context) => constructSelectionValue(selection, context, "from", value(context))),
|
|
229
|
+
decoded: (value: (context: any) => unknown) =>
|
|
230
|
+
wrap((context) => constructSelectionValue(selection, context, "decoded", value(context))),
|
|
231
|
+
resolve: wrap
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const decorateTransitionSelection = (
|
|
236
|
+
selection: Topology.TargetSelection,
|
|
237
|
+
reenterSource = false
|
|
238
|
+
): Topology.TargetSelection =>
|
|
223
239
|
Object.freeze({
|
|
224
240
|
...selection,
|
|
241
|
+
...(reenterSource ? makeDirectTransitionDescriptor(selection, undefined, undefined, true) : {}),
|
|
242
|
+
guard: (predicate: (context: any) => boolean) => guardedSelection(selection, predicate, reenterSource),
|
|
243
|
+
from: (value: (context: any) => unknown) =>
|
|
244
|
+
makeDirectTransitionDescriptor(
|
|
245
|
+
selection,
|
|
246
|
+
(context) => constructSelectionValue(selection, context, "from", value(context)),
|
|
247
|
+
undefined,
|
|
248
|
+
reenterSource
|
|
249
|
+
),
|
|
250
|
+
decoded: (value: (context: any) => unknown) =>
|
|
251
|
+
makeDirectTransitionDescriptor(
|
|
252
|
+
selection,
|
|
253
|
+
(context) => constructSelectionValue(selection, context, "decoded", value(context)),
|
|
254
|
+
undefined,
|
|
255
|
+
reenterSource
|
|
256
|
+
),
|
|
225
257
|
resolve: (resolve: (context: any, enqueue: unknown) => unknown, options?: unknown) =>
|
|
226
|
-
makeDirectTransitionDescriptor(selection, resolve, options),
|
|
227
|
-
reenter: () =>
|
|
258
|
+
makeDirectTransitionDescriptor(selection, resolve, options, reenterSource),
|
|
259
|
+
reenter: () => decorateTransitionSelection(selection, true),
|
|
228
260
|
updating: (owner: unknown) => {
|
|
229
261
|
if (typeof owner !== "function") {
|
|
230
262
|
throw new Error("Machine updating owner must be a state selector")
|
|
@@ -237,20 +269,12 @@ const decorateTransitionSelection = (selection: Topology.TargetSelection): Topol
|
|
|
237
269
|
throw new Error("Machine updating owner must be addressed by one branch state selector")
|
|
238
270
|
}
|
|
239
271
|
return decorateTransitionSelection(
|
|
240
|
-
Topology.makeTargetSelection(selection.kind, selection.path, selection.scope, ownerSelection.path)
|
|
272
|
+
Topology.makeTargetSelection(selection.kind, selection.path, selection.scope, ownerSelection.path),
|
|
273
|
+
reenterSource
|
|
241
274
|
)
|
|
242
275
|
}
|
|
243
276
|
})
|
|
244
277
|
|
|
245
|
-
const decorateStateUpdateSelection = (selection: Topology.TargetSelection): Topology.TargetSelection => {
|
|
246
|
-
const update = (
|
|
247
|
-
resolve: (context: any, enqueue: unknown) => unknown,
|
|
248
|
-
options?: unknown
|
|
249
|
-
) => makeDirectTransitionDescriptor(selection, resolve, options)
|
|
250
|
-
Object.assign(update, selection)
|
|
251
|
-
return Object.freeze(update) as unknown as Topology.TargetSelection
|
|
252
|
-
}
|
|
253
|
-
|
|
254
278
|
const noneTransitionSelection = decorateTransitionSelection(Topology.noneTargetSelection)
|
|
255
279
|
|
|
256
280
|
const makeInitialBuilderDescriptor = (
|
|
@@ -266,6 +290,10 @@ const makeInitialBuilderDescriptor = (
|
|
|
266
290
|
const decorateInitialSelection = (selection: Topology.TargetSelection): Topology.TargetSelection =>
|
|
267
291
|
Object.freeze({
|
|
268
292
|
...selection,
|
|
293
|
+
from: (value: (context: any) => unknown) =>
|
|
294
|
+
makeInitialBuilderDescriptor(selection, (context) => context.target.from(value(context))),
|
|
295
|
+
decoded: (value: (context: any) => unknown) =>
|
|
296
|
+
makeInitialBuilderDescriptor(selection, (context) => context.target.decoded(value(context))),
|
|
269
297
|
resolve: (resolve: (context: any) => unknown) => makeInitialBuilderDescriptor(selection, resolve)
|
|
270
298
|
})
|
|
271
299
|
|
|
@@ -292,7 +320,12 @@ const decorateInitialSelectorNode = (node: unknown): unknown => {
|
|
|
292
320
|
|
|
293
321
|
const decorateTransitionSelectorNode = (node: unknown): unknown => {
|
|
294
322
|
if (Topology.isTargetSelection(node)) {
|
|
295
|
-
if (node.kind === "
|
|
323
|
+
if (node.kind === "state" && node.scope === "full" && hasProperty(node, "initial")) {
|
|
324
|
+
return Object.freeze({
|
|
325
|
+
...decorateTransitionSelection(node),
|
|
326
|
+
initial: decorateTransitionSelection(node.initial as Topology.TargetSelection)
|
|
327
|
+
})
|
|
328
|
+
}
|
|
296
329
|
return node === Topology.noneTargetSelection ? noneTransitionSelection : decorateTransitionSelection(node)
|
|
297
330
|
}
|
|
298
331
|
if (typeof node === "function") {
|
|
@@ -314,29 +347,31 @@ const decorateTransitionSelectorNode = (node: unknown): unknown => {
|
|
|
314
347
|
return node
|
|
315
348
|
}
|
|
316
349
|
|
|
350
|
+
const decorateBranches = (declarations: unknown, reenterSource = false): object =>
|
|
351
|
+
Object.freeze({
|
|
352
|
+
reenter: () => decorateBranches(declarations, true),
|
|
353
|
+
resolve: (
|
|
354
|
+
resolve: (context: any, enqueue: unknown) => unknown,
|
|
355
|
+
options?: unknown
|
|
356
|
+
): BranchesTransitionDescriptor =>
|
|
357
|
+
Object.freeze({
|
|
358
|
+
[TransitionBuilderDescriptorTypeId]: TransitionBuilderDescriptorTypeId,
|
|
359
|
+
type: "branches",
|
|
360
|
+
declarations,
|
|
361
|
+
resolve,
|
|
362
|
+
reenterSource,
|
|
363
|
+
...transitionOptions(options)
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
|
|
317
367
|
const makeTransitionSelector = (
|
|
318
368
|
stateNodes: Machine.StateNodes,
|
|
319
369
|
source: string
|
|
320
|
-
): unknown =>
|
|
321
|
-
|
|
322
|
-
...decorateTransitionSelectorNode(makeTargetSelector(stateNodes, source)) as Record<string, unknown
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
Object.freeze({
|
|
326
|
-
resolve: (
|
|
327
|
-
resolve: (context: any, enqueue: unknown) => unknown,
|
|
328
|
-
options?: unknown
|
|
329
|
-
): BranchesTransitionDescriptor =>
|
|
330
|
-
Object.freeze({
|
|
331
|
-
[TransitionBuilderDescriptorTypeId]: TransitionBuilderDescriptorTypeId,
|
|
332
|
-
type: "branches",
|
|
333
|
-
declarations,
|
|
334
|
-
resolve,
|
|
335
|
-
...transitionOptions(options)
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
return Object.freeze(selector)
|
|
339
|
-
}
|
|
370
|
+
): unknown =>
|
|
371
|
+
Object.freeze({
|
|
372
|
+
...decorateTransitionSelectorNode(makeTargetSelector(stateNodes, source)) as Record<string, unknown>,
|
|
373
|
+
branches: (declarations: unknown) => decorateBranches(declarations)
|
|
374
|
+
})
|
|
340
375
|
|
|
341
376
|
const normalizeTransitionBuilder = (
|
|
342
377
|
transition: (selector: unknown) => unknown,
|
|
@@ -344,7 +379,7 @@ const normalizeTransitionBuilder = (
|
|
|
344
379
|
path: string
|
|
345
380
|
): unknown => {
|
|
346
381
|
const result = transition(makeTransitionSelector(stateNodes, path))
|
|
347
|
-
if (Topology.isTargetSelection(result)) {
|
|
382
|
+
if (Topology.isTargetSelection(result) && !hasProperty(result, TransitionBuilderDescriptorTypeId)) {
|
|
348
383
|
const selection = plainTargetSelection(result)
|
|
349
384
|
return { target: () => selection }
|
|
350
385
|
}
|
|
@@ -354,14 +389,14 @@ const normalizeTransitionBuilder = (
|
|
|
354
389
|
return {
|
|
355
390
|
branches: () => descriptor.declarations,
|
|
356
391
|
resolve: descriptor.resolve,
|
|
357
|
-
reenter: descriptor.
|
|
392
|
+
reenter: descriptor.reenterSource,
|
|
358
393
|
declinable: descriptor.declinable
|
|
359
394
|
}
|
|
360
395
|
}
|
|
361
396
|
return {
|
|
362
397
|
target: () => descriptor.selection,
|
|
363
|
-
resolve: descriptor.
|
|
364
|
-
reenter: descriptor.
|
|
398
|
+
resolve: descriptor.resolver,
|
|
399
|
+
reenter: descriptor.reenterSource,
|
|
365
400
|
declinable: descriptor.declinable
|
|
366
401
|
}
|
|
367
402
|
}
|
|
@@ -430,7 +465,7 @@ const makeSelectionNode = (
|
|
|
430
465
|
}
|
|
431
466
|
if (
|
|
432
467
|
scope === "branch" && source !== undefined && node.schema !== undefined &&
|
|
433
|
-
(source === path ||
|
|
468
|
+
(source === path || Configuration.isDescendantOf(source, path)) &&
|
|
434
469
|
getTargetBuilderNode(stateNodes, source).type !== "choice"
|
|
435
470
|
) {
|
|
436
471
|
Object.defineProperty(method, "update", {
|
|
@@ -439,6 +474,9 @@ const makeSelectionNode = (
|
|
|
439
474
|
})
|
|
440
475
|
}
|
|
441
476
|
}
|
|
477
|
+
if (node.type === "atomic" && scope === "branch" && source === path && node.schema !== undefined) {
|
|
478
|
+
Object.defineProperty(method, "update", { value: makeStateUpdateSelection(path, "branch"), enumerable: true })
|
|
479
|
+
}
|
|
442
480
|
return method
|
|
443
481
|
}
|
|
444
482
|
|
|
@@ -463,15 +501,12 @@ const makeTargetSelector = (
|
|
|
463
501
|
stateNodes: Machine.StateNodes,
|
|
464
502
|
source: string
|
|
465
503
|
): unknown => {
|
|
466
|
-
const full
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
full[node.key] = makeSelectionNode(stateNodes, node.path, "full")
|
|
470
|
-
}
|
|
471
|
-
}
|
|
504
|
+
const full = Object.assign({}, makeSelectionValue("state", "", "full"), {
|
|
505
|
+
initial: makeSelectionValue("initial", "", "full")
|
|
506
|
+
})
|
|
472
507
|
const branch: Record<string, unknown> = {}
|
|
473
|
-
const root = getTargetBuilderNode(stateNodes,
|
|
474
|
-
branch
|
|
508
|
+
const root = getTargetBuilderNode(stateNodes, stateNodes.roots[0]!)
|
|
509
|
+
addSelectionChildren(branch, stateNodes, root.path, "branch", source)
|
|
475
510
|
const local: Record<string, unknown> = {}
|
|
476
511
|
const localScope = getLocalTargetScope(stateNodes, source)
|
|
477
512
|
if (localScope !== undefined) {
|
|
@@ -486,10 +521,15 @@ const makeTargetSelector = (
|
|
|
486
521
|
}
|
|
487
522
|
return {
|
|
488
523
|
none: Topology.noneTargetSelection,
|
|
524
|
+
self: getTargetBuilderNode(stateNodes, source).schema === undefined ||
|
|
525
|
+
getTargetBuilderNode(stateNodes, source).type === "final"
|
|
526
|
+
? {}
|
|
527
|
+
: { update: makeStateUpdateSelection(source, "branch") },
|
|
528
|
+
root: makeSelectionNode(stateNodes, root.path, "branch", source),
|
|
489
529
|
local,
|
|
490
530
|
branch,
|
|
491
531
|
full,
|
|
492
|
-
history: makeHistorySelectionTree(stateNodes,
|
|
532
|
+
history: makeHistorySelectionTree(stateNodes, "")
|
|
493
533
|
}
|
|
494
534
|
}
|
|
495
535
|
|
|
@@ -580,6 +620,7 @@ const getSelectionBuilder = (
|
|
|
580
620
|
let parts = selection.path!.split(".")
|
|
581
621
|
if (selection.kind === "history") {
|
|
582
622
|
builder = target.history
|
|
623
|
+
if (selection.path !== "") parts.unshift("")
|
|
583
624
|
} else if (selection.scope === "local") {
|
|
584
625
|
builder = target.local
|
|
585
626
|
const scope = getLocalTargetScope(stateNodes, source)
|
|
@@ -588,11 +629,12 @@ const getSelectionBuilder = (
|
|
|
588
629
|
builder = builder.with
|
|
589
630
|
parts = []
|
|
590
631
|
} else {
|
|
591
|
-
parts = selection.path!.slice(scope.length + 1).split(".")
|
|
632
|
+
parts = (scope === "" ? selection.path! : selection.path!.slice(scope.length + 1)).split(".")
|
|
592
633
|
}
|
|
593
634
|
}
|
|
594
635
|
} else if (selection.scope === "branch") {
|
|
595
636
|
builder = target.branch
|
|
637
|
+
if (selection.path !== "") parts.unshift("")
|
|
596
638
|
} else {
|
|
597
639
|
builder = target.full
|
|
598
640
|
}
|
|
@@ -645,7 +687,7 @@ const validateResolvedSelection = (
|
|
|
645
687
|
(selectedNode?.type === "compound" || selectedNode?.type === "parallel")
|
|
646
688
|
if (
|
|
647
689
|
resultPath === undefined ||
|
|
648
|
-
(resultPath !== selection.path && !(acceptsDescendant &&
|
|
690
|
+
(resultPath !== selection.path && !(acceptsDescendant && Configuration.isDescendantOf(resultPath, selection.path!)))
|
|
649
691
|
) {
|
|
650
692
|
throw new Error(
|
|
651
693
|
`Machine transition resolver selected "${selection.path}" but constructed "${resultPath ?? "<invalid>"}"`
|
|
@@ -737,6 +779,11 @@ const captureNamedBranches = (
|
|
|
737
779
|
if (target.updatePath !== undefined) {
|
|
738
780
|
throw new Error(`Machine transition branch "${key}" cannot declare an updating target`)
|
|
739
781
|
}
|
|
782
|
+
if (hasProperty(target, TransitionBuilderDescriptorTypeId)) {
|
|
783
|
+
throw new Error(
|
|
784
|
+
`Machine transition branch "${key}" requires a topology selection; apply .reenter() to .branches(...)`
|
|
785
|
+
)
|
|
786
|
+
}
|
|
740
787
|
if (title !== undefined && (typeof title !== "string" || title.length === 0)) {
|
|
741
788
|
throw new Error(`Machine transition branch "${key}" title must be a non-empty string`)
|
|
742
789
|
}
|
|
@@ -1005,9 +1052,9 @@ const captureInvokeDefinition = (
|
|
|
1005
1052
|
captured[key] = captureTransition(captured[key], stateNodes, path, key)
|
|
1006
1053
|
}
|
|
1007
1054
|
}
|
|
1008
|
-
return captured
|
|
1055
|
+
return InvocationDefinition.capture(captured, path)
|
|
1009
1056
|
})
|
|
1010
|
-
if (Array.isArray(authored)) return capturedDefinitions
|
|
1057
|
+
if (Array.isArray(authored)) return Object.freeze(capturedDefinitions)
|
|
1011
1058
|
return capturedDefinitions[0]
|
|
1012
1059
|
}
|
|
1013
1060
|
|
|
@@ -1028,6 +1075,14 @@ const flattenHandlers = (
|
|
|
1028
1075
|
throw new Error(`Machine expected state "${path}" handler to be an object`)
|
|
1029
1076
|
}
|
|
1030
1077
|
const { states: childConfig, ...stateConfig } = nodeConfig as Record<string, unknown>
|
|
1078
|
+
if (typeof stateConfig.history === "object" && stateConfig.history !== null) {
|
|
1079
|
+
stateConfig.history = Object.freeze(Object.fromEntries(
|
|
1080
|
+
Object.entries(stateConfig.history).map(([key, entry]) => [
|
|
1081
|
+
key,
|
|
1082
|
+
typeof entry === "object" && entry !== null ? Object.freeze({ ...entry }) : entry
|
|
1083
|
+
])
|
|
1084
|
+
))
|
|
1085
|
+
}
|
|
1031
1086
|
const on = stateConfig.on
|
|
1032
1087
|
if (typeof on === "object" && on !== null) {
|
|
1033
1088
|
const capturedOn = captureEventHandlers(on, stateNodes, path)
|
|
@@ -1073,7 +1128,7 @@ const flattenHandlers = (
|
|
|
1073
1128
|
const makeHandle = (self: Definition.Any): Definition.Any["handle"] =>
|
|
1074
1129
|
((config: Record<string, unknown>) => {
|
|
1075
1130
|
const handlers: Record<PropertyKey, Machine.AnyStateConfig> = Object.create(null)
|
|
1076
|
-
flattenHandlers(handlers, self.stateNodes, self.states, "", config)
|
|
1131
|
+
flattenHandlers(handlers, self.stateNodes, self.states, "", { "": config })
|
|
1077
1132
|
return makeWithHandlers(self, handlers)
|
|
1078
1133
|
}) as Definition.Any["handle"]
|
|
1079
1134
|
|
|
@@ -1114,523 +1169,6 @@ export const isFinal = <
|
|
|
1114
1169
|
state: Machine.Snapshot<States>
|
|
1115
1170
|
): state is Machine.SnapshotContainingFinal<States, FinalStates> => internalPlanner.isFinal(machine as any, state)
|
|
1116
1171
|
|
|
1117
|
-
type SnapshotBuilderOptions = {
|
|
1118
|
-
readonly mode: "initial" | "full"
|
|
1119
|
-
readonly prefix: string
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
type FromMethodKind = "leaf" | "nested"
|
|
1123
|
-
|
|
1124
|
-
const withFrom = <Method extends (value: unknown, ...args: ReadonlyArray<any>) => unknown>(
|
|
1125
|
-
method: Method,
|
|
1126
|
-
kind: FromMethodKind,
|
|
1127
|
-
valued: boolean
|
|
1128
|
-
): {
|
|
1129
|
-
readonly decoded?: Method
|
|
1130
|
-
readonly from: (...args: ReadonlyArray<any>) => unknown
|
|
1131
|
-
} => {
|
|
1132
|
-
const builder: Record<string, unknown> = {}
|
|
1133
|
-
if (valued) {
|
|
1134
|
-
Object.defineProperty(builder, "decoded", {
|
|
1135
|
-
value: method,
|
|
1136
|
-
enumerable: false
|
|
1137
|
-
})
|
|
1138
|
-
}
|
|
1139
|
-
Object.defineProperty(builder, "from", {
|
|
1140
|
-
value: (...args: ReadonlyArray<any>) => {
|
|
1141
|
-
if (!valued) {
|
|
1142
|
-
return method(undefined, ...args)
|
|
1143
|
-
}
|
|
1144
|
-
const omitted = args.length === 0 || (kind === "nested" && args.length === 1 && typeof args[0] === "function")
|
|
1145
|
-
const input = omitted ? {} : args[0]
|
|
1146
|
-
const rest = omitted ? args : args.slice(1)
|
|
1147
|
-
return method(Topology.makeStateInput(input), ...rest)
|
|
1148
|
-
},
|
|
1149
|
-
enumerable: false
|
|
1150
|
-
})
|
|
1151
|
-
return builder as {
|
|
1152
|
-
readonly decoded?: Method
|
|
1153
|
-
readonly from: (...args: ReadonlyArray<any>) => unknown
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
const withInitial = <Builder extends object>(
|
|
1158
|
-
builder: Builder,
|
|
1159
|
-
path: string,
|
|
1160
|
-
valued: boolean,
|
|
1161
|
-
values?: Readonly<Record<string, unknown>>
|
|
1162
|
-
): Builder => {
|
|
1163
|
-
const initial = withFrom(
|
|
1164
|
-
(value: unknown) => Topology.makeInitialTarget(path, value, values),
|
|
1165
|
-
"leaf",
|
|
1166
|
-
valued
|
|
1167
|
-
)
|
|
1168
|
-
Object.defineProperty(builder, "initial", {
|
|
1169
|
-
value: initial,
|
|
1170
|
-
enumerable: false
|
|
1171
|
-
})
|
|
1172
|
-
return builder
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
const makeSnapshotBuilder = (
|
|
1176
|
-
states: Machine.StateTree,
|
|
1177
|
-
options: SnapshotBuilderOptions
|
|
1178
|
-
): unknown => {
|
|
1179
|
-
const builder: Record<string, unknown> = {}
|
|
1180
|
-
for (const key of Object.keys(states)) {
|
|
1181
|
-
const definition = states[key]!
|
|
1182
|
-
const pseudoType = (definition as { readonly type?: unknown }).type
|
|
1183
|
-
if (pseudoType === "history") {
|
|
1184
|
-
continue
|
|
1185
|
-
}
|
|
1186
|
-
const path = options.prefix === "" ? key : `${options.prefix}.${key}`
|
|
1187
|
-
if (pseudoType === "choice") {
|
|
1188
|
-
builder[key] = () => Topology.makeChoiceTarget(path, getParentPathRuntime(path))
|
|
1189
|
-
continue
|
|
1190
|
-
}
|
|
1191
|
-
const node = Topology.getStateNodeDefinition(path, definition)
|
|
1192
|
-
const method = withFrom(
|
|
1193
|
-
(value: unknown, selector?: (builder: unknown) => unknown) =>
|
|
1194
|
-
makeSnapshotForNode(definition, key, value, selector, options),
|
|
1195
|
-
node.states === undefined ? "leaf" : "nested",
|
|
1196
|
-
node.schema !== undefined
|
|
1197
|
-
)
|
|
1198
|
-
builder[key] = node.states === undefined || options.mode !== "full" || options.prefix !== ""
|
|
1199
|
-
? method
|
|
1200
|
-
: withInitial(method, path, node.schema !== undefined)
|
|
1201
|
-
}
|
|
1202
|
-
return builder
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
const makeParallelSnapshotBuilder = (
|
|
1206
|
-
states: Machine.StateTree,
|
|
1207
|
-
options: SnapshotBuilderOptions,
|
|
1208
|
-
regions: Readonly<Record<string, unknown>>
|
|
1209
|
-
): unknown => {
|
|
1210
|
-
const builder: Record<string, unknown> = {}
|
|
1211
|
-
Object.defineProperty(builder, SnapshotBuilderStateTypeId, {
|
|
1212
|
-
value: regions,
|
|
1213
|
-
enumerable: false
|
|
1214
|
-
})
|
|
1215
|
-
for (const key of Object.keys(states)) {
|
|
1216
|
-
const definition = states[key]!
|
|
1217
|
-
const pseudoType = (definition as { readonly type?: unknown }).type
|
|
1218
|
-
if (pseudoType === "history" || pseudoType === "choice") {
|
|
1219
|
-
continue
|
|
1220
|
-
}
|
|
1221
|
-
if (hasProperty(regions, key)) {
|
|
1222
|
-
continue
|
|
1223
|
-
}
|
|
1224
|
-
const path = options.prefix === "" ? key : `${options.prefix}.${key}`
|
|
1225
|
-
const node = Topology.getStateNodeDefinition(path, definition)
|
|
1226
|
-
const method = withFrom(
|
|
1227
|
-
(value: unknown, selector?: (builder: unknown) => unknown) => {
|
|
1228
|
-
const nextRegions: Record<string, unknown> = {}
|
|
1229
|
-
for (const regionKey of Object.keys(regions)) {
|
|
1230
|
-
nextRegions[regionKey] = regions[regionKey]
|
|
1231
|
-
}
|
|
1232
|
-
nextRegions[key] = makeSnapshotForNode(definition, key, value, selector, options)
|
|
1233
|
-
return makeParallelSnapshotBuilder(states, options, nextRegions)
|
|
1234
|
-
},
|
|
1235
|
-
node.states === undefined ? "leaf" : "nested",
|
|
1236
|
-
node.schema !== undefined
|
|
1237
|
-
)
|
|
1238
|
-
builder[key] = method
|
|
1239
|
-
}
|
|
1240
|
-
return builder
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
const getParallelSnapshotBuilderRegions = (
|
|
1244
|
-
path: string,
|
|
1245
|
-
states: Machine.StateTree,
|
|
1246
|
-
builder: unknown
|
|
1247
|
-
): Readonly<Record<string, unknown>> => {
|
|
1248
|
-
if (typeof builder !== "object" || builder === null || !hasProperty(builder, SnapshotBuilderStateTypeId)) {
|
|
1249
|
-
throw new Error(`Machine expected parallel state "${path}" builder callback to return a builder`)
|
|
1250
|
-
}
|
|
1251
|
-
const regions = (builder as { readonly [SnapshotBuilderStateTypeId]: Readonly<Record<string, unknown>> })[
|
|
1252
|
-
SnapshotBuilderStateTypeId
|
|
1253
|
-
]
|
|
1254
|
-
for (const key of Object.keys(states)) {
|
|
1255
|
-
const pseudoType = (states[key] as { readonly type?: unknown }).type
|
|
1256
|
-
if (pseudoType === "history" || pseudoType === "choice") {
|
|
1257
|
-
continue
|
|
1258
|
-
}
|
|
1259
|
-
if (!hasProperty(regions, key)) {
|
|
1260
|
-
throw new Error(`Machine expected parallel state "${path}" builder callback to provide region "${key}"`)
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
return regions
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
const makeSnapshotForNode = (
|
|
1267
|
-
definition: Machine.TaggedSchema | Machine.StateNodeConfig,
|
|
1268
|
-
key: string,
|
|
1269
|
-
value: unknown,
|
|
1270
|
-
selector: ((builder: unknown) => unknown) | undefined,
|
|
1271
|
-
options: SnapshotBuilderOptions
|
|
1272
|
-
): Record<string, unknown> => {
|
|
1273
|
-
const path = options.prefix === "" ? key : `${options.prefix}.${key}`
|
|
1274
|
-
const node = Topology.getStateNodeDefinition(path, definition)
|
|
1275
|
-
const snapshot: Record<string, unknown> = {
|
|
1276
|
-
path,
|
|
1277
|
-
value
|
|
1278
|
-
}
|
|
1279
|
-
if (node.states === undefined) {
|
|
1280
|
-
return snapshot
|
|
1281
|
-
}
|
|
1282
|
-
if (selector === undefined) {
|
|
1283
|
-
throw new Error(`Machine expected state "${path}" builder to provide active child states`)
|
|
1284
|
-
}
|
|
1285
|
-
if (node.type === "parallel") {
|
|
1286
|
-
const builder = makeParallelSnapshotBuilder(node.states, { ...options, prefix: path }, {})
|
|
1287
|
-
const selected = selector(builder)
|
|
1288
|
-
snapshot.states = getParallelSnapshotBuilderRegions(path, node.states, selected)
|
|
1289
|
-
return snapshot
|
|
1290
|
-
}
|
|
1291
|
-
const childStates = options.mode === "initial" && node.initial !== undefined
|
|
1292
|
-
? { [node.initial]: node.states[node.initial]! }
|
|
1293
|
-
: node.states
|
|
1294
|
-
const selected = selector(makeSnapshotBuilder(childStates, { ...options, prefix: path }))
|
|
1295
|
-
snapshot.state = selected
|
|
1296
|
-
return snapshot
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
const getTargetBuilderNode = (
|
|
1300
|
-
stateNodes: Machine.StateNodes,
|
|
1301
|
-
path: string
|
|
1302
|
-
): Machine.StateNode => {
|
|
1303
|
-
const node = stateNodes.byPath.get(path)
|
|
1304
|
-
if (node === undefined) {
|
|
1305
|
-
throw new Error(`Machine expected state path "${path}" to exist`)
|
|
1306
|
-
}
|
|
1307
|
-
return node
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
const getLocalTargetScope = (
|
|
1311
|
-
stateNodes: Machine.StateNodes,
|
|
1312
|
-
source: string
|
|
1313
|
-
): string | undefined => {
|
|
1314
|
-
let current: string | undefined = source
|
|
1315
|
-
while (current !== undefined) {
|
|
1316
|
-
const node = stateNodes.byPath.get(current)
|
|
1317
|
-
if (node === undefined) {
|
|
1318
|
-
return undefined
|
|
1319
|
-
}
|
|
1320
|
-
if (node.type === "compound") {
|
|
1321
|
-
return node.path
|
|
1322
|
-
}
|
|
1323
|
-
current = node.parent
|
|
1324
|
-
}
|
|
1325
|
-
return undefined
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
const hasTargetValues = (
|
|
1329
|
-
values: Readonly<Record<string, unknown>> | undefined
|
|
1330
|
-
): values is Readonly<Record<string, unknown>> => values !== undefined && Object.keys(values).length > 0
|
|
1331
|
-
|
|
1332
|
-
const makeTargetWithValues = (
|
|
1333
|
-
path: string,
|
|
1334
|
-
value: unknown,
|
|
1335
|
-
values: Readonly<Record<string, unknown>> | undefined
|
|
1336
|
-
): Machine.Target<any, any> =>
|
|
1337
|
-
hasTargetValues(values)
|
|
1338
|
-
? Topology.makeTarget(path as any, value as any, { values: values as any })
|
|
1339
|
-
: Topology.makeTarget(path as any, value as any)
|
|
1340
|
-
|
|
1341
|
-
const getTargetBuilderDefinition = (
|
|
1342
|
-
states: Machine.StateTree,
|
|
1343
|
-
targetPath: string
|
|
1344
|
-
): Machine.TaggedSchema | Machine.StateNodeConfig => {
|
|
1345
|
-
let children = states
|
|
1346
|
-
let path = ""
|
|
1347
|
-
let definition: Machine.TaggedSchema | Machine.StateNodeConfig | undefined
|
|
1348
|
-
for (const key of targetPath.split(".")) {
|
|
1349
|
-
if (!hasProperty(children, key)) {
|
|
1350
|
-
throw new Error(`Machine expected state path "${targetPath}" to exist`)
|
|
1351
|
-
}
|
|
1352
|
-
definition = children[key]!
|
|
1353
|
-
path = path === "" ? key : `${path}.${key}`
|
|
1354
|
-
const node = Topology.getStateNodeDefinition(path, definition)
|
|
1355
|
-
children = node.states ?? {}
|
|
1356
|
-
}
|
|
1357
|
-
return definition!
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
const makeParallelTarget = (
|
|
1361
|
-
states: Machine.StateTree,
|
|
1362
|
-
node: Machine.StateNode,
|
|
1363
|
-
value: unknown,
|
|
1364
|
-
selector: ((builder: unknown) => unknown) | undefined,
|
|
1365
|
-
values: Readonly<Record<string, unknown>> | undefined
|
|
1366
|
-
): Machine.Target<any, any> => {
|
|
1367
|
-
if (selector === undefined) {
|
|
1368
|
-
throw new Error(`Machine expected parallel target "${node.path}" builder to provide every active region`)
|
|
1369
|
-
}
|
|
1370
|
-
const snapshot = makeSnapshotForNode(
|
|
1371
|
-
getTargetBuilderDefinition(states, node.path),
|
|
1372
|
-
node.key,
|
|
1373
|
-
value,
|
|
1374
|
-
selector,
|
|
1375
|
-
{ mode: "full", prefix: node.parent ?? "" }
|
|
1376
|
-
)
|
|
1377
|
-
return Topology.makeTarget(node.path as any, value as any, {
|
|
1378
|
-
snapshot: snapshot as any,
|
|
1379
|
-
values: values as any
|
|
1380
|
-
})
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
const extendTargetValues = (
|
|
1384
|
-
values: Readonly<Record<string, unknown>> | undefined,
|
|
1385
|
-
path: string,
|
|
1386
|
-
value: unknown
|
|
1387
|
-
): Readonly<Record<string, unknown>> => {
|
|
1388
|
-
const next: Record<string, unknown> = {}
|
|
1389
|
-
if (values !== undefined) {
|
|
1390
|
-
for (const key of Object.keys(values)) {
|
|
1391
|
-
next[key] = values[key]
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
next[path] = value
|
|
1395
|
-
return next
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
const makeLocalTargetChildBuilder = (
|
|
1399
|
-
states: Machine.StateTree,
|
|
1400
|
-
stateNodes: Machine.StateNodes,
|
|
1401
|
-
parentPath: string,
|
|
1402
|
-
values: Readonly<Record<string, unknown>> | undefined,
|
|
1403
|
-
source: string
|
|
1404
|
-
): unknown => {
|
|
1405
|
-
const parent = getTargetBuilderNode(stateNodes, parentPath)
|
|
1406
|
-
const builder: Record<string, unknown> = {}
|
|
1407
|
-
for (
|
|
1408
|
-
const childPath of Array.from(stateNodes.byPath.values())
|
|
1409
|
-
.filter((node) => node.parent === parent.path && node.type !== "history")
|
|
1410
|
-
.map((node) => node.path)
|
|
1411
|
-
) {
|
|
1412
|
-
const child = getTargetBuilderNode(stateNodes, childPath)
|
|
1413
|
-
if (child.type === "choice") {
|
|
1414
|
-
builder[child.key] = () => Topology.makeChoiceTarget(child.path, parent.path, values)
|
|
1415
|
-
continue
|
|
1416
|
-
}
|
|
1417
|
-
const method = withFrom(
|
|
1418
|
-
(value: unknown, selector?: (builder: unknown) => unknown) => {
|
|
1419
|
-
if (child.type === "atomic" || child.type === "final") {
|
|
1420
|
-
return makeTargetWithValues(child.path, value, values)
|
|
1421
|
-
}
|
|
1422
|
-
if (child.type === "parallel") {
|
|
1423
|
-
if (source !== child.path && !source.startsWith(`${child.path}.`)) {
|
|
1424
|
-
return makeParallelTarget(states, child, value, selector, values)
|
|
1425
|
-
}
|
|
1426
|
-
if (selector === undefined) {
|
|
1427
|
-
throw new Error(`Machine expected target "${child.path}" builder to provide an active child state`)
|
|
1428
|
-
}
|
|
1429
|
-
return selector(makeLocalTargetChildBuilder(
|
|
1430
|
-
states,
|
|
1431
|
-
stateNodes,
|
|
1432
|
-
child.path,
|
|
1433
|
-
child.schema === undefined ? values : extendTargetValues(values, child.path, value),
|
|
1434
|
-
source
|
|
1435
|
-
))
|
|
1436
|
-
}
|
|
1437
|
-
if (selector === undefined) {
|
|
1438
|
-
throw new Error(`Machine expected target "${child.path}" builder to provide an active child state`)
|
|
1439
|
-
}
|
|
1440
|
-
return selector(makeLocalTargetChildBuilder(
|
|
1441
|
-
states,
|
|
1442
|
-
stateNodes,
|
|
1443
|
-
child.path,
|
|
1444
|
-
child.schema === undefined ? values : extendTargetValues(values, child.path, value),
|
|
1445
|
-
source
|
|
1446
|
-
))
|
|
1447
|
-
},
|
|
1448
|
-
child.type === "atomic" || child.type === "final" ? "leaf" : "nested",
|
|
1449
|
-
child.schema !== undefined
|
|
1450
|
-
)
|
|
1451
|
-
builder[child.key] = child.type === "atomic" || child.type === "final"
|
|
1452
|
-
? method
|
|
1453
|
-
: withInitial(method, child.path, child.schema !== undefined, values)
|
|
1454
|
-
}
|
|
1455
|
-
return builder
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
const makeLocalTargetBuilder = (
|
|
1459
|
-
states: Machine.StateTree,
|
|
1460
|
-
stateNodes: Machine.StateNodes,
|
|
1461
|
-
source: string
|
|
1462
|
-
): unknown => {
|
|
1463
|
-
const scope = getLocalTargetScope(stateNodes, source)
|
|
1464
|
-
if (scope === undefined) {
|
|
1465
|
-
return {}
|
|
1466
|
-
}
|
|
1467
|
-
const builder = makeLocalTargetChildBuilder(states, stateNodes, scope, undefined, source) as Record<string, unknown>
|
|
1468
|
-
const scopeNode = getTargetBuilderNode(stateNodes, scope)
|
|
1469
|
-
if (scopeNode.schema !== undefined) {
|
|
1470
|
-
builder.with = withFrom(
|
|
1471
|
-
(value: unknown, selector?: (builder: unknown) => unknown) => {
|
|
1472
|
-
if (selector === undefined) {
|
|
1473
|
-
throw new Error(`Machine expected target "${scope}" builder to provide an active child state`)
|
|
1474
|
-
}
|
|
1475
|
-
return selector(makeLocalTargetChildBuilder(states, stateNodes, scope, { [scope]: value }, source))
|
|
1476
|
-
},
|
|
1477
|
-
"nested",
|
|
1478
|
-
true
|
|
1479
|
-
)
|
|
1480
|
-
}
|
|
1481
|
-
return builder
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
const addBranchTargetChildren = (
|
|
1485
|
-
builder: Record<string, unknown>,
|
|
1486
|
-
states: Machine.StateTree,
|
|
1487
|
-
stateNodes: Machine.StateNodes,
|
|
1488
|
-
parentPath: string,
|
|
1489
|
-
values: Readonly<Record<string, unknown>> | undefined,
|
|
1490
|
-
source: string
|
|
1491
|
-
): void => {
|
|
1492
|
-
const parent = getTargetBuilderNode(stateNodes, parentPath)
|
|
1493
|
-
for (
|
|
1494
|
-
const childPath of Array.from(stateNodes.byPath.values())
|
|
1495
|
-
.filter((node) => node.parent === parent.path && node.type !== "history")
|
|
1496
|
-
.map((node) => node.path)
|
|
1497
|
-
) {
|
|
1498
|
-
const child = getTargetBuilderNode(stateNodes, childPath)
|
|
1499
|
-
if (child.type === "choice") {
|
|
1500
|
-
builder[child.key] = () => Topology.makeChoiceTarget(child.path, parent.path, values)
|
|
1501
|
-
continue
|
|
1502
|
-
}
|
|
1503
|
-
builder[child.key] = makeBranchTargetNodeBuilder(states, stateNodes, child.path, values, source)
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
const makeBranchTargetNodeBuilder = (
|
|
1508
|
-
states: Machine.StateTree,
|
|
1509
|
-
stateNodes: Machine.StateNodes,
|
|
1510
|
-
path: string,
|
|
1511
|
-
values: Readonly<Record<string, unknown>> | undefined,
|
|
1512
|
-
source: string
|
|
1513
|
-
): unknown => {
|
|
1514
|
-
const node = getTargetBuilderNode(stateNodes, path)
|
|
1515
|
-
if (node.type === "atomic" || node.type === "final") {
|
|
1516
|
-
return withFrom(
|
|
1517
|
-
(value: unknown) => makeTargetWithValues(node.path, value, values),
|
|
1518
|
-
"leaf",
|
|
1519
|
-
node.schema !== undefined
|
|
1520
|
-
)
|
|
1521
|
-
}
|
|
1522
|
-
const builder = withFrom(
|
|
1523
|
-
(value: unknown, selector?: (builder: unknown) => unknown) => {
|
|
1524
|
-
if (node.type === "parallel") {
|
|
1525
|
-
if (source !== node.path && !source.startsWith(`${node.path}.`)) {
|
|
1526
|
-
return makeParallelTarget(states, node, value, selector, values)
|
|
1527
|
-
}
|
|
1528
|
-
if (selector === undefined) {
|
|
1529
|
-
throw new Error(`Machine expected target "${node.path}" builder to provide an active child state`)
|
|
1530
|
-
}
|
|
1531
|
-
const nextBuilder: Record<string, unknown> = {}
|
|
1532
|
-
addBranchTargetChildren(
|
|
1533
|
-
nextBuilder,
|
|
1534
|
-
states,
|
|
1535
|
-
stateNodes,
|
|
1536
|
-
node.path,
|
|
1537
|
-
node.schema === undefined ? values : extendTargetValues(values, node.path, value),
|
|
1538
|
-
source
|
|
1539
|
-
)
|
|
1540
|
-
return selector(nextBuilder)
|
|
1541
|
-
}
|
|
1542
|
-
if (selector === undefined) {
|
|
1543
|
-
throw new Error(`Machine expected target "${node.path}" builder to provide an active child state`)
|
|
1544
|
-
}
|
|
1545
|
-
const nextBuilder: Record<string, unknown> = {}
|
|
1546
|
-
addBranchTargetChildren(
|
|
1547
|
-
nextBuilder,
|
|
1548
|
-
states,
|
|
1549
|
-
stateNodes,
|
|
1550
|
-
node.path,
|
|
1551
|
-
node.schema === undefined ? values : extendTargetValues(values, node.path, value),
|
|
1552
|
-
source
|
|
1553
|
-
)
|
|
1554
|
-
return selector(nextBuilder)
|
|
1555
|
-
},
|
|
1556
|
-
"nested",
|
|
1557
|
-
node.schema !== undefined
|
|
1558
|
-
) as unknown as Record<string, unknown>
|
|
1559
|
-
withInitial(builder, node.path, node.schema !== undefined, values)
|
|
1560
|
-
if (node.type !== "parallel" || source === node.path || source.startsWith(`${node.path}.`)) {
|
|
1561
|
-
addBranchTargetChildren(builder, states, stateNodes, node.path, values, source)
|
|
1562
|
-
}
|
|
1563
|
-
return builder
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
const makeBranchTargetBuilder = (
|
|
1567
|
-
states: Machine.StateTree,
|
|
1568
|
-
stateNodes: Machine.StateNodes,
|
|
1569
|
-
source: string
|
|
1570
|
-
): unknown => {
|
|
1571
|
-
const rootPath = source.split(".")[0]!
|
|
1572
|
-
const root = getTargetBuilderNode(stateNodes, rootPath)
|
|
1573
|
-
return {
|
|
1574
|
-
[root.key]: makeBranchTargetNodeBuilder(states, stateNodes, root.path, undefined, source)
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
const makeHistoryTargetBuilder = (
|
|
1579
|
-
states: Machine.StateTree,
|
|
1580
|
-
prefix: string
|
|
1581
|
-
): unknown => {
|
|
1582
|
-
const builder: Record<string, unknown> = {}
|
|
1583
|
-
for (const key of Object.keys(states)) {
|
|
1584
|
-
const path = prefix === "" ? key : `${prefix}.${key}`
|
|
1585
|
-
const definition = Topology.getStateNodeDefinition(path, states[key]!)
|
|
1586
|
-
if (definition.type === "history") {
|
|
1587
|
-
const parent = getParentPathRuntime(path)
|
|
1588
|
-
builder[key] = () => Topology.makeHistoryTarget(path, parent)
|
|
1589
|
-
continue
|
|
1590
|
-
}
|
|
1591
|
-
if (definition.states !== undefined) {
|
|
1592
|
-
builder[key] = makeHistoryTargetBuilder(definition.states, path)
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
return builder
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
const getParentPathRuntime = (path: string): string => {
|
|
1599
|
-
const separator = path.lastIndexOf(".")
|
|
1600
|
-
if (separator < 0) {
|
|
1601
|
-
throw new Error(`Machine expected history state "${path}" to have an active parent`)
|
|
1602
|
-
}
|
|
1603
|
-
return path.slice(0, separator)
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
const makeTargetBuilder = <const States extends Machine.StateSchemas>(
|
|
1607
|
-
states: States,
|
|
1608
|
-
stateNodes: Machine.StateNodes
|
|
1609
|
-
) => {
|
|
1610
|
-
const full = makeSnapshotBuilder(states, { mode: "full", prefix: "" }) as Machine.FullTargetBuilder<States>
|
|
1611
|
-
const history = makeHistoryTargetBuilder(states, "") as Machine.HistoryTargetBuilder<States>
|
|
1612
|
-
return <Source extends Machine.StateNodeIdentifier<States>>(source: Source): Machine.TargetBuilder<States, Source> =>
|
|
1613
|
-
({
|
|
1614
|
-
none: Topology.makeNoTarget,
|
|
1615
|
-
local: makeLocalTargetBuilder(states, stateNodes, source),
|
|
1616
|
-
branch: makeBranchTargetBuilder(states, stateNodes, source),
|
|
1617
|
-
full,
|
|
1618
|
-
history
|
|
1619
|
-
}) as Machine.TargetBuilder<States, Source>
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
const makeInitialSelector = (stateNodes: Machine.StateNodes): unknown => {
|
|
1623
|
-
const selector: Record<string, unknown> = {}
|
|
1624
|
-
for (const node of stateNodes.byPath.values()) {
|
|
1625
|
-
if (node.parent === undefined && node.type !== "history" && node.type !== "choice") {
|
|
1626
|
-
selector[node.key] = node.type === "atomic" || node.type === "final"
|
|
1627
|
-
? makeSelectionMethod("state", node.path, "initial")
|
|
1628
|
-
: Object.freeze({ initial: makeSelectionValue("initial", node.path, "initial") })
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
return Object.freeze(selector)
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
1172
|
const getInitialSelectionBuilder = (
|
|
1635
1173
|
initialBuilder: Record<string, any>,
|
|
1636
1174
|
selection: Topology.TargetSelection
|
|
@@ -1648,17 +1186,18 @@ const getInitialSelectionBuilder = (
|
|
|
1648
1186
|
|
|
1649
1187
|
const captureInitialBranch = (
|
|
1650
1188
|
definition: unknown,
|
|
1651
|
-
|
|
1652
|
-
|
|
1189
|
+
initialBuilder: Record<string, any>,
|
|
1190
|
+
configuration: boolean
|
|
1653
1191
|
): {
|
|
1654
1192
|
readonly selection: Topology.TargetSelection
|
|
1655
1193
|
readonly resolve?: (context: any) => unknown
|
|
1656
1194
|
readonly builder: Record<string, any>
|
|
1657
1195
|
} => {
|
|
1658
|
-
if (typeof definition !== "function") {
|
|
1196
|
+
if (definition !== undefined && typeof definition !== "function") {
|
|
1659
1197
|
throw new Error("Machine initial definition must be a target-first callback")
|
|
1660
1198
|
}
|
|
1661
|
-
const
|
|
1199
|
+
const selector = decorateInitialSelection(makeSelectionValue(configuration ? "state" : "initial", "", "initial"))
|
|
1200
|
+
const result = definition === undefined ? selector : definition(selector)
|
|
1662
1201
|
let selection: Topology.TargetSelection
|
|
1663
1202
|
let resolve: ((context: any) => unknown) | undefined
|
|
1664
1203
|
if (Topology.isTargetSelection(result)) {
|
|
@@ -1694,13 +1233,17 @@ const validateInitialSelection = (result: unknown, selection: Topology.TargetSel
|
|
|
1694
1233
|
const compileInitial = (
|
|
1695
1234
|
definition: unknown,
|
|
1696
1235
|
states: Machine.StateTree,
|
|
1697
|
-
stateNodes: Machine.StateNodes
|
|
1236
|
+
stateNodes: Machine.StateNodes,
|
|
1237
|
+
configuration = false
|
|
1698
1238
|
): {
|
|
1699
1239
|
readonly initial: (input?: unknown) => unknown
|
|
1700
1240
|
readonly definition: Machine.InitialDefinition
|
|
1701
1241
|
} => {
|
|
1702
|
-
const
|
|
1703
|
-
const
|
|
1242
|
+
const rootNode = getTargetBuilderNode(stateNodes, "")
|
|
1243
|
+
const initialBuilder = configuration ?
|
|
1244
|
+
makeSnapshotBuilder(states, { mode: "full", prefix: "" }) as Record<string, any>
|
|
1245
|
+
: { "": withFrom((value: unknown) => Topology.makeInitialTarget("", value), "leaf", rootNode.schema !== undefined) }
|
|
1246
|
+
const branch = captureInitialBranch(definition, initialBuilder, configuration)
|
|
1704
1247
|
return {
|
|
1705
1248
|
initial: (input?: unknown) => {
|
|
1706
1249
|
const result = branch.resolve === undefined
|
|
@@ -1716,62 +1259,35 @@ const compileInitial = (
|
|
|
1716
1259
|
}
|
|
1717
1260
|
}
|
|
1718
1261
|
|
|
1719
|
-
export const state
|
|
1720
|
-
StateDefinition.
|
|
1721
|
-
|
|
1722
|
-
})
|
|
1262
|
+
export const state = (node: unknown): State<Machine.StateNodeConfig> => {
|
|
1263
|
+
const captured = StateDefinition.captureRoot(node) as Machine.StateNodeConfig
|
|
1264
|
+
const access = makeStateHelpers()
|
|
1265
|
+
return Object.freeze({ ...access, "~effect/Machine/State": "~effect/Machine/State", node: captured })
|
|
1266
|
+
}
|
|
1723
1267
|
|
|
1724
|
-
|
|
1725
|
-
states: States
|
|
1726
|
-
): Machine.DefinedStates<States> => {
|
|
1727
|
-
StateDefinition.validateStateDefinitions(states, "Machine.states")
|
|
1728
|
-
const captured = StateDefinition.captureStateDefinitions(states)
|
|
1268
|
+
const makeStateHelpers = (): Machine.StateAccessors<{ readonly "": Machine.StateNodeConfig }> => {
|
|
1729
1269
|
return {
|
|
1730
|
-
|
|
1731
|
-
path: ((path: string) => path) as Machine.DefinedStates<States>["path"],
|
|
1270
|
+
path: ((path: string) => path) as Machine.StateAccessors<{ readonly "": Machine.StateNodeConfig }>["path"],
|
|
1732
1271
|
get:
|
|
1733
1272
|
((snapshot: Machine.AtomicSnapshot<string, unknown>, path: string) =>
|
|
1734
1273
|
Topology.getSnapshotByPath(snapshot, path).pipe(
|
|
1735
1274
|
Option.map((snapshot) => snapshot.value)
|
|
1736
|
-
)) as Machine.
|
|
1275
|
+
)) as Machine.StateAccessors<{ readonly "": Machine.StateNodeConfig }>["get"],
|
|
1737
1276
|
getWithParents: ((snapshot, path) => {
|
|
1738
1277
|
const parents: Record<string, unknown> = {}
|
|
1739
1278
|
return Topology.getSnapshotByPath(snapshot, path, parents).pipe(
|
|
1740
1279
|
Option.map((snapshot) => ({ value: snapshot.value, parents }))
|
|
1741
1280
|
)
|
|
1742
|
-
}) as Machine.
|
|
1743
|
-
getSnapshot: Topology.getSnapshotByPath as unknown as Machine.
|
|
1281
|
+
}) as Machine.StateAccessors<{ readonly "": Machine.StateNodeConfig }>["getWithParents"],
|
|
1282
|
+
getSnapshot: Topology.getSnapshotByPath as unknown as Machine.StateAccessors<
|
|
1283
|
+
{ readonly "": Machine.StateNodeConfig }
|
|
1284
|
+
>["getSnapshot"],
|
|
1744
1285
|
matches:
|
|
1745
1286
|
((snapshot: Machine.AtomicSnapshot<string, unknown>, path: string) =>
|
|
1746
|
-
Option.isSome(Topology.getSnapshotByPath(snapshot, path))) as Machine.
|
|
1287
|
+
Option.isSome(Topology.getSnapshotByPath(snapshot, path))) as Machine.StateAccessors<
|
|
1288
|
+
{ readonly "": Machine.StateNodeConfig }
|
|
1289
|
+
>["matches"]
|
|
1747
1290
|
}
|
|
1748
|
-
}) as StatesConstructor
|
|
1749
|
-
|
|
1750
|
-
type MakeConfig<
|
|
1751
|
-
States extends Machine.StateSchemas,
|
|
1752
|
-
InputEvents extends ReadonlyArray<Machine.TaggedSchema>,
|
|
1753
|
-
Emits extends ReadonlyArray<Machine.TaggedSchema>,
|
|
1754
|
-
Input extends Schema.Top,
|
|
1755
|
-
InitialE,
|
|
1756
|
-
InitialR,
|
|
1757
|
-
InternalEvents extends ReadonlyArray<Machine.TaggedSchema>,
|
|
1758
|
-
ParentDeclaration extends Parent.Any | undefined
|
|
1759
|
-
> = {
|
|
1760
|
-
readonly id?: string
|
|
1761
|
-
readonly states: States & DefineStateTreeInput<NoInfer<States>>
|
|
1762
|
-
readonly events:
|
|
1763
|
-
& Machine.EventProtocol<"public", InputEvents>
|
|
1764
|
-
& ValidateInputEventProtocol<NoInfer<InputEvents>>
|
|
1765
|
-
readonly internalEvents?:
|
|
1766
|
-
& Machine.EventProtocol<"internal", InternalEvents>
|
|
1767
|
-
& ValidateInternalEventProtocol<
|
|
1768
|
-
NoInfer<InputEvents>,
|
|
1769
|
-
NoInfer<InternalEvents>
|
|
1770
|
-
>
|
|
1771
|
-
readonly emittedEvents?: Machine.EventProtocol<"emitted", Emits>
|
|
1772
|
-
readonly parent?: ParentDeclaration
|
|
1773
|
-
readonly input?: Input
|
|
1774
|
-
readonly initial: unknown
|
|
1775
1291
|
}
|
|
1776
1292
|
|
|
1777
1293
|
type MakeResult<
|
|
@@ -1796,40 +1312,7 @@ type MakeResult<
|
|
|
1796
1312
|
Machine.ParentEventsOf<ParentDeclaration>
|
|
1797
1313
|
>
|
|
1798
1314
|
|
|
1799
|
-
|
|
1800
|
-
<
|
|
1801
|
-
const States extends Machine.StateSchemas,
|
|
1802
|
-
const InputEvents extends ReadonlyArray<Machine.TaggedSchema>,
|
|
1803
|
-
const Emits extends ReadonlyArray<Machine.TaggedSchema> = readonly [],
|
|
1804
|
-
const Input extends Schema.Top = typeof Schema.Void,
|
|
1805
|
-
InitialE = never,
|
|
1806
|
-
InitialR = never,
|
|
1807
|
-
const InternalEvents extends ReadonlyArray<Machine.TaggedSchema> = readonly [],
|
|
1808
|
-
const ParentDeclaration extends Parent.Any | undefined = undefined
|
|
1809
|
-
>(
|
|
1810
|
-
config: MakeConfig<States, InputEvents, Emits, Input, InitialE, InitialR, InternalEvents, ParentDeclaration>,
|
|
1811
|
-
..._validation: ValidateDefinedStates<NoInfer<States>>
|
|
1812
|
-
): MakeResult<States, InputEvents, Emits, Input, InitialE, InitialR, InternalEvents, ParentDeclaration>
|
|
1813
|
-
<
|
|
1814
|
-
const States extends Machine.StateSchemas,
|
|
1815
|
-
const InputEvents extends ReadonlyArray<Machine.TaggedSchema>,
|
|
1816
|
-
const Emits extends ReadonlyArray<Machine.TaggedSchema> = readonly [],
|
|
1817
|
-
const Input extends Schema.Top = typeof Schema.Void,
|
|
1818
|
-
InitialE = never,
|
|
1819
|
-
InitialR = never,
|
|
1820
|
-
const InternalEvents extends ReadonlyArray<Machine.TaggedSchema> = readonly [],
|
|
1821
|
-
const ParentDeclaration extends Parent.Any | undefined = undefined
|
|
1822
|
-
>(
|
|
1823
|
-
config:
|
|
1824
|
-
& Omit<
|
|
1825
|
-
MakeConfig<States, InputEvents, Emits, Input, InitialE, InitialR, InternalEvents, ParentDeclaration>,
|
|
1826
|
-
"states"
|
|
1827
|
-
>
|
|
1828
|
-
& { readonly states: InvalidDefinedStateTreeInput<States> }
|
|
1829
|
-
): never
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1832
|
-
export const make: Make = (<
|
|
1315
|
+
export const make = <
|
|
1833
1316
|
const States extends Machine.StateSchemas,
|
|
1834
1317
|
const InputEvents extends ReadonlyArray<Machine.TaggedSchema>,
|
|
1835
1318
|
const Emits extends ReadonlyArray<Machine.TaggedSchema> = readonly [],
|
|
@@ -1841,7 +1324,8 @@ export const make: Make = (<
|
|
|
1841
1324
|
>(
|
|
1842
1325
|
config: {
|
|
1843
1326
|
readonly id?: string
|
|
1844
|
-
readonly
|
|
1327
|
+
readonly root: State<Machine.StateNodeConfig>
|
|
1328
|
+
readonly initialConfiguration?: unknown
|
|
1845
1329
|
readonly events: Machine.EventProtocol<"public", InputEvents>
|
|
1846
1330
|
readonly internalEvents?: Machine.EventProtocol<"internal", InternalEvents>
|
|
1847
1331
|
readonly emittedEvents?: Machine.EventProtocol<"emitted", Emits>
|
|
@@ -1850,25 +1334,31 @@ export const make: Make = (<
|
|
|
1850
1334
|
readonly initial: unknown
|
|
1851
1335
|
}
|
|
1852
1336
|
): MakeResult<States, InputEvents, Emits, Input, InitialE, InitialR, InternalEvents, ParentDeclaration> => {
|
|
1853
|
-
|
|
1337
|
+
const states = Object.freeze({ "": config.root.node })
|
|
1854
1338
|
const self = Object.create(Proto)
|
|
1855
|
-
self.states =
|
|
1339
|
+
self.states = states
|
|
1340
|
+
self.root = config.root
|
|
1856
1341
|
self.events = config.events
|
|
1857
1342
|
self.internalEvents = config.internalEvents ?? Protocol.makeEventProtocol("internal", [] as const)
|
|
1858
1343
|
self.emittedEvents = config.emittedEvents ?? Protocol.makeEventProtocol("emitted", [] as const)
|
|
1859
1344
|
self.parent = config.parent
|
|
1860
1345
|
self.input = config.input
|
|
1861
1346
|
self.id = config.id
|
|
1862
|
-
self.stateNodes = Topology.compileStateNodes(
|
|
1863
|
-
const compiledInitial = compileInitial(
|
|
1347
|
+
self.stateNodes = Topology.compileStateNodes(states)
|
|
1348
|
+
const compiledInitial = compileInitial(
|
|
1349
|
+
config.initialConfiguration ?? config.initial,
|
|
1350
|
+
states,
|
|
1351
|
+
self.stateNodes,
|
|
1352
|
+
config.initialConfiguration !== undefined
|
|
1353
|
+
)
|
|
1864
1354
|
self.initial = compiledInitial.initial
|
|
1865
1355
|
self.initialDefinition = compiledInitial.definition
|
|
1866
|
-
self.makeTargetBuilder = makeTargetBuilder(
|
|
1356
|
+
self.makeTargetBuilder = makeTargetBuilder(states, self.stateNodes)
|
|
1867
1357
|
self.handlers = Object.create(null)
|
|
1868
1358
|
self.handle = makeHandle(self)
|
|
1869
1359
|
Protocol.setProtocol(self)
|
|
1870
1360
|
return self
|
|
1871
|
-
}
|
|
1361
|
+
}
|
|
1872
1362
|
|
|
1873
1363
|
const flattenEventProtocolInputs = <Kind extends Machine.EventProtocolKind>(
|
|
1874
1364
|
kind: Kind,
|
|
@@ -1888,6 +1378,22 @@ export const events = <const Inputs extends ReadonlyArray<Machine.EventProtocolI
|
|
|
1888
1378
|
flattenEventProtocolInputs("public", inputs)
|
|
1889
1379
|
) as Machine.EventProtocol<"public", Machine.EventProtocolInputSchemasOf<"public", Inputs>>
|
|
1890
1380
|
|
|
1381
|
+
const eventFieldSchemas = (
|
|
1382
|
+
cases: Readonly<Record<string, Schema.Struct.Fields>>
|
|
1383
|
+
): ReadonlyArray<Machine.TaggedSchema> => {
|
|
1384
|
+
for (const [tag, fields] of Object.entries(cases)) {
|
|
1385
|
+
if (Object.hasOwn(fields, "_tag")) throw new Error(`Machine event "${tag}" fields cannot declare _tag`)
|
|
1386
|
+
}
|
|
1387
|
+
return Object.keys(cases).length === 0 ? [] : [Schema.TaggedUnion(cases)]
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
export const eventsFromFields = (cases: Readonly<Record<string, Schema.Struct.Fields>>) =>
|
|
1391
|
+
Protocol.makeEventProtocol("public", eventFieldSchemas(cases))
|
|
1392
|
+
export const internalEventsFromFields = (cases: Readonly<Record<string, Schema.Struct.Fields>>) =>
|
|
1393
|
+
Protocol.makeEventProtocol("internal", eventFieldSchemas(cases))
|
|
1394
|
+
export const emittedEventsFromFields = (cases: Readonly<Record<string, Schema.Struct.Fields>>) =>
|
|
1395
|
+
Protocol.makeEventProtocol("emitted", eventFieldSchemas(cases))
|
|
1396
|
+
|
|
1891
1397
|
const makeParent = <
|
|
1892
1398
|
const Mode extends ParentMode,
|
|
1893
1399
|
const Events extends ReadonlyArray<Machine.TaggedSchema>
|
|
@@ -2038,7 +1544,7 @@ export const planInitial: <
|
|
|
2038
1544
|
readonly initialEntryPaths: ReadonlyArray<Machine.StateIdentifier<States>>
|
|
2039
1545
|
readonly state: Machine.Snapshot<States>
|
|
2040
1546
|
readonly commands: ReadonlyArray<Command>
|
|
2041
|
-
readonly emittedEvents: ReadonlyArray<Machine.
|
|
1547
|
+
readonly emittedEvents: ReadonlyArray<Machine.EmittedEventOf<Emits>>
|
|
2042
1548
|
readonly microsteps: ReadonlyArray<{
|
|
2043
1549
|
readonly next: Machine.Snapshot<States>
|
|
2044
1550
|
readonly event: Machine.EventOf<Events> | InitialEventModel
|
|
@@ -2051,7 +1557,7 @@ export const planInitial: <
|
|
|
2051
1557
|
>
|
|
2052
1558
|
readonly commands: ReadonlyArray<Command>
|
|
2053
1559
|
readonly raisedEvents: ReadonlyArray<Machine.EventOf<Events>>
|
|
2054
|
-
readonly emittedEvents: ReadonlyArray<Machine.
|
|
1560
|
+
readonly emittedEvents: ReadonlyArray<Machine.EmittedEventOf<Emits>>
|
|
2055
1561
|
readonly exitPaths: ReadonlyArray<string>
|
|
2056
1562
|
readonly entryPaths: ReadonlyArray<string>
|
|
2057
1563
|
readonly changed: boolean
|
|
@@ -2216,7 +1722,7 @@ export const plan: <
|
|
|
2216
1722
|
& {
|
|
2217
1723
|
readonly next: Machine.Snapshot<States>
|
|
2218
1724
|
readonly commands: ReadonlyArray<Command>
|
|
2219
|
-
readonly emittedEvents: ReadonlyArray<Machine.
|
|
1725
|
+
readonly emittedEvents: ReadonlyArray<Machine.EmittedEventOf<Emits>>
|
|
2220
1726
|
readonly microsteps: ReadonlyArray<{
|
|
2221
1727
|
readonly next: Machine.Snapshot<States>
|
|
2222
1728
|
readonly event: Machine.EventOf<Events> | InitialEventModel
|
|
@@ -2229,7 +1735,7 @@ export const plan: <
|
|
|
2229
1735
|
>
|
|
2230
1736
|
readonly commands: ReadonlyArray<Command>
|
|
2231
1737
|
readonly raisedEvents: ReadonlyArray<Machine.EventOf<Events>>
|
|
2232
|
-
readonly emittedEvents: ReadonlyArray<Machine.
|
|
1738
|
+
readonly emittedEvents: ReadonlyArray<Machine.EmittedEventOf<Emits>>
|
|
2233
1739
|
readonly exitPaths: ReadonlyArray<string>
|
|
2234
1740
|
readonly entryPaths: ReadonlyArray<string>
|
|
2235
1741
|
readonly changed: boolean
|
|
@@ -2450,7 +1956,7 @@ export const start: <
|
|
|
2450
1956
|
ExcludeCompatibleRuntime<
|
|
2451
1957
|
ExecutionServices<InitialR | R>,
|
|
2452
1958
|
Machine.EventOf<Events>,
|
|
2453
|
-
Machine.
|
|
1959
|
+
Machine.EmittedEventOf<Emits>
|
|
2454
1960
|
>
|
|
2455
1961
|
> = internalProcess.start as any
|
|
2456
1962
|
|
|
@@ -2503,6 +2009,6 @@ export const resume: <
|
|
|
2503
2009
|
ExcludeCompatibleRuntime<
|
|
2504
2010
|
ExecutionServices<R>,
|
|
2505
2011
|
Machine.EventOf<Events>,
|
|
2506
|
-
Machine.
|
|
2012
|
+
Machine.EmittedEventOf<Emits>
|
|
2507
2013
|
>
|
|
2508
2014
|
> = internalProcess.resume as any
|