xstate 6.0.0-alpha.2 → 6.0.0-alpha.21
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 +19 -17
- package/bin/xstate.js +36 -0
- package/dist/{StateMachine-64813f46.cjs.js → StateMachine-1b155670.cjs.js} +182 -40
- package/dist/{StateMachine-2dcdb1f5.esm.js → StateMachine-3c17fe3e.esm.js} +182 -40
- package/dist/{StateMachine-8d22a79c.development.cjs.js → StateMachine-550ff7f2.development.cjs.js} +193 -36
- package/dist/{StateMachine-2ea0a7fa.development.esm.js → StateMachine-e25dd61f.development.esm.js} +193 -36
- package/dist/declarations/src/State.d.ts +13 -2
- package/dist/declarations/src/StateMachine.d.ts +23 -13
- package/dist/declarations/src/actions.d.ts +2 -1
- package/dist/declarations/src/actors/promise.d.ts +4 -2
- package/dist/declarations/src/createActor.d.ts +9 -11
- package/dist/declarations/src/createMachine.d.ts +14 -11
- package/dist/declarations/src/createMachineFromConfig.d.ts +61 -28
- package/dist/declarations/src/fsm.d.ts +74 -0
- package/dist/declarations/src/graph/graph.d.ts +3 -3
- package/dist/declarations/src/graph/shortestPaths.d.ts +2 -2
- package/dist/declarations/src/graph/simplePaths.d.ts +2 -2
- package/dist/declarations/src/index.d.ts +6 -5
- package/dist/declarations/src/serialize.d.ts +10 -18
- package/dist/declarations/src/setup.d.ts +277 -65
- package/dist/declarations/src/spawn.d.ts +3 -3
- package/dist/declarations/src/stateUtils.d.ts +4 -1
- package/dist/declarations/src/system.d.ts +1 -1
- package/dist/declarations/src/transition.d.ts +8 -5
- package/dist/declarations/src/transitionActions.d.ts +12 -0
- package/dist/declarations/src/types.d.ts +237 -102
- package/dist/declarations/src/types.v6.d.ts +132 -58
- package/dist/declarations/src/utils.d.ts +4 -3
- package/dist/{index-93edd3bd.esm.js → index-3f87408c.esm.js} +936 -1389
- package/dist/{index-e61170ba.development.esm.js → index-d39fb138.development.esm.js} +968 -1421
- package/dist/{index-9cb3b3a0.cjs.js → index-e694228c.cjs.js} +945 -1394
- package/dist/{index-f6ef20d1.development.cjs.js → index-ec7c7a2d.development.cjs.js} +977 -1426
- package/dist/xstate-actors.cjs.js +1 -1
- package/dist/xstate-actors.development.cjs.js +1 -1
- package/dist/xstate-actors.development.esm.js +1 -1
- package/dist/xstate-actors.esm.js +1 -1
- package/dist/xstate-actors.umd.min.js +1 -1
- package/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/xstate-graph.cjs.js +2 -2
- package/dist/xstate-graph.development.cjs.js +2 -2
- package/dist/xstate-graph.development.esm.js +2 -2
- package/dist/xstate-graph.esm.js +2 -2
- package/dist/xstate-graph.umd.min.js +1 -1
- package/dist/xstate-graph.umd.min.js.map +1 -1
- package/dist/xstate.cjs.js +1100 -182
- package/dist/xstate.cjs.mjs +3 -5
- package/dist/xstate.development.cjs.js +1100 -182
- package/dist/xstate.development.cjs.mjs +3 -5
- package/dist/xstate.development.esm.js +1101 -181
- package/dist/xstate.esm.js +1101 -181
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/package.json +6 -2
- package/dist/declarations/src/atom.d.ts +0 -81
package/README.md
CHANGED
|
@@ -119,7 +119,7 @@ npm install xstate
|
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
```ts
|
|
122
|
-
import { createMachine, createActor
|
|
122
|
+
import { createMachine, createActor } from 'xstate';
|
|
123
123
|
|
|
124
124
|
// State machine
|
|
125
125
|
const toggleMachine = createMachine({
|
|
@@ -135,7 +135,9 @@ const toggleMachine = createMachine({
|
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
active: {
|
|
138
|
-
entry:
|
|
138
|
+
entry: ({ context }) => ({
|
|
139
|
+
context: { count: context.count + 1 }
|
|
140
|
+
}),
|
|
139
141
|
on: {
|
|
140
142
|
TOGGLE: { target: 'inactive' }
|
|
141
143
|
}
|
|
@@ -164,7 +166,7 @@ toggleActor.send({ type: 'TOGGLE' });
|
|
|
164
166
|
- Deploy to Stately Sky
|
|
165
167
|
- Generate & modify machines with Stately AI
|
|
166
168
|
|
|
167
|
-
<a href="stately.ai/registry/new?ref=github" title="Stately Studio">
|
|
169
|
+
<a href="https://stately.ai/registry/new?ref=github" title="Stately Studio">
|
|
168
170
|
<img src="https://github.com/statelyai/xstate/assets/1093738/74ed9cbc-b824-4ed7-a16d-f104947af8a7" alt="XState Viz" width="800" />
|
|
169
171
|
</a>
|
|
170
172
|
|
|
@@ -365,10 +367,10 @@ const wordMachine = createMachine({
|
|
|
365
367
|
initial: 'off',
|
|
366
368
|
states: {
|
|
367
369
|
on: {
|
|
368
|
-
on: { TOGGLE_BOLD: 'off' }
|
|
370
|
+
on: { TOGGLE_BOLD: { target: 'off' } }
|
|
369
371
|
},
|
|
370
372
|
off: {
|
|
371
|
-
on: { TOGGLE_BOLD: 'on' }
|
|
373
|
+
on: { TOGGLE_BOLD: { target: 'on' } }
|
|
372
374
|
}
|
|
373
375
|
}
|
|
374
376
|
},
|
|
@@ -376,10 +378,10 @@ const wordMachine = createMachine({
|
|
|
376
378
|
initial: 'off',
|
|
377
379
|
states: {
|
|
378
380
|
on: {
|
|
379
|
-
on: { TOGGLE_UNDERLINE: 'off' }
|
|
381
|
+
on: { TOGGLE_UNDERLINE: { target: 'off' } }
|
|
380
382
|
},
|
|
381
383
|
off: {
|
|
382
|
-
on: { TOGGLE_UNDERLINE: 'on' }
|
|
384
|
+
on: { TOGGLE_UNDERLINE: { target: 'on' } }
|
|
383
385
|
}
|
|
384
386
|
}
|
|
385
387
|
},
|
|
@@ -387,10 +389,10 @@ const wordMachine = createMachine({
|
|
|
387
389
|
initial: 'off',
|
|
388
390
|
states: {
|
|
389
391
|
on: {
|
|
390
|
-
on: { TOGGLE_ITALICS: 'off' }
|
|
392
|
+
on: { TOGGLE_ITALICS: { target: 'off' } }
|
|
391
393
|
},
|
|
392
394
|
off: {
|
|
393
|
-
on: { TOGGLE_ITALICS: 'on' }
|
|
395
|
+
on: { TOGGLE_ITALICS: { target: 'on' } }
|
|
394
396
|
}
|
|
395
397
|
}
|
|
396
398
|
},
|
|
@@ -399,20 +401,20 @@ const wordMachine = createMachine({
|
|
|
399
401
|
states: {
|
|
400
402
|
none: {
|
|
401
403
|
on: {
|
|
402
|
-
BULLETS: 'bullets',
|
|
403
|
-
NUMBERS: 'numbers'
|
|
404
|
+
BULLETS: { target: 'bullets' },
|
|
405
|
+
NUMBERS: { target: 'numbers' }
|
|
404
406
|
}
|
|
405
407
|
},
|
|
406
408
|
bullets: {
|
|
407
409
|
on: {
|
|
408
|
-
NONE: 'none',
|
|
409
|
-
NUMBERS: 'numbers'
|
|
410
|
+
NONE: { target: 'none' },
|
|
411
|
+
NUMBERS: { target: 'numbers' }
|
|
410
412
|
}
|
|
411
413
|
},
|
|
412
414
|
numbers: {
|
|
413
415
|
on: {
|
|
414
|
-
BULLETS: 'bullets',
|
|
415
|
-
NONE: 'none'
|
|
416
|
+
BULLETS: { target: 'bullets' },
|
|
417
|
+
NONE: { target: 'none' }
|
|
416
418
|
}
|
|
417
419
|
}
|
|
418
420
|
}
|
|
@@ -493,10 +495,10 @@ const paymentMachine = createMachine({
|
|
|
493
495
|
},
|
|
494
496
|
hist: { type: 'history' }
|
|
495
497
|
},
|
|
496
|
-
on: { NEXT: 'review' }
|
|
498
|
+
on: { NEXT: { target: 'review' } }
|
|
497
499
|
},
|
|
498
500
|
review: {
|
|
499
|
-
on: { PREVIOUS: 'method.hist' }
|
|
501
|
+
on: { PREVIOUS: { target: 'method.hist' } }
|
|
500
502
|
}
|
|
501
503
|
}
|
|
502
504
|
});
|
package/bin/xstate.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Lightweight `xstate` CLI. Heavy commands are delegated to dedicated
|
|
3
|
+
// packages fetched on demand so the core package stays dependency-free.
|
|
4
|
+
const { spawnSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
7
|
+
|
|
8
|
+
switch (command) {
|
|
9
|
+
case 'migrate': {
|
|
10
|
+
// Delegates to @xstate/codemod (ts-morph based v5 → v6 codemods).
|
|
11
|
+
const result = spawnSync(
|
|
12
|
+
process.platform === 'win32' ? 'npx.cmd' : 'npx',
|
|
13
|
+
['-y', '@xstate/codemod', 'migrate', ...rest],
|
|
14
|
+
{ stdio: 'inherit' }
|
|
15
|
+
);
|
|
16
|
+
process.exit(result.status ?? 1);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
case '--help':
|
|
20
|
+
case 'help':
|
|
21
|
+
case undefined:
|
|
22
|
+
console.log(
|
|
23
|
+
[
|
|
24
|
+
'Usage: xstate <command>',
|
|
25
|
+
'',
|
|
26
|
+
'Commands:',
|
|
27
|
+
' migrate [globs...] [--dry] Migrate source files to the current XState version',
|
|
28
|
+
' (delegates to @xstate/codemod)'
|
|
29
|
+
].join('\n')
|
|
30
|
+
);
|
|
31
|
+
process.exit(command ? 0 : 1);
|
|
32
|
+
break;
|
|
33
|
+
default:
|
|
34
|
+
console.error(`Unknown command: ${command}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var dist_xstateActors = require('./index-
|
|
3
|
+
var dist_xstateActors = require('./index-e694228c.cjs.js');
|
|
4
4
|
|
|
5
5
|
function createSpawner(actorScope, {
|
|
6
6
|
machine,
|
|
@@ -22,7 +22,7 @@ function createSpawner(actorScope, {
|
|
|
22
22
|
self: actorScope.self
|
|
23
23
|
}) : options?.input,
|
|
24
24
|
src,
|
|
25
|
-
|
|
25
|
+
registryKey: options?.registryKey
|
|
26
26
|
});
|
|
27
27
|
spawnedChildren[actor.id] = actor;
|
|
28
28
|
return actor;
|
|
@@ -33,7 +33,7 @@ function createSpawner(actorScope, {
|
|
|
33
33
|
syncSnapshot: options?.syncSnapshot,
|
|
34
34
|
input: options?.input,
|
|
35
35
|
src,
|
|
36
|
-
|
|
36
|
+
registryKey: options?.registryKey
|
|
37
37
|
});
|
|
38
38
|
return actor;
|
|
39
39
|
}
|
|
@@ -66,7 +66,6 @@ function memo(object, key, fn) {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
const EMPTY_OBJECT = {};
|
|
69
|
-
const CHOICE_CONFIG_KEYS = ['invoke', 'after', 'on', 'entry', 'exit', 'always', 'states', 'initial', 'onDone', 'timeout', 'onTimeout', 'history', 'target', 'output'];
|
|
70
69
|
class StateNode {
|
|
71
70
|
constructor(/** The raw config used to create the machine. */
|
|
72
71
|
config, options) {
|
|
@@ -173,7 +172,7 @@ class StateNode {
|
|
|
173
172
|
this.invoke = dist_xstateActors.toArray(this.config.invoke).map((invokeConfig, i) => {
|
|
174
173
|
const {
|
|
175
174
|
src,
|
|
176
|
-
|
|
175
|
+
registryKey
|
|
177
176
|
} = invokeConfig;
|
|
178
177
|
const invokeId = dist_xstateActors.createInvokeId(this.id, i);
|
|
179
178
|
const resolvedId = invokeConfig.id ?? invokeId;
|
|
@@ -186,7 +185,7 @@ class StateNode {
|
|
|
186
185
|
src: sourceName,
|
|
187
186
|
logic: src,
|
|
188
187
|
id: resolvedId,
|
|
189
|
-
|
|
188
|
+
registryKey
|
|
190
189
|
};
|
|
191
190
|
});
|
|
192
191
|
}
|
|
@@ -246,30 +245,17 @@ class StateNode {
|
|
|
246
245
|
function validateStateNodeConfig(stateNode) {
|
|
247
246
|
const config = stateNode.config;
|
|
248
247
|
if (stateNode.type !== 'choice') {
|
|
249
|
-
if (config.choice !== undefined) {
|
|
250
|
-
throw new Error(`State "${stateNode.id}" has \`choice\`, but \`choice\` can only be used with \`type: 'choice'\`.`);
|
|
251
|
-
}
|
|
252
248
|
return;
|
|
253
249
|
}
|
|
254
250
|
if (typeof config.choice !== 'function') {
|
|
255
|
-
throw new Error(`
|
|
256
|
-
}
|
|
257
|
-
for (const key of CHOICE_CONFIG_KEYS) {
|
|
258
|
-
if (config[key] !== undefined) {
|
|
259
|
-
throw new Error(`Choice state "${stateNode.id}" cannot declare \`${key}\`.`);
|
|
260
|
-
}
|
|
251
|
+
throw new Error(`Missing \`choice\` function on "${stateNode.id}"`);
|
|
261
252
|
}
|
|
262
253
|
}
|
|
263
254
|
function formatChoiceTransitions(stateNode) {
|
|
264
255
|
const choice = stateNode.config.choice;
|
|
265
256
|
const validateChoiceResult = result => {
|
|
266
257
|
if (!result || result.target === undefined) {
|
|
267
|
-
throw new Error(`Choice
|
|
268
|
-
}
|
|
269
|
-
for (const key of ['actions', 'to', 'context']) {
|
|
270
|
-
if (result[key] !== undefined) {
|
|
271
|
-
throw new Error(`Choice state "${stateNode.id}" cannot declare \`${key}\` on a choice.`);
|
|
272
|
-
}
|
|
258
|
+
throw new Error(`Choice "${stateNode.id}" has no target`);
|
|
273
259
|
}
|
|
274
260
|
return result;
|
|
275
261
|
};
|
|
@@ -290,7 +276,7 @@ function formatTransitions(stateNode) {
|
|
|
290
276
|
if (stateNode.config.on) {
|
|
291
277
|
for (const descriptor of Object.keys(stateNode.config.on)) {
|
|
292
278
|
if (descriptor === dist_xstateActors.NULL_EVENT) {
|
|
293
|
-
throw new Error('Null
|
|
279
|
+
throw new Error('Null event transition key');
|
|
294
280
|
}
|
|
295
281
|
const transitionsConfig = stateNode.config.on[descriptor];
|
|
296
282
|
transitions.set(descriptor, mapTransitionConfigs(transitionsConfig, transition => dist_xstateActors.formatTransition(stateNode, descriptor, transition)));
|
|
@@ -300,6 +286,10 @@ function formatTransitions(stateNode) {
|
|
|
300
286
|
const descriptor = `xstate.done.state.${stateNode.id}`;
|
|
301
287
|
transitions.set(descriptor, mapTransitionConfigs(stateNode.config.onDone, transition => dist_xstateActors.formatTransition(stateNode, descriptor, transition)));
|
|
302
288
|
}
|
|
289
|
+
if (stateNode.config.onError) {
|
|
290
|
+
const descriptor = 'xstate.error.*';
|
|
291
|
+
transitions.set(descriptor, mapTransitionConfigs(stateNode.config.onError, transition => dist_xstateActors.formatTransition(stateNode, descriptor, transition)));
|
|
292
|
+
}
|
|
303
293
|
const createCancelInvokeTimeoutTransition = (descriptor, timeoutEventType) => dist_xstateActors.formatTransition(stateNode, descriptor, {
|
|
304
294
|
to: (_args, enq) => {
|
|
305
295
|
enq.cancel(timeoutEventType);
|
|
@@ -386,7 +376,7 @@ function formatInitialTransition(stateNode, _target) {
|
|
|
386
376
|
const input = typeof _target === 'object' && _target !== null ? _target.input : undefined;
|
|
387
377
|
const resolvedTarget = typeof targetString === 'string' ? stateNode.states[targetString] : undefined;
|
|
388
378
|
if (!resolvedTarget && targetString) {
|
|
389
|
-
throw new Error(`Initial state
|
|
379
|
+
throw new Error(`Initial state "${targetString}" not found on "#${stateNode.id}"`);
|
|
390
380
|
}
|
|
391
381
|
const transition = {
|
|
392
382
|
source: stateNode,
|
|
@@ -397,6 +387,45 @@ function formatInitialTransition(stateNode, _target) {
|
|
|
397
387
|
}
|
|
398
388
|
|
|
399
389
|
const STATE_IDENTIFIER = '#';
|
|
390
|
+
let emptyCanActor;
|
|
391
|
+
let emptyCanActorScope;
|
|
392
|
+
function getEmptyCanActor() {
|
|
393
|
+
// A minimal inert actor used purely as the `self`/`parent` argument when
|
|
394
|
+
// dry-running transitions for `snapshot.can(...)`. Intentionally not built
|
|
395
|
+
// on `createLogic` so `can()` does not pull that machinery into bundles.
|
|
396
|
+
return emptyCanActor ??= dist_xstateActors.createActor({
|
|
397
|
+
transition: snapshot => [snapshot, []],
|
|
398
|
+
initialTransition: () => [{
|
|
399
|
+
status: 'active',
|
|
400
|
+
output: undefined,
|
|
401
|
+
error: undefined
|
|
402
|
+
}, []],
|
|
403
|
+
getInitialSnapshot: () => ({
|
|
404
|
+
status: 'active',
|
|
405
|
+
output: undefined,
|
|
406
|
+
error: undefined
|
|
407
|
+
}),
|
|
408
|
+
getPersistedSnapshot: snapshot => snapshot
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
function getEmptyCanActorScope() {
|
|
412
|
+
if (emptyCanActorScope) {
|
|
413
|
+
return emptyCanActorScope;
|
|
414
|
+
}
|
|
415
|
+
const actor = getEmptyCanActor();
|
|
416
|
+
emptyCanActorScope = {
|
|
417
|
+
self: actor,
|
|
418
|
+
logger: () => {},
|
|
419
|
+
id: '',
|
|
420
|
+
sessionId: '',
|
|
421
|
+
defer: () => {},
|
|
422
|
+
system: actor.system,
|
|
423
|
+
stopChild: () => {},
|
|
424
|
+
emit: () => {},
|
|
425
|
+
actionExecutor: () => {}
|
|
426
|
+
};
|
|
427
|
+
return emptyCanActorScope;
|
|
428
|
+
}
|
|
400
429
|
class StateMachine {
|
|
401
430
|
constructor(/** The raw config used to create the machine. */
|
|
402
431
|
config, implementations) {
|
|
@@ -424,7 +453,7 @@ class StateMachine {
|
|
|
424
453
|
this._json = void 0;
|
|
425
454
|
this.id = config.id || '(machine)';
|
|
426
455
|
this.implementations = {
|
|
427
|
-
|
|
456
|
+
actorSources: config.actorSources ?? {},
|
|
428
457
|
actions: config.actions ?? {},
|
|
429
458
|
delays: config.delays ?? {},
|
|
430
459
|
guards: config.guards ?? {},
|
|
@@ -438,6 +467,7 @@ class StateMachine {
|
|
|
438
467
|
...this.config.options
|
|
439
468
|
};
|
|
440
469
|
this.transition = this.transition.bind(this);
|
|
470
|
+
this.initialTransition = this.initialTransition.bind(this);
|
|
441
471
|
this.getInitialSnapshot = this.getInitialSnapshot.bind(this);
|
|
442
472
|
this.getPersistedSnapshot = this.getPersistedSnapshot.bind(this);
|
|
443
473
|
this.restoreSnapshot = this.restoreSnapshot.bind(this);
|
|
@@ -456,15 +486,15 @@ class StateMachine {
|
|
|
456
486
|
/**
|
|
457
487
|
* Clones this state machine with the provided implementations.
|
|
458
488
|
*
|
|
459
|
-
* @param implementations Options (`actions`, `guards`, `
|
|
460
|
-
* recursively merge with the existing options.
|
|
489
|
+
* @param implementations Options (`actions`, `guards`, `actorSources`,
|
|
490
|
+
* `delays`) to recursively merge with the existing options.
|
|
461
491
|
* @returns A new `StateMachine` instance with the provided implementations.
|
|
462
492
|
*/
|
|
463
493
|
provide(implementations) {
|
|
464
494
|
const {
|
|
465
495
|
actions,
|
|
466
496
|
guards,
|
|
467
|
-
|
|
497
|
+
actorSources,
|
|
468
498
|
delays
|
|
469
499
|
} = this.implementations;
|
|
470
500
|
const provided = new StateMachine(this.config, {
|
|
@@ -476,9 +506,9 @@ class StateMachine {
|
|
|
476
506
|
...guards,
|
|
477
507
|
...implementations.guards
|
|
478
508
|
},
|
|
479
|
-
|
|
480
|
-
...
|
|
481
|
-
...implementations.
|
|
509
|
+
actorSources: {
|
|
510
|
+
...actorSources,
|
|
511
|
+
...implementations.actorSources
|
|
482
512
|
},
|
|
483
513
|
delays: {
|
|
484
514
|
...delays,
|
|
@@ -513,7 +543,56 @@ class StateMachine {
|
|
|
513
543
|
* @param event The received event
|
|
514
544
|
*/
|
|
515
545
|
transition(snapshot, event, actorScope) {
|
|
516
|
-
|
|
546
|
+
const fastSnapshot = this._transitionFast(snapshot, event, actorScope);
|
|
547
|
+
if (fastSnapshot) {
|
|
548
|
+
return [fastSnapshot, []];
|
|
549
|
+
}
|
|
550
|
+
const {
|
|
551
|
+
snapshot: nextSnapshot,
|
|
552
|
+
microsteps
|
|
553
|
+
} = dist_xstateActors.macrostep(snapshot, event, actorScope, []);
|
|
554
|
+
return [nextSnapshot, this._collectEffects(microsteps)];
|
|
555
|
+
}
|
|
556
|
+
_collectEffects(microsteps, initialActions = []) {
|
|
557
|
+
const effects = [...initialActions, ...microsteps.flatMap(([, actions]) => actions)];
|
|
558
|
+
return [...effects, ...dist_xstateActors.deriveDeferredStarts(effects)];
|
|
559
|
+
}
|
|
560
|
+
_transitionFast(snapshot, event, actorScope) {
|
|
561
|
+
if (snapshot.status !== 'active' || typeof snapshot.value !== 'string' || this.root.always?.length) {
|
|
562
|
+
return undefined;
|
|
563
|
+
}
|
|
564
|
+
const sourceNode = this.root.states[snapshot.value];
|
|
565
|
+
if (!sourceNode || sourceNode.type !== 'atomic' || sourceNode.exit || sourceNode.invoke.length || sourceNode.always?.length || sourceNode.after?.length) {
|
|
566
|
+
return undefined;
|
|
567
|
+
}
|
|
568
|
+
const transitions = sourceNode.transitions.get(event.type);
|
|
569
|
+
if (transitions?.length !== 1) {
|
|
570
|
+
return undefined;
|
|
571
|
+
}
|
|
572
|
+
const selected = transitions[0];
|
|
573
|
+
if (selected.guard || selected.actions || selected.to || selected.reenter || selected.input || typeof selected.context === 'function' || selected.target && selected.target.length !== 1) {
|
|
574
|
+
return undefined;
|
|
575
|
+
}
|
|
576
|
+
const targetNode = selected.target?.[0] ?? sourceNode;
|
|
577
|
+
const stateChanged = targetNode !== sourceNode;
|
|
578
|
+
if (targetNode.parent !== this.root || targetNode.type !== 'atomic' || stateChanged && (targetNode.entry || targetNode.invoke.length || targetNode.always?.length || targetNode.after?.length)) {
|
|
579
|
+
return undefined;
|
|
580
|
+
}
|
|
581
|
+
const context = selected.context !== undefined ? {
|
|
582
|
+
...snapshot.context,
|
|
583
|
+
...selected.context
|
|
584
|
+
} : snapshot.context;
|
|
585
|
+
const collectedMicrosteps = actorScope.self._collectedMicrosteps || [];
|
|
586
|
+
collectedMicrosteps.push(selected);
|
|
587
|
+
actorScope.self._collectedMicrosteps = collectedMicrosteps;
|
|
588
|
+
return dist_xstateActors.cloneMachineSnapshot(snapshot, {
|
|
589
|
+
...(context !== snapshot.context ? {
|
|
590
|
+
context
|
|
591
|
+
} : {}),
|
|
592
|
+
...(stateChanged ? {
|
|
593
|
+
_nodes: [this.root, targetNode]
|
|
594
|
+
} : {})
|
|
595
|
+
});
|
|
517
596
|
}
|
|
518
597
|
|
|
519
598
|
/**
|
|
@@ -545,6 +624,49 @@ class StateMachine {
|
|
|
545
624
|
return false;
|
|
546
625
|
}
|
|
547
626
|
|
|
627
|
+
/**
|
|
628
|
+
* Determines whether sending the `event` to the given snapshot would select a
|
|
629
|
+
* non-forbidden transition. Backs `snapshot.can(...)`; lives here so that
|
|
630
|
+
* non-machine bundles don't pay for the transition-resolution machinery.
|
|
631
|
+
*
|
|
632
|
+
* @internal
|
|
633
|
+
*/
|
|
634
|
+
_canTransition(snapshot, event) {
|
|
635
|
+
const emptyActor = getEmptyCanActor();
|
|
636
|
+
const emptyActorScope = getEmptyCanActorScope();
|
|
637
|
+
const transitionData = this.getTransitionData(snapshot, event, emptyActor);
|
|
638
|
+
if (!transitionData?.length) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Check that at least one transition is not forbidden
|
|
643
|
+
for (const transition of transitionData) {
|
|
644
|
+
if (transition.target !== undefined) {
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
const res = dist_xstateActors.getTransitionResult(transition, snapshot, event, emptyActorScope, {
|
|
648
|
+
resolveActions: false
|
|
649
|
+
});
|
|
650
|
+
if (res.targets?.length || res.context || dist_xstateActors.hasEffect(transition, snapshot.context, event, snapshot, emptyActor)) {
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Returns the error event that the actor should transition with to recover
|
|
659
|
+
* from an execution error, if any active state node declares `onError`.
|
|
660
|
+
*
|
|
661
|
+
* @internal
|
|
662
|
+
*/
|
|
663
|
+
getExecutionErrorEvent(snapshot, error) {
|
|
664
|
+
if (snapshot?.status !== 'active' || !snapshot._nodes?.some(stateNode => stateNode.config.onError)) {
|
|
665
|
+
return undefined;
|
|
666
|
+
}
|
|
667
|
+
return dist_xstateActors.createErrorPlatformEvent('execution', error);
|
|
668
|
+
}
|
|
669
|
+
|
|
548
670
|
/**
|
|
549
671
|
* The initial state _before_ evaluating any microsteps. This "pre-initial"
|
|
550
672
|
* state is provided to initial actions executed in the initial state.
|
|
@@ -568,9 +690,9 @@ class StateMachine {
|
|
|
568
690
|
spawn,
|
|
569
691
|
input: initEvent.input,
|
|
570
692
|
self: actorScope.self,
|
|
571
|
-
|
|
693
|
+
actorSources: this.implementations.actorSources
|
|
572
694
|
});
|
|
573
|
-
const nextState = dist_xstateActors.
|
|
695
|
+
const [nextState] = dist_xstateActors.resolveActionsWithContext(preInitial, initEvent, actorScope, []);
|
|
574
696
|
if (resolvedContext) {
|
|
575
697
|
nextState.context = resolvedContext;
|
|
576
698
|
}
|
|
@@ -590,14 +712,33 @@ class StateMachine {
|
|
|
590
712
|
* `ActorRef`.
|
|
591
713
|
*/
|
|
592
714
|
getInitialSnapshot(actorScope, input) {
|
|
715
|
+
return this.initialTransition(input, actorScope)[0];
|
|
716
|
+
}
|
|
717
|
+
initialTransition(input, actorScope) {
|
|
593
718
|
const initEvent = dist_xstateActors.createInitEvent(input); // TODO: fix;
|
|
594
719
|
const internalQueue = [];
|
|
595
720
|
const preInitialState = this._getPreInitialState(actorScope, initEvent);
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
721
|
+
let nextState;
|
|
722
|
+
let initialActions = [];
|
|
723
|
+
let microsteps = [];
|
|
724
|
+
let macroState;
|
|
725
|
+
try {
|
|
726
|
+
[nextState, initialActions] = dist_xstateActors.initialMicrostep(this.root, preInitialState, actorScope, initEvent, internalQueue);
|
|
727
|
+
({
|
|
728
|
+
snapshot: macroState,
|
|
729
|
+
microsteps
|
|
730
|
+
} = dist_xstateActors.macrostep(nextState, initEvent, actorScope, internalQueue));
|
|
731
|
+
} catch (err) {
|
|
732
|
+
if (!this.root.config.onError) {
|
|
733
|
+
throw err;
|
|
734
|
+
}
|
|
735
|
+
const errorEvent = dist_xstateActors.createErrorPlatformEvent('execution', err);
|
|
736
|
+
const errorMacrostep = dist_xstateActors.macrostep(preInitialState, errorEvent, actorScope, []);
|
|
737
|
+
macroState = errorMacrostep.snapshot;
|
|
738
|
+
microsteps = errorMacrostep.microsteps;
|
|
739
|
+
initialActions = [];
|
|
740
|
+
}
|
|
741
|
+
return [macroState, this._collectEffects(microsteps, initialActions)];
|
|
601
742
|
}
|
|
602
743
|
start(snapshot) {
|
|
603
744
|
// Start rehydrated children that were active when persisted. Freshly
|
|
@@ -651,7 +792,7 @@ class StateMachine {
|
|
|
651
792
|
syncSnapshot: actorData.syncSnapshot,
|
|
652
793
|
snapshot: childState,
|
|
653
794
|
src,
|
|
654
|
-
|
|
795
|
+
registryKey: actorData.registryKey
|
|
655
796
|
});
|
|
656
797
|
// Mark so `start()` knows to start this child (freshly invoked/spawned
|
|
657
798
|
// children are started via deferred `@xstate.start` actions instead).
|
|
@@ -695,7 +836,8 @@ class StateMachine {
|
|
|
695
836
|
children,
|
|
696
837
|
_nodes: nodes,
|
|
697
838
|
value: snapshotData.value,
|
|
698
|
-
historyValue: revivedHistoryValue
|
|
839
|
+
historyValue: revivedHistoryValue,
|
|
840
|
+
_stateInputs: snapshotData.stateInputs ?? {}
|
|
699
841
|
}, this);
|
|
700
842
|
const seen = new WeakSet();
|
|
701
843
|
function reviveContext(contextPart) {
|