xstate 5.0.0-beta.34 → 5.0.0-beta.36
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 +1 -1
- package/actors/dist/xstate-actors.development.cjs.js +1 -1
- package/actors/dist/xstate-actors.development.esm.js +1 -1
- package/actors/dist/xstate-actors.esm.js +1 -1
- 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/State.d.ts +0 -1
- package/dist/declarations/src/interpreter.d.ts +2 -0
- package/dist/declarations/src/stateUtils.d.ts +8 -7
- package/dist/declarations/src/types.d.ts +3 -6
- package/dist/{interpreter-dee56dc8.development.esm.js → interpreter-5c4e6634.development.esm.js} +59 -57
- package/dist/{interpreter-1301970f.cjs.js → interpreter-69605bf0.cjs.js} +59 -57
- package/dist/{interpreter-70ed62f2.development.cjs.js → interpreter-d3567419.development.cjs.js} +59 -57
- package/dist/{interpreter-83f7f2d4.esm.js → interpreter-de5217bc.esm.js} +59 -57
- package/dist/{raise-38b707c0.development.cjs.js → raise-106ea558.development.cjs.js} +160 -160
- package/dist/{raise-05f8b2a6.development.esm.js → raise-5b7ad3b7.development.esm.js} +160 -160
- package/dist/{raise-1dd65455.cjs.js → raise-c51b81a3.cjs.js} +157 -160
- package/dist/{raise-b5cfe1bb.esm.js → raise-ffe1014a.esm.js} +157 -160
- package/dist/{send-0b5eda0c.esm.js → send-0a7aa74e.esm.js} +5 -3
- package/dist/{send-3764c866.development.cjs.js → send-25e70bd4.development.cjs.js} +5 -3
- package/dist/{send-fe94de2b.cjs.js → send-778692de.cjs.js} +5 -3
- package/dist/{send-9526366e.development.esm.js → send-e93554d6.development.esm.js} +5 -3
- package/dist/xstate.cjs.js +32 -13
- package/dist/xstate.development.cjs.js +32 -13
- package/dist/xstate.development.esm.js +35 -16
- package/dist/xstate.esm.js +35 -16
- 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
|
@@ -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.
|
|
@@ -865,6 +830,17 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
865
830
|
}
|
|
866
831
|
return [...statesToExit];
|
|
867
832
|
}
|
|
833
|
+
function areConfigurationsEqual(previousConfiguration, nextConfigurationSet) {
|
|
834
|
+
if (previousConfiguration.length !== nextConfigurationSet.size) {
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
for (const node of previousConfiguration) {
|
|
838
|
+
if (!nextConfigurationSet.has(node)) {
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
868
844
|
|
|
869
845
|
/**
|
|
870
846
|
* https://www.w3.org/TR/scxml/#microstepProcedure
|
|
@@ -874,56 +850,36 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
874
850
|
* @param currentState
|
|
875
851
|
* @param mutConfiguration
|
|
876
852
|
*/
|
|
877
|
-
|
|
878
|
-
function microstep(transitions, currentState, actorCtx, event, isInitial) {
|
|
879
|
-
const mutConfiguration = new Set(currentState.configuration);
|
|
853
|
+
function microstep(transitions, currentState, actorCtx, event, isInitial, internalQueue) {
|
|
880
854
|
if (!transitions.length) {
|
|
881
855
|
return currentState;
|
|
882
856
|
}
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
value: {} // TODO: make optional
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
|
|
890
|
-
const historyValue = {
|
|
891
|
-
...currentState.historyValue
|
|
892
|
-
};
|
|
857
|
+
const mutConfiguration = new Set(currentState.configuration);
|
|
858
|
+
let historyValue = currentState.historyValue;
|
|
893
859
|
const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
|
|
894
|
-
|
|
895
|
-
// TODO: this `cloneState` is really just a hack to prevent infinite loops
|
|
896
|
-
// we need to take another look at how internal queue is managed
|
|
897
|
-
let nextState = cloneState(currentState, {
|
|
898
|
-
_internalQueue: []
|
|
899
|
-
});
|
|
860
|
+
let nextState = currentState;
|
|
900
861
|
|
|
901
862
|
// Exit states
|
|
902
863
|
if (!isInitial) {
|
|
903
|
-
nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
|
|
864
|
+
[nextState, historyValue] = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue, internalQueue);
|
|
904
865
|
}
|
|
905
866
|
|
|
906
867
|
// Execute transition content
|
|
907
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
|
|
868
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions), internalQueue);
|
|
908
869
|
|
|
909
870
|
// Enter states
|
|
910
871
|
nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
|
|
911
872
|
const nextConfiguration = [...mutConfiguration];
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
|
|
873
|
+
if (nextState.status === 'done') {
|
|
874
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
|
|
915
875
|
}
|
|
916
876
|
try {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
877
|
+
if (historyValue === currentState.historyValue && areConfigurationsEqual(currentState.configuration, mutConfiguration)) {
|
|
878
|
+
return nextState;
|
|
879
|
+
}
|
|
880
|
+
return cloneState(nextState, {
|
|
920
881
|
configuration: nextConfiguration,
|
|
921
|
-
historyValue
|
|
922
|
-
_internalQueue: internalQueue,
|
|
923
|
-
context: nextState.context,
|
|
924
|
-
status: done ? 'done' : currentState.status,
|
|
925
|
-
output,
|
|
926
|
-
children: nextState.children
|
|
882
|
+
historyValue
|
|
927
883
|
});
|
|
928
884
|
} catch (e) {
|
|
929
885
|
// TODO: Refactor this once proper error handling is implemented.
|
|
@@ -931,6 +887,13 @@ function microstepProcedure(transitions, currentState, mutConfiguration, event,
|
|
|
931
887
|
throw e;
|
|
932
888
|
}
|
|
933
889
|
}
|
|
890
|
+
function getMachineOutput(state, event, actorCtx, rootNode, rootCompletionNode) {
|
|
891
|
+
if (!rootNode.output) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const doneStateEvent = interpreter.createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output && rootCompletionNode.parent ? interpreter.resolveOutput(rootCompletionNode.output, state.context, event, actorCtx.self) : undefined);
|
|
895
|
+
return interpreter.resolveOutput(rootNode.output, state.context, doneStateEvent, actorCtx.self);
|
|
896
|
+
}
|
|
934
897
|
function enterStates(currentState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial) {
|
|
935
898
|
let nextState = currentState;
|
|
936
899
|
const statesToEnter = new Set();
|
|
@@ -941,6 +904,7 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
|
|
|
941
904
|
if (isInitial) {
|
|
942
905
|
statesForDefaultEntry.add(currentState.machine.root);
|
|
943
906
|
}
|
|
907
|
+
const completedNodes = new Set();
|
|
944
908
|
for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
|
|
945
909
|
mutConfiguration.add(stateNodeToEnter);
|
|
946
910
|
const actions = [];
|
|
@@ -951,26 +915,34 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
|
|
|
951
915
|
actions.push(invoke(invokeDef));
|
|
952
916
|
}
|
|
953
917
|
if (statesForDefaultEntry.has(stateNodeToEnter)) {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
actions.push(...initialActions);
|
|
957
|
-
}
|
|
918
|
+
const initialActions = stateNodeToEnter.initial.actions;
|
|
919
|
+
actions.push(...initialActions);
|
|
958
920
|
}
|
|
959
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
921
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
960
922
|
if (stateNodeToEnter.type === 'final') {
|
|
961
923
|
const parent = stateNodeToEnter.parent;
|
|
962
|
-
if (
|
|
924
|
+
if (completedNodes.has(parent)) {
|
|
963
925
|
continue;
|
|
964
926
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
927
|
+
completedNodes.add(parent);
|
|
928
|
+
let rootCompletionNode = parent?.type === 'parallel' ? parent : stateNodeToEnter;
|
|
929
|
+
let ancestorMarker = parent?.parent;
|
|
930
|
+
if (ancestorMarker) {
|
|
931
|
+
internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, nextState.context, event, actorCtx.self) : undefined));
|
|
932
|
+
while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutConfiguration, ancestorMarker)) {
|
|
933
|
+
completedNodes.add(ancestorMarker);
|
|
934
|
+
internalQueue.push(interpreter.createDoneStateEvent(ancestorMarker.id));
|
|
935
|
+
rootCompletionNode = ancestorMarker;
|
|
936
|
+
ancestorMarker = ancestorMarker.parent;
|
|
972
937
|
}
|
|
973
938
|
}
|
|
939
|
+
if (ancestorMarker) {
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
nextState = cloneState(nextState, {
|
|
943
|
+
status: 'done',
|
|
944
|
+
output: getMachineOutput(nextState, event, actorCtx, currentState.configuration[0].machine.root, rootCompletionNode)
|
|
945
|
+
});
|
|
974
946
|
}
|
|
975
947
|
}
|
|
976
948
|
return nextState;
|
|
@@ -1016,13 +988,9 @@ function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEnt
|
|
|
1016
988
|
statesToEnter.add(stateNode);
|
|
1017
989
|
if (stateNode.type === 'compound') {
|
|
1018
990
|
statesForDefaultEntry.add(stateNode);
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1023
|
-
for (const initialState of initialStates) {
|
|
1024
|
-
addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
|
1025
|
-
}
|
|
991
|
+
const [initialState] = stateNode.initial.target;
|
|
992
|
+
addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
|
|
993
|
+
addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
|
1026
994
|
} else {
|
|
1027
995
|
if (stateNode.type === 'parallel') {
|
|
1028
996
|
for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
|
|
@@ -1047,10 +1015,11 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
|
|
|
1047
1015
|
}
|
|
1048
1016
|
}
|
|
1049
1017
|
}
|
|
1050
|
-
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
|
|
1018
|
+
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue, internalQueue) {
|
|
1051
1019
|
let nextState = currentState;
|
|
1052
1020
|
const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
|
|
1053
1021
|
statesToExit.sort((a, b) => b.order - a.order);
|
|
1022
|
+
let changedHistory;
|
|
1054
1023
|
|
|
1055
1024
|
// From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates
|
|
1056
1025
|
for (const exitStateNode of statesToExit) {
|
|
@@ -1063,14 +1032,17 @@ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration
|
|
|
1063
1032
|
return sn.parent === exitStateNode;
|
|
1064
1033
|
};
|
|
1065
1034
|
}
|
|
1066
|
-
|
|
1035
|
+
changedHistory ??= {
|
|
1036
|
+
...historyValue
|
|
1037
|
+
};
|
|
1038
|
+
changedHistory[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
|
|
1067
1039
|
}
|
|
1068
1040
|
}
|
|
1069
1041
|
for (const s of statesToExit) {
|
|
1070
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))]);
|
|
1042
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))], internalQueue);
|
|
1071
1043
|
mutConfiguration.delete(s);
|
|
1072
1044
|
}
|
|
1073
|
-
return nextState;
|
|
1045
|
+
return [nextState, changedHistory || historyValue];
|
|
1074
1046
|
}
|
|
1075
1047
|
function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
|
|
1076
1048
|
const {
|
|
@@ -1135,9 +1107,10 @@ function resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
|
1135
1107
|
}
|
|
1136
1108
|
return intermediateState;
|
|
1137
1109
|
}
|
|
1138
|
-
function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
|
|
1110
|
+
function resolveActionsAndContext(currentState, event, actorCtx, actions, internalQueue, deferredActorIds) {
|
|
1139
1111
|
const retries = deferredActorIds ? [] : undefined;
|
|
1140
|
-
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
1112
|
+
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, {
|
|
1113
|
+
internalQueue,
|
|
1141
1114
|
deferredActorIds
|
|
1142
1115
|
}, retries);
|
|
1143
1116
|
retries?.forEach(([builtinAction, params]) => {
|
|
@@ -1145,13 +1118,13 @@ function resolveActionsAndContext(currentState, event, actorCtx, actions, deferr
|
|
|
1145
1118
|
});
|
|
1146
1119
|
return nextState;
|
|
1147
1120
|
}
|
|
1148
|
-
function macrostep(state, event, actorCtx) {
|
|
1121
|
+
function macrostep(state, event, actorCtx, internalQueue = []) {
|
|
1149
1122
|
let nextState = state;
|
|
1150
1123
|
const states = [];
|
|
1151
1124
|
|
|
1152
1125
|
// Handle stop event
|
|
1153
1126
|
if (event.type === interpreter.XSTATE_STOP) {
|
|
1154
|
-
nextState =
|
|
1127
|
+
nextState = stopChildren(nextState, event, actorCtx);
|
|
1155
1128
|
states.push(nextState);
|
|
1156
1129
|
return {
|
|
1157
1130
|
state: nextState,
|
|
@@ -1164,44 +1137,37 @@ function macrostep(state, event, actorCtx) {
|
|
|
1164
1137
|
// Determine the next state based on the next microstep
|
|
1165
1138
|
if (nextEvent.type !== interpreter.XSTATE_INIT) {
|
|
1166
1139
|
const transitions = selectTransitions(nextEvent, nextState);
|
|
1167
|
-
nextState = microstep(transitions, state, actorCtx, nextEvent, false);
|
|
1140
|
+
nextState = microstep(transitions, state, actorCtx, nextEvent, false, internalQueue);
|
|
1168
1141
|
states.push(nextState);
|
|
1169
1142
|
}
|
|
1143
|
+
let shouldSelectEventlessTransitions = true;
|
|
1170
1144
|
while (nextState.status === 'active') {
|
|
1171
|
-
let enabledTransitions = selectEventlessTransitions(nextState, nextEvent);
|
|
1145
|
+
let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextState, nextEvent) : [];
|
|
1146
|
+
|
|
1147
|
+
// eventless transitions should always be selected after selecting *regular* transitions
|
|
1148
|
+
// by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case
|
|
1149
|
+
const previousState = enabledTransitions.length ? nextState : undefined;
|
|
1172
1150
|
if (!enabledTransitions.length) {
|
|
1173
|
-
if (!
|
|
1151
|
+
if (!internalQueue.length) {
|
|
1174
1152
|
break;
|
|
1175
|
-
} else {
|
|
1176
|
-
nextEvent = nextState._internalQueue[0];
|
|
1177
|
-
const transitions = selectTransitions(nextEvent, nextState);
|
|
1178
|
-
nextState = microstep(transitions, nextState, actorCtx, nextEvent, false);
|
|
1179
|
-
nextState._internalQueue.shift();
|
|
1180
|
-
states.push(nextState);
|
|
1181
1153
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
states.push(nextState);
|
|
1154
|
+
nextEvent = internalQueue.shift();
|
|
1155
|
+
enabledTransitions = selectTransitions(nextEvent, nextState);
|
|
1185
1156
|
}
|
|
1157
|
+
nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false, internalQueue);
|
|
1158
|
+
shouldSelectEventlessTransitions = nextState !== previousState;
|
|
1159
|
+
states.push(nextState);
|
|
1186
1160
|
}
|
|
1187
1161
|
if (nextState.status !== 'active') {
|
|
1188
|
-
|
|
1189
|
-
stopStep(nextEvent, nextState, actorCtx);
|
|
1162
|
+
stopChildren(nextState, nextEvent, actorCtx);
|
|
1190
1163
|
}
|
|
1191
1164
|
return {
|
|
1192
1165
|
state: nextState,
|
|
1193
1166
|
microstates: states
|
|
1194
1167
|
};
|
|
1195
1168
|
}
|
|
1196
|
-
function
|
|
1197
|
-
|
|
1198
|
-
for (const stateNode of nextState.configuration.sort((a, b) => b.order - a.order)) {
|
|
1199
|
-
actions.push(...stateNode.exit);
|
|
1200
|
-
}
|
|
1201
|
-
for (const child of Object.values(nextState.children)) {
|
|
1202
|
-
actions.push(stop(child));
|
|
1203
|
-
}
|
|
1204
|
-
return resolveActionsAndContext(nextState, event, actorCtx, actions);
|
|
1169
|
+
function stopChildren(nextState, event, actorCtx) {
|
|
1170
|
+
return resolveActionsAndContext(nextState, event, actorCtx, Object.values(nextState.children).map(child => stop(child)), []);
|
|
1205
1171
|
}
|
|
1206
1172
|
function selectTransitions(event, nextState) {
|
|
1207
1173
|
return nextState.machine.getTransitionData(nextState, event);
|
|
@@ -1307,11 +1273,9 @@ class State {
|
|
|
1307
1273
|
this.error = void 0;
|
|
1308
1274
|
this.context = void 0;
|
|
1309
1275
|
this.historyValue = {};
|
|
1310
|
-
this._internalQueue = void 0;
|
|
1311
1276
|
this.configuration = void 0;
|
|
1312
1277
|
this.children = void 0;
|
|
1313
1278
|
this.context = config.context;
|
|
1314
|
-
this._internalQueue = config._internalQueue ?? [];
|
|
1315
1279
|
this.historyValue = config.historyValue || {};
|
|
1316
1280
|
this.matches = this.matches.bind(this);
|
|
1317
1281
|
this.toStrings = this.toStrings.bind(this);
|
|
@@ -1410,6 +1374,7 @@ function getPersistedState(state) {
|
|
|
1410
1374
|
tags,
|
|
1411
1375
|
machine,
|
|
1412
1376
|
children,
|
|
1377
|
+
context,
|
|
1413
1378
|
...jsonValues
|
|
1414
1379
|
} = state;
|
|
1415
1380
|
const childrenJson = {};
|
|
@@ -1422,14 +1387,45 @@ function getPersistedState(state) {
|
|
|
1422
1387
|
}
|
|
1423
1388
|
return {
|
|
1424
1389
|
...jsonValues,
|
|
1390
|
+
// TODO: this makes `PersistedMachineState`'s type kind of a lie
|
|
1391
|
+
// it doesn't truly use `TContext` but rather some kind of a derived form of it
|
|
1392
|
+
context: persistContext(context),
|
|
1425
1393
|
children: childrenJson
|
|
1426
1394
|
};
|
|
1427
1395
|
}
|
|
1396
|
+
function persistContext(contextPart) {
|
|
1397
|
+
let copy;
|
|
1398
|
+
for (const key in contextPart) {
|
|
1399
|
+
const value = contextPart[key];
|
|
1400
|
+
if (value && typeof value === 'object') {
|
|
1401
|
+
if ('sessionId' in value && 'send' in value && 'ref' in value) {
|
|
1402
|
+
copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
|
|
1403
|
+
...contextPart
|
|
1404
|
+
};
|
|
1405
|
+
copy[key] = {
|
|
1406
|
+
xstate$$type: interpreter.$$ACTOR_TYPE,
|
|
1407
|
+
id: value.id
|
|
1408
|
+
};
|
|
1409
|
+
} else {
|
|
1410
|
+
const result = persistContext(value);
|
|
1411
|
+
if (result !== value) {
|
|
1412
|
+
copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
|
|
1413
|
+
...contextPart
|
|
1414
|
+
};
|
|
1415
|
+
copy[key] = result;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
return copy ?? contextPart;
|
|
1421
|
+
}
|
|
1428
1422
|
|
|
1429
1423
|
function resolveRaise(_, state, args, {
|
|
1430
1424
|
event: eventOrExpr,
|
|
1431
1425
|
id,
|
|
1432
1426
|
delay
|
|
1427
|
+
}, {
|
|
1428
|
+
internalQueue
|
|
1433
1429
|
}) {
|
|
1434
1430
|
const delaysMap = state.machine.implementations.delays;
|
|
1435
1431
|
if (typeof eventOrExpr === 'string') {
|
|
@@ -1443,9 +1439,10 @@ function resolveRaise(_, state, args, {
|
|
|
1443
1439
|
} else {
|
|
1444
1440
|
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
1445
1441
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
}
|
|
1442
|
+
if (typeof resolvedDelay !== 'number') {
|
|
1443
|
+
internalQueue.push(resolvedEvent);
|
|
1444
|
+
}
|
|
1445
|
+
return [state, {
|
|
1449
1446
|
event: resolvedEvent,
|
|
1450
1447
|
id,
|
|
1451
1448
|
delay: resolvedDelay
|
|
@@ -1487,10 +1484,10 @@ exports.getCandidates = getCandidates;
|
|
|
1487
1484
|
exports.getConfiguration = getConfiguration;
|
|
1488
1485
|
exports.getDelayedTransitions = getDelayedTransitions;
|
|
1489
1486
|
exports.getInitialConfiguration = getInitialConfiguration;
|
|
1487
|
+
exports.getInitialStateNodes = getInitialStateNodes;
|
|
1490
1488
|
exports.getPersistedState = getPersistedState;
|
|
1491
1489
|
exports.getStateNodeByPath = getStateNodeByPath;
|
|
1492
1490
|
exports.getStateNodes = getStateNodes;
|
|
1493
|
-
exports.isAtomicStateNode = isAtomicStateNode;
|
|
1494
1491
|
exports.isInFinalState = isInFinalState;
|
|
1495
1492
|
exports.isStateId = isStateId;
|
|
1496
1493
|
exports.macrostep = macrostep;
|