xstate 5.0.0-beta.35 → 5.0.0-beta.37
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/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/stateUtils.d.ts +3 -3
- package/dist/declarations/src/typegenTypes.d.ts +2 -0
- package/dist/declarations/src/types.d.ts +1 -2
- package/dist/declarations/src/utils.d.ts +6 -6
- package/dist/declarations/src/waitFor.d.ts +1 -1
- package/dist/{interpreter-5c4e6634.development.esm.js → interpreter-1c52b23c.development.esm.js} +13 -23
- package/dist/{interpreter-de5217bc.esm.js → interpreter-8def682e.esm.js} +13 -23
- package/dist/{interpreter-69605bf0.cjs.js → interpreter-97aff8d2.cjs.js} +13 -23
- package/dist/{interpreter-d3567419.development.cjs.js → interpreter-e58ca48d.development.cjs.js} +13 -23
- package/dist/{raise-26e4d83c.development.cjs.js → raise-1fd59c65.development.cjs.js} +129 -102
- package/dist/{raise-511399cc.esm.js → raise-21c417c1.esm.js} +129 -102
- package/dist/{raise-0ff57677.cjs.js → raise-800296d7.cjs.js} +129 -102
- package/dist/{raise-cdcdf834.development.esm.js → raise-e342a840.development.esm.js} +129 -102
- package/dist/{send-19ffc568.cjs.js → send-4cc29786.cjs.js} +7 -4
- package/dist/{send-1de74f4d.development.esm.js → send-83ccc98b.development.esm.js} +7 -4
- package/dist/{send-211a2a94.esm.js → send-92854675.esm.js} +7 -4
- package/dist/{send-894c4b18.development.cjs.js → send-b309ef4e.development.cjs.js} +7 -4
- package/dist/xstate.cjs.js +11 -19
- package/dist/xstate.development.cjs.js +11 -19
- package/dist/xstate.development.esm.js +14 -22
- package/dist/xstate.esm.js +14 -22
- 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 +1 -1
- 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-97aff8d2.cjs.js');
|
|
4
4
|
|
|
5
5
|
const cache = new WeakMap();
|
|
6
6
|
function memo(object, key, fn) {
|
|
@@ -49,14 +49,17 @@ function resolveInvoke(actorContext, state, actionArgs, {
|
|
|
49
49
|
input,
|
|
50
50
|
syncSnapshot
|
|
51
51
|
}) {
|
|
52
|
-
const referenced = interpreter.resolveReferencedActor(state.machine
|
|
52
|
+
const referenced = typeof src === 'string' ? interpreter.resolveReferencedActor(state.machine, src) : {
|
|
53
|
+
src,
|
|
54
|
+
input: undefined
|
|
55
|
+
};
|
|
53
56
|
let actorRef;
|
|
54
57
|
if (referenced) {
|
|
55
58
|
// TODO: inline `input: undefined` should win over the referenced one
|
|
56
59
|
const configuredInput = input || referenced.input;
|
|
57
60
|
actorRef = interpreter.createActor(referenced.src, {
|
|
58
61
|
id,
|
|
59
|
-
src,
|
|
62
|
+
src: typeof src === 'string' ? src : undefined,
|
|
60
63
|
parent: actorContext?.self,
|
|
61
64
|
systemId,
|
|
62
65
|
input: typeof configuredInput === 'function' ? configuredInput({
|
|
@@ -153,11 +156,16 @@ function executeStop(actorContext, actorRef) {
|
|
|
153
156
|
if (!actorRef) {
|
|
154
157
|
return;
|
|
155
158
|
}
|
|
159
|
+
// this allows us to prevent an actor from being started if it gets stopped within the same macrostep
|
|
160
|
+
// this can happen, for example, when the invoking state is being exited immediately by an always transition
|
|
156
161
|
if (actorRef.status !== interpreter.ActorStatus.Running) {
|
|
157
162
|
actorContext.stopChild(actorRef);
|
|
158
163
|
return;
|
|
159
164
|
}
|
|
160
|
-
//
|
|
165
|
+
// stopping a child enqueues a stop event in the child actor's mailbox
|
|
166
|
+
// we need for all of the already enqueued events to be processed before we stop the child
|
|
167
|
+
// the parent itself might want to send some events to a child (for example from exit actions on the invoking state)
|
|
168
|
+
// and we don't want to ignore those events
|
|
161
169
|
actorContext.defer(() => {
|
|
162
170
|
actorContext.stopChild(actorRef);
|
|
163
171
|
});
|
|
@@ -181,7 +189,8 @@ function checkStateIn(state, _, {
|
|
|
181
189
|
stateValue
|
|
182
190
|
}) {
|
|
183
191
|
if (typeof stateValue === 'string' && isStateId(stateValue)) {
|
|
184
|
-
|
|
192
|
+
const target = state.machine.getStateNodeById(stateValue);
|
|
193
|
+
return state.configuration.some(sn => sn === target);
|
|
185
194
|
}
|
|
186
195
|
return state.matches(stateValue);
|
|
187
196
|
}
|
|
@@ -285,6 +294,9 @@ function getChildren(stateNode) {
|
|
|
285
294
|
}
|
|
286
295
|
function getProperAncestors(stateNode, toStateNode) {
|
|
287
296
|
const ancestors = [];
|
|
297
|
+
if (toStateNode === stateNode) {
|
|
298
|
+
return ancestors;
|
|
299
|
+
}
|
|
288
300
|
|
|
289
301
|
// add all ancestors
|
|
290
302
|
let m = stateNode.parent;
|
|
@@ -561,12 +573,14 @@ function resolveTarget(stateNode, targets) {
|
|
|
561
573
|
}
|
|
562
574
|
});
|
|
563
575
|
}
|
|
564
|
-
function
|
|
576
|
+
function resolveHistoryDefaultTransition(stateNode) {
|
|
565
577
|
const normalizedTarget = interpreter.normalizeTarget(stateNode.config.target);
|
|
566
578
|
if (!normalizedTarget) {
|
|
567
|
-
return stateNode.parent.initial
|
|
579
|
+
return stateNode.parent.initial;
|
|
568
580
|
}
|
|
569
|
-
return
|
|
581
|
+
return {
|
|
582
|
+
target: normalizedTarget.map(t => typeof t === 'string' ? getStateNodeByPath(stateNode.parent, t) : t)
|
|
583
|
+
};
|
|
570
584
|
}
|
|
571
585
|
function isHistoryNode(stateNode) {
|
|
572
586
|
return stateNode.type === 'history';
|
|
@@ -793,9 +807,7 @@ function getEffectiveTargetStates(transition, historyValue) {
|
|
|
793
807
|
targets.add(node);
|
|
794
808
|
}
|
|
795
809
|
} else {
|
|
796
|
-
for (const node of getEffectiveTargetStates({
|
|
797
|
-
target: resolveHistoryTarget(targetNode)
|
|
798
|
-
}, historyValue)) {
|
|
810
|
+
for (const node of getEffectiveTargetStates(resolveHistoryDefaultTransition(targetNode), historyValue)) {
|
|
799
811
|
targets.add(node);
|
|
800
812
|
}
|
|
801
813
|
}
|
|
@@ -808,9 +820,9 @@ function getEffectiveTargetStates(transition, historyValue) {
|
|
|
808
820
|
function getTransitionDomain(transition, historyValue) {
|
|
809
821
|
const targetStates = getEffectiveTargetStates(transition, historyValue);
|
|
810
822
|
if (!targetStates) {
|
|
811
|
-
return
|
|
823
|
+
return;
|
|
812
824
|
}
|
|
813
|
-
if (!transition.reenter &&
|
|
825
|
+
if (!transition.reenter && targetStates.every(target => target === transition.source || isDescendant(target, transition.source))) {
|
|
814
826
|
return transition.source;
|
|
815
827
|
}
|
|
816
828
|
const lcca = findLCCA(targetStates.concat(transition.source));
|
|
@@ -821,6 +833,9 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
821
833
|
for (const t of transitions) {
|
|
822
834
|
if (t.target?.length) {
|
|
823
835
|
const domain = getTransitionDomain(t, historyValue);
|
|
836
|
+
if (t.reenter && t.source === domain) {
|
|
837
|
+
statesToExit.add(domain);
|
|
838
|
+
}
|
|
824
839
|
for (const stateNode of configuration) {
|
|
825
840
|
if (isDescendant(stateNode, domain)) {
|
|
826
841
|
statesToExit.add(stateNode);
|
|
@@ -830,6 +845,17 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
830
845
|
}
|
|
831
846
|
return [...statesToExit];
|
|
832
847
|
}
|
|
848
|
+
function areConfigurationsEqual(previousConfiguration, nextConfigurationSet) {
|
|
849
|
+
if (previousConfiguration.length !== nextConfigurationSet.size) {
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
for (const node of previousConfiguration) {
|
|
853
|
+
if (!nextConfigurationSet.has(node)) {
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return true;
|
|
858
|
+
}
|
|
833
859
|
|
|
834
860
|
/**
|
|
835
861
|
* https://www.w3.org/TR/scxml/#microstepProcedure
|
|
@@ -839,50 +865,36 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
839
865
|
* @param currentState
|
|
840
866
|
* @param mutConfiguration
|
|
841
867
|
*/
|
|
842
|
-
|
|
843
|
-
function microstep(transitions, currentState, actorCtx, event, isInitial) {
|
|
844
|
-
const mutConfiguration = new Set(currentState.configuration);
|
|
868
|
+
function microstep(transitions, currentState, actorCtx, event, isInitial, internalQueue) {
|
|
845
869
|
if (!transitions.length) {
|
|
846
870
|
return currentState;
|
|
847
871
|
}
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
value: {} // TODO: make optional
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
|
|
855
|
-
const historyValue = {
|
|
856
|
-
...currentState.historyValue
|
|
857
|
-
};
|
|
872
|
+
const mutConfiguration = new Set(currentState.configuration);
|
|
873
|
+
let historyValue = currentState.historyValue;
|
|
858
874
|
const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
|
|
859
|
-
|
|
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
|
-
});
|
|
875
|
+
let nextState = currentState;
|
|
865
876
|
|
|
866
877
|
// Exit states
|
|
867
878
|
if (!isInitial) {
|
|
868
|
-
nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
|
|
879
|
+
[nextState, historyValue] = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue, internalQueue);
|
|
869
880
|
}
|
|
870
881
|
|
|
871
882
|
// Execute transition content
|
|
872
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
|
|
883
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions), internalQueue);
|
|
873
884
|
|
|
874
885
|
// Enter states
|
|
875
886
|
nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
|
|
876
887
|
const nextConfiguration = [...mutConfiguration];
|
|
877
888
|
if (nextState.status === 'done') {
|
|
878
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
|
|
889
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
|
|
879
890
|
}
|
|
880
891
|
try {
|
|
881
|
-
|
|
892
|
+
if (historyValue === currentState.historyValue && areConfigurationsEqual(currentState.configuration, mutConfiguration)) {
|
|
893
|
+
return nextState;
|
|
894
|
+
}
|
|
882
895
|
return cloneState(nextState, {
|
|
883
896
|
configuration: nextConfiguration,
|
|
884
|
-
historyValue
|
|
885
|
-
_internalQueue: internalQueue
|
|
897
|
+
historyValue
|
|
886
898
|
});
|
|
887
899
|
} catch (e) {
|
|
888
900
|
// TODO: Refactor this once proper error handling is implemented.
|
|
@@ -900,6 +912,9 @@ function getMachineOutput(state, event, actorCtx, rootNode, rootCompletionNode)
|
|
|
900
912
|
function enterStates(currentState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial) {
|
|
901
913
|
let nextState = currentState;
|
|
902
914
|
const statesToEnter = new Set();
|
|
915
|
+
// those are states that were directly targeted or indirectly targeted by the explicit target
|
|
916
|
+
// in other words, those are states for which initial actions should be executed
|
|
917
|
+
// when we target `#deep_child` initial actions of its ancestors shouldn't be executed
|
|
903
918
|
const statesForDefaultEntry = new Set();
|
|
904
919
|
computeEntrySet(filteredTransitions, historyValue, statesForDefaultEntry, statesToEnter);
|
|
905
920
|
|
|
@@ -921,23 +936,19 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
|
|
|
921
936
|
const initialActions = stateNodeToEnter.initial.actions;
|
|
922
937
|
actions.push(...initialActions);
|
|
923
938
|
}
|
|
924
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
939
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
925
940
|
if (stateNodeToEnter.type === 'final') {
|
|
926
941
|
const parent = stateNodeToEnter.parent;
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
completedNodes.add(parent);
|
|
931
|
-
let rootCompletionNode = parent?.type === 'parallel' ? parent : stateNodeToEnter;
|
|
932
|
-
let ancestorMarker = parent?.parent;
|
|
933
|
-
if (ancestorMarker) {
|
|
942
|
+
let ancestorMarker = parent?.type === 'parallel' ? parent : parent?.parent;
|
|
943
|
+
let rootCompletionNode = ancestorMarker || stateNodeToEnter;
|
|
944
|
+
if (parent?.type === 'compound') {
|
|
934
945
|
internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, nextState.context, event, actorCtx.self) : undefined));
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
946
|
+
}
|
|
947
|
+
while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutConfiguration, ancestorMarker)) {
|
|
948
|
+
completedNodes.add(ancestorMarker);
|
|
949
|
+
internalQueue.push(interpreter.createDoneStateEvent(ancestorMarker.id));
|
|
950
|
+
rootCompletionNode = ancestorMarker;
|
|
951
|
+
ancestorMarker = ancestorMarker.parent;
|
|
941
952
|
}
|
|
942
953
|
if (ancestorMarker) {
|
|
943
954
|
continue;
|
|
@@ -952,13 +963,24 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
|
|
|
952
963
|
}
|
|
953
964
|
function computeEntrySet(transitions, historyValue, statesForDefaultEntry, statesToEnter) {
|
|
954
965
|
for (const t of transitions) {
|
|
966
|
+
const domain = getTransitionDomain(t, historyValue);
|
|
955
967
|
for (const s of t.target || []) {
|
|
968
|
+
if (!isHistoryNode(s) && (
|
|
969
|
+
// if the target is different than the source then it will *definitely* be entered
|
|
970
|
+
t.source !== s ||
|
|
971
|
+
// we know that the domain can't lie within the source
|
|
972
|
+
// if it's different than the source then it's outside of it and it means that the target has to be entered as well
|
|
973
|
+
t.source !== domain ||
|
|
974
|
+
// reentering transitions always enter the target, even if it's the source itself
|
|
975
|
+
t.reenter)) {
|
|
976
|
+
statesToEnter.add(s);
|
|
977
|
+
statesForDefaultEntry.add(s);
|
|
978
|
+
}
|
|
956
979
|
addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
|
|
957
980
|
}
|
|
958
|
-
const ancestor = getTransitionDomain(t, historyValue);
|
|
959
981
|
const targetStates = getEffectiveTargetStates(t, historyValue);
|
|
960
982
|
for (const s of targetStates) {
|
|
961
|
-
addAncestorStatesToEnter(s,
|
|
983
|
+
addAncestorStatesToEnter(s, domain, statesToEnter, historyValue, statesForDefaultEntry);
|
|
962
984
|
}
|
|
963
985
|
}
|
|
964
986
|
}
|
|
@@ -967,37 +989,42 @@ function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEnt
|
|
|
967
989
|
if (historyValue[stateNode.id]) {
|
|
968
990
|
const historyStateNodes = historyValue[stateNode.id];
|
|
969
991
|
for (const s of historyStateNodes) {
|
|
992
|
+
statesToEnter.add(s);
|
|
970
993
|
addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
|
|
971
994
|
}
|
|
972
995
|
for (const s of historyStateNodes) {
|
|
973
996
|
addAncestorStatesToEnter(s, stateNode.parent, statesToEnter, historyValue, statesForDefaultEntry);
|
|
974
|
-
for (const stateForDefaultEntry of statesForDefaultEntry) {
|
|
975
|
-
statesForDefaultEntry.add(stateForDefaultEntry);
|
|
976
|
-
}
|
|
977
997
|
}
|
|
978
998
|
} else {
|
|
979
|
-
const
|
|
980
|
-
for (const s of
|
|
999
|
+
const historyDefaultTransition = resolveHistoryDefaultTransition(stateNode);
|
|
1000
|
+
for (const s of historyDefaultTransition.target) {
|
|
1001
|
+
statesToEnter.add(s);
|
|
1002
|
+
if (historyDefaultTransition === stateNode.parent?.initial) {
|
|
1003
|
+
statesForDefaultEntry.add(stateNode.parent);
|
|
1004
|
+
}
|
|
981
1005
|
addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
|
|
982
1006
|
}
|
|
983
|
-
for (const s of
|
|
1007
|
+
for (const s of historyDefaultTransition.target) {
|
|
984
1008
|
addAncestorStatesToEnter(s, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
|
985
|
-
for (const stateForDefaultEntry of statesForDefaultEntry) {
|
|
986
|
-
statesForDefaultEntry.add(stateForDefaultEntry);
|
|
987
|
-
}
|
|
988
1009
|
}
|
|
989
1010
|
}
|
|
990
1011
|
} else {
|
|
991
|
-
statesToEnter.add(stateNode);
|
|
992
1012
|
if (stateNode.type === 'compound') {
|
|
993
|
-
statesForDefaultEntry.add(stateNode);
|
|
994
1013
|
const [initialState] = stateNode.initial.target;
|
|
1014
|
+
if (!isHistoryNode(initialState)) {
|
|
1015
|
+
statesToEnter.add(initialState);
|
|
1016
|
+
statesForDefaultEntry.add(initialState);
|
|
1017
|
+
}
|
|
995
1018
|
addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
|
|
996
1019
|
addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
|
997
1020
|
} else {
|
|
998
1021
|
if (stateNode.type === 'parallel') {
|
|
999
1022
|
for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
|
|
1000
1023
|
if (![...statesToEnter].some(s => isDescendant(s, child))) {
|
|
1024
|
+
if (!isHistoryNode(child)) {
|
|
1025
|
+
statesToEnter.add(child);
|
|
1026
|
+
statesForDefaultEntry.add(child);
|
|
1027
|
+
}
|
|
1001
1028
|
addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter);
|
|
1002
1029
|
}
|
|
1003
1030
|
}
|
|
@@ -1012,16 +1039,18 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
|
|
|
1012
1039
|
if (anc.type === 'parallel') {
|
|
1013
1040
|
for (const child of getChildren(anc).filter(sn => !isHistoryNode(sn))) {
|
|
1014
1041
|
if (![...statesToEnter].some(s => isDescendant(s, child))) {
|
|
1042
|
+
statesToEnter.add(child);
|
|
1015
1043
|
addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter);
|
|
1016
1044
|
}
|
|
1017
1045
|
}
|
|
1018
1046
|
}
|
|
1019
1047
|
}
|
|
1020
1048
|
}
|
|
1021
|
-
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
|
|
1049
|
+
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue, internalQueue) {
|
|
1022
1050
|
let nextState = currentState;
|
|
1023
1051
|
const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
|
|
1024
1052
|
statesToExit.sort((a, b) => b.order - a.order);
|
|
1053
|
+
let changedHistory;
|
|
1025
1054
|
|
|
1026
1055
|
// From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates
|
|
1027
1056
|
for (const exitStateNode of statesToExit) {
|
|
@@ -1034,14 +1063,17 @@ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration
|
|
|
1034
1063
|
return sn.parent === exitStateNode;
|
|
1035
1064
|
};
|
|
1036
1065
|
}
|
|
1037
|
-
|
|
1066
|
+
changedHistory ??= {
|
|
1067
|
+
...historyValue
|
|
1068
|
+
};
|
|
1069
|
+
changedHistory[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
|
|
1038
1070
|
}
|
|
1039
1071
|
}
|
|
1040
1072
|
for (const s of statesToExit) {
|
|
1041
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))]);
|
|
1073
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))], internalQueue);
|
|
1042
1074
|
mutConfiguration.delete(s);
|
|
1043
1075
|
}
|
|
1044
|
-
return nextState;
|
|
1076
|
+
return [nextState, changedHistory || historyValue];
|
|
1045
1077
|
}
|
|
1046
1078
|
function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
|
|
1047
1079
|
const {
|
|
@@ -1106,9 +1138,10 @@ function resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
|
1106
1138
|
}
|
|
1107
1139
|
return intermediateState;
|
|
1108
1140
|
}
|
|
1109
|
-
function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
|
|
1141
|
+
function resolveActionsAndContext(currentState, event, actorCtx, actions, internalQueue, deferredActorIds) {
|
|
1110
1142
|
const retries = deferredActorIds ? [] : undefined;
|
|
1111
|
-
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
1143
|
+
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, {
|
|
1144
|
+
internalQueue,
|
|
1112
1145
|
deferredActorIds
|
|
1113
1146
|
}, retries);
|
|
1114
1147
|
retries?.forEach(([builtinAction, params]) => {
|
|
@@ -1116,13 +1149,13 @@ function resolveActionsAndContext(currentState, event, actorCtx, actions, deferr
|
|
|
1116
1149
|
});
|
|
1117
1150
|
return nextState;
|
|
1118
1151
|
}
|
|
1119
|
-
function macrostep(state, event, actorCtx) {
|
|
1152
|
+
function macrostep(state, event, actorCtx, internalQueue = []) {
|
|
1120
1153
|
let nextState = state;
|
|
1121
1154
|
const states = [];
|
|
1122
1155
|
|
|
1123
1156
|
// Handle stop event
|
|
1124
1157
|
if (event.type === interpreter.XSTATE_STOP) {
|
|
1125
|
-
nextState =
|
|
1158
|
+
nextState = stopChildren(nextState, event, actorCtx);
|
|
1126
1159
|
states.push(nextState);
|
|
1127
1160
|
return {
|
|
1128
1161
|
state: nextState,
|
|
@@ -1135,44 +1168,37 @@ function macrostep(state, event, actorCtx) {
|
|
|
1135
1168
|
// Determine the next state based on the next microstep
|
|
1136
1169
|
if (nextEvent.type !== interpreter.XSTATE_INIT) {
|
|
1137
1170
|
const transitions = selectTransitions(nextEvent, nextState);
|
|
1138
|
-
nextState = microstep(transitions, state, actorCtx, nextEvent, false);
|
|
1171
|
+
nextState = microstep(transitions, state, actorCtx, nextEvent, false, internalQueue);
|
|
1139
1172
|
states.push(nextState);
|
|
1140
1173
|
}
|
|
1174
|
+
let shouldSelectEventlessTransitions = true;
|
|
1141
1175
|
while (nextState.status === 'active') {
|
|
1142
|
-
let enabledTransitions = selectEventlessTransitions(nextState, nextEvent);
|
|
1176
|
+
let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextState, nextEvent) : [];
|
|
1177
|
+
|
|
1178
|
+
// eventless transitions should always be selected after selecting *regular* transitions
|
|
1179
|
+
// by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case
|
|
1180
|
+
const previousState = enabledTransitions.length ? nextState : undefined;
|
|
1143
1181
|
if (!enabledTransitions.length) {
|
|
1144
|
-
if (!
|
|
1182
|
+
if (!internalQueue.length) {
|
|
1145
1183
|
break;
|
|
1146
|
-
} else {
|
|
1147
|
-
nextEvent = nextState._internalQueue[0];
|
|
1148
|
-
const transitions = selectTransitions(nextEvent, nextState);
|
|
1149
|
-
nextState = microstep(transitions, nextState, actorCtx, nextEvent, false);
|
|
1150
|
-
nextState._internalQueue.shift();
|
|
1151
|
-
states.push(nextState);
|
|
1152
1184
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
states.push(nextState);
|
|
1185
|
+
nextEvent = internalQueue.shift();
|
|
1186
|
+
enabledTransitions = selectTransitions(nextEvent, nextState);
|
|
1156
1187
|
}
|
|
1188
|
+
nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false, internalQueue);
|
|
1189
|
+
shouldSelectEventlessTransitions = nextState !== previousState;
|
|
1190
|
+
states.push(nextState);
|
|
1157
1191
|
}
|
|
1158
1192
|
if (nextState.status !== 'active') {
|
|
1159
|
-
|
|
1160
|
-
stopStep(nextEvent, nextState, actorCtx);
|
|
1193
|
+
stopChildren(nextState, nextEvent, actorCtx);
|
|
1161
1194
|
}
|
|
1162
1195
|
return {
|
|
1163
1196
|
state: nextState,
|
|
1164
1197
|
microstates: states
|
|
1165
1198
|
};
|
|
1166
1199
|
}
|
|
1167
|
-
function
|
|
1168
|
-
|
|
1169
|
-
for (const stateNode of nextState.configuration.sort((a, b) => b.order - a.order)) {
|
|
1170
|
-
actions.push(...stateNode.exit);
|
|
1171
|
-
}
|
|
1172
|
-
for (const child of Object.values(nextState.children)) {
|
|
1173
|
-
actions.push(stop(child));
|
|
1174
|
-
}
|
|
1175
|
-
return resolveActionsAndContext(nextState, event, actorCtx, actions);
|
|
1200
|
+
function stopChildren(nextState, event, actorCtx) {
|
|
1201
|
+
return resolveActionsAndContext(nextState, event, actorCtx, Object.values(nextState.children).map(child => stop(child)), []);
|
|
1176
1202
|
}
|
|
1177
1203
|
function selectTransitions(event, nextState) {
|
|
1178
1204
|
return nextState.machine.getTransitionData(nextState, event);
|
|
@@ -1181,7 +1207,7 @@ function selectEventlessTransitions(nextState, event) {
|
|
|
1181
1207
|
const enabledTransitionSet = new Set();
|
|
1182
1208
|
const atomicStates = nextState.configuration.filter(isAtomicStateNode);
|
|
1183
1209
|
for (const stateNode of atomicStates) {
|
|
1184
|
-
loop: for (const s of [stateNode].concat(getProperAncestors(stateNode,
|
|
1210
|
+
loop: for (const s of [stateNode].concat(getProperAncestors(stateNode, undefined))) {
|
|
1185
1211
|
if (!s.always) {
|
|
1186
1212
|
continue;
|
|
1187
1213
|
}
|
|
@@ -1278,11 +1304,9 @@ class State {
|
|
|
1278
1304
|
this.error = void 0;
|
|
1279
1305
|
this.context = void 0;
|
|
1280
1306
|
this.historyValue = {};
|
|
1281
|
-
this._internalQueue = void 0;
|
|
1282
1307
|
this.configuration = void 0;
|
|
1283
1308
|
this.children = void 0;
|
|
1284
1309
|
this.context = config.context;
|
|
1285
|
-
this._internalQueue = config._internalQueue ?? [];
|
|
1286
1310
|
this.historyValue = config.historyValue || {};
|
|
1287
1311
|
this.matches = this.matches.bind(this);
|
|
1288
1312
|
this.toStrings = this.toStrings.bind(this);
|
|
@@ -1431,6 +1455,8 @@ function resolveRaise(_, state, args, {
|
|
|
1431
1455
|
event: eventOrExpr,
|
|
1432
1456
|
id,
|
|
1433
1457
|
delay
|
|
1458
|
+
}, {
|
|
1459
|
+
internalQueue
|
|
1434
1460
|
}) {
|
|
1435
1461
|
const delaysMap = state.machine.implementations.delays;
|
|
1436
1462
|
if (typeof eventOrExpr === 'string') {
|
|
@@ -1444,9 +1470,10 @@ function resolveRaise(_, state, args, {
|
|
|
1444
1470
|
} else {
|
|
1445
1471
|
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
1446
1472
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}
|
|
1473
|
+
if (typeof resolvedDelay !== 'number') {
|
|
1474
|
+
internalQueue.push(resolvedEvent);
|
|
1475
|
+
}
|
|
1476
|
+
return [state, {
|
|
1450
1477
|
event: resolvedEvent,
|
|
1451
1478
|
id,
|
|
1452
1479
|
delay: resolvedDelay
|