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