xstate 5.0.0-beta.33 → 5.0.0-beta.35
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 +1 -1
- package/actions/dist/xstate-actions.cjs.js +3 -3
- package/actions/dist/xstate-actions.development.cjs.js +3 -3
- package/actions/dist/xstate-actions.development.esm.js +3 -3
- package/actions/dist/xstate-actions.esm.js +3 -3
- package/actions/dist/xstate-actions.umd.min.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js.map +1 -1
- package/actors/dist/xstate-actors.cjs.js +3 -3
- package/actors/dist/xstate-actors.development.cjs.js +3 -3
- package/actors/dist/xstate-actors.development.esm.js +3 -3
- package/actors/dist/xstate-actors.esm.js +3 -3
- package/actors/dist/xstate-actors.umd.min.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/declarations/src/index.d.ts +1 -0
- package/dist/declarations/src/interpreter.d.ts +3 -1
- package/dist/declarations/src/stateUtils.d.ts +6 -5
- package/dist/declarations/src/types.d.ts +3 -5
- package/dist/{interpreter-825f3d6e.development.esm.js → interpreter-5c4e6634.development.esm.js} +67 -65
- package/dist/{interpreter-054e9fb7.cjs.js → interpreter-69605bf0.cjs.js} +67 -65
- package/dist/{interpreter-0c630f66.development.cjs.js → interpreter-d3567419.development.cjs.js} +67 -65
- package/dist/{interpreter-03737810.esm.js → interpreter-de5217bc.esm.js} +67 -65
- package/dist/{raise-987c242e.cjs.js → raise-0ff57677.cjs.js} +142 -124
- package/dist/{raise-4c6a5a96.development.cjs.js → raise-26e4d83c.development.cjs.js} +145 -124
- package/dist/{raise-2d92eae8.esm.js → raise-511399cc.esm.js} +142 -124
- package/dist/{raise-46f122aa.development.esm.js → raise-cdcdf834.development.esm.js} +145 -124
- package/dist/{send-bd1bd0e3.cjs.js → send-19ffc568.cjs.js} +16 -8
- package/dist/{send-4d5b92dc.development.esm.js → send-1de74f4d.development.esm.js} +16 -8
- package/dist/{send-0edee2b4.esm.js → send-211a2a94.esm.js} +16 -8
- package/dist/{send-0e8675c8.development.cjs.js → send-894c4b18.development.cjs.js} +16 -8
- package/dist/xstate.cjs.js +28 -9
- package/dist/xstate.development.cjs.js +28 -9
- package/dist/xstate.development.esm.js +31 -12
- package/dist/xstate.esm.js +31 -12
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/guards/dist/xstate-guards.cjs.js +2 -2
- package/guards/dist/xstate-guards.development.cjs.js +2 -2
- package/guards/dist/xstate-guards.development.esm.js +2 -2
- package/guards/dist/xstate-guards.esm.js +2 -2
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,62 +9,6 @@ const XSTATE_INIT = 'xstate.init';
|
|
|
9
9
|
const XSTATE_ERROR = 'xstate.error';
|
|
10
10
|
const XSTATE_STOP = 'xstate.stop';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Returns an event that represents an implicit event that
|
|
14
|
-
* is sent after the specified `delay`.
|
|
15
|
-
*
|
|
16
|
-
* @param delayRef The delay in milliseconds
|
|
17
|
-
* @param id The state node ID where this event is handled
|
|
18
|
-
*/
|
|
19
|
-
function createAfterEvent(delayRef, id) {
|
|
20
|
-
const idSuffix = id ? `#${id}` : '';
|
|
21
|
-
return {
|
|
22
|
-
type: `xstate.after(${delayRef})${idSuffix}`
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Returns an event that represents that a final state node
|
|
28
|
-
* has been reached in the parent state node.
|
|
29
|
-
*
|
|
30
|
-
* @param id The final state node's parent state node `id`
|
|
31
|
-
* @param output The data to pass into the event
|
|
32
|
-
*/
|
|
33
|
-
function createDoneStateEvent(id, output) {
|
|
34
|
-
return {
|
|
35
|
-
type: `xstate.done.state.${id}`,
|
|
36
|
-
output
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Returns an event that represents that an invoked service has terminated.
|
|
42
|
-
*
|
|
43
|
-
* An invoked service is terminated when it has reached a top-level final state node,
|
|
44
|
-
* but not when it is canceled.
|
|
45
|
-
*
|
|
46
|
-
* @param invokeId The invoked service ID
|
|
47
|
-
* @param output The data to pass into the event
|
|
48
|
-
*/
|
|
49
|
-
function createDoneActorEvent(invokeId, output) {
|
|
50
|
-
return {
|
|
51
|
-
type: `xstate.done.actor.${invokeId}`,
|
|
52
|
-
output
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function createErrorActorEvent(id, data) {
|
|
56
|
-
return {
|
|
57
|
-
type: `xstate.error.actor.${id}`,
|
|
58
|
-
data
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function createInitEvent(input) {
|
|
62
|
-
return {
|
|
63
|
-
type: XSTATE_INIT,
|
|
64
|
-
input
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
12
|
class Mailbox {
|
|
69
13
|
constructor(_process) {
|
|
70
14
|
this._process = _process;
|
|
@@ -132,6 +76,62 @@ class Mailbox {
|
|
|
132
76
|
}
|
|
133
77
|
}
|
|
134
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Returns an event that represents an implicit event that
|
|
81
|
+
* is sent after the specified `delay`.
|
|
82
|
+
*
|
|
83
|
+
* @param delayRef The delay in milliseconds
|
|
84
|
+
* @param id The state node ID where this event is handled
|
|
85
|
+
*/
|
|
86
|
+
function createAfterEvent(delayRef, id) {
|
|
87
|
+
const idSuffix = id ? `#${id}` : '';
|
|
88
|
+
return {
|
|
89
|
+
type: `xstate.after(${delayRef})${idSuffix}`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Returns an event that represents that a final state node
|
|
95
|
+
* has been reached in the parent state node.
|
|
96
|
+
*
|
|
97
|
+
* @param id The final state node's parent state node `id`
|
|
98
|
+
* @param output The data to pass into the event
|
|
99
|
+
*/
|
|
100
|
+
function createDoneStateEvent(id, output) {
|
|
101
|
+
return {
|
|
102
|
+
type: `xstate.done.state.${id}`,
|
|
103
|
+
output
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Returns an event that represents that an invoked service has terminated.
|
|
109
|
+
*
|
|
110
|
+
* An invoked service is terminated when it has reached a top-level final state node,
|
|
111
|
+
* but not when it is canceled.
|
|
112
|
+
*
|
|
113
|
+
* @param invokeId The invoked service ID
|
|
114
|
+
* @param output The data to pass into the event
|
|
115
|
+
*/
|
|
116
|
+
function createDoneActorEvent(invokeId, output) {
|
|
117
|
+
return {
|
|
118
|
+
type: `xstate.done.actor.${invokeId}`,
|
|
119
|
+
output
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function createErrorActorEvent(id, data) {
|
|
123
|
+
return {
|
|
124
|
+
type: `xstate.error.actor.${id}`,
|
|
125
|
+
data
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function createInitEvent(input) {
|
|
129
|
+
return {
|
|
130
|
+
type: XSTATE_INIT,
|
|
131
|
+
input
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
135
|
/**
|
|
136
136
|
* This function makes sure that unhandled errors are thrown in a separate macrotask.
|
|
137
137
|
* It allows those errors to be detected by global error handlers and reported to bug tracking services
|
|
@@ -340,6 +340,7 @@ function resolveReferencedActor(referenced) {
|
|
|
340
340
|
} : referenced : undefined;
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
const $$ACTOR_TYPE = 1;
|
|
343
344
|
let ActorStatus = /*#__PURE__*/function (ActorStatus) {
|
|
344
345
|
ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
|
|
345
346
|
ActorStatus[ActorStatus["Running"] = 1] = "Running";
|
|
@@ -557,7 +558,7 @@ class Actor {
|
|
|
557
558
|
const status = this._state.status;
|
|
558
559
|
switch (status) {
|
|
559
560
|
case 'done':
|
|
560
|
-
// a state machine can be "done" upon
|
|
561
|
+
// a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
|
|
561
562
|
// we still need to complete observers, flush deferreds etc
|
|
562
563
|
this.update(this._state, initEvent);
|
|
563
564
|
// fallthrough
|
|
@@ -712,14 +713,14 @@ class Actor {
|
|
|
712
713
|
}
|
|
713
714
|
|
|
714
715
|
// TODO: make private (and figure out a way to do this within the machine)
|
|
715
|
-
delaySend({
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
716
|
+
delaySend(params) {
|
|
717
|
+
const {
|
|
718
|
+
event,
|
|
719
|
+
id,
|
|
720
|
+
delay
|
|
721
|
+
} = params;
|
|
721
722
|
const timerId = this.clock.setTimeout(() => {
|
|
722
|
-
this.system._relay(this, to ?? this, event);
|
|
723
|
+
this.system._relay(this, params.to ?? this, event);
|
|
723
724
|
}, delay);
|
|
724
725
|
|
|
725
726
|
// TODO: consider the rehydration story here
|
|
@@ -744,6 +745,7 @@ class Actor {
|
|
|
744
745
|
}
|
|
745
746
|
toJSON() {
|
|
746
747
|
return {
|
|
748
|
+
xstate$$type: $$ACTOR_TYPE,
|
|
747
749
|
id: this.id
|
|
748
750
|
};
|
|
749
751
|
}
|
|
@@ -781,4 +783,4 @@ const interpret = createActor;
|
|
|
781
783
|
* @deprecated Use `Actor` instead.
|
|
782
784
|
*/
|
|
783
785
|
|
|
784
|
-
export { Actor as A, InterpreterStatus as I, NULL_EVENT as N, STATE_DELIMITER as S, WILDCARD as W,
|
|
786
|
+
export { $$ACTOR_TYPE as $, Actor as A, InterpreterStatus as I, NULL_EVENT as N, STATE_DELIMITER as S, WILDCARD as W, XSTATE_STOP as X, toTransitionConfigArray as a, createInitEvent as b, createInvokeId as c, createActor as d, matchesState as e, ActorStatus as f, interpret as g, toObserver as h, isErrorActorEvent as i, createErrorActorEvent as j, toStateValue as k, STATE_IDENTIFIER as l, mapValues as m, normalizeTarget as n, toStatePath as o, pathToStateValue as p, createDoneStateEvent as q, resolveReferencedActor as r, resolveOutput as s, toArray as t, XSTATE_INIT as u, createAfterEvent as v, flatten as w, XSTATE_ERROR as x };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var interpreter = require('./interpreter-
|
|
3
|
+
var interpreter = require('./interpreter-69605bf0.cjs.js');
|
|
4
4
|
|
|
5
5
|
const cache = new WeakMap();
|
|
6
6
|
function memo(object, key, fn) {
|
|
@@ -279,20 +279,6 @@ function evaluateGuard(guard, context, event, state) {
|
|
|
279
279
|
);
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
function getOutput(configuration, context, event, self) {
|
|
283
|
-
const {
|
|
284
|
-
machine
|
|
285
|
-
} = configuration[0];
|
|
286
|
-
const {
|
|
287
|
-
root
|
|
288
|
-
} = machine;
|
|
289
|
-
if (!root.output) {
|
|
290
|
-
return undefined;
|
|
291
|
-
}
|
|
292
|
-
const finalChildStateNode = configuration.find(stateNode => stateNode.type === 'final' && stateNode.parent === machine.root);
|
|
293
|
-
const doneStateEvent = interpreter.createDoneStateEvent(finalChildStateNode.id, finalChildStateNode.output ? interpreter.resolveOutput(finalChildStateNode.output, context, event, self) : undefined);
|
|
294
|
-
return interpreter.resolveOutput(root.output, context, doneStateEvent, self);
|
|
295
|
-
}
|
|
296
282
|
const isAtomicStateNode = stateNode => stateNode.type === 'atomic' || stateNode.type === 'final';
|
|
297
283
|
function getChildren(stateNode) {
|
|
298
284
|
return Object.values(stateNode.states).filter(sn => sn.type !== 'history');
|
|
@@ -317,7 +303,7 @@ function getConfiguration(stateNodes) {
|
|
|
317
303
|
for (const s of configuration) {
|
|
318
304
|
// if previously active, add existing child nodes
|
|
319
305
|
if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) {
|
|
320
|
-
|
|
306
|
+
getInitialStateNodesWithTheirAncestors(s).forEach(sn => configurationSet.add(sn));
|
|
321
307
|
} else {
|
|
322
308
|
if (s.type === 'parallel') {
|
|
323
309
|
for (const child of getChildren(s)) {
|
|
@@ -325,7 +311,8 @@ function getConfiguration(stateNodes) {
|
|
|
325
311
|
continue;
|
|
326
312
|
}
|
|
327
313
|
if (!configurationSet.has(child)) {
|
|
328
|
-
|
|
314
|
+
const initialStates = getInitialStateNodesWithTheirAncestors(child);
|
|
315
|
+
for (const initialStateNode of initialStates) {
|
|
329
316
|
configurationSet.add(initialStateNode);
|
|
330
317
|
}
|
|
331
318
|
}
|
|
@@ -385,14 +372,14 @@ function getStateValue(rootNode, configuration) {
|
|
|
385
372
|
const config = getConfiguration(configuration);
|
|
386
373
|
return getValueFromAdj(rootNode, getAdjList(config));
|
|
387
374
|
}
|
|
388
|
-
function isInFinalState(configuration, stateNode
|
|
375
|
+
function isInFinalState(configuration, stateNode) {
|
|
389
376
|
if (stateNode.type === 'compound') {
|
|
390
|
-
return getChildren(stateNode).some(s => s.type === 'final' && configuration.
|
|
377
|
+
return getChildren(stateNode).some(s => s.type === 'final' && configuration.has(s));
|
|
391
378
|
}
|
|
392
379
|
if (stateNode.type === 'parallel') {
|
|
393
380
|
return getChildren(stateNode).every(sn => isInFinalState(configuration, sn));
|
|
394
381
|
}
|
|
395
|
-
return
|
|
382
|
+
return stateNode.type === 'final';
|
|
396
383
|
}
|
|
397
384
|
const isStateId = str => str[0] === interpreter.STATE_IDENTIFIER;
|
|
398
385
|
function getCandidates(stateNode, receivedEventType) {
|
|
@@ -442,13 +429,7 @@ function getDelayedTransitions(stateNode) {
|
|
|
442
429
|
stateNode.exit.push(cancel(eventType));
|
|
443
430
|
return eventType;
|
|
444
431
|
};
|
|
445
|
-
const delayedTransitions =
|
|
446
|
-
const eventType = mutateEntryExit(transition.delay, i);
|
|
447
|
-
return {
|
|
448
|
-
...transition,
|
|
449
|
-
event: eventType
|
|
450
|
-
};
|
|
451
|
-
}) : Object.keys(afterConfig).flatMap((delay, i) => {
|
|
432
|
+
const delayedTransitions = Object.keys(afterConfig).flatMap((delay, i) => {
|
|
452
433
|
const configTransition = afterConfig[delay];
|
|
453
434
|
const resolvedTransition = typeof configTransition === 'string' ? {
|
|
454
435
|
target: configTransition
|
|
@@ -531,43 +512,23 @@ function formatTransitions(stateNode) {
|
|
|
531
512
|
return transitions;
|
|
532
513
|
}
|
|
533
514
|
function formatInitialTransition(stateNode, _target) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
// to their state node
|
|
538
|
-
const descStateNode = typeof t === 'string' ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
|
|
539
|
-
if (!descStateNode) {
|
|
540
|
-
throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
|
|
541
|
-
}
|
|
542
|
-
if (!isDescendant(descStateNode, stateNode)) {
|
|
543
|
-
throw new Error(`Invalid initial target: state node #${descStateNode.id} is not a descendant of #${stateNode.id}`);
|
|
544
|
-
}
|
|
545
|
-
return descStateNode;
|
|
546
|
-
});
|
|
547
|
-
const resolvedTarget = resolveTarget(stateNode, targets);
|
|
548
|
-
const transition = {
|
|
549
|
-
source: stateNode,
|
|
550
|
-
actions: [],
|
|
551
|
-
eventType: null,
|
|
552
|
-
reenter: false,
|
|
553
|
-
target: resolvedTarget,
|
|
554
|
-
toJSON: () => ({
|
|
555
|
-
...transition,
|
|
556
|
-
source: `#${stateNode.id}`,
|
|
557
|
-
target: resolvedTarget ? resolvedTarget.map(t => `#${t.id}`) : undefined
|
|
558
|
-
})
|
|
559
|
-
};
|
|
560
|
-
return transition;
|
|
515
|
+
const resolvedTarget = typeof _target === 'string' ? stateNode.states[_target] : _target ? stateNode.states[_target.target] : undefined;
|
|
516
|
+
if (!resolvedTarget && _target) {
|
|
517
|
+
throw new Error(`Initial state node "${_target}" not found on parent state node #${stateNode.id}`);
|
|
561
518
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
519
|
+
const transition = {
|
|
520
|
+
source: stateNode,
|
|
521
|
+
actions: !_target || typeof _target === 'string' ? [] : interpreter.toArray(_target.actions),
|
|
522
|
+
eventType: null,
|
|
523
|
+
reenter: false,
|
|
524
|
+
target: resolvedTarget ? [resolvedTarget] : [],
|
|
525
|
+
toJSON: () => ({
|
|
526
|
+
...transition,
|
|
527
|
+
source: `#${stateNode.id}`,
|
|
528
|
+
target: resolvedTarget ? [`#${resolvedTarget.id}`] : []
|
|
529
|
+
})
|
|
530
|
+
};
|
|
531
|
+
return transition;
|
|
571
532
|
}
|
|
572
533
|
function resolveTarget(stateNode, targets) {
|
|
573
534
|
if (targets === undefined) {
|
|
@@ -610,6 +571,15 @@ function resolveHistoryTarget(stateNode) {
|
|
|
610
571
|
function isHistoryNode(stateNode) {
|
|
611
572
|
return stateNode.type === 'history';
|
|
612
573
|
}
|
|
574
|
+
function getInitialStateNodesWithTheirAncestors(stateNode) {
|
|
575
|
+
const states = getInitialStateNodes(stateNode);
|
|
576
|
+
for (const initialState of states) {
|
|
577
|
+
for (const ancestor of getProperAncestors(initialState, stateNode)) {
|
|
578
|
+
states.add(ancestor);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return states;
|
|
582
|
+
}
|
|
613
583
|
function getInitialStateNodes(stateNode) {
|
|
614
584
|
const set = new Set();
|
|
615
585
|
function iter(descStateNode) {
|
|
@@ -618,12 +588,7 @@ function getInitialStateNodes(stateNode) {
|
|
|
618
588
|
}
|
|
619
589
|
set.add(descStateNode);
|
|
620
590
|
if (descStateNode.type === 'compound') {
|
|
621
|
-
|
|
622
|
-
for (const a of getProperAncestors(targetStateNode, stateNode)) {
|
|
623
|
-
set.add(a);
|
|
624
|
-
}
|
|
625
|
-
iter(targetStateNode);
|
|
626
|
-
}
|
|
591
|
+
iter(descStateNode.initial.target[0]);
|
|
627
592
|
} else if (descStateNode.type === 'parallel') {
|
|
628
593
|
for (const child of getChildren(descStateNode)) {
|
|
629
594
|
iter(child);
|
|
@@ -631,7 +596,7 @@ function getInitialStateNodes(stateNode) {
|
|
|
631
596
|
}
|
|
632
597
|
}
|
|
633
598
|
iter(stateNode);
|
|
634
|
-
return
|
|
599
|
+
return set;
|
|
635
600
|
}
|
|
636
601
|
/**
|
|
637
602
|
* Returns the child state node from its relative `stateKey`, or throws.
|
|
@@ -887,41 +852,37 @@ function microstep(transitions, currentState, actorCtx, event, isInitial) {
|
|
|
887
852
|
}
|
|
888
853
|
|
|
889
854
|
function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
|
|
890
|
-
const actions = [];
|
|
891
855
|
const historyValue = {
|
|
892
856
|
...currentState.historyValue
|
|
893
857
|
};
|
|
894
858
|
const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
|
|
895
859
|
const internalQueue = [...currentState._internalQueue];
|
|
860
|
+
// TODO: this `cloneState` is really just a hack to prevent infinite loops
|
|
861
|
+
// we need to take another look at how internal queue is managed
|
|
862
|
+
let nextState = cloneState(currentState, {
|
|
863
|
+
_internalQueue: []
|
|
864
|
+
});
|
|
896
865
|
|
|
897
866
|
// Exit states
|
|
898
867
|
if (!isInitial) {
|
|
899
|
-
exitStates(filteredTransitions, mutConfiguration, historyValue
|
|
868
|
+
nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
|
|
900
869
|
}
|
|
901
870
|
|
|
902
871
|
// Execute transition content
|
|
903
|
-
|
|
872
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
|
|
904
873
|
|
|
905
874
|
// Enter states
|
|
906
|
-
enterStates(event, filteredTransitions, mutConfiguration,
|
|
875
|
+
nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
|
|
907
876
|
const nextConfiguration = [...mutConfiguration];
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
const finalActions = nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit);
|
|
911
|
-
actions.push(...finalActions);
|
|
877
|
+
if (nextState.status === 'done') {
|
|
878
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
|
|
912
879
|
}
|
|
913
880
|
try {
|
|
914
|
-
const nextState = resolveActionsAndContext(actions, event, currentState, actorCtx);
|
|
915
|
-
const output = done ? getOutput(nextConfiguration, nextState.context, event, actorCtx.self) : undefined;
|
|
916
881
|
internalQueue.push(...nextState._internalQueue);
|
|
917
|
-
return cloneState(
|
|
882
|
+
return cloneState(nextState, {
|
|
918
883
|
configuration: nextConfiguration,
|
|
919
884
|
historyValue,
|
|
920
|
-
_internalQueue: internalQueue
|
|
921
|
-
context: nextState.context,
|
|
922
|
-
status: done ? 'done' : currentState.status,
|
|
923
|
-
output,
|
|
924
|
-
children: nextState.children
|
|
885
|
+
_internalQueue: internalQueue
|
|
925
886
|
});
|
|
926
887
|
} catch (e) {
|
|
927
888
|
// TODO: Refactor this once proper error handling is implemented.
|
|
@@ -929,7 +890,15 @@ function microstepProcedure(transitions, currentState, mutConfiguration, event,
|
|
|
929
890
|
throw e;
|
|
930
891
|
}
|
|
931
892
|
}
|
|
932
|
-
function
|
|
893
|
+
function getMachineOutput(state, event, actorCtx, rootNode, rootCompletionNode) {
|
|
894
|
+
if (!rootNode.output) {
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
const doneStateEvent = interpreter.createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output && rootCompletionNode.parent ? interpreter.resolveOutput(rootCompletionNode.output, state.context, event, actorCtx.self) : undefined);
|
|
898
|
+
return interpreter.resolveOutput(rootNode.output, state.context, doneStateEvent, actorCtx.self);
|
|
899
|
+
}
|
|
900
|
+
function enterStates(currentState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial) {
|
|
901
|
+
let nextState = currentState;
|
|
933
902
|
const statesToEnter = new Set();
|
|
934
903
|
const statesForDefaultEntry = new Set();
|
|
935
904
|
computeEntrySet(filteredTransitions, historyValue, statesForDefaultEntry, statesToEnter);
|
|
@@ -938,36 +907,48 @@ function enterStates(event, filteredTransitions, mutConfiguration, actions, inte
|
|
|
938
907
|
if (isInitial) {
|
|
939
908
|
statesForDefaultEntry.add(currentState.machine.root);
|
|
940
909
|
}
|
|
910
|
+
const completedNodes = new Set();
|
|
941
911
|
for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
|
|
942
912
|
mutConfiguration.add(stateNodeToEnter);
|
|
943
|
-
|
|
944
|
-
actions.push(invoke(invokeDef));
|
|
945
|
-
}
|
|
913
|
+
const actions = [];
|
|
946
914
|
|
|
947
915
|
// Add entry actions
|
|
948
916
|
actions.push(...stateNodeToEnter.entry);
|
|
917
|
+
for (const invokeDef of stateNodeToEnter.invoke) {
|
|
918
|
+
actions.push(invoke(invokeDef));
|
|
919
|
+
}
|
|
949
920
|
if (statesForDefaultEntry.has(stateNodeToEnter)) {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
actions.push(...initialActions);
|
|
953
|
-
}
|
|
921
|
+
const initialActions = stateNodeToEnter.initial.actions;
|
|
922
|
+
actions.push(...initialActions);
|
|
954
923
|
}
|
|
924
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
955
925
|
if (stateNodeToEnter.type === 'final') {
|
|
956
926
|
const parent = stateNodeToEnter.parent;
|
|
957
|
-
if (
|
|
927
|
+
if (completedNodes.has(parent)) {
|
|
958
928
|
continue;
|
|
959
929
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
930
|
+
completedNodes.add(parent);
|
|
931
|
+
let rootCompletionNode = parent?.type === 'parallel' ? parent : stateNodeToEnter;
|
|
932
|
+
let ancestorMarker = parent?.parent;
|
|
933
|
+
if (ancestorMarker) {
|
|
934
|
+
internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, nextState.context, event, actorCtx.self) : undefined));
|
|
935
|
+
while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutConfiguration, ancestorMarker)) {
|
|
936
|
+
completedNodes.add(ancestorMarker);
|
|
937
|
+
internalQueue.push(interpreter.createDoneStateEvent(ancestorMarker.id));
|
|
938
|
+
rootCompletionNode = ancestorMarker;
|
|
939
|
+
ancestorMarker = ancestorMarker.parent;
|
|
967
940
|
}
|
|
968
941
|
}
|
|
942
|
+
if (ancestorMarker) {
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
nextState = cloneState(nextState, {
|
|
946
|
+
status: 'done',
|
|
947
|
+
output: getMachineOutput(nextState, event, actorCtx, currentState.configuration[0].machine.root, rootCompletionNode)
|
|
948
|
+
});
|
|
969
949
|
}
|
|
970
950
|
}
|
|
951
|
+
return nextState;
|
|
971
952
|
}
|
|
972
953
|
function computeEntrySet(transitions, historyValue, statesForDefaultEntry, statesToEnter) {
|
|
973
954
|
for (const t of transitions) {
|
|
@@ -1010,13 +991,9 @@ function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEnt
|
|
|
1010
991
|
statesToEnter.add(stateNode);
|
|
1011
992
|
if (stateNode.type === 'compound') {
|
|
1012
993
|
statesForDefaultEntry.add(stateNode);
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1017
|
-
for (const initialState of initialStates) {
|
|
1018
|
-
addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
|
1019
|
-
}
|
|
994
|
+
const [initialState] = stateNode.initial.target;
|
|
995
|
+
addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
|
|
996
|
+
addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
|
1020
997
|
} else {
|
|
1021
998
|
if (stateNode.type === 'parallel') {
|
|
1022
999
|
for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
|
|
@@ -1041,7 +1018,8 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
|
|
|
1041
1018
|
}
|
|
1042
1019
|
}
|
|
1043
1020
|
}
|
|
1044
|
-
function exitStates(transitions, mutConfiguration, historyValue
|
|
1021
|
+
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
|
|
1022
|
+
let nextState = currentState;
|
|
1045
1023
|
const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
|
|
1046
1024
|
statesToExit.sort((a, b) => b.order - a.order);
|
|
1047
1025
|
|
|
@@ -1060,19 +1038,16 @@ function exitStates(transitions, mutConfiguration, historyValue, actions) {
|
|
|
1060
1038
|
}
|
|
1061
1039
|
}
|
|
1062
1040
|
for (const s of statesToExit) {
|
|
1063
|
-
|
|
1041
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))]);
|
|
1064
1042
|
mutConfiguration.delete(s);
|
|
1065
1043
|
}
|
|
1044
|
+
return nextState;
|
|
1066
1045
|
}
|
|
1067
|
-
function
|
|
1046
|
+
function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
|
|
1068
1047
|
const {
|
|
1069
1048
|
machine
|
|
1070
1049
|
} = currentState;
|
|
1071
|
-
|
|
1072
|
-
// we need to take another look at how internal queue is managed
|
|
1073
|
-
let intermediateState = cloneState(currentState, {
|
|
1074
|
-
_internalQueue: []
|
|
1075
|
-
});
|
|
1050
|
+
let intermediateState = currentState;
|
|
1076
1051
|
for (const action of actions) {
|
|
1077
1052
|
const isInline = typeof action === 'function';
|
|
1078
1053
|
const resolvedAction = isInline ? action :
|
|
@@ -1111,11 +1086,14 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
|
|
|
1111
1086
|
continue;
|
|
1112
1087
|
}
|
|
1113
1088
|
const builtinAction = resolvedAction;
|
|
1114
|
-
const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, actionArgs, resolvedAction
|
|
1115
|
-
|
|
1116
|
-
|
|
1089
|
+
const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, actionArgs, resolvedAction,
|
|
1090
|
+
// this holds all params
|
|
1091
|
+
extra);
|
|
1117
1092
|
intermediateState = nextState;
|
|
1118
|
-
if ('
|
|
1093
|
+
if ('retryResolve' in builtinAction) {
|
|
1094
|
+
retries?.push([builtinAction, params]);
|
|
1095
|
+
}
|
|
1096
|
+
if ('execute' in builtinAction) {
|
|
1119
1097
|
if (actorCtx?.self.status === interpreter.ActorStatus.Running) {
|
|
1120
1098
|
builtinAction.execute(actorCtx, params);
|
|
1121
1099
|
} else {
|
|
@@ -1123,11 +1101,21 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
|
|
|
1123
1101
|
}
|
|
1124
1102
|
}
|
|
1125
1103
|
if (actions) {
|
|
1126
|
-
intermediateState =
|
|
1104
|
+
intermediateState = resolveActionsAndContextWorker(intermediateState, event, actorCtx, actions, extra, retries);
|
|
1127
1105
|
}
|
|
1128
1106
|
}
|
|
1129
1107
|
return intermediateState;
|
|
1130
1108
|
}
|
|
1109
|
+
function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
|
|
1110
|
+
const retries = deferredActorIds ? [] : undefined;
|
|
1111
|
+
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, deferredActorIds && {
|
|
1112
|
+
deferredActorIds
|
|
1113
|
+
}, retries);
|
|
1114
|
+
retries?.forEach(([builtinAction, params]) => {
|
|
1115
|
+
builtinAction.retryResolve(actorCtx, nextState, params);
|
|
1116
|
+
});
|
|
1117
|
+
return nextState;
|
|
1118
|
+
}
|
|
1131
1119
|
function macrostep(state, event, actorCtx) {
|
|
1132
1120
|
let nextState = state;
|
|
1133
1121
|
const states = [];
|
|
@@ -1184,7 +1172,7 @@ function stopStep(event, nextState, actorCtx) {
|
|
|
1184
1172
|
for (const child of Object.values(nextState.children)) {
|
|
1185
1173
|
actions.push(stop(child));
|
|
1186
1174
|
}
|
|
1187
|
-
return resolveActionsAndContext(
|
|
1175
|
+
return resolveActionsAndContext(nextState, event, actorCtx, actions);
|
|
1188
1176
|
}
|
|
1189
1177
|
function selectTransitions(event, nextState) {
|
|
1190
1178
|
return nextState.machine.getTransitionData(nextState, event);
|
|
@@ -1393,6 +1381,7 @@ function getPersistedState(state) {
|
|
|
1393
1381
|
tags,
|
|
1394
1382
|
machine,
|
|
1395
1383
|
children,
|
|
1384
|
+
context,
|
|
1396
1385
|
...jsonValues
|
|
1397
1386
|
} = state;
|
|
1398
1387
|
const childrenJson = {};
|
|
@@ -1405,9 +1394,38 @@ function getPersistedState(state) {
|
|
|
1405
1394
|
}
|
|
1406
1395
|
return {
|
|
1407
1396
|
...jsonValues,
|
|
1397
|
+
// TODO: this makes `PersistedMachineState`'s type kind of a lie
|
|
1398
|
+
// it doesn't truly use `TContext` but rather some kind of a derived form of it
|
|
1399
|
+
context: persistContext(context),
|
|
1408
1400
|
children: childrenJson
|
|
1409
1401
|
};
|
|
1410
1402
|
}
|
|
1403
|
+
function persistContext(contextPart) {
|
|
1404
|
+
let copy;
|
|
1405
|
+
for (const key in contextPart) {
|
|
1406
|
+
const value = contextPart[key];
|
|
1407
|
+
if (value && typeof value === 'object') {
|
|
1408
|
+
if ('sessionId' in value && 'send' in value && 'ref' in value) {
|
|
1409
|
+
copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
|
|
1410
|
+
...contextPart
|
|
1411
|
+
};
|
|
1412
|
+
copy[key] = {
|
|
1413
|
+
xstate$$type: interpreter.$$ACTOR_TYPE,
|
|
1414
|
+
id: value.id
|
|
1415
|
+
};
|
|
1416
|
+
} else {
|
|
1417
|
+
const result = persistContext(value);
|
|
1418
|
+
if (result !== value) {
|
|
1419
|
+
copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
|
|
1420
|
+
...contextPart
|
|
1421
|
+
};
|
|
1422
|
+
copy[key] = result;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
return copy ?? contextPart;
|
|
1428
|
+
}
|
|
1411
1429
|
|
|
1412
1430
|
function resolveRaise(_, state, args, {
|
|
1413
1431
|
event: eventOrExpr,
|
|
@@ -1470,10 +1488,10 @@ exports.getCandidates = getCandidates;
|
|
|
1470
1488
|
exports.getConfiguration = getConfiguration;
|
|
1471
1489
|
exports.getDelayedTransitions = getDelayedTransitions;
|
|
1472
1490
|
exports.getInitialConfiguration = getInitialConfiguration;
|
|
1491
|
+
exports.getInitialStateNodes = getInitialStateNodes;
|
|
1473
1492
|
exports.getPersistedState = getPersistedState;
|
|
1474
1493
|
exports.getStateNodeByPath = getStateNodeByPath;
|
|
1475
1494
|
exports.getStateNodes = getStateNodes;
|
|
1476
|
-
exports.isAtomicStateNode = isAtomicStateNode;
|
|
1477
1495
|
exports.isInFinalState = isInFinalState;
|
|
1478
1496
|
exports.isStateId = isStateId;
|
|
1479
1497
|
exports.macrostep = macrostep;
|