xstate 6.0.0-alpha.47 → 6.0.0-alpha.49
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 +30 -1
- package/dist/{StateMachine-7046f677.cjs.js → StateMachine-0adb3a70.cjs.js} +15 -12
- package/dist/{StateMachine-70c06bdd.development.cjs.js → StateMachine-29450e6d.development.cjs.js} +15 -12
- package/dist/{StateMachine-74929087.esm.js → StateMachine-2af31c11.esm.js} +10 -7
- package/dist/{StateMachine-ee10f67e.development.esm.js → StateMachine-faf50c5c.development.esm.js} +10 -7
- package/dist/{createActor-915ea40c.esm.js → createActor-268165d4.esm.js} +79 -23
- package/dist/{createActor-ff132afa.development.esm.js → createActor-88709f74.development.esm.js} +79 -23
- package/dist/{createActor-6736cbbe.development.cjs.js → createActor-a1e0dffb.development.cjs.js} +78 -25
- package/dist/{createActor-bfe8b6bd.cjs.js → createActor-b4dd05ae.cjs.js} +78 -25
- package/dist/declarations/src/createMachineFromConfig.d.ts +5 -77
- package/dist/declarations/src/fsm/createFSMActor.d.ts +67 -0
- package/dist/declarations/src/fsm/index.d.ts +2 -0
- package/dist/declarations/src/fsm.d.ts +5 -4
- package/dist/declarations/src/scxml/index.d.ts +1 -0
- package/dist/declarations/src/scxml/runtime.d.ts +251 -0
- package/dist/declarations/src/scxml/scxml.d.ts +19 -0
- package/dist/declarations/src/types.d.ts +1 -0
- package/dist/{effectDescriptor-8be60443.esm.js → effectDescriptor-30c9a744.esm.js} +1 -1
- package/dist/{effectDescriptor-fbe67d5a.development.esm.js → effectDescriptor-39d22100.development.esm.js} +1 -1
- package/dist/{effectDescriptor-3c699328.development.cjs.js → effectDescriptor-7ff6802f.development.cjs.js} +1 -1
- package/dist/{effectDescriptor-a7e2d4d1.cjs.js → effectDescriptor-be348e50.cjs.js} +1 -1
- package/dist/fsm-7a2e9697.cjs.js +777 -0
- package/dist/fsm-b804b3e9.esm.js +775 -0
- package/dist/fsm-c1316948.development.cjs.js +777 -0
- package/dist/fsm-e18a7cb4.development.esm.js +775 -0
- package/dist/types-3c3455f7.esm.js +185 -0
- package/dist/types-adda3842.development.esm.js +185 -0
- package/dist/types-b3fea5bd.development.cjs.js +189 -0
- package/dist/types-fbabaeee.cjs.js +189 -0
- package/dist/validation-05f1d517.esm.js +8 -0
- package/dist/validation-4561b43c.cjs.js +10 -0
- package/dist/validation-e69470ad.development.esm.js +8 -0
- package/dist/validation-f2714a35.development.cjs.js +10 -0
- package/dist/xstate-actors.cjs.js +934 -9
- package/dist/xstate-actors.development.cjs.js +934 -9
- package/dist/xstate-actors.development.esm.js +932 -2
- package/dist/xstate-actors.esm.js +932 -2
- package/dist/xstate-durable.cjs.js +2 -2
- package/dist/xstate-durable.development.cjs.js +2 -2
- package/dist/xstate-durable.development.esm.js +2 -2
- package/dist/xstate-durable.esm.js +2 -2
- package/dist/xstate-fsm.cjs.d.mts +2 -0
- package/dist/xstate-fsm.cjs.d.ts +2 -0
- package/dist/xstate-fsm.cjs.js +409 -0
- package/dist/xstate-fsm.cjs.mjs +5 -0
- package/dist/xstate-fsm.development.cjs.js +409 -0
- package/dist/xstate-fsm.development.cjs.mjs +5 -0
- package/dist/xstate-fsm.development.esm.js +403 -0
- package/dist/xstate-fsm.esm.js +403 -0
- package/dist/xstate-fsm.umd.min.js +2 -0
- package/dist/xstate-fsm.umd.min.js.map +1 -0
- package/dist/xstate-graph.cjs.js +4 -3
- package/dist/xstate-graph.development.cjs.js +4 -3
- package/dist/xstate-graph.development.esm.js +4 -3
- package/dist/xstate-graph.esm.js +4 -3
- package/dist/xstate-graph.umd.min.js +1 -1
- package/dist/xstate-graph.umd.min.js.map +1 -1
- package/dist/xstate-scxml.cjs.d.mts +2 -0
- package/dist/xstate-scxml.cjs.d.ts +2 -0
- package/dist/xstate-scxml.cjs.js +2387 -0
- package/dist/xstate-scxml.cjs.mjs +3 -0
- package/dist/xstate-scxml.development.cjs.js +2387 -0
- package/dist/xstate-scxml.development.cjs.mjs +3 -0
- package/dist/xstate-scxml.development.esm.js +2383 -0
- package/dist/xstate-scxml.esm.js +2383 -0
- package/dist/xstate-scxml.umd.min.js +26 -0
- package/dist/xstate-scxml.umd.min.js.map +1 -0
- package/dist/xstate-validation.cjs.js +1 -1
- package/dist/xstate-validation.development.cjs.js +1 -1
- package/dist/xstate-validation.development.esm.js +1 -1
- package/dist/xstate-validation.esm.js +1 -1
- package/dist/xstate.cjs.js +143 -1412
- package/dist/xstate.development.cjs.js +143 -1412
- package/dist/xstate.development.esm.js +143 -1411
- package/dist/xstate.esm.js +143 -1411
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/fsm/package.json +8 -0
- package/package.json +37 -3
- package/scxml/package.json +8 -0
- package/dist/index-0f498ef2.development.cjs.js +0 -946
- package/dist/index-70d56425.development.esm.js +0 -937
- package/dist/index-b051c924.esm.js +0 -937
- package/dist/index-b3fe59bc.cjs.js +0 -946
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var dist_xstateActors = require('./
|
|
6
|
-
var createActor = require('./createActor-
|
|
7
|
-
var
|
|
8
|
-
var
|
|
5
|
+
var dist_xstateActors = require('./xstate-actors.development.cjs.js');
|
|
6
|
+
var createActor = require('./createActor-a1e0dffb.development.cjs.js');
|
|
7
|
+
var types$1 = require('./types-b3fea5bd.development.cjs.js');
|
|
8
|
+
var fsm = require('./fsm-c1316948.development.cjs.js');
|
|
9
|
+
var StateMachine = require('./StateMachine-29450e6d.development.cjs.js');
|
|
10
|
+
var effectDescriptor = require('./effectDescriptor-7ff6802f.development.cjs.js');
|
|
11
|
+
require('./validation-f2714a35.development.cjs.js');
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Asserts that the given event object is of the specified type or types. Throws
|
|
@@ -39,453 +42,11 @@ function assertEvent(event, type) {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
/**
|
|
43
|
-
* Creates a state machine (statechart) with the given configuration.
|
|
44
|
-
*
|
|
45
|
-
* The state machine represents the pure logic of a state machine actor.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
*
|
|
49
|
-
* ```ts
|
|
50
|
-
* import { createMachine } from 'xstate';
|
|
51
|
-
*
|
|
52
|
-
* const lightMachine = createMachine({
|
|
53
|
-
* id: 'light',
|
|
54
|
-
* initial: 'green',
|
|
55
|
-
* states: {
|
|
56
|
-
* green: {
|
|
57
|
-
* on: {
|
|
58
|
-
* TIMER: { target: 'yellow' }
|
|
59
|
-
* }
|
|
60
|
-
* },
|
|
61
|
-
* yellow: {
|
|
62
|
-
* on: {
|
|
63
|
-
* TIMER: { target: 'red' }
|
|
64
|
-
* }
|
|
65
|
-
* },
|
|
66
|
-
* red: {
|
|
67
|
-
* on: {
|
|
68
|
-
* TIMER: { target: 'green' }
|
|
69
|
-
* }
|
|
70
|
-
* }
|
|
71
|
-
* }
|
|
72
|
-
* });
|
|
73
|
-
*
|
|
74
|
-
* const lightActor = createActor(lightMachine);
|
|
75
|
-
* lightActor.start();
|
|
76
|
-
*
|
|
77
|
-
* lightActor.send({ type: 'TIMER' });
|
|
78
|
-
* ```
|
|
79
|
-
*
|
|
80
|
-
* @param config The state machine configuration.
|
|
81
|
-
* @param options DEPRECATED: use `setup({ ... })` or `machine.provide({ ... })`
|
|
82
|
-
* to provide machine sources instead.
|
|
83
|
-
*/
|
|
84
|
-
// Overload 1: With schemas.context — context type inferred from schema
|
|
85
|
-
|
|
86
|
-
// Overload 2: Without schemas.context — context type inferred from config.context
|
|
87
|
-
|
|
88
|
-
// Implementation
|
|
89
|
-
function createMachine(config) {
|
|
90
|
-
return new StateMachine.StateMachine(config);
|
|
91
|
-
}
|
|
92
|
-
function createStateConfig(config) {
|
|
93
|
-
return config;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const emptySources = {
|
|
97
|
-
actions: {},
|
|
98
|
-
actors: {},
|
|
99
|
-
guards: {},
|
|
100
|
-
delays: {}
|
|
101
|
-
};
|
|
102
|
-
const emptyExecutableActions = [];
|
|
103
|
-
const emptyRawActions = [];
|
|
104
|
-
const builtInActionSet = new Set(Object.values(createActor.builtInActions));
|
|
105
|
-
function toArray(value) {
|
|
106
|
-
return value === undefined ? [] : Array.isArray(value) ? value : [value];
|
|
107
|
-
}
|
|
108
|
-
function resolveContext(context, input) {
|
|
109
|
-
return typeof context === 'function' ? context({
|
|
110
|
-
input
|
|
111
|
-
}) : context ?? {};
|
|
112
|
-
}
|
|
113
|
-
function resolveTransitionContext(context, args) {
|
|
114
|
-
return typeof context === 'function' ? context(args) : context;
|
|
115
|
-
}
|
|
116
|
-
function resolveInput(input, context, event) {
|
|
117
|
-
return typeof input === 'function' ? input({
|
|
118
|
-
context,
|
|
119
|
-
event
|
|
120
|
-
}) : input;
|
|
121
|
-
}
|
|
122
|
-
function mergeContextPatch(context, patch) {
|
|
123
|
-
for (const key of Object.keys(patch)) {
|
|
124
|
-
if (!Object.prototype.hasOwnProperty.call(context, key) || !Object.is(context[key], patch[key])) {
|
|
125
|
-
return {
|
|
126
|
-
...context,
|
|
127
|
-
...patch
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return context;
|
|
132
|
-
}
|
|
133
|
-
function createSnapshot(value, context, input, machine, stateInput) {
|
|
134
|
-
return {
|
|
135
|
-
status: 'active',
|
|
136
|
-
output: undefined,
|
|
137
|
-
error: undefined,
|
|
138
|
-
value,
|
|
139
|
-
context,
|
|
140
|
-
input,
|
|
141
|
-
children: {},
|
|
142
|
-
timers: {},
|
|
143
|
-
_nextTimerId: 0,
|
|
144
|
-
_stateInput: stateInput,
|
|
145
|
-
machine
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
function cloneSnapshot(snapshot, value, context, stateInput) {
|
|
149
|
-
return {
|
|
150
|
-
status: snapshot.status,
|
|
151
|
-
output: snapshot.output,
|
|
152
|
-
error: snapshot.error,
|
|
153
|
-
value,
|
|
154
|
-
context,
|
|
155
|
-
input: snapshot.input,
|
|
156
|
-
children: snapshot.children,
|
|
157
|
-
timers: snapshot.timers,
|
|
158
|
-
_nextTimerId: snapshot._nextTimerId,
|
|
159
|
-
// Carried across state changes: dropping these would let a later spawn
|
|
160
|
-
// reuse the id of a still-running child.
|
|
161
|
-
_nextActorIds: snapshot._nextActorIds,
|
|
162
|
-
_stateInput: stateInput,
|
|
163
|
-
machine: snapshot.machine
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function stopSnapshot(snapshot) {
|
|
167
|
-
return {
|
|
168
|
-
status: 'stopped',
|
|
169
|
-
output: undefined,
|
|
170
|
-
error: undefined,
|
|
171
|
-
value: snapshot.value,
|
|
172
|
-
context: snapshot.context,
|
|
173
|
-
input: undefined,
|
|
174
|
-
children: snapshot.children,
|
|
175
|
-
timers: snapshot.timers,
|
|
176
|
-
_nextTimerId: snapshot._nextTimerId,
|
|
177
|
-
_nextActorIds: snapshot._nextActorIds,
|
|
178
|
-
_stateInput: snapshot._stateInput,
|
|
179
|
-
machine: snapshot.machine
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
function assertNoStringTransitions(config) {
|
|
183
|
-
for (const [stateKey, stateConfig] of Object.entries(config.states)) {
|
|
184
|
-
for (const [eventType, transitionConfig] of Object.entries(stateConfig.on ?? {})) {
|
|
185
|
-
for (const transition of toArray(transitionConfig)) {
|
|
186
|
-
if (typeof transition === 'string') {
|
|
187
|
-
const target = transition;
|
|
188
|
-
throw new Error(`Invalid transition for "${stateKey}.${eventType}": use { target: "${target}" } instead of a string target.`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function resolveSimpleEnqueuedActions(rawActions) {
|
|
195
|
-
const executableActions = [];
|
|
196
|
-
for (const action of rawActions) {
|
|
197
|
-
if (!action || typeof action !== 'object' || !('action' in action) || typeof action.action !== 'function' || builtInActionSet.has(action.action) || '_special' in action.action) {
|
|
198
|
-
return undefined;
|
|
199
|
-
}
|
|
200
|
-
executableActions.push({
|
|
201
|
-
kind: 'action',
|
|
202
|
-
type: action.action.name || '(anonymous)',
|
|
203
|
-
params: undefined,
|
|
204
|
-
args: action.args,
|
|
205
|
-
action: action.action,
|
|
206
|
-
exec() {
|
|
207
|
-
return this.action?.(...this.args);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
return executableActions;
|
|
212
|
-
}
|
|
213
|
-
function createFSM(config) {
|
|
214
|
-
const machine = {
|
|
215
|
-
id: config.id ?? '(fsm)',
|
|
216
|
-
sources: emptySources
|
|
217
|
-
};
|
|
218
|
-
assertNoStringTransitions(config);
|
|
219
|
-
const runActions = (snapshot, event, actorScope, rawActions) => {
|
|
220
|
-
if (!rawActions?.length) {
|
|
221
|
-
return [snapshot, emptyExecutableActions];
|
|
222
|
-
}
|
|
223
|
-
const simpleExecutableActions = resolveSimpleEnqueuedActions(rawActions);
|
|
224
|
-
if (simpleExecutableActions) {
|
|
225
|
-
return [snapshot, simpleExecutableActions];
|
|
226
|
-
}
|
|
227
|
-
return createActor.resolveActionsWithContext(snapshot, event, actorScope, rawActions);
|
|
228
|
-
};
|
|
229
|
-
const runStateActions = (snapshot, event, actorScope, actionsConfig, stateInput, internalQueue) => {
|
|
230
|
-
if (!actionsConfig) {
|
|
231
|
-
return [snapshot, emptyExecutableActions];
|
|
232
|
-
}
|
|
233
|
-
const actions = [];
|
|
234
|
-
const enq = createActor.createTransitionEnqueue(actorScope, actions, internalQueue, true);
|
|
235
|
-
let context;
|
|
236
|
-
const actionCount = Array.isArray(actionsConfig) ? actionsConfig.length : 1;
|
|
237
|
-
for (let i = 0; i < actionCount; i++) {
|
|
238
|
-
const action = Array.isArray(actionsConfig) ? actionsConfig[i] : actionsConfig;
|
|
239
|
-
const result = action(createActor.withActorScope({
|
|
240
|
-
context: context ?? snapshot.context,
|
|
241
|
-
event: event,
|
|
242
|
-
input: stateInput,
|
|
243
|
-
value: snapshot.value,
|
|
244
|
-
children: snapshot.children
|
|
245
|
-
}, actorScope), enq);
|
|
246
|
-
if (result?.context !== undefined) {
|
|
247
|
-
const currentContext = context ?? snapshot.context;
|
|
248
|
-
const nextContext = mergeContextPatch(currentContext, result.context);
|
|
249
|
-
if (nextContext !== currentContext) {
|
|
250
|
-
context = nextContext;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const nextSnapshot = context !== undefined ? cloneSnapshot(snapshot, snapshot.value, context, snapshot._stateInput) : snapshot;
|
|
255
|
-
return runActions(nextSnapshot, event, actorScope, actions);
|
|
256
|
-
};
|
|
257
|
-
const selectTransition = (snapshot, event, actorScope, internalQueue) => {
|
|
258
|
-
const state = config.states[snapshot.value];
|
|
259
|
-
const transitionsConfig = state?.on?.[event.type];
|
|
260
|
-
if (!transitionsConfig) {
|
|
261
|
-
return undefined;
|
|
262
|
-
}
|
|
263
|
-
const transitionCount = Array.isArray(transitionsConfig) ? transitionsConfig.length : 1;
|
|
264
|
-
for (let i = 0; i < transitionCount; i++) {
|
|
265
|
-
const transition = Array.isArray(transitionsConfig) ? transitionsConfig[i] : transitionsConfig;
|
|
266
|
-
const args = createActor.withActorScope({
|
|
267
|
-
context: snapshot.context,
|
|
268
|
-
event,
|
|
269
|
-
input: snapshot.input,
|
|
270
|
-
value: snapshot.value,
|
|
271
|
-
children: snapshot.children
|
|
272
|
-
}, actorScope);
|
|
273
|
-
if (typeof transition === 'function') {
|
|
274
|
-
const actions = [];
|
|
275
|
-
const enq = createActor.createTransitionEnqueue(actorScope, actions, internalQueue, true);
|
|
276
|
-
const result = transition(args, enq);
|
|
277
|
-
if (!result) {
|
|
278
|
-
if (actions.length) {
|
|
279
|
-
return {
|
|
280
|
-
actions
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
return {
|
|
286
|
-
target: result.target,
|
|
287
|
-
context: result.context,
|
|
288
|
-
input: result.input,
|
|
289
|
-
actions
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
if ('guard' in transition && transition.guard && !transition.guard(args)) {
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
return {
|
|
296
|
-
target: transition.target,
|
|
297
|
-
context: resolveTransitionContext(transition.context, args),
|
|
298
|
-
input: transition.input,
|
|
299
|
-
actions: 'actions' in transition && transition.actions ? toArray(transition.actions) : emptyRawActions
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
return undefined;
|
|
303
|
-
};
|
|
304
|
-
const transitionCore = (snapshot, event, actorScope) => {
|
|
305
|
-
if (snapshot.status !== 'active') {
|
|
306
|
-
return [snapshot, []];
|
|
307
|
-
}
|
|
308
|
-
if (event.type === createActor.XSTATE_STOP) {
|
|
309
|
-
const actions = [];
|
|
310
|
-
const enqueue = createActor.createTransitionEnqueue(actorScope, actions, []);
|
|
311
|
-
for (const id of Object.keys(snapshot.timers)) {
|
|
312
|
-
enqueue.cancel(id);
|
|
313
|
-
}
|
|
314
|
-
const [withoutTimers, cancelEffects] = createActor.resolveActionsWithContext(snapshot, event, actorScope, actions);
|
|
315
|
-
return [stopSnapshot(withoutTimers), cancelEffects];
|
|
316
|
-
}
|
|
317
|
-
if (event.type === createActor.XSTATE_TIMER) {
|
|
318
|
-
const timer = snapshot.timers[event.id];
|
|
319
|
-
if (!timer) {
|
|
320
|
-
return [snapshot, emptyExecutableActions];
|
|
321
|
-
}
|
|
322
|
-
const timers = {
|
|
323
|
-
...snapshot.timers
|
|
324
|
-
};
|
|
325
|
-
delete timers[timer.id];
|
|
326
|
-
const nextSnapshot = {
|
|
327
|
-
...snapshot,
|
|
328
|
-
timers
|
|
329
|
-
};
|
|
330
|
-
if (timer.type === '@xstate.raise') {
|
|
331
|
-
return transitionCore(nextSnapshot, timer.event, actorScope);
|
|
332
|
-
}
|
|
333
|
-
const target = timer.target === 'self' ? actorScope.self : timer.target;
|
|
334
|
-
return [nextSnapshot, [createActor.createSendToEffect(actorScope, target, timer.event)]];
|
|
335
|
-
}
|
|
336
|
-
const stateConfig = config.states[snapshot.value];
|
|
337
|
-
const directTransition = stateConfig?.on?.[event.type];
|
|
338
|
-
if (!directTransition) {
|
|
339
|
-
return [snapshot, emptyExecutableActions];
|
|
340
|
-
}
|
|
341
|
-
if (!Array.isArray(directTransition) && typeof directTransition !== 'function' && !('guard' in directTransition) && !('actions' in directTransition && directTransition.actions) && typeof directTransition.input !== 'function') {
|
|
342
|
-
const target = directTransition.target ?? snapshot.value;
|
|
343
|
-
const stateChanged = target !== snapshot.value;
|
|
344
|
-
if (stateChanged && (stateConfig.exit || config.states[target]?.entry)) ; else {
|
|
345
|
-
const hasContext = directTransition.context !== undefined;
|
|
346
|
-
const hasInput = directTransition.input !== undefined;
|
|
347
|
-
const resolvedContext = !createActor.isLazyActorScope(actorScope) ? resolveTransitionContext(directTransition.context, {
|
|
348
|
-
context: snapshot.context,
|
|
349
|
-
event,
|
|
350
|
-
input: snapshot.input,
|
|
351
|
-
value: snapshot.value,
|
|
352
|
-
self: actorScope.self,
|
|
353
|
-
system: actorScope.system,
|
|
354
|
-
parent: actorScope.self._parent,
|
|
355
|
-
children: snapshot.children
|
|
356
|
-
}) : typeof directTransition.context === 'function' ? directTransition.context(createActor.withActorScope({
|
|
357
|
-
context: snapshot.context,
|
|
358
|
-
event,
|
|
359
|
-
input: snapshot.input,
|
|
360
|
-
value: snapshot.value,
|
|
361
|
-
children: snapshot.children
|
|
362
|
-
}, actorScope)) : directTransition.context;
|
|
363
|
-
const context = hasContext && resolvedContext ? mergeContextPatch(snapshot.context, resolvedContext) : snapshot.context;
|
|
364
|
-
if (!stateChanged && context === snapshot.context && !hasInput && snapshot._stateInput === undefined) {
|
|
365
|
-
return [snapshot, emptyExecutableActions];
|
|
366
|
-
}
|
|
367
|
-
return [cloneSnapshot(snapshot, target, context, hasInput ? resolveInput(directTransition.input, context, event) : undefined), emptyExecutableActions];
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
if (typeof directTransition === 'function' && directTransition.length < 2 && !stateConfig?.exit) {
|
|
371
|
-
const result = directTransition(createActor.withActorScope({
|
|
372
|
-
context: snapshot.context,
|
|
373
|
-
event,
|
|
374
|
-
input: snapshot.input,
|
|
375
|
-
value: snapshot.value,
|
|
376
|
-
children: snapshot.children
|
|
377
|
-
}, actorScope), undefined);
|
|
378
|
-
if (result) {
|
|
379
|
-
const target = result.target ?? snapshot.value;
|
|
380
|
-
if (!config.states[target]?.entry) {
|
|
381
|
-
const hasContext = result.context !== undefined;
|
|
382
|
-
const hasInput = result.input !== undefined;
|
|
383
|
-
const context = hasContext && result.context ? mergeContextPatch(snapshot.context, result.context) : snapshot.context;
|
|
384
|
-
if (target === snapshot.value && context === snapshot.context && !hasInput && snapshot._stateInput === undefined) {
|
|
385
|
-
return [snapshot, emptyExecutableActions];
|
|
386
|
-
}
|
|
387
|
-
return [cloneSnapshot(snapshot, target, context, hasInput ? resolveInput(result.input, context, event) : undefined), emptyExecutableActions];
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
let nextSnapshot = snapshot;
|
|
392
|
-
const executableActions = [];
|
|
393
|
-
const internalQueue = [event];
|
|
394
|
-
let iterations = 0;
|
|
395
|
-
while (internalQueue.length) {
|
|
396
|
-
if (++iterations > 1000) {
|
|
397
|
-
throw new Error('FSM microstep count exceeded 1000');
|
|
398
|
-
}
|
|
399
|
-
const nextEvent = internalQueue.shift();
|
|
400
|
-
const selected = selectTransition(nextSnapshot, nextEvent, actorScope, internalQueue);
|
|
401
|
-
if (!selected) {
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
const nextValue = selected.target ?? nextSnapshot.value;
|
|
405
|
-
const stateChanged = nextValue !== nextSnapshot.value;
|
|
406
|
-
if (stateChanged) {
|
|
407
|
-
const [exited, exitActions] = runStateActions(nextSnapshot, nextEvent, actorScope, config.states[nextSnapshot.value]?.exit, nextSnapshot._stateInput, internalQueue);
|
|
408
|
-
nextSnapshot = exited;
|
|
409
|
-
executableActions.push(...exitActions);
|
|
410
|
-
}
|
|
411
|
-
let context = nextSnapshot.context;
|
|
412
|
-
if (selected.context !== undefined) {
|
|
413
|
-
context = mergeContextPatch(context, selected.context);
|
|
414
|
-
}
|
|
415
|
-
const hasInput = selected.input !== undefined;
|
|
416
|
-
const stateInput = hasInput ? resolveInput(selected.input, context, nextEvent) : undefined;
|
|
417
|
-
if (stateChanged || context !== nextSnapshot.context || hasInput || nextSnapshot._stateInput !== undefined) {
|
|
418
|
-
nextSnapshot = cloneSnapshot(nextSnapshot, nextValue, context, stateInput);
|
|
419
|
-
}
|
|
420
|
-
const [afterTransition, transitionActions] = runActions(nextSnapshot, nextEvent, actorScope, selected.actions);
|
|
421
|
-
nextSnapshot = afterTransition;
|
|
422
|
-
executableActions.push(...transitionActions);
|
|
423
|
-
if (stateChanged) {
|
|
424
|
-
const [entered, entryActions] = runStateActions(nextSnapshot, nextEvent, actorScope, config.states[nextValue]?.entry, stateInput, internalQueue);
|
|
425
|
-
nextSnapshot = entered;
|
|
426
|
-
executableActions.push(...entryActions);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
return [nextSnapshot, executableActions];
|
|
430
|
-
};
|
|
431
|
-
const transition = (...args) => {
|
|
432
|
-
createActor.beginSpawnAllocation(args[2]);
|
|
433
|
-
const [nextSnapshot, effects] = transitionCore(...args);
|
|
434
|
-
return createActor.finalizeTransitionResult(args[2], args[0], [nextSnapshot, [...effects, ...createActor.deriveDeferredStarts(effects)]]);
|
|
435
|
-
};
|
|
436
|
-
const logic = {
|
|
437
|
-
id: config.id,
|
|
438
|
-
config,
|
|
439
|
-
transition,
|
|
440
|
-
initialTransition: (input, actorScope) => {
|
|
441
|
-
createActor.beginSpawnAllocation(actorScope);
|
|
442
|
-
const context = resolveContext(config.context, input);
|
|
443
|
-
const snapshot = createSnapshot(config.initial, context, input, machine);
|
|
444
|
-
const internalQueue = [];
|
|
445
|
-
let [nextSnapshot, actions] = runStateActions(snapshot, {
|
|
446
|
-
type: createActor.XSTATE_INIT
|
|
447
|
-
}, actorScope, config.states[config.initial]?.entry, undefined, internalQueue);
|
|
448
|
-
if (!actions.length) {
|
|
449
|
-
actions = [];
|
|
450
|
-
}
|
|
451
|
-
while (internalQueue.length) {
|
|
452
|
-
const [raisedSnapshot, raisedActions] = transitionCore(nextSnapshot, internalQueue.shift(), actorScope);
|
|
453
|
-
nextSnapshot = raisedSnapshot;
|
|
454
|
-
actions.push(...raisedActions);
|
|
455
|
-
}
|
|
456
|
-
return createActor.finalizeTransitionResult(actorScope, undefined, [nextSnapshot, [...actions, ...createActor.deriveDeferredStarts(actions)]]);
|
|
457
|
-
},
|
|
458
|
-
getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
|
|
459
|
-
getPersistedSnapshot: ({
|
|
460
|
-
machine: _,
|
|
461
|
-
...snapshot
|
|
462
|
-
}) => snapshot,
|
|
463
|
-
restoreSnapshot: snapshot => ({
|
|
464
|
-
...snapshot,
|
|
465
|
-
machine: machine
|
|
466
|
-
})
|
|
467
|
-
};
|
|
468
|
-
return logic;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
45
|
function delayToMs(delay) {
|
|
472
46
|
const parsedDelay = createActor.parseDelayToMilliseconds(delay);
|
|
473
47
|
if (parsedDelay !== undefined) return parsedDelay;
|
|
474
48
|
return typeof delay === 'string' ? parseFloat(delay) || 0 : delay;
|
|
475
49
|
}
|
|
476
|
-
function normalizeScxmlEventType(eventType) {
|
|
477
|
-
return /^error(\.|$)/.test(eventType) ? `xstate.${eventType}` : eventType;
|
|
478
|
-
}
|
|
479
|
-
function toScxmlEventName(eventType) {
|
|
480
|
-
return eventType.startsWith('xstate.error.') ? eventType.slice('xstate.'.length) : eventType;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Isolated executable-content block. Errors in nested actions stop this block
|
|
485
|
-
* but do not propagate to the surrounding action list. Used to model SCXML's
|
|
486
|
-
* separate <onentry>/<onexit> blocks: each is its own block per spec.
|
|
487
|
-
*/
|
|
488
|
-
|
|
489
50
|
function isExpression(value) {
|
|
490
51
|
return !!value && typeof value === 'object' && typeof value['@expr'] === 'string';
|
|
491
52
|
}
|
|
@@ -498,9 +59,6 @@ function isResolvable(value) {
|
|
|
498
59
|
function isBuiltInActionType(type) {
|
|
499
60
|
return type.startsWith('@xstate.');
|
|
500
61
|
}
|
|
501
|
-
function isScxmlActionType(type) {
|
|
502
|
-
return type.startsWith('scxml.');
|
|
503
|
-
}
|
|
504
62
|
function toPath(parent, key) {
|
|
505
63
|
return typeof key === 'number' ? `${parent}[${key}]` : `${parent}.${key}`;
|
|
506
64
|
}
|
|
@@ -641,7 +199,7 @@ function assertMachineJSON(json, resolvedSources, expressionResolver) {
|
|
|
641
199
|
assertCondition(json.guards[condition.type].when, `$.guards.${condition.type}.when`);
|
|
642
200
|
return;
|
|
643
201
|
}
|
|
644
|
-
if (!resolvedSources.guards[condition.type] && !['
|
|
202
|
+
if (!resolvedSources.guards[condition.type] && !['xstate.stateIn', 'xstate.not'].includes(condition.type)) {
|
|
645
203
|
throw new Error(`Missing guard source "${condition.type}"`);
|
|
646
204
|
}
|
|
647
205
|
}
|
|
@@ -654,7 +212,7 @@ function assertMachineJSON(json, resolvedSources, expressionResolver) {
|
|
|
654
212
|
throw new Error(`Invalid action at ${path}`);
|
|
655
213
|
}
|
|
656
214
|
assertResolvable(action.params, `${path}.params`);
|
|
657
|
-
if (isBuiltInActionType(action.type)
|
|
215
|
+
if (isBuiltInActionType(action.type)) {
|
|
658
216
|
assertResolvable(action, path);
|
|
659
217
|
return;
|
|
660
218
|
}
|
|
@@ -720,8 +278,7 @@ function assertMachineJSON(json, resolvedSources, expressionResolver) {
|
|
|
720
278
|
const invokes = Array.isArray(node.invoke) ? node.invoke : [node.invoke];
|
|
721
279
|
invokes.forEach((invoke, index) => {
|
|
722
280
|
const invokePath = `${path}.invoke${Array.isArray(node.invoke) ? `[${index}]` : ''}`;
|
|
723
|
-
|
|
724
|
-
if (!extInv._nestedMachineJSON && !resolvedSources.actors[invoke.src]) {
|
|
281
|
+
if (!resolvedSources.actors[invoke.src]) {
|
|
725
282
|
throw new Error(`Missing actor source "${invoke.src}"`);
|
|
726
283
|
}
|
|
727
284
|
assertResolvable(invoke.input, `${invokePath}.input`);
|
|
@@ -773,78 +330,6 @@ function assertMachineJSON(json, resolvedSources, expressionResolver) {
|
|
|
773
330
|
}
|
|
774
331
|
assertStateNode(json, '$');
|
|
775
332
|
}
|
|
776
|
-
let _scxmlSessionId = 'session_scxml';
|
|
777
|
-
let _scxmlMachineName = '';
|
|
778
|
-
|
|
779
|
-
/** Evaluates an SCXML expression with context variables available via `with`. */
|
|
780
|
-
function evaluateExpr(context, expr, event, self) {
|
|
781
|
-
const fnBody = `
|
|
782
|
-
with (context) {
|
|
783
|
-
return (${expr});
|
|
784
|
-
}
|
|
785
|
-
`.trim();
|
|
786
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
787
|
-
const fn = new Function('context', '_event', '_sessionid', '_name', '_ioprocessors', 'In', fnBody);
|
|
788
|
-
const In = stateId => {
|
|
789
|
-
if (!self) return false;
|
|
790
|
-
try {
|
|
791
|
-
const snap = self.getSnapshot?.();
|
|
792
|
-
if (snap?.nodes) {
|
|
793
|
-
const sanitized = stateId.replace(/\./g, '$');
|
|
794
|
-
return snap.nodes.some(node => node.id === sanitized || node.id.endsWith('.' + sanitized));
|
|
795
|
-
}
|
|
796
|
-
} catch {
|
|
797
|
-
// ignore
|
|
798
|
-
}
|
|
799
|
-
return false;
|
|
800
|
-
};
|
|
801
|
-
const SCXML_ORIGIN = `#_scxml_${_scxmlSessionId}`;
|
|
802
|
-
const SCXML_ORIGIN_TYPE = 'http://www.w3.org/TR/scxml/#SCXMLEventProcessor';
|
|
803
|
-
const isExternal = event && event._scxmlExternal;
|
|
804
|
-
const isInitEvent = event && event.type === '@xstate.init';
|
|
805
|
-
// Per SCXML spec, _event has these fields. Fields that don't apply to a
|
|
806
|
-
// particular event are present with value `undefined` (so `'name' in _event`
|
|
807
|
-
// is true but `typeof _event.name === 'undefined'` for unset fields).
|
|
808
|
-
// For xstate.done.* events, _event.data is the `output` payload (matches
|
|
809
|
-
// SCXML's done event semantics where data is the donedata).
|
|
810
|
-
const isDoneEvent = event && typeof event.type === 'string' && event.type.startsWith('xstate.done.');
|
|
811
|
-
const explicitType = event && event._scxmlEventType;
|
|
812
|
-
const scxmlEvent = event && !isInitEvent ? {
|
|
813
|
-
name: event._scxmlEventName ?? toScxmlEventName(event.type),
|
|
814
|
-
type: explicitType || (isExternal ? 'external' : 'internal'),
|
|
815
|
-
sendid: event._scxmlSendId,
|
|
816
|
-
origin: isExternal ? SCXML_ORIGIN : undefined,
|
|
817
|
-
origintype: isExternal ? SCXML_ORIGIN_TYPE : undefined,
|
|
818
|
-
invokeid: event._scxmlInvokeId,
|
|
819
|
-
data: isDoneEvent ? event.output : event._scxmlEventData !== undefined ? event._scxmlEventData : event
|
|
820
|
-
} : undefined;
|
|
821
|
-
const result = fn(context, scxmlEvent, _scxmlSessionId, _scxmlMachineName, {
|
|
822
|
-
scxml: {
|
|
823
|
-
location: `#_scxml_${_scxmlSessionId}`
|
|
824
|
-
}
|
|
825
|
-
}, In);
|
|
826
|
-
return result;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
/** Executes an SCXML script block and returns updated context values. */
|
|
830
|
-
function executeScript(context, code) {
|
|
831
|
-
// Create a proxy to track which properties are modified
|
|
832
|
-
const updates = {};
|
|
833
|
-
const contextKeys = Object.keys(context);
|
|
834
|
-
|
|
835
|
-
// Build variable declarations and reassignment capture
|
|
836
|
-
const varDeclarations = contextKeys.map(k => `let ${k} = context.${k};`).join('\n');
|
|
837
|
-
const captureUpdates = contextKeys.map(k => `updates.${k} = ${k};`).join('\n');
|
|
838
|
-
const fnBody = `
|
|
839
|
-
${varDeclarations}
|
|
840
|
-
${code}
|
|
841
|
-
${captureUpdates}
|
|
842
|
-
return updates;
|
|
843
|
-
`;
|
|
844
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
845
|
-
const fn = new Function('context', 'updates', fnBody);
|
|
846
|
-
return fn(context, updates);
|
|
847
|
-
}
|
|
848
333
|
function createMachineFromConfig(json, sources = {}) {
|
|
849
334
|
const resolvedSources = mergeSources(json, sources);
|
|
850
335
|
const expressionResolver = createExpressionResolver(json['@exprLang'], resolvedSources);
|
|
@@ -855,9 +340,7 @@ function createMachineFromConfig(json, sources = {}) {
|
|
|
855
340
|
getDurationConfig
|
|
856
341
|
} = expressionResolver;
|
|
857
342
|
function resolveCondition(condition, slot, path) {
|
|
858
|
-
if (!condition)
|
|
859
|
-
return undefined;
|
|
860
|
-
}
|
|
343
|
+
if (!condition) return undefined;
|
|
861
344
|
if (isResolvable(condition)) {
|
|
862
345
|
return args => !!evaluateResolvable(condition, slot, makeScope(args), path);
|
|
863
346
|
}
|
|
@@ -878,10 +361,11 @@ function createMachineFromConfig(json, sources = {}) {
|
|
|
878
361
|
return guardImpl(args, params);
|
|
879
362
|
};
|
|
880
363
|
}
|
|
364
|
+
function getMissingGuardMessage(type, guards) {
|
|
365
|
+
return `Guard '${type}' is not implemented in machine '${json.id ?? '(machine)'}'. Available guards: ${Object.keys(guards).map(key => `'${key}'`).join(', ') || '(none)'}.`;
|
|
366
|
+
}
|
|
881
367
|
function makeChoiceConfig(choice, path) {
|
|
882
|
-
if (!choice)
|
|
883
|
-
return undefined;
|
|
884
|
-
}
|
|
368
|
+
if (!choice) return undefined;
|
|
885
369
|
if (isResolvable(choice)) {
|
|
886
370
|
return args => evaluateResolvable(choice, 'choice', makeScope(args), path);
|
|
887
371
|
}
|
|
@@ -904,32 +388,8 @@ function createMachineFromConfig(json, sources = {}) {
|
|
|
904
388
|
throw new Error(`Choice state at ${path} did not match any branch.`);
|
|
905
389
|
};
|
|
906
390
|
}
|
|
907
|
-
|
|
908
|
-
// Pending transition actions: set by .to functions, consumed by entry functions.
|
|
909
|
-
// This bridges SCXML's exit→transition→entry action ordering with XState's
|
|
910
|
-
// .to function receiving pre-exit context.
|
|
911
|
-
// Map keyed by target state ID so parallel transitions don't overwrite each other.
|
|
912
|
-
const pendingTransitionActionsMap = {};
|
|
913
|
-
|
|
914
|
-
// Ordered queue of ALL transition actions (targeted + targetless) for parallel
|
|
915
|
-
// context sharing. In SCXML, all transition actions execute sequentially in
|
|
916
|
-
// document order with a shared evolving data model.
|
|
917
|
-
const allTransitionActions = [];
|
|
918
|
-
// Pre-transition context saved when a targetless .to executes. Used by entry
|
|
919
|
-
// functions to re-execute all transition actions from scratch when parallel
|
|
920
|
-
// targetless transitions coexist with targeted transitions.
|
|
921
|
-
let contextBeforeTargetless = null;
|
|
922
|
-
// Platform errors collected during transition selection (e.g., failing
|
|
923
|
-
// <transition cond>). Drained by the next state's entry into the internal
|
|
924
|
-
// event queue so they're processed before any external events.
|
|
925
|
-
const pendingPlatformErrors = [];
|
|
926
|
-
function getMissingGuardMessage(type, guards) {
|
|
927
|
-
return `Guard '${type}' is not implemented in machine '${json.id ?? '(machine)'}'. Available guards: ${Object.keys(guards).map(key => `'${key}'`).join(', ') || '(none)'}.`;
|
|
928
|
-
}
|
|
929
391
|
function resolveRouteConfig(route, path) {
|
|
930
|
-
if (!route || typeof route === 'function')
|
|
931
|
-
return route;
|
|
932
|
-
}
|
|
392
|
+
if (!route || typeof route === 'function') return route;
|
|
933
393
|
if (isResolvable(route)) {
|
|
934
394
|
return args => evaluateResolvable(route, 'transition', makeScope(args), path);
|
|
935
395
|
}
|
|
@@ -937,263 +397,15 @@ function createMachineFromConfig(json, sources = {}) {
|
|
|
937
397
|
guard,
|
|
938
398
|
...routeConfig
|
|
939
399
|
} = route;
|
|
940
|
-
if (!guard)
|
|
941
|
-
return routeConfig;
|
|
942
|
-
}
|
|
400
|
+
if (!guard) return routeConfig;
|
|
943
401
|
const resolvedGuard = resolveCondition({
|
|
944
402
|
type: guard
|
|
945
403
|
}, 'guard', path);
|
|
946
404
|
return args => resolvedGuard(args) ? routeConfig : undefined;
|
|
947
405
|
}
|
|
948
|
-
function
|
|
949
|
-
const originalEntryActions = toActionArray(node.entry);
|
|
950
|
-
const stateId = node.id || nodeKey;
|
|
951
|
-
|
|
952
|
-
// Wrap entry to first execute any pending transition actions, then normal entry.
|
|
953
|
-
// This ensures SCXML execution order: exit → transition_actions → entry_actions
|
|
954
|
-
// because pending transition actions are set by .to (before exit) but executed
|
|
955
|
-
// in entry (after exit), thus seeing post-exit context.
|
|
956
|
-
const entryFn = (x, enq) => {
|
|
957
|
-
// Drain any platform errors queued during transition selection (e.g.,
|
|
958
|
-
// failing <transition cond="..."> evaluations). These must be raised
|
|
959
|
-
// internally so they're processed before subsequent external events.
|
|
960
|
-
while (pendingPlatformErrors.length) {
|
|
961
|
-
const err = pendingPlatformErrors.shift();
|
|
962
|
-
enq.raise({
|
|
963
|
-
type: 'xstate.error.execution',
|
|
964
|
-
error: err,
|
|
965
|
-
_scxmlEventType: 'platform',
|
|
966
|
-
_scxmlEventName: 'error.execution',
|
|
967
|
-
_scxmlEventData: err
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
let context;
|
|
971
|
-
|
|
972
|
-
// If targetless transitions were interleaved with targeted transitions
|
|
973
|
-
// (parallel state), re-execute ALL transition actions from the original
|
|
974
|
-
// pre-transition context. This overrides any .to-produced context with
|
|
975
|
-
// the correct SCXML document-order sequential execution.
|
|
976
|
-
// Only trigger when BOTH targeted (pending in map) and targetless fired
|
|
977
|
-
// in the same microstep — prevents stale data from previous events.
|
|
978
|
-
if (contextBeforeTargetless && allTransitionActions.length > 0 && Object.keys(pendingTransitionActionsMap).length > 0) {
|
|
979
|
-
let ctx = contextBeforeTargetless;
|
|
980
|
-
for (const actions of allTransitionActions) {
|
|
981
|
-
const mergedX = {
|
|
982
|
-
...x,
|
|
983
|
-
context: ctx
|
|
984
|
-
};
|
|
985
|
-
const result = executeActions(actions, mergedX, enq);
|
|
986
|
-
if (result.context) {
|
|
987
|
-
ctx = result.context;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
allTransitionActions.length = 0;
|
|
991
|
-
contextBeforeTargetless = null;
|
|
992
|
-
// Clear per-target map since we re-processed everything
|
|
993
|
-
for (const key of Object.keys(pendingTransitionActionsMap)) {
|
|
994
|
-
delete pendingTransitionActionsMap[key];
|
|
995
|
-
}
|
|
996
|
-
context = ctx;
|
|
997
|
-
} else {
|
|
998
|
-
// Normal path: consume pending transition actions for THIS state.
|
|
999
|
-
// In parallel states, each target gets its own pending actions.
|
|
1000
|
-
const transActions = stateId ? pendingTransitionActionsMap[stateId] : undefined;
|
|
1001
|
-
if (transActions) {
|
|
1002
|
-
delete pendingTransitionActionsMap[stateId];
|
|
1003
|
-
const result = executeActions(transActions, x, enq);
|
|
1004
|
-
if (result.context) {
|
|
1005
|
-
context = result.context;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
// Clear stale targetless data from previous microsteps
|
|
1009
|
-
contextBeforeTargetless = null;
|
|
1010
|
-
allTransitionActions.length = 0;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// Execute normal entry actions
|
|
1014
|
-
if (originalEntryActions.length) {
|
|
1015
|
-
const mergedX = context ? {
|
|
1016
|
-
...x,
|
|
1017
|
-
context
|
|
1018
|
-
} : x;
|
|
1019
|
-
const result = executeActions(originalEntryActions, mergedX, enq);
|
|
1020
|
-
if (result.context) {
|
|
1021
|
-
context = result.context;
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
return {
|
|
1025
|
-
context
|
|
1026
|
-
};
|
|
1027
|
-
};
|
|
1028
|
-
const nodeConfig = {
|
|
1029
|
-
id: node.id,
|
|
1030
|
-
initial: node.initial,
|
|
1031
|
-
type: node.type,
|
|
1032
|
-
history: node.history,
|
|
1033
|
-
target: node.target,
|
|
1034
|
-
description: node.description,
|
|
1035
|
-
tags: node.tags,
|
|
1036
|
-
input: node.input,
|
|
1037
|
-
timeout: getDurationConfig(node.timeout, `$.states.${nodeKey}.timeout`),
|
|
1038
|
-
states: node.states ? Object.entries(node.states).reduce((acc, [key, value]) => {
|
|
1039
|
-
acc[key] = iterNode(value, key);
|
|
1040
|
-
return acc;
|
|
1041
|
-
}, {}) : undefined,
|
|
1042
|
-
on: node.on ? Object.entries(node.on).reduce((acc, [key, value]) => {
|
|
1043
|
-
acc[key] = getTransitionConfig(value);
|
|
1044
|
-
return acc;
|
|
1045
|
-
}, {}) : undefined,
|
|
1046
|
-
always: node.always ? getTransitionConfig(node.always) : undefined,
|
|
1047
|
-
onError: node.onError ? getTransitionConfig(node.onError) : undefined,
|
|
1048
|
-
choice: makeChoiceConfig(node.choice, `$.states.${nodeKey}.choice`),
|
|
1049
|
-
route: resolveRouteConfig(node.route, `$.states.${nodeKey}.route`),
|
|
1050
|
-
after: node.after ? Object.entries(node.after).reduce((acc, [key, value]) => {
|
|
1051
|
-
acc[key] = getTransitionConfig(value);
|
|
1052
|
-
return acc;
|
|
1053
|
-
}, {}) : undefined,
|
|
1054
|
-
onTimeout: node.onTimeout ? getTransitionConfig(node.onTimeout) : undefined,
|
|
1055
|
-
entry: node.type === 'choice' ? undefined : entryFn,
|
|
1056
|
-
exit: node.exit ? iterActions(toActionArray(node.exit)) : undefined,
|
|
1057
|
-
invoke: node.invoke ? iterInvokeConfigs(node.invoke) : undefined,
|
|
1058
|
-
meta: node.meta,
|
|
1059
|
-
output: node._scxmlDonedata ? makeDonedataOutput(node._scxmlDonedata) : isResolvable(node.output) ? ({
|
|
1060
|
-
context,
|
|
1061
|
-
event,
|
|
1062
|
-
self
|
|
1063
|
-
}) => evaluateResolvable(node.output, 'output', {
|
|
1064
|
-
context,
|
|
1065
|
-
event,
|
|
1066
|
-
self
|
|
1067
|
-
}, `$.states.${nodeKey}.output`) : node.output
|
|
1068
|
-
};
|
|
1069
|
-
return nodeConfig;
|
|
1070
|
-
}
|
|
1071
|
-
function makeDonedataOutput(donedata) {
|
|
1072
|
-
return ({
|
|
1073
|
-
context,
|
|
1074
|
-
event,
|
|
1075
|
-
self
|
|
1076
|
-
}) => {
|
|
1077
|
-
try {
|
|
1078
|
-
if (donedata.params && donedata.params.length) {
|
|
1079
|
-
const out = {};
|
|
1080
|
-
for (const param of donedata.params) {
|
|
1081
|
-
out[param.name] = evaluateExpr(context, param.expr, event, self);
|
|
1082
|
-
}
|
|
1083
|
-
return out;
|
|
1084
|
-
}
|
|
1085
|
-
if (donedata.contentExpr !== undefined) {
|
|
1086
|
-
return evaluateExpr(context, donedata.contentExpr, event, self);
|
|
1087
|
-
}
|
|
1088
|
-
if (donedata.contentText !== undefined) {
|
|
1089
|
-
// Try parsing as a JS expression (number/object/array literals);
|
|
1090
|
-
// fall back to the raw string.
|
|
1091
|
-
try {
|
|
1092
|
-
return evaluateExpr(context, donedata.contentText, event, self);
|
|
1093
|
-
} catch {
|
|
1094
|
-
return donedata.contentText;
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
} catch (err) {
|
|
1098
|
-
// Per SCXML, donedata expression errors raise error.execution and
|
|
1099
|
-
// result in undefined event.data. Queue for the next entry to drain.
|
|
1100
|
-
const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
|
|
1101
|
-
pendingPlatformErrors.push({
|
|
1102
|
-
tagname: 'donedata',
|
|
1103
|
-
message,
|
|
1104
|
-
line: NaN,
|
|
1105
|
-
column: NaN,
|
|
1106
|
-
reason: message
|
|
1107
|
-
});
|
|
1108
|
-
}
|
|
1109
|
-
return undefined;
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
function iterInvokeConfigs(invokes) {
|
|
1113
|
-
const invokeArray = Array.isArray(invokes) ? invokes : [invokes];
|
|
1114
|
-
return invokeArray.map(inv => {
|
|
1115
|
-
const extInv = inv;
|
|
1116
|
-
// Create child machine from nested SCXML JSON
|
|
1117
|
-
let src;
|
|
1118
|
-
if (extInv._nestedMachineJSON) {
|
|
1119
|
-
src = createMachineFromConfig(extInv._nestedMachineJSON, resolvedSources);
|
|
1120
|
-
} else {
|
|
1121
|
-
src = resolvedSources.actors[inv.src] ?? inv.src;
|
|
1122
|
-
}
|
|
1123
|
-
return {
|
|
1124
|
-
src,
|
|
1125
|
-
id: inv.id,
|
|
1126
|
-
registryKey: inv.registryKey,
|
|
1127
|
-
input: inv.input !== undefined ? args => resolveValue(inv.input, 'input', makeScope(args), '$.invoke.input') : undefined,
|
|
1128
|
-
onDone: inv.onDone ? getTransitionConfig(inv.onDone) : undefined,
|
|
1129
|
-
onError: inv.onError ? getTransitionConfig(inv.onError) : undefined,
|
|
1130
|
-
onSnapshot: inv.onSnapshot ? getTransitionConfig(inv.onSnapshot) : undefined,
|
|
1131
|
-
timeout: getDurationConfig(inv.timeout, '$.invoke.timeout'),
|
|
1132
|
-
onTimeout: inv.onTimeout ? getTransitionConfig(inv.onTimeout) : undefined
|
|
1133
|
-
};
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
/**
|
|
1138
|
-
* Raise an SCXML error.execution platform event onto the internal queue. Per
|
|
1139
|
-
* spec, error.execution is type='platform' and _event.data contains error
|
|
1140
|
-
* info. The surrounding block of executable content stops.
|
|
1141
|
-
*/
|
|
1142
|
-
function raiseErrorExecution(state, tagname, err) {
|
|
1143
|
-
const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
|
|
1144
|
-
state.enq.raise({
|
|
1145
|
-
type: 'xstate.error.execution',
|
|
1146
|
-
error: {
|
|
1147
|
-
tagname,
|
|
1148
|
-
message,
|
|
1149
|
-
line: NaN,
|
|
1150
|
-
column: NaN,
|
|
1151
|
-
reason: message
|
|
1152
|
-
},
|
|
1153
|
-
_scxmlEventType: 'platform',
|
|
1154
|
-
_scxmlEventName: 'error.execution',
|
|
1155
|
-
_scxmlEventData: {
|
|
1156
|
-
tagname,
|
|
1157
|
-
message,
|
|
1158
|
-
line: NaN,
|
|
1159
|
-
column: NaN,
|
|
1160
|
-
reason: message
|
|
1161
|
-
}
|
|
1162
|
-
});
|
|
1163
|
-
state.errored = true;
|
|
1164
|
-
}
|
|
1165
|
-
function executeActionDefinition(action, x, enq, params, parentState, stack) {
|
|
1166
|
-
const definition = json.actions?.[action.type];
|
|
1167
|
-
if (!definition) {
|
|
1168
|
-
enq(x.actions[action.type], params);
|
|
1169
|
-
return {
|
|
1170
|
-
context: undefined,
|
|
1171
|
-
errored: parentState.errored
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
if (stack.includes(action.type)) {
|
|
1175
|
-
raiseErrorExecution(parentState, 'action', new Error(`Circular action reference: ${stack.concat(action.type).join(' -> ')}`));
|
|
1176
|
-
return {
|
|
1177
|
-
context: undefined,
|
|
1178
|
-
errored: true
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
const definitions = Array.isArray(definition) ? definition : [definition];
|
|
1182
|
-
return executeActions(definitions, {
|
|
1183
|
-
...x,
|
|
1184
|
-
params
|
|
1185
|
-
}, enq, parentState, stack.concat(action.type));
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
/** Execute an array of SCXML action JSON descriptors with context and enqueue. */
|
|
1189
|
-
function executeActions(actions, x, enq, parentState, stack = []) {
|
|
1190
|
-
const state = parentState ?? {
|
|
1191
|
-
enq,
|
|
1192
|
-
errored: false
|
|
1193
|
-
};
|
|
406
|
+
function executeActions(actions, x, enq, stack = []) {
|
|
1194
407
|
let context;
|
|
1195
408
|
for (const action of actions) {
|
|
1196
|
-
if (state.errored) break;
|
|
1197
409
|
if (isResolvable(action)) {
|
|
1198
410
|
const result = evaluateResolvable(action, 'action', makeScope(x, {
|
|
1199
411
|
params: x.params,
|
|
@@ -1203,31 +415,18 @@ function createMachineFromConfig(json, sources = {}) {
|
|
|
1203
415
|
context ??= {};
|
|
1204
416
|
Object.assign(context, result.context);
|
|
1205
417
|
}
|
|
1206
|
-
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (isBuiltInActionJSON(action)) {
|
|
1207
421
|
switch (action.type) {
|
|
1208
422
|
case '@xstate.raise':
|
|
1209
|
-
{
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
const event = isExternal || action.id !== undefined ? {
|
|
1217
|
-
...resolvedEvent,
|
|
1218
|
-
...(isExternal ? {
|
|
1219
|
-
_scxmlExternal: true
|
|
1220
|
-
} : {}),
|
|
1221
|
-
...(action.id !== undefined ? {
|
|
1222
|
-
_scxmlSendId: action.id
|
|
1223
|
-
} : {})
|
|
1224
|
-
} : resolvedEvent;
|
|
1225
|
-
enq.raise(event, {
|
|
1226
|
-
id: action.id,
|
|
1227
|
-
delay: action.delay
|
|
1228
|
-
});
|
|
1229
|
-
break;
|
|
1230
|
-
}
|
|
423
|
+
enq.raise(resolveValue(action.event, 'actionParams', makeScope(x, {
|
|
424
|
+
params: x.params
|
|
425
|
+
}), '$.actions.event'), {
|
|
426
|
+
id: action.id,
|
|
427
|
+
delay: action.delay
|
|
428
|
+
});
|
|
429
|
+
break;
|
|
1231
430
|
case '@xstate.cancel':
|
|
1232
431
|
enq.cancel(action.id);
|
|
1233
432
|
break;
|
|
@@ -1245,501 +444,161 @@ function createMachineFromConfig(json, sources = {}) {
|
|
|
1245
444
|
params: x.params
|
|
1246
445
|
}), '$.actions.context'));
|
|
1247
446
|
break;
|
|
1248
|
-
default:
|
|
1249
|
-
throw new Error(`Unknown built-in action: ${action.type}`);
|
|
1250
|
-
}
|
|
1251
|
-
} else if (action.type === 'scxml.assign') {
|
|
1252
|
-
const scxmlAction = action;
|
|
1253
|
-
const mergedContext = {
|
|
1254
|
-
...x.context,
|
|
1255
|
-
...context
|
|
1256
|
-
};
|
|
1257
|
-
let value;
|
|
1258
|
-
try {
|
|
1259
|
-
value = evaluateExpr(mergedContext, scxmlAction.expr, x.event, x.self);
|
|
1260
|
-
} catch (err) {
|
|
1261
|
-
raiseErrorExecution(state, 'assign', err);
|
|
1262
|
-
continue;
|
|
1263
|
-
}
|
|
1264
|
-
// Per SCXML, assigning to a location that doesn't exist on the
|
|
1265
|
-
// datamodel is an error. Allow setting an own property via context;
|
|
1266
|
-
// detect deep paths (a.b.c) which we don't support.
|
|
1267
|
-
if (scxmlAction.location.includes('.')) {
|
|
1268
|
-
raiseErrorExecution(state, 'assign', new Error(`Invalid assign location: ${scxmlAction.location}`));
|
|
1269
|
-
continue;
|
|
1270
|
-
}
|
|
1271
|
-
context ??= {};
|
|
1272
|
-
context[scxmlAction.location] = value;
|
|
1273
|
-
} else if (action.type === 'scxml.raise') {
|
|
1274
|
-
const scxmlAction = action;
|
|
1275
|
-
const mergedContext = {
|
|
1276
|
-
...x.context,
|
|
1277
|
-
...context
|
|
1278
|
-
};
|
|
1279
|
-
let eventType;
|
|
1280
|
-
let eventData;
|
|
1281
|
-
let target;
|
|
1282
|
-
let delay;
|
|
1283
|
-
try {
|
|
1284
|
-
eventType = scxmlAction.eventexpr ? evaluateExpr(mergedContext, scxmlAction.eventexpr, x.event, x.self) : scxmlAction.event || 'unknown';
|
|
1285
|
-
eventType = normalizeScxmlEventType(eventType);
|
|
1286
|
-
eventData = {
|
|
1287
|
-
type: eventType,
|
|
1288
|
-
_scxmlEventName: toScxmlEventName(eventType)
|
|
1289
|
-
};
|
|
1290
|
-
if (scxmlAction.params) {
|
|
1291
|
-
for (const param of scxmlAction.params) {
|
|
1292
|
-
eventData[param.name] = evaluateExpr(mergedContext, param.expr, x.event, x.self);
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
target = scxmlAction.targetexpr ? evaluateExpr(mergedContext, scxmlAction.targetexpr, x.event, x.self) : scxmlAction.target;
|
|
1296
|
-
const isInternalTarget = target === '#_internal';
|
|
1297
|
-
delay = scxmlAction.delayexpr ? delayToMs(evaluateExpr(mergedContext, scxmlAction.delayexpr, x.event, x.self)) : isInternalTarget ? undefined : scxmlAction.delay;
|
|
1298
|
-
} catch (err) {
|
|
1299
|
-
raiseErrorExecution(state, 'send', err);
|
|
1300
|
-
continue;
|
|
1301
|
-
}
|
|
1302
|
-
const isInternalTarget = target === '#_internal';
|
|
1303
|
-
const isParentTarget = target === '#_parent';
|
|
1304
|
-
|
|
1305
|
-
// Validate target. SCXML targets must be '#_internal', '#_parent',
|
|
1306
|
-
// or '#_<id>'. A bare string without the '#_' prefix is invalid and
|
|
1307
|
-
// raises error.execution.
|
|
1308
|
-
if (typeof target === 'string' && target.length > 0 && !target.startsWith('#_')) {
|
|
1309
|
-
raiseErrorExecution(state, 'send', new Error(`Invalid send target: ${target}`));
|
|
1310
|
-
continue;
|
|
1311
|
-
}
|
|
1312
|
-
// Attach send id so _event.sendid can be read in expressions.
|
|
1313
|
-
if (scxmlAction.id !== undefined) {
|
|
1314
|
-
eventData._scxmlSendId = scxmlAction.id;
|
|
1315
|
-
}
|
|
1316
|
-
// Resolve target at runtime: parent, child, or self
|
|
1317
|
-
if (isParentTarget && x.parent) {
|
|
1318
|
-
// Send to parent via sendTo; pass delay if present
|
|
1319
|
-
enq.sendTo(x.parent, eventData, delay !== undefined ? {
|
|
1320
|
-
delay
|
|
1321
|
-
} : undefined);
|
|
1322
|
-
} else if (typeof target === 'string' && target.startsWith('#_') && !isParentTarget && !isInternalTarget) {
|
|
1323
|
-
// #_<invokeId> → try to send to child actor, fall back to self-raise
|
|
1324
|
-
const childId = target.slice(2); // strip '#_'
|
|
1325
|
-
const childRef = x.children?.[childId];
|
|
1326
|
-
if (childRef) {
|
|
1327
|
-
enq.sendTo(childRef, eventData);
|
|
1328
|
-
} else if (childId.startsWith('scxml_') && childId !== `scxml_${_scxmlSessionId}`) {
|
|
1329
|
-
const message = `Unable to dispatch event to target: ${target}`;
|
|
1330
|
-
enq.raise({
|
|
1331
|
-
type: 'xstate.error.communication',
|
|
1332
|
-
error: {
|
|
1333
|
-
tagname: 'send',
|
|
1334
|
-
message,
|
|
1335
|
-
line: NaN,
|
|
1336
|
-
column: NaN,
|
|
1337
|
-
reason: message
|
|
1338
|
-
},
|
|
1339
|
-
_scxmlEventType: 'platform',
|
|
1340
|
-
_scxmlEventName: 'error.communication',
|
|
1341
|
-
_scxmlEventData: {
|
|
1342
|
-
tagname: 'send',
|
|
1343
|
-
message,
|
|
1344
|
-
line: NaN,
|
|
1345
|
-
column: NaN,
|
|
1346
|
-
reason: message
|
|
1347
|
-
}
|
|
1348
|
-
});
|
|
1349
|
-
} else {
|
|
1350
|
-
// This SCXML session id uses the external event queue.
|
|
1351
|
-
eventData._scxmlExternal = true;
|
|
1352
|
-
enq.sendTo(x.self, eventData, {
|
|
1353
|
-
id: scxmlAction.id,
|
|
1354
|
-
delay
|
|
1355
|
-
});
|
|
1356
|
-
}
|
|
1357
|
-
} else {
|
|
1358
|
-
// #_internal uses the internal queue; self-send/no target use the
|
|
1359
|
-
// external event queue.
|
|
1360
|
-
if (isInternalTarget) {
|
|
1361
|
-
enq.raise(eventData, {
|
|
1362
|
-
id: scxmlAction.id,
|
|
1363
|
-
delay
|
|
1364
|
-
});
|
|
1365
|
-
} else {
|
|
1366
|
-
eventData._scxmlExternal = true;
|
|
1367
|
-
enq.sendTo(x.self, eventData, {
|
|
1368
|
-
id: scxmlAction.id,
|
|
1369
|
-
delay
|
|
1370
|
-
});
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
} else if (action.type === 'scxml.cancel') {
|
|
1374
|
-
const scxmlAction = action;
|
|
1375
|
-
const mergedContext = {
|
|
1376
|
-
...x.context,
|
|
1377
|
-
...context
|
|
1378
|
-
};
|
|
1379
|
-
try {
|
|
1380
|
-
const sendId = evaluateExpr(mergedContext, scxmlAction.sendidexpr, x.event, x.self);
|
|
1381
|
-
if (sendId) {
|
|
1382
|
-
enq.cancel(sendId);
|
|
1383
|
-
}
|
|
1384
|
-
} catch {
|
|
1385
|
-
// ignore evaluation errors
|
|
1386
|
-
}
|
|
1387
|
-
} else if (action.type === 'scxml.script') {
|
|
1388
|
-
const scxmlAction = action;
|
|
1389
|
-
const mergedContext = {
|
|
1390
|
-
...x.context,
|
|
1391
|
-
...context
|
|
1392
|
-
};
|
|
1393
|
-
try {
|
|
1394
|
-
const updatedContext = executeScript(mergedContext, scxmlAction.code);
|
|
1395
|
-
context ??= {};
|
|
1396
|
-
Object.assign(context, updatedContext);
|
|
1397
|
-
} catch (err) {
|
|
1398
|
-
raiseErrorExecution(state, 'script', err);
|
|
1399
|
-
}
|
|
1400
|
-
} else if (action.type === 'scxml.foreach') {
|
|
1401
|
-
const scxmlAction = action;
|
|
1402
|
-
const mergedContext = {
|
|
1403
|
-
...x.context,
|
|
1404
|
-
...context
|
|
1405
|
-
};
|
|
1406
|
-
// SCXML: `item` (and `index` if present) must be valid datamodel
|
|
1407
|
-
// locations — i.e. legal identifiers. Reject things like 'continue'
|
|
1408
|
-
// (string literal) or '7' (number).
|
|
1409
|
-
const isLegalIdentifier = s => /^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(s);
|
|
1410
|
-
if (!isLegalIdentifier(scxmlAction.item) || scxmlAction.index && !isLegalIdentifier(scxmlAction.index)) {
|
|
1411
|
-
raiseErrorExecution(state, 'foreach', new Error('foreach item/index is not a legal location'));
|
|
1412
|
-
continue;
|
|
1413
|
-
}
|
|
1414
|
-
let arr;
|
|
1415
|
-
try {
|
|
1416
|
-
arr = evaluateExpr(mergedContext, scxmlAction.array, x.event, x.self);
|
|
1417
|
-
} catch (err) {
|
|
1418
|
-
raiseErrorExecution(state, 'foreach', err);
|
|
1419
|
-
continue;
|
|
1420
|
-
}
|
|
1421
|
-
if (!Array.isArray(arr)) {
|
|
1422
|
-
raiseErrorExecution(state, 'foreach', new Error('foreach array is not iterable'));
|
|
1423
|
-
continue;
|
|
1424
447
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
if (state.errored) break;
|
|
1443
|
-
}
|
|
1444
|
-
} else if (action.type === 'scxml.block') {
|
|
1445
|
-
const scxmlAction = action;
|
|
1446
|
-
const blockX = {
|
|
1447
|
-
...x,
|
|
1448
|
-
context: {
|
|
1449
|
-
...x.context,
|
|
1450
|
-
...context
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
// Block has its own ExecState — errors don't propagate to parent.
|
|
1454
|
-
const blockResult = executeActions(scxmlAction.actions, blockX, enq);
|
|
1455
|
-
if (blockResult.context) {
|
|
1456
|
-
context ??= {};
|
|
1457
|
-
for (const key of Object.keys(blockResult.context)) {
|
|
1458
|
-
if (blockResult.context[key] !== x.context[key]) {
|
|
1459
|
-
context[key] = blockResult.context[key];
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
} else if (action.type === 'scxml.if') {
|
|
1464
|
-
const scxmlAction = action;
|
|
1465
|
-
const mergedContext = {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
const params = resolveValue(action.params, 'actionParams', makeScope(x, {
|
|
451
|
+
params: x.params
|
|
452
|
+
}), '$.actions.params');
|
|
453
|
+
const definition = json.actions?.[action.type];
|
|
454
|
+
if (!definition) {
|
|
455
|
+
enq(x.actions[action.type], params);
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (stack.includes(action.type)) {
|
|
459
|
+
throw new Error(`Circular action reference: ${stack.concat(action.type).join(' -> ')}`);
|
|
460
|
+
}
|
|
461
|
+
const definitions = Array.isArray(definition) ? definition : [definition];
|
|
462
|
+
const result = executeActions(definitions, {
|
|
463
|
+
...x,
|
|
464
|
+
context: {
|
|
1466
465
|
...x.context,
|
|
1467
466
|
...context
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
try {
|
|
1473
|
-
condResult = !!evaluateExpr(mergedContext, branch.cond, x.event, x.self);
|
|
1474
|
-
} catch (err) {
|
|
1475
|
-
raiseErrorExecution(state, 'if', err);
|
|
1476
|
-
condResult = false;
|
|
1477
|
-
}
|
|
1478
|
-
} else {
|
|
1479
|
-
condResult = true;
|
|
1480
|
-
}
|
|
1481
|
-
if (condResult) {
|
|
1482
|
-
if (branch.actions.length) {
|
|
1483
|
-
const branchX = {
|
|
1484
|
-
...x,
|
|
1485
|
-
context: mergedContext
|
|
1486
|
-
};
|
|
1487
|
-
const branchResult = executeActions(branch.actions, branchX, enq, state);
|
|
1488
|
-
if (branchResult.context) {
|
|
1489
|
-
context ??= {};
|
|
1490
|
-
for (const key of Object.keys(branchResult.context)) {
|
|
1491
|
-
if (branchResult.context[key] !== x.context[key]) {
|
|
1492
|
-
context[key] = branchResult.context[key];
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
break;
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
} else {
|
|
1501
|
-
const params = resolveValue(action.params, 'actionParams', makeScope(x, {
|
|
1502
|
-
params: x.params
|
|
1503
|
-
}), '$.actions.params');
|
|
1504
|
-
const result = executeActionDefinition(action, x, enq, params, state, stack);
|
|
1505
|
-
if (result.context) {
|
|
1506
|
-
context ??= {};
|
|
1507
|
-
Object.assign(context, result.context);
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
467
|
+
},
|
|
468
|
+
params
|
|
469
|
+
}, enq, stack.concat(action.type));
|
|
470
|
+
if (result.context) context = result.context;
|
|
1510
471
|
}
|
|
1511
472
|
return {
|
|
1512
473
|
context: context ? {
|
|
1513
474
|
...x.context,
|
|
1514
475
|
...context
|
|
1515
|
-
} : undefined
|
|
1516
|
-
errored: state.errored
|
|
476
|
+
} : undefined
|
|
1517
477
|
};
|
|
1518
478
|
}
|
|
1519
479
|
function iterActions(actions) {
|
|
1520
|
-
|
|
480
|
+
const actionArray = toActionArray(actions);
|
|
481
|
+
return (x, enq) => executeActions(actionArray, x, enq);
|
|
1521
482
|
}
|
|
1522
483
|
function getTransitionConfig(transition) {
|
|
1523
484
|
const transitions = Array.isArray(transition) ? transition : [transition];
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
// This ensures guards are evaluated by XState's evaluateCandidate (once,
|
|
1528
|
-
// with pre-exit context) and NOT re-evaluated in computeEntrySet.
|
|
1529
|
-
return transitions.map((t, index) => {
|
|
1530
|
-
if (isResolvable(t)) {
|
|
1531
|
-
return (x, enq) => evaluateResolvable(t, 'transition', makeScope(x, {
|
|
485
|
+
return transitions.map((item, index) => {
|
|
486
|
+
if (isResolvable(item)) {
|
|
487
|
+
return (x, enq) => evaluateResolvable(item, 'transition', makeScope(x, {
|
|
1532
488
|
enq
|
|
1533
489
|
}), `$.transition${transitions.length > 1 ? `[${index}]` : ''}`);
|
|
1534
490
|
}
|
|
1535
|
-
const
|
|
1536
|
-
const
|
|
1537
|
-
const
|
|
1538
|
-
const resolveTransitionContext = x => t.context ? resolveValue(t.context, 'transitionContext', makeScope(x), '$.transition.context') : undefined;
|
|
1539
|
-
const resolveTransitionInput = x => t.input !== undefined ? resolveValue(t.input, 'input', makeScope(x), '$.transition.input') : undefined;
|
|
1540
|
-
|
|
1541
|
-
// No guard and no actions: simple static config
|
|
1542
|
-
if (!guard && !t.actions?.length) {
|
|
1543
|
-
if (t.context) {
|
|
1544
|
-
return {
|
|
1545
|
-
matches: t.matches,
|
|
1546
|
-
to: x => ({
|
|
1547
|
-
target: targetConfig,
|
|
1548
|
-
context: resolveTransitionContext(x),
|
|
1549
|
-
reenter: t.reenter
|
|
1550
|
-
}),
|
|
1551
|
-
description: t.description,
|
|
1552
|
-
meta: t.meta,
|
|
1553
|
-
input: t.input !== undefined ? resolveTransitionInput : undefined
|
|
1554
|
-
};
|
|
1555
|
-
}
|
|
1556
|
-
return {
|
|
1557
|
-
matches: t.matches,
|
|
1558
|
-
target: targetConfig,
|
|
1559
|
-
description: t.description,
|
|
1560
|
-
reenter: t.reenter,
|
|
1561
|
-
meta: t.meta,
|
|
1562
|
-
input: t.input !== undefined ? resolveTransitionInput : undefined
|
|
1563
|
-
};
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
// Guard but no actions: static config with guard
|
|
1567
|
-
if (guard && !t.actions?.length) {
|
|
1568
|
-
if (t.context) {
|
|
1569
|
-
return {
|
|
1570
|
-
matches: t.matches,
|
|
1571
|
-
guard,
|
|
1572
|
-
to: x => ({
|
|
1573
|
-
target: targetConfig,
|
|
1574
|
-
context: resolveTransitionContext(x),
|
|
1575
|
-
reenter: t.reenter
|
|
1576
|
-
}),
|
|
1577
|
-
description: t.description,
|
|
1578
|
-
meta: t.meta,
|
|
1579
|
-
input: t.input !== undefined ? resolveTransitionInput : undefined
|
|
1580
|
-
};
|
|
1581
|
-
}
|
|
1582
|
-
return {
|
|
1583
|
-
matches: t.matches,
|
|
1584
|
-
target: targetConfig,
|
|
1585
|
-
guard,
|
|
1586
|
-
description: t.description,
|
|
1587
|
-
reenter: t.reenter,
|
|
1588
|
-
meta: t.meta,
|
|
1589
|
-
input: t.input !== undefined ? resolveTransitionInput : undefined
|
|
1590
|
-
};
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
// Targetless transitions: execute actions directly in .to AND track for
|
|
1594
|
-
// parallel re-execution. For non-parallel, .to result is used directly.
|
|
1595
|
-
// For parallel (entries exist), first entry re-executes all in document order.
|
|
1596
|
-
if (!target) {
|
|
1597
|
-
return {
|
|
1598
|
-
matches: t.matches,
|
|
1599
|
-
guard,
|
|
1600
|
-
description: t.description,
|
|
1601
|
-
reenter: t.reenter,
|
|
1602
|
-
meta: t.meta,
|
|
1603
|
-
input: t.input !== undefined ? resolveTransitionInput : undefined,
|
|
1604
|
-
to: (x, enq) => {
|
|
1605
|
-
const context = resolveTransitionContext(x);
|
|
1606
|
-
if (t.actions?.length) {
|
|
1607
|
-
// Track for parallel re-execution (dedup by reference)
|
|
1608
|
-
if (!allTransitionActions.includes(t.actions)) {
|
|
1609
|
-
allTransitionActions.push(t.actions);
|
|
1610
|
-
}
|
|
1611
|
-
// Save pre-transition context for parallel override
|
|
1612
|
-
contextBeforeTargetless ??= x.context;
|
|
1613
|
-
// Execute immediately (fallback for non-parallel case)
|
|
1614
|
-
const result = executeActions(t.actions, x, enq);
|
|
1615
|
-
if (result.context) {
|
|
1616
|
-
return {
|
|
1617
|
-
context: {
|
|
1618
|
-
...context,
|
|
1619
|
-
...result.context
|
|
1620
|
-
}
|
|
1621
|
-
};
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
return context ? {
|
|
1625
|
-
context
|
|
1626
|
-
} : {};
|
|
1627
|
-
}
|
|
1628
|
-
};
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
// Has target + actions: use guard (for XState evaluation) + .to (for pending actions).
|
|
1632
|
-
// The .to function does NOT re-check the guard — XState's evaluateCandidate
|
|
1633
|
-
// already validated it. The .to just stores actions for entry to execute.
|
|
1634
|
-
// Map by target state ID so parallel transitions each get their own actions.
|
|
491
|
+
const context = item.context ? x => resolveValue(item.context, 'transitionContext', makeScope(x), '$.transition.context') : undefined;
|
|
492
|
+
const input = item.input !== undefined ? x => resolveValue(item.input, 'input', makeScope(x), '$.transition.input') : undefined;
|
|
493
|
+
const dynamic = !!context || !!item.actions?.length;
|
|
1635
494
|
return {
|
|
1636
|
-
matches:
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
const targetId = target.replace(/^#/, '');
|
|
1646
|
-
pendingTransitionActionsMap[targetId] = t.actions;
|
|
1647
|
-
// Track for parallel re-execution (dedup by reference)
|
|
1648
|
-
if (!allTransitionActions.includes(t.actions)) {
|
|
1649
|
-
allTransitionActions.push(t.actions);
|
|
495
|
+
matches: item.matches,
|
|
496
|
+
target: dynamic ? undefined : item.target,
|
|
497
|
+
to: dynamic ? (x, enq) => {
|
|
498
|
+
const resolvedContext = context?.(x);
|
|
499
|
+
const result = item.actions?.length ? executeActions(item.actions, resolvedContext ? {
|
|
500
|
+
...x,
|
|
501
|
+
context: {
|
|
502
|
+
...x.context,
|
|
503
|
+
...resolvedContext
|
|
1650
504
|
}
|
|
1651
|
-
}
|
|
505
|
+
} : x, enq) : undefined;
|
|
1652
506
|
return {
|
|
1653
|
-
target:
|
|
1654
|
-
context,
|
|
1655
|
-
reenter:
|
|
507
|
+
target: item.target,
|
|
508
|
+
context: result?.context ?? resolvedContext,
|
|
509
|
+
reenter: item.reenter
|
|
1656
510
|
};
|
|
1657
|
-
}
|
|
511
|
+
} : undefined,
|
|
512
|
+
guard: resolveCondition(item.guard, 'guard', '$.transition.guard'),
|
|
513
|
+
description: item.description,
|
|
514
|
+
reenter: item.reenter,
|
|
515
|
+
meta: item.meta,
|
|
516
|
+
input
|
|
1658
517
|
};
|
|
1659
518
|
});
|
|
1660
519
|
}
|
|
520
|
+
function iterInvokeConfigs(invokes) {
|
|
521
|
+
return (Array.isArray(invokes) ? invokes : [invokes]).map(inv => ({
|
|
522
|
+
src: resolvedSources.actors[inv.src] ?? inv.src,
|
|
523
|
+
id: inv.id,
|
|
524
|
+
registryKey: inv.registryKey,
|
|
525
|
+
input: inv.input !== undefined ? args => resolveValue(inv.input, 'input', makeScope(args), '$.invoke.input') : undefined,
|
|
526
|
+
onDone: inv.onDone ? getTransitionConfig(inv.onDone) : undefined,
|
|
527
|
+
onError: inv.onError ? getTransitionConfig(inv.onError) : undefined,
|
|
528
|
+
onSnapshot: inv.onSnapshot ? getTransitionConfig(inv.onSnapshot) : undefined,
|
|
529
|
+
timeout: getDurationConfig(inv.timeout, '$.invoke.timeout'),
|
|
530
|
+
onTimeout: inv.onTimeout ? getTransitionConfig(inv.onTimeout) : undefined
|
|
531
|
+
}));
|
|
532
|
+
}
|
|
533
|
+
function iterNode(node, nodeKey) {
|
|
534
|
+
return {
|
|
535
|
+
id: node.id,
|
|
536
|
+
initial: node.initial,
|
|
537
|
+
type: node.type,
|
|
538
|
+
history: node.history,
|
|
539
|
+
target: node.target,
|
|
540
|
+
description: node.description,
|
|
541
|
+
tags: node.tags,
|
|
542
|
+
input: node.input,
|
|
543
|
+
timeout: getDurationConfig(node.timeout, `$.states.${nodeKey}.timeout`),
|
|
544
|
+
states: node.states ? Object.fromEntries(Object.entries(node.states).map(([key, value]) => [key, iterNode(value, key)])) : undefined,
|
|
545
|
+
on: node.on ? Object.fromEntries(Object.entries(node.on).map(([key, value]) => [key, getTransitionConfig(value)])) : undefined,
|
|
546
|
+
always: node.always ? getTransitionConfig(node.always) : undefined,
|
|
547
|
+
onError: node.onError ? getTransitionConfig(node.onError) : undefined,
|
|
548
|
+
choice: makeChoiceConfig(node.choice, `$.states.${nodeKey}.choice`),
|
|
549
|
+
route: resolveRouteConfig(node.route, `$.states.${nodeKey}.route`),
|
|
550
|
+
after: node.after ? Object.fromEntries(Object.entries(node.after).map(([key, value]) => [key, getTransitionConfig(value)])) : undefined,
|
|
551
|
+
onTimeout: node.onTimeout ? getTransitionConfig(node.onTimeout) : undefined,
|
|
552
|
+
entry: node.entry ? iterActions(node.entry) : undefined,
|
|
553
|
+
exit: node.exit ? iterActions(node.exit) : undefined,
|
|
554
|
+
invoke: node.invoke ? iterInvokeConfigs(node.invoke) : undefined,
|
|
555
|
+
meta: node.meta,
|
|
556
|
+
output: isResolvable(node.output) ? ({
|
|
557
|
+
context,
|
|
558
|
+
event,
|
|
559
|
+
self
|
|
560
|
+
}) => evaluateResolvable(node.output, 'output', {
|
|
561
|
+
context,
|
|
562
|
+
event,
|
|
563
|
+
self
|
|
564
|
+
}, `$.states.${nodeKey}.output`) : node.output
|
|
565
|
+
};
|
|
566
|
+
}
|
|
1661
567
|
if (json.delays) {
|
|
1662
|
-
for (const key of Object.
|
|
1663
|
-
|
|
1664
|
-
if (typeof delay === 'number') {
|
|
1665
|
-
resolvedSources.delays[key] = delay;
|
|
1666
|
-
} else if (typeof delay === 'string') {
|
|
1667
|
-
resolvedSources.delays[key] = delayToMs(delay);
|
|
1668
|
-
} else if (delay && typeof delay === 'object') {
|
|
568
|
+
for (const [key, delay] of Object.entries(json.delays)) {
|
|
569
|
+
if (typeof delay === 'number') resolvedSources.delays[key] = delay;else if (typeof delay === 'string') resolvedSources.delays[key] = delayToMs(delay);else if (delay && typeof delay === 'object') {
|
|
1669
570
|
resolvedSources.delays[key] = args => delayToMs(resolveValue(delay.duration, 'delay', makeScope(args), `$.delays.${key}.duration`));
|
|
1670
571
|
}
|
|
1671
572
|
}
|
|
1672
573
|
}
|
|
1673
574
|
assertMachineJSON(json, resolvedSources, expressionResolver);
|
|
1674
|
-
const rootNodeConfig = iterNode(json);
|
|
1675
575
|
const contextConfig = json.context ? {
|
|
1676
576
|
context: args => resolveValue(json.context, 'context', args, '$.context')
|
|
1677
577
|
} : {};
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
const machine = createMachine({
|
|
1681
|
-
...rootNodeConfig,
|
|
578
|
+
const machine = types$1.createMachine({
|
|
579
|
+
...iterNode(json),
|
|
1682
580
|
...contextConfig,
|
|
1683
581
|
version: json.version
|
|
1684
582
|
});
|
|
1685
|
-
|
|
1686
|
-
// Register SCXML guard sources
|
|
1687
|
-
const providedGuards = {
|
|
1688
|
-
'scxml.cond': ({
|
|
1689
|
-
context,
|
|
1690
|
-
event,
|
|
1691
|
-
self
|
|
1692
|
-
}, params) => {
|
|
1693
|
-
const expr = params?.expr;
|
|
1694
|
-
if (!expr) return true;
|
|
1695
|
-
try {
|
|
1696
|
-
return !!evaluateExpr(context, expr, event, self);
|
|
1697
|
-
} catch (err) {
|
|
1698
|
-
// Per SCXML spec, a cond that fails to evaluate is treated as false
|
|
1699
|
-
// AND raises error.execution. We can't enqueue from a guard, so
|
|
1700
|
-
// queue it for the next entry to drain.
|
|
1701
|
-
const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
|
|
1702
|
-
pendingPlatformErrors.push({
|
|
1703
|
-
tagname: 'cond',
|
|
1704
|
-
message,
|
|
1705
|
-
line: NaN,
|
|
1706
|
-
column: NaN,
|
|
1707
|
-
reason: message
|
|
1708
|
-
});
|
|
1709
|
-
return false;
|
|
1710
|
-
}
|
|
1711
|
-
},
|
|
1712
|
-
'xstate.stateIn': (args, params) => {
|
|
1713
|
-
const stateId = params?.stateId;
|
|
1714
|
-
if (!stateId) return false;
|
|
1715
|
-
const normalizedId = stateId.replace(/^#/, '');
|
|
1716
|
-
const snapshot = args._snapshot;
|
|
1717
|
-
if (snapshot?.nodes) {
|
|
1718
|
-
return snapshot.nodes.some(node => node.id === normalizedId);
|
|
1719
|
-
}
|
|
1720
|
-
return false;
|
|
1721
|
-
},
|
|
1722
|
-
'xstate.not': (args, params) => {
|
|
1723
|
-
const inner = params?.guard;
|
|
1724
|
-
const innerImpl = inner && args.guards?.[inner.type];
|
|
1725
|
-
if (!innerImpl) {
|
|
1726
|
-
throw new Error(`Guard '${inner?.type}' referenced by 'xstate.not' is not implemented.`);
|
|
1727
|
-
}
|
|
1728
|
-
return !innerImpl(args, inner.params);
|
|
1729
|
-
}
|
|
1730
|
-
};
|
|
1731
583
|
const provided = machine.provide({
|
|
1732
584
|
actions: resolvedSources.actions,
|
|
1733
585
|
actors: resolvedSources.actors,
|
|
1734
586
|
guards: {
|
|
1735
|
-
|
|
587
|
+
'xstate.stateIn': (args, params) => {
|
|
588
|
+
const stateId = params?.stateId;
|
|
589
|
+
const snapshot = args._snapshot;
|
|
590
|
+
return !!stateId && !!snapshot?.nodes?.some(node => node.id === stateId.replace(/^#/, ''));
|
|
591
|
+
},
|
|
592
|
+
'xstate.not': (args, params) => {
|
|
593
|
+
const inner = params?.guard;
|
|
594
|
+
const impl = inner && args.guards?.[inner.type];
|
|
595
|
+
if (!impl) throw new Error(`Guard '${inner?.type}' referenced by 'xstate.not' is not implemented.`);
|
|
596
|
+
return !impl(args, inner.params);
|
|
597
|
+
},
|
|
1736
598
|
...resolvedSources.guards
|
|
1737
599
|
},
|
|
1738
600
|
delays: resolvedSources.delays
|
|
1739
601
|
});
|
|
1740
|
-
|
|
1741
|
-
// Keep the original JSON so `serializeMachine(machine)`
|
|
1742
|
-
// round-trip losslessly.
|
|
1743
602
|
provided._json = json;
|
|
1744
603
|
return provided;
|
|
1745
604
|
}
|
|
@@ -2628,134 +1487,6 @@ function toPromise(actor) {
|
|
|
2628
1487
|
});
|
|
2629
1488
|
}
|
|
2630
1489
|
|
|
2631
|
-
// this is needed to make JSDoc `@link` work properly
|
|
2632
|
-
// oxlint-disable-next-line no-unused-vars
|
|
2633
|
-
|
|
2634
|
-
/**
|
|
2635
|
-
* @remarks
|
|
2636
|
-
* `T | unknown` reduces to `unknown` and that can be problematic when it comes
|
|
2637
|
-
* to contextual typing. It especially is a problem when the union has a
|
|
2638
|
-
* function member, like here:
|
|
2639
|
-
*
|
|
2640
|
-
* ```ts
|
|
2641
|
-
* declare function test(
|
|
2642
|
-
* cbOrVal: ((arg: number) => unknown) | unknown
|
|
2643
|
-
* ): void;
|
|
2644
|
-
* test((arg) => {}); // oops, implicit any
|
|
2645
|
-
* ```
|
|
2646
|
-
*
|
|
2647
|
-
* This type can be used to avoid this problem. This union represents the same
|
|
2648
|
-
* value space as `unknown`.
|
|
2649
|
-
*/
|
|
2650
|
-
|
|
2651
|
-
// https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379091887
|
|
2652
|
-
|
|
2653
|
-
// @TODO: we can't use native `NoInfer` as we need those:
|
|
2654
|
-
// https://github.com/microsoft/TypeScript/pull/61092
|
|
2655
|
-
// https://github.com/microsoft/TypeScript/pull/61077
|
|
2656
|
-
// but even with those fixes native NoInfer still doesn't work - further issues have to be reproduced and fixed
|
|
2657
|
-
|
|
2658
|
-
/** @deprecated Use the built-in `NoInfer` type instead */
|
|
2659
|
-
|
|
2660
|
-
/** The full definition of an event, with a string `type`. */
|
|
2661
|
-
|
|
2662
|
-
/**
|
|
2663
|
-
* The string or object representing the state value relative to the parent
|
|
2664
|
-
* state node.
|
|
2665
|
-
*
|
|
2666
|
-
* @remarks
|
|
2667
|
-
* - For a child atomic state node, this is a string, e.g., `"pending"`.
|
|
2668
|
-
* - For complex state nodes, this is an object, e.g., `{ success:
|
|
2669
|
-
* "someChildState" }`.
|
|
2670
|
-
*/
|
|
2671
|
-
|
|
2672
|
-
// Accept any StateNode instance regardless of generic parameters
|
|
2673
|
-
// Using a union type to handle variance issues with machine.resolveState
|
|
2674
|
-
|
|
2675
|
-
let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
|
|
2676
|
-
SpecialTargets["Internal"] = "#_internal";
|
|
2677
|
-
return SpecialTargets;
|
|
2678
|
-
}({});
|
|
2679
|
-
|
|
2680
|
-
/** A deterministic delayed-delivery declaration owned by a logic snapshot. */
|
|
2681
|
-
|
|
2682
|
-
/** The logical input delivered to a timer's source when its runtime delay ends. */
|
|
2683
|
-
|
|
2684
|
-
/** A persisted snapshot tied to a versioned actor logic identity. */
|
|
2685
|
-
|
|
2686
|
-
/**
|
|
2687
|
-
* A persisted snapshot restorable into the given actor logic: any snapshot
|
|
2688
|
-
* created by logic with the same machine `id` is accepted, regardless of
|
|
2689
|
-
* version (version mismatches are handled at runtime, e.g. by `migrate`).
|
|
2690
|
-
*/
|
|
2691
|
-
|
|
2692
|
-
/** @deprecated Use `AnyActor` instead. */
|
|
2693
|
-
|
|
2694
|
-
// Based on RxJS types
|
|
2695
|
-
|
|
2696
|
-
/**
|
|
2697
|
-
* A consumer-facing actor handle.
|
|
2698
|
-
*
|
|
2699
|
-
* `ActorRef` describes the contract a consumer needs: which events can be sent
|
|
2700
|
-
* to the actor, which snapshot it publishes for observation, and which emitted
|
|
2701
|
-
* events can be listened to. It intentionally does not expose lifecycle control
|
|
2702
|
-
* or runtime internals. A concrete `Actor` satisfies this interface, so APIs
|
|
2703
|
-
* should accept `ActorRef` whenever they only need to send events, read
|
|
2704
|
-
* snapshots, or listen to emitted events.
|
|
2705
|
-
*/
|
|
2706
|
-
|
|
2707
|
-
/**
|
|
2708
|
-
* Runtime-only actor capabilities.
|
|
2709
|
-
*
|
|
2710
|
-
* These members are needed by the interpreter, scheduler, inspection, and child
|
|
2711
|
-
* management code. Public consumer APIs should prefer `ActorRef` unless they
|
|
2712
|
-
* genuinely need lifecycle control such as starting, stopping, or accessing
|
|
2713
|
-
* system-owned runtime state.
|
|
2714
|
-
*/
|
|
2715
|
-
|
|
2716
|
-
/**
|
|
2717
|
-
* A concrete actor instance type.
|
|
2718
|
-
*
|
|
2719
|
-
* `ActorInstance` combines the consumer `ActorRef` contract with runtime
|
|
2720
|
-
* lifecycle capabilities. Values returned by `createActor(...)` and
|
|
2721
|
-
* `spawn(...)` naturally satisfy narrower `ActorRef` contracts.
|
|
2722
|
-
*/
|
|
2723
|
-
|
|
2724
|
-
/**
|
|
2725
|
-
* The actor's own full self handle.
|
|
2726
|
-
*
|
|
2727
|
-
* Internals and action/guard sources receive this shape because `self` can
|
|
2728
|
-
* participate in runtime-owned behavior while still being usable wherever an
|
|
2729
|
-
* `ActorRef` is expected.
|
|
2730
|
-
*/
|
|
2731
|
-
|
|
2732
|
-
// TODO: in v6, this should only accept AnyActorLogic, like ActorRefFromLogic
|
|
2733
|
-
|
|
2734
|
-
/** The concrete actor instance type produced from actor logic. */
|
|
2735
|
-
|
|
2736
|
-
/**
|
|
2737
|
-
* Represents logic which can be used by an actor.
|
|
2738
|
-
*
|
|
2739
|
-
* @template TSnapshot - The type of the snapshot.
|
|
2740
|
-
* @template TEvent - The type of the event object.
|
|
2741
|
-
* @template TInput - The type of the input.
|
|
2742
|
-
* @template TSystem - The type of the actor system.
|
|
2743
|
-
*/
|
|
2744
|
-
|
|
2745
|
-
// Actors that don't have literal string IDs — these are the only ones
|
|
2746
|
-
// that should appear in the index signature fallback, since actors with
|
|
2747
|
-
// literal IDs are already covered by ToConcreteChildren.
|
|
2748
|
-
|
|
2749
|
-
/** Maps state IDs to their input types based on the StateSchema. */
|
|
2750
|
-
|
|
2751
|
-
/** @deprecated */
|
|
2752
|
-
|
|
2753
|
-
/** The terminal result published when an actor completes or errors. */
|
|
2754
|
-
|
|
2755
|
-
/** An executable effect that publishes an actor's terminal result. */
|
|
2756
|
-
|
|
2757
|
-
/** Mappers for subscribeTo - maps lifecycle events to machine events */
|
|
2758
|
-
|
|
2759
1490
|
const defaultWaitForOptions = {
|
|
2760
1491
|
timeout: Infinity // much more than 10 seconds
|
|
2761
1492
|
};
|
|
@@ -2888,6 +1619,10 @@ exports.stopActor = createActor.stopActor;
|
|
|
2888
1619
|
exports.subscriptionLogic = createActor.subscriptionLogic;
|
|
2889
1620
|
exports.terminateActor = createActor.terminateActor;
|
|
2890
1621
|
exports.toObserver = createActor.toObserver;
|
|
1622
|
+
exports.SpecialTargets = types$1.SpecialTargets;
|
|
1623
|
+
exports.createMachine = types$1.createMachine;
|
|
1624
|
+
exports.createStateConfig = types$1.createStateConfig;
|
|
1625
|
+
exports.createFSM = fsm.createFSM;
|
|
2891
1626
|
exports.StateMachine = StateMachine.StateMachine;
|
|
2892
1627
|
exports.StateNode = StateMachine.StateNode;
|
|
2893
1628
|
exports.getEffectDescriptor = effectDescriptor.getEffectDescriptor;
|
|
@@ -2897,12 +1632,8 @@ exports.getNextTransitions = effectDescriptor.getNextTransitions;
|
|
|
2897
1632
|
exports.initialTransition = effectDescriptor.initialTransition;
|
|
2898
1633
|
exports.transition = effectDescriptor.transition;
|
|
2899
1634
|
exports.SimulatedClock = SimulatedClock;
|
|
2900
|
-
exports.SpecialTargets = SpecialTargets;
|
|
2901
1635
|
exports.assertEvent = assertEvent;
|
|
2902
|
-
exports.createFSM = createFSM;
|
|
2903
|
-
exports.createMachine = createMachine;
|
|
2904
1636
|
exports.createMachineFromConfig = createMachineFromConfig;
|
|
2905
|
-
exports.createStateConfig = createStateConfig;
|
|
2906
1637
|
exports.createSystem = createSystem;
|
|
2907
1638
|
exports.isTypeSchema = isTypeSchema;
|
|
2908
1639
|
exports.machineConfigToJSON = machineConfigToJSON;
|