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.
Files changed (29) hide show
  1. package/actions/dist/xstate-actions.cjs.js +2 -2
  2. package/actions/dist/xstate-actions.development.cjs.js +2 -2
  3. package/actions/dist/xstate-actions.development.esm.js +2 -2
  4. package/actions/dist/xstate-actions.esm.js +2 -2
  5. package/actions/dist/xstate-actions.umd.min.js +1 -1
  6. package/actions/dist/xstate-actions.umd.min.js.map +1 -1
  7. package/dist/declarations/src/State.d.ts +0 -1
  8. package/dist/declarations/src/stateUtils.d.ts +3 -3
  9. package/dist/declarations/src/types.d.ts +0 -1
  10. package/dist/{raise-26e4d83c.development.cjs.js → raise-106ea558.development.cjs.js} +58 -62
  11. package/dist/{raise-cdcdf834.development.esm.js → raise-5b7ad3b7.development.esm.js} +58 -62
  12. package/dist/{raise-0ff57677.cjs.js → raise-c51b81a3.cjs.js} +58 -62
  13. package/dist/{raise-511399cc.esm.js → raise-ffe1014a.esm.js} +58 -62
  14. package/dist/{send-211a2a94.esm.js → send-0a7aa74e.esm.js} +2 -2
  15. package/dist/{send-894c4b18.development.cjs.js → send-25e70bd4.development.cjs.js} +2 -2
  16. package/dist/{send-19ffc568.cjs.js → send-778692de.cjs.js} +2 -2
  17. package/dist/{send-1de74f4d.development.esm.js → send-e93554d6.development.esm.js} +2 -2
  18. package/dist/xstate.cjs.js +8 -8
  19. package/dist/xstate.development.cjs.js +8 -8
  20. package/dist/xstate.development.esm.js +10 -10
  21. package/dist/xstate.esm.js +10 -10
  22. package/dist/xstate.umd.min.js +1 -1
  23. package/dist/xstate.umd.min.js.map +1 -1
  24. package/guards/dist/xstate-guards.cjs.js +1 -1
  25. package/guards/dist/xstate-guards.development.cjs.js +1 -1
  26. package/guards/dist/xstate-guards.development.esm.js +1 -1
  27. package/guards/dist/xstate-guards.esm.js +1 -1
  28. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  29. 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<TransitionDefinition<TContext, TEvent>>, currentState: AnyState, actorCtx: AnyActorContext, event: TEvent, isInitial: boolean): AnyState;
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 microstate = microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial);
880
- return cloneState(microstate, {
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
- const internalQueue = [...currentState._internalQueue];
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
- internalQueue.push(...nextState._internalQueue);
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
- historyValue[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
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, deferredActorIds && {
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 = stopStep(event, nextState, actorCtx);
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 (!nextState._internalQueue.length) {
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
- } else {
1188
- nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false);
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
- // Perform the stop step to ensure that child actors are stopped
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 stopStep(event, nextState, actorCtx) {
1202
- const actions = [];
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
- return [typeof resolvedDelay !== 'number' ? cloneState(state, {
1488
- _internalQueue: state._internalQueue.concat(resolvedEvent)
1489
- }) : state, {
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 microstate = microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial);
878
- return cloneState(microstate, {
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
- const internalQueue = [...currentState._internalQueue];
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
- internalQueue.push(...nextState._internalQueue);
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
- historyValue[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
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, deferredActorIds && {
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 = stopStep(event, nextState, actorCtx);
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 (!nextState._internalQueue.length) {
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
- } else {
1186
- nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false);
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
- // Perform the stop step to ensure that child actors are stopped
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 stopStep(event, nextState, actorCtx) {
1200
- const actions = [];
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
- return [typeof resolvedDelay !== 'number' ? cloneState(state, {
1486
- _internalQueue: state._internalQueue.concat(resolvedEvent)
1487
- }) : state, {
1480
+ if (typeof resolvedDelay !== 'number') {
1481
+ internalQueue.push(resolvedEvent);
1482
+ }
1483
+ return [state, {
1488
1484
  event: resolvedEvent,
1489
1485
  id,
1490
1486
  delay: resolvedDelay