xstate 5.0.0-beta.35 → 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/actions/dist/xstate-actions.cjs.js +2 -2
- package/actions/dist/xstate-actions.development.cjs.js +2 -2
- package/actions/dist/xstate-actions.development.esm.js +2 -2
- package/actions/dist/xstate-actions.esm.js +2 -2
- package/actions/dist/xstate-actions.umd.min.js +1 -1
- package/actions/dist/xstate-actions.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/types.d.ts +0 -1
- package/dist/{raise-26e4d83c.development.cjs.js → raise-106ea558.development.cjs.js} +58 -62
- package/dist/{raise-cdcdf834.development.esm.js → raise-5b7ad3b7.development.esm.js} +58 -62
- package/dist/{raise-0ff57677.cjs.js → raise-c51b81a3.cjs.js} +58 -62
- package/dist/{raise-511399cc.esm.js → raise-ffe1014a.esm.js} +58 -62
- package/dist/{send-211a2a94.esm.js → send-0a7aa74e.esm.js} +2 -2
- package/dist/{send-894c4b18.development.cjs.js → send-25e70bd4.development.cjs.js} +2 -2
- package/dist/{send-19ffc568.cjs.js → send-778692de.cjs.js} +2 -2
- package/dist/{send-1de74f4d.development.esm.js → send-e93554d6.development.esm.js} +2 -2
- package/dist/xstate.cjs.js +8 -8
- package/dist/xstate.development.cjs.js +8 -8
- package/dist/xstate.development.esm.js +10 -10
- package/dist/xstate.esm.js +10 -10
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/guards/dist/xstate-guards.cjs.js +1 -1
- package/guards/dist/xstate-guards.development.cjs.js +1 -1
- package/guards/dist/xstate-guards.development.esm.js +1 -1
- package/guards/dist/xstate-guards.esm.js +1 -1
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -27,7 +27,6 @@ export declare class State<TContext extends MachineContext, TEvent extends Event
|
|
|
27
27
|
error: unknown;
|
|
28
28
|
context: TContext;
|
|
29
29
|
historyValue: Readonly<HistoryValue<TContext, TEvent>>;
|
|
30
|
-
_internalQueue: Array<TEvent>;
|
|
31
30
|
/**
|
|
32
31
|
* The enabled state nodes representative of the state value.
|
|
33
32
|
*/
|
|
@@ -50,9 +50,9 @@ export declare function removeConflictingTransitions(enabledTransitions: Array<A
|
|
|
50
50
|
* @param currentState
|
|
51
51
|
* @param mutConfiguration
|
|
52
52
|
*/
|
|
53
|
-
export declare function microstep<TContext extends MachineContext, TEvent extends EventObject>(transitions: Array<
|
|
54
|
-
export declare function resolveActionsAndContext(currentState: AnyState, event: AnyEventObject, actorCtx: AnyActorContext, actions: UnknownAction[], deferredActorIds?: string[]): AnyState;
|
|
55
|
-
export declare function macrostep(state: AnyState, event: EventObject, actorCtx: AnyActorContext): {
|
|
53
|
+
export declare function microstep<TContext extends MachineContext, TEvent extends EventObject>(transitions: Array<AnyTransitionDefinition>, currentState: AnyState, actorCtx: AnyActorContext, event: AnyEventObject, isInitial: boolean, internalQueue: Array<AnyEventObject>): AnyState;
|
|
54
|
+
export declare function resolveActionsAndContext(currentState: AnyState, event: AnyEventObject, actorCtx: AnyActorContext, actions: UnknownAction[], internalQueue: AnyEventObject[], deferredActorIds?: string[]): AnyState;
|
|
55
|
+
export declare function macrostep(state: AnyState, event: EventObject, actorCtx: AnyActorContext, internalQueue?: AnyEventObject[]): {
|
|
56
56
|
state: typeof state;
|
|
57
57
|
microstates: Array<typeof state>;
|
|
58
58
|
};
|
|
@@ -554,7 +554,6 @@ export interface StateConfig<TContext extends MachineContext, TEvent extends Eve
|
|
|
554
554
|
error?: unknown;
|
|
555
555
|
tags?: Set<string>;
|
|
556
556
|
machine?: StateMachine<TContext, TEvent, any, any, any, any, any, any, any>;
|
|
557
|
-
_internalQueue?: Array<TEvent>;
|
|
558
557
|
}
|
|
559
558
|
export interface ActorOptions<TLogic extends AnyActorLogic> {
|
|
560
559
|
/**
|
|
@@ -861,6 +861,17 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
861
861
|
}
|
|
862
862
|
return [...statesToExit];
|
|
863
863
|
}
|
|
864
|
+
function areConfigurationsEqual(previousConfiguration, nextConfigurationSet) {
|
|
865
|
+
if (previousConfiguration.length !== nextConfigurationSet.size) {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
for (const node of previousConfiguration) {
|
|
869
|
+
if (!nextConfigurationSet.has(node)) {
|
|
870
|
+
return false;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return true;
|
|
874
|
+
}
|
|
864
875
|
|
|
865
876
|
/**
|
|
866
877
|
* https://www.w3.org/TR/scxml/#microstepProcedure
|
|
@@ -870,50 +881,36 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
870
881
|
* @param currentState
|
|
871
882
|
* @param mutConfiguration
|
|
872
883
|
*/
|
|
873
|
-
|
|
874
|
-
function microstep(transitions, currentState, actorCtx, event, isInitial) {
|
|
875
|
-
const mutConfiguration = new Set(currentState.configuration);
|
|
884
|
+
function microstep(transitions, currentState, actorCtx, event, isInitial, internalQueue) {
|
|
876
885
|
if (!transitions.length) {
|
|
877
886
|
return currentState;
|
|
878
887
|
}
|
|
879
|
-
const
|
|
880
|
-
|
|
881
|
-
value: {} // TODO: make optional
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
|
|
886
|
-
const historyValue = {
|
|
887
|
-
...currentState.historyValue
|
|
888
|
-
};
|
|
888
|
+
const mutConfiguration = new Set(currentState.configuration);
|
|
889
|
+
let historyValue = currentState.historyValue;
|
|
889
890
|
const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
|
|
890
|
-
|
|
891
|
-
// TODO: this `cloneState` is really just a hack to prevent infinite loops
|
|
892
|
-
// we need to take another look at how internal queue is managed
|
|
893
|
-
let nextState = cloneState(currentState, {
|
|
894
|
-
_internalQueue: []
|
|
895
|
-
});
|
|
891
|
+
let nextState = currentState;
|
|
896
892
|
|
|
897
893
|
// Exit states
|
|
898
894
|
if (!isInitial) {
|
|
899
|
-
nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
|
|
895
|
+
[nextState, historyValue] = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue, internalQueue);
|
|
900
896
|
}
|
|
901
897
|
|
|
902
898
|
// Execute transition content
|
|
903
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
|
|
899
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions), internalQueue);
|
|
904
900
|
|
|
905
901
|
// Enter states
|
|
906
902
|
nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
|
|
907
903
|
const nextConfiguration = [...mutConfiguration];
|
|
908
904
|
if (nextState.status === 'done') {
|
|
909
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
|
|
905
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
|
|
910
906
|
}
|
|
911
907
|
try {
|
|
912
|
-
|
|
908
|
+
if (historyValue === currentState.historyValue && areConfigurationsEqual(currentState.configuration, mutConfiguration)) {
|
|
909
|
+
return nextState;
|
|
910
|
+
}
|
|
913
911
|
return cloneState(nextState, {
|
|
914
912
|
configuration: nextConfiguration,
|
|
915
|
-
historyValue
|
|
916
|
-
_internalQueue: internalQueue
|
|
913
|
+
historyValue
|
|
917
914
|
});
|
|
918
915
|
} catch (e) {
|
|
919
916
|
// TODO: Refactor this once proper error handling is implemented.
|
|
@@ -952,7 +949,7 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
|
|
|
952
949
|
const initialActions = stateNodeToEnter.initial.actions;
|
|
953
950
|
actions.push(...initialActions);
|
|
954
951
|
}
|
|
955
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
952
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
956
953
|
if (stateNodeToEnter.type === 'final') {
|
|
957
954
|
const parent = stateNodeToEnter.parent;
|
|
958
955
|
if (completedNodes.has(parent)) {
|
|
@@ -1049,10 +1046,11 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
|
|
|
1049
1046
|
}
|
|
1050
1047
|
}
|
|
1051
1048
|
}
|
|
1052
|
-
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
|
|
1049
|
+
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue, internalQueue) {
|
|
1053
1050
|
let nextState = currentState;
|
|
1054
1051
|
const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
|
|
1055
1052
|
statesToExit.sort((a, b) => b.order - a.order);
|
|
1053
|
+
let changedHistory;
|
|
1056
1054
|
|
|
1057
1055
|
// From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates
|
|
1058
1056
|
for (const exitStateNode of statesToExit) {
|
|
@@ -1065,14 +1063,17 @@ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration
|
|
|
1065
1063
|
return sn.parent === exitStateNode;
|
|
1066
1064
|
};
|
|
1067
1065
|
}
|
|
1068
|
-
|
|
1066
|
+
changedHistory ??= {
|
|
1067
|
+
...historyValue
|
|
1068
|
+
};
|
|
1069
|
+
changedHistory[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
|
|
1069
1070
|
}
|
|
1070
1071
|
}
|
|
1071
1072
|
for (const s of statesToExit) {
|
|
1072
|
-
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);
|
|
1073
1074
|
mutConfiguration.delete(s);
|
|
1074
1075
|
}
|
|
1075
|
-
return nextState;
|
|
1076
|
+
return [nextState, changedHistory || historyValue];
|
|
1076
1077
|
}
|
|
1077
1078
|
function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
|
|
1078
1079
|
const {
|
|
@@ -1137,9 +1138,10 @@ function resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
|
1137
1138
|
}
|
|
1138
1139
|
return intermediateState;
|
|
1139
1140
|
}
|
|
1140
|
-
function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
|
|
1141
|
+
function resolveActionsAndContext(currentState, event, actorCtx, actions, internalQueue, deferredActorIds) {
|
|
1141
1142
|
const retries = deferredActorIds ? [] : undefined;
|
|
1142
|
-
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
1143
|
+
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, {
|
|
1144
|
+
internalQueue,
|
|
1143
1145
|
deferredActorIds
|
|
1144
1146
|
}, retries);
|
|
1145
1147
|
retries?.forEach(([builtinAction, params]) => {
|
|
@@ -1147,7 +1149,7 @@ function resolveActionsAndContext(currentState, event, actorCtx, actions, deferr
|
|
|
1147
1149
|
});
|
|
1148
1150
|
return nextState;
|
|
1149
1151
|
}
|
|
1150
|
-
function macrostep(state, event, actorCtx) {
|
|
1152
|
+
function macrostep(state, event, actorCtx, internalQueue = []) {
|
|
1151
1153
|
if (event.type === interpreter.WILDCARD) {
|
|
1152
1154
|
throw new Error(`An event cannot have the wildcard type ('${interpreter.WILDCARD}')`);
|
|
1153
1155
|
}
|
|
@@ -1156,7 +1158,7 @@ function macrostep(state, event, actorCtx) {
|
|
|
1156
1158
|
|
|
1157
1159
|
// Handle stop event
|
|
1158
1160
|
if (event.type === interpreter.XSTATE_STOP) {
|
|
1159
|
-
nextState =
|
|
1161
|
+
nextState = stopChildren(nextState, event, actorCtx);
|
|
1160
1162
|
states.push(nextState);
|
|
1161
1163
|
return {
|
|
1162
1164
|
state: nextState,
|
|
@@ -1169,44 +1171,37 @@ function macrostep(state, event, actorCtx) {
|
|
|
1169
1171
|
// Determine the next state based on the next microstep
|
|
1170
1172
|
if (nextEvent.type !== interpreter.XSTATE_INIT) {
|
|
1171
1173
|
const transitions = selectTransitions(nextEvent, nextState);
|
|
1172
|
-
nextState = microstep(transitions, state, actorCtx, nextEvent, false);
|
|
1174
|
+
nextState = microstep(transitions, state, actorCtx, nextEvent, false, internalQueue);
|
|
1173
1175
|
states.push(nextState);
|
|
1174
1176
|
}
|
|
1177
|
+
let shouldSelectEventlessTransitions = true;
|
|
1175
1178
|
while (nextState.status === 'active') {
|
|
1176
|
-
let enabledTransitions = selectEventlessTransitions(nextState, nextEvent);
|
|
1179
|
+
let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextState, nextEvent) : [];
|
|
1180
|
+
|
|
1181
|
+
// eventless transitions should always be selected after selecting *regular* transitions
|
|
1182
|
+
// by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case
|
|
1183
|
+
const previousState = enabledTransitions.length ? nextState : undefined;
|
|
1177
1184
|
if (!enabledTransitions.length) {
|
|
1178
|
-
if (!
|
|
1185
|
+
if (!internalQueue.length) {
|
|
1179
1186
|
break;
|
|
1180
|
-
} else {
|
|
1181
|
-
nextEvent = nextState._internalQueue[0];
|
|
1182
|
-
const transitions = selectTransitions(nextEvent, nextState);
|
|
1183
|
-
nextState = microstep(transitions, nextState, actorCtx, nextEvent, false);
|
|
1184
|
-
nextState._internalQueue.shift();
|
|
1185
|
-
states.push(nextState);
|
|
1186
1187
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
states.push(nextState);
|
|
1188
|
+
nextEvent = internalQueue.shift();
|
|
1189
|
+
enabledTransitions = selectTransitions(nextEvent, nextState);
|
|
1190
1190
|
}
|
|
1191
|
+
nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false, internalQueue);
|
|
1192
|
+
shouldSelectEventlessTransitions = nextState !== previousState;
|
|
1193
|
+
states.push(nextState);
|
|
1191
1194
|
}
|
|
1192
1195
|
if (nextState.status !== 'active') {
|
|
1193
|
-
|
|
1194
|
-
stopStep(nextEvent, nextState, actorCtx);
|
|
1196
|
+
stopChildren(nextState, nextEvent, actorCtx);
|
|
1195
1197
|
}
|
|
1196
1198
|
return {
|
|
1197
1199
|
state: nextState,
|
|
1198
1200
|
microstates: states
|
|
1199
1201
|
};
|
|
1200
1202
|
}
|
|
1201
|
-
function
|
|
1202
|
-
|
|
1203
|
-
for (const stateNode of nextState.configuration.sort((a, b) => b.order - a.order)) {
|
|
1204
|
-
actions.push(...stateNode.exit);
|
|
1205
|
-
}
|
|
1206
|
-
for (const child of Object.values(nextState.children)) {
|
|
1207
|
-
actions.push(stop(child));
|
|
1208
|
-
}
|
|
1209
|
-
return resolveActionsAndContext(nextState, event, actorCtx, actions);
|
|
1203
|
+
function stopChildren(nextState, event, actorCtx) {
|
|
1204
|
+
return resolveActionsAndContext(nextState, event, actorCtx, Object.values(nextState.children).map(child => stop(child)), []);
|
|
1210
1205
|
}
|
|
1211
1206
|
function selectTransitions(event, nextState) {
|
|
1212
1207
|
return nextState.machine.getTransitionData(nextState, event);
|
|
@@ -1312,11 +1307,9 @@ class State {
|
|
|
1312
1307
|
this.error = void 0;
|
|
1313
1308
|
this.context = void 0;
|
|
1314
1309
|
this.historyValue = {};
|
|
1315
|
-
this._internalQueue = void 0;
|
|
1316
1310
|
this.configuration = void 0;
|
|
1317
1311
|
this.children = void 0;
|
|
1318
1312
|
this.context = config.context;
|
|
1319
|
-
this._internalQueue = config._internalQueue ?? [];
|
|
1320
1313
|
this.historyValue = config.historyValue || {};
|
|
1321
1314
|
this.matches = this.matches.bind(this);
|
|
1322
1315
|
this.toStrings = this.toStrings.bind(this);
|
|
@@ -1471,6 +1464,8 @@ function resolveRaise(_, state, args, {
|
|
|
1471
1464
|
event: eventOrExpr,
|
|
1472
1465
|
id,
|
|
1473
1466
|
delay
|
|
1467
|
+
}, {
|
|
1468
|
+
internalQueue
|
|
1474
1469
|
}) {
|
|
1475
1470
|
const delaysMap = state.machine.implementations.delays;
|
|
1476
1471
|
if (typeof eventOrExpr === 'string') {
|
|
@@ -1484,9 +1479,10 @@ function resolveRaise(_, state, args, {
|
|
|
1484
1479
|
} else {
|
|
1485
1480
|
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
1486
1481
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
}
|
|
1482
|
+
if (typeof resolvedDelay !== 'number') {
|
|
1483
|
+
internalQueue.push(resolvedEvent);
|
|
1484
|
+
}
|
|
1485
|
+
return [state, {
|
|
1490
1486
|
event: resolvedEvent,
|
|
1491
1487
|
id,
|
|
1492
1488
|
delay: resolvedDelay
|
|
@@ -859,6 +859,17 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
859
859
|
}
|
|
860
860
|
return [...statesToExit];
|
|
861
861
|
}
|
|
862
|
+
function areConfigurationsEqual(previousConfiguration, nextConfigurationSet) {
|
|
863
|
+
if (previousConfiguration.length !== nextConfigurationSet.size) {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
for (const node of previousConfiguration) {
|
|
867
|
+
if (!nextConfigurationSet.has(node)) {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
862
873
|
|
|
863
874
|
/**
|
|
864
875
|
* https://www.w3.org/TR/scxml/#microstepProcedure
|
|
@@ -868,50 +879,36 @@ function computeExitSet(transitions, configuration, historyValue) {
|
|
|
868
879
|
* @param currentState
|
|
869
880
|
* @param mutConfiguration
|
|
870
881
|
*/
|
|
871
|
-
|
|
872
|
-
function microstep(transitions, currentState, actorCtx, event, isInitial) {
|
|
873
|
-
const mutConfiguration = new Set(currentState.configuration);
|
|
882
|
+
function microstep(transitions, currentState, actorCtx, event, isInitial, internalQueue) {
|
|
874
883
|
if (!transitions.length) {
|
|
875
884
|
return currentState;
|
|
876
885
|
}
|
|
877
|
-
const
|
|
878
|
-
|
|
879
|
-
value: {} // TODO: make optional
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
|
|
884
|
-
const historyValue = {
|
|
885
|
-
...currentState.historyValue
|
|
886
|
-
};
|
|
886
|
+
const mutConfiguration = new Set(currentState.configuration);
|
|
887
|
+
let historyValue = currentState.historyValue;
|
|
887
888
|
const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
|
|
888
|
-
|
|
889
|
-
// TODO: this `cloneState` is really just a hack to prevent infinite loops
|
|
890
|
-
// we need to take another look at how internal queue is managed
|
|
891
|
-
let nextState = cloneState(currentState, {
|
|
892
|
-
_internalQueue: []
|
|
893
|
-
});
|
|
889
|
+
let nextState = currentState;
|
|
894
890
|
|
|
895
891
|
// Exit states
|
|
896
892
|
if (!isInitial) {
|
|
897
|
-
nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
|
|
893
|
+
[nextState, historyValue] = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue, internalQueue);
|
|
898
894
|
}
|
|
899
895
|
|
|
900
896
|
// Execute transition content
|
|
901
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
|
|
897
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions), internalQueue);
|
|
902
898
|
|
|
903
899
|
// Enter states
|
|
904
900
|
nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
|
|
905
901
|
const nextConfiguration = [...mutConfiguration];
|
|
906
902
|
if (nextState.status === 'done') {
|
|
907
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
|
|
903
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
|
|
908
904
|
}
|
|
909
905
|
try {
|
|
910
|
-
|
|
906
|
+
if (historyValue === currentState.historyValue && areConfigurationsEqual(currentState.configuration, mutConfiguration)) {
|
|
907
|
+
return nextState;
|
|
908
|
+
}
|
|
911
909
|
return cloneState(nextState, {
|
|
912
910
|
configuration: nextConfiguration,
|
|
913
|
-
historyValue
|
|
914
|
-
_internalQueue: internalQueue
|
|
911
|
+
historyValue
|
|
915
912
|
});
|
|
916
913
|
} catch (e) {
|
|
917
914
|
// TODO: Refactor this once proper error handling is implemented.
|
|
@@ -950,7 +947,7 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
|
|
|
950
947
|
const initialActions = stateNodeToEnter.initial.actions;
|
|
951
948
|
actions.push(...initialActions);
|
|
952
949
|
}
|
|
953
|
-
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
950
|
+
nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
|
954
951
|
if (stateNodeToEnter.type === 'final') {
|
|
955
952
|
const parent = stateNodeToEnter.parent;
|
|
956
953
|
if (completedNodes.has(parent)) {
|
|
@@ -1047,10 +1044,11 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
|
|
|
1047
1044
|
}
|
|
1048
1045
|
}
|
|
1049
1046
|
}
|
|
1050
|
-
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
|
|
1047
|
+
function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue, internalQueue) {
|
|
1051
1048
|
let nextState = currentState;
|
|
1052
1049
|
const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
|
|
1053
1050
|
statesToExit.sort((a, b) => b.order - a.order);
|
|
1051
|
+
let changedHistory;
|
|
1054
1052
|
|
|
1055
1053
|
// From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates
|
|
1056
1054
|
for (const exitStateNode of statesToExit) {
|
|
@@ -1063,14 +1061,17 @@ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration
|
|
|
1063
1061
|
return sn.parent === exitStateNode;
|
|
1064
1062
|
};
|
|
1065
1063
|
}
|
|
1066
|
-
|
|
1064
|
+
changedHistory ??= {
|
|
1065
|
+
...historyValue
|
|
1066
|
+
};
|
|
1067
|
+
changedHistory[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
|
|
1067
1068
|
}
|
|
1068
1069
|
}
|
|
1069
1070
|
for (const s of statesToExit) {
|
|
1070
|
-
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);
|
|
1071
1072
|
mutConfiguration.delete(s);
|
|
1072
1073
|
}
|
|
1073
|
-
return nextState;
|
|
1074
|
+
return [nextState, changedHistory || historyValue];
|
|
1074
1075
|
}
|
|
1075
1076
|
function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
|
|
1076
1077
|
const {
|
|
@@ -1135,9 +1136,10 @@ function resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
|
1135
1136
|
}
|
|
1136
1137
|
return intermediateState;
|
|
1137
1138
|
}
|
|
1138
|
-
function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
|
|
1139
|
+
function resolveActionsAndContext(currentState, event, actorCtx, actions, internalQueue, deferredActorIds) {
|
|
1139
1140
|
const retries = deferredActorIds ? [] : undefined;
|
|
1140
|
-
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
|
|
1141
|
+
const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, {
|
|
1142
|
+
internalQueue,
|
|
1141
1143
|
deferredActorIds
|
|
1142
1144
|
}, retries);
|
|
1143
1145
|
retries?.forEach(([builtinAction, params]) => {
|
|
@@ -1145,7 +1147,7 @@ function resolveActionsAndContext(currentState, event, actorCtx, actions, deferr
|
|
|
1145
1147
|
});
|
|
1146
1148
|
return nextState;
|
|
1147
1149
|
}
|
|
1148
|
-
function macrostep(state, event, actorCtx) {
|
|
1150
|
+
function macrostep(state, event, actorCtx, internalQueue = []) {
|
|
1149
1151
|
if (event.type === WILDCARD) {
|
|
1150
1152
|
throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);
|
|
1151
1153
|
}
|
|
@@ -1154,7 +1156,7 @@ function macrostep(state, event, actorCtx) {
|
|
|
1154
1156
|
|
|
1155
1157
|
// Handle stop event
|
|
1156
1158
|
if (event.type === XSTATE_STOP) {
|
|
1157
|
-
nextState =
|
|
1159
|
+
nextState = stopChildren(nextState, event, actorCtx);
|
|
1158
1160
|
states.push(nextState);
|
|
1159
1161
|
return {
|
|
1160
1162
|
state: nextState,
|
|
@@ -1167,44 +1169,37 @@ function macrostep(state, event, actorCtx) {
|
|
|
1167
1169
|
// Determine the next state based on the next microstep
|
|
1168
1170
|
if (nextEvent.type !== XSTATE_INIT) {
|
|
1169
1171
|
const transitions = selectTransitions(nextEvent, nextState);
|
|
1170
|
-
nextState = microstep(transitions, state, actorCtx, nextEvent, false);
|
|
1172
|
+
nextState = microstep(transitions, state, actorCtx, nextEvent, false, internalQueue);
|
|
1171
1173
|
states.push(nextState);
|
|
1172
1174
|
}
|
|
1175
|
+
let shouldSelectEventlessTransitions = true;
|
|
1173
1176
|
while (nextState.status === 'active') {
|
|
1174
|
-
let enabledTransitions = selectEventlessTransitions(nextState, nextEvent);
|
|
1177
|
+
let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextState, nextEvent) : [];
|
|
1178
|
+
|
|
1179
|
+
// eventless transitions should always be selected after selecting *regular* transitions
|
|
1180
|
+
// by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case
|
|
1181
|
+
const previousState = enabledTransitions.length ? nextState : undefined;
|
|
1175
1182
|
if (!enabledTransitions.length) {
|
|
1176
|
-
if (!
|
|
1183
|
+
if (!internalQueue.length) {
|
|
1177
1184
|
break;
|
|
1178
|
-
} else {
|
|
1179
|
-
nextEvent = nextState._internalQueue[0];
|
|
1180
|
-
const transitions = selectTransitions(nextEvent, nextState);
|
|
1181
|
-
nextState = microstep(transitions, nextState, actorCtx, nextEvent, false);
|
|
1182
|
-
nextState._internalQueue.shift();
|
|
1183
|
-
states.push(nextState);
|
|
1184
1185
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
states.push(nextState);
|
|
1186
|
+
nextEvent = internalQueue.shift();
|
|
1187
|
+
enabledTransitions = selectTransitions(nextEvent, nextState);
|
|
1188
1188
|
}
|
|
1189
|
+
nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false, internalQueue);
|
|
1190
|
+
shouldSelectEventlessTransitions = nextState !== previousState;
|
|
1191
|
+
states.push(nextState);
|
|
1189
1192
|
}
|
|
1190
1193
|
if (nextState.status !== 'active') {
|
|
1191
|
-
|
|
1192
|
-
stopStep(nextEvent, nextState, actorCtx);
|
|
1194
|
+
stopChildren(nextState, nextEvent, actorCtx);
|
|
1193
1195
|
}
|
|
1194
1196
|
return {
|
|
1195
1197
|
state: nextState,
|
|
1196
1198
|
microstates: states
|
|
1197
1199
|
};
|
|
1198
1200
|
}
|
|
1199
|
-
function
|
|
1200
|
-
|
|
1201
|
-
for (const stateNode of nextState.configuration.sort((a, b) => b.order - a.order)) {
|
|
1202
|
-
actions.push(...stateNode.exit);
|
|
1203
|
-
}
|
|
1204
|
-
for (const child of Object.values(nextState.children)) {
|
|
1205
|
-
actions.push(stop(child));
|
|
1206
|
-
}
|
|
1207
|
-
return resolveActionsAndContext(nextState, event, actorCtx, actions);
|
|
1201
|
+
function stopChildren(nextState, event, actorCtx) {
|
|
1202
|
+
return resolveActionsAndContext(nextState, event, actorCtx, Object.values(nextState.children).map(child => stop(child)), []);
|
|
1208
1203
|
}
|
|
1209
1204
|
function selectTransitions(event, nextState) {
|
|
1210
1205
|
return nextState.machine.getTransitionData(nextState, event);
|
|
@@ -1310,11 +1305,9 @@ class State {
|
|
|
1310
1305
|
this.error = void 0;
|
|
1311
1306
|
this.context = void 0;
|
|
1312
1307
|
this.historyValue = {};
|
|
1313
|
-
this._internalQueue = void 0;
|
|
1314
1308
|
this.configuration = void 0;
|
|
1315
1309
|
this.children = void 0;
|
|
1316
1310
|
this.context = config.context;
|
|
1317
|
-
this._internalQueue = config._internalQueue ?? [];
|
|
1318
1311
|
this.historyValue = config.historyValue || {};
|
|
1319
1312
|
this.matches = this.matches.bind(this);
|
|
1320
1313
|
this.toStrings = this.toStrings.bind(this);
|
|
@@ -1469,6 +1462,8 @@ function resolveRaise(_, state, args, {
|
|
|
1469
1462
|
event: eventOrExpr,
|
|
1470
1463
|
id,
|
|
1471
1464
|
delay
|
|
1465
|
+
}, {
|
|
1466
|
+
internalQueue
|
|
1472
1467
|
}) {
|
|
1473
1468
|
const delaysMap = state.machine.implementations.delays;
|
|
1474
1469
|
if (typeof eventOrExpr === 'string') {
|
|
@@ -1482,9 +1477,10 @@ function resolveRaise(_, state, args, {
|
|
|
1482
1477
|
} else {
|
|
1483
1478
|
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
1484
1479
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
}
|
|
1480
|
+
if (typeof resolvedDelay !== 'number') {
|
|
1481
|
+
internalQueue.push(resolvedEvent);
|
|
1482
|
+
}
|
|
1483
|
+
return [state, {
|
|
1488
1484
|
event: resolvedEvent,
|
|
1489
1485
|
id,
|
|
1490
1486
|
delay: resolvedDelay
|