xstate 5.0.0-beta.34 → 5.0.0-beta.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/actions/dist/xstate-actions.cjs.js +3 -3
  3. package/actions/dist/xstate-actions.development.cjs.js +3 -3
  4. package/actions/dist/xstate-actions.development.esm.js +3 -3
  5. package/actions/dist/xstate-actions.esm.js +3 -3
  6. package/actions/dist/xstate-actions.umd.min.js +1 -1
  7. package/actions/dist/xstate-actions.umd.min.js.map +1 -1
  8. package/actors/dist/xstate-actors.cjs.js +1 -1
  9. package/actors/dist/xstate-actors.development.cjs.js +1 -1
  10. package/actors/dist/xstate-actors.development.esm.js +1 -1
  11. package/actors/dist/xstate-actors.esm.js +1 -1
  12. package/actors/dist/xstate-actors.umd.min.js +1 -1
  13. package/actors/dist/xstate-actors.umd.min.js.map +1 -1
  14. package/dist/declarations/src/State.d.ts +0 -1
  15. package/dist/declarations/src/interpreter.d.ts +2 -0
  16. package/dist/declarations/src/stateUtils.d.ts +8 -7
  17. package/dist/declarations/src/types.d.ts +3 -6
  18. package/dist/{interpreter-dee56dc8.development.esm.js → interpreter-5c4e6634.development.esm.js} +59 -57
  19. package/dist/{interpreter-1301970f.cjs.js → interpreter-69605bf0.cjs.js} +59 -57
  20. package/dist/{interpreter-70ed62f2.development.cjs.js → interpreter-d3567419.development.cjs.js} +59 -57
  21. package/dist/{interpreter-83f7f2d4.esm.js → interpreter-de5217bc.esm.js} +59 -57
  22. package/dist/{raise-38b707c0.development.cjs.js → raise-106ea558.development.cjs.js} +160 -160
  23. package/dist/{raise-05f8b2a6.development.esm.js → raise-5b7ad3b7.development.esm.js} +160 -160
  24. package/dist/{raise-1dd65455.cjs.js → raise-c51b81a3.cjs.js} +157 -160
  25. package/dist/{raise-b5cfe1bb.esm.js → raise-ffe1014a.esm.js} +157 -160
  26. package/dist/{send-0b5eda0c.esm.js → send-0a7aa74e.esm.js} +5 -3
  27. package/dist/{send-3764c866.development.cjs.js → send-25e70bd4.development.cjs.js} +5 -3
  28. package/dist/{send-fe94de2b.cjs.js → send-778692de.cjs.js} +5 -3
  29. package/dist/{send-9526366e.development.esm.js → send-e93554d6.development.esm.js} +5 -3
  30. package/dist/xstate.cjs.js +32 -13
  31. package/dist/xstate.development.cjs.js +32 -13
  32. package/dist/xstate.development.esm.js +35 -16
  33. package/dist/xstate.esm.js +35 -16
  34. package/dist/xstate.umd.min.js +1 -1
  35. package/dist/xstate.umd.min.js.map +1 -1
  36. package/guards/dist/xstate-guards.cjs.js +2 -2
  37. package/guards/dist/xstate-guards.development.cjs.js +2 -2
  38. package/guards/dist/xstate-guards.development.esm.js +2 -2
  39. package/guards/dist/xstate-guards.esm.js +2 -2
  40. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  41. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var interpreter = require('./interpreter-1301970f.cjs.js');
3
+ var interpreter = require('./interpreter-69605bf0.cjs.js');
4
4
 
5
5
  const cache = new WeakMap();
6
6
  function memo(object, key, fn) {
@@ -279,20 +279,6 @@ function evaluateGuard(guard, context, event, state) {
279
279
  );
280
280
  }
281
281
 
282
- function getOutput(configuration, context, event, self) {
283
- const {
284
- machine
285
- } = configuration[0];
286
- const {
287
- root
288
- } = machine;
289
- if (!root.output) {
290
- return undefined;
291
- }
292
- const finalChildStateNode = configuration.find(stateNode => stateNode.type === 'final' && stateNode.parent === machine.root);
293
- const doneStateEvent = interpreter.createDoneStateEvent(finalChildStateNode.id, finalChildStateNode.output ? interpreter.resolveOutput(finalChildStateNode.output, context, event, self) : undefined);
294
- return interpreter.resolveOutput(root.output, context, doneStateEvent, self);
295
- }
296
282
  const isAtomicStateNode = stateNode => stateNode.type === 'atomic' || stateNode.type === 'final';
297
283
  function getChildren(stateNode) {
298
284
  return Object.values(stateNode.states).filter(sn => sn.type !== 'history');
@@ -317,7 +303,7 @@ function getConfiguration(stateNodes) {
317
303
  for (const s of configuration) {
318
304
  // if previously active, add existing child nodes
319
305
  if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) {
320
- getInitialStateNodes(s).forEach(sn => configurationSet.add(sn));
306
+ getInitialStateNodesWithTheirAncestors(s).forEach(sn => configurationSet.add(sn));
321
307
  } else {
322
308
  if (s.type === 'parallel') {
323
309
  for (const child of getChildren(s)) {
@@ -325,7 +311,8 @@ function getConfiguration(stateNodes) {
325
311
  continue;
326
312
  }
327
313
  if (!configurationSet.has(child)) {
328
- for (const initialStateNode of getInitialStateNodes(child)) {
314
+ const initialStates = getInitialStateNodesWithTheirAncestors(child);
315
+ for (const initialStateNode of initialStates) {
329
316
  configurationSet.add(initialStateNode);
330
317
  }
331
318
  }
@@ -385,14 +372,14 @@ function getStateValue(rootNode, configuration) {
385
372
  const config = getConfiguration(configuration);
386
373
  return getValueFromAdj(rootNode, getAdjList(config));
387
374
  }
388
- function isInFinalState(configuration, stateNode = configuration[0].machine.root) {
375
+ function isInFinalState(configuration, stateNode) {
389
376
  if (stateNode.type === 'compound') {
390
- return getChildren(stateNode).some(s => s.type === 'final' && configuration.includes(s));
377
+ return getChildren(stateNode).some(s => s.type === 'final' && configuration.has(s));
391
378
  }
392
379
  if (stateNode.type === 'parallel') {
393
380
  return getChildren(stateNode).every(sn => isInFinalState(configuration, sn));
394
381
  }
395
- return false;
382
+ return stateNode.type === 'final';
396
383
  }
397
384
  const isStateId = str => str[0] === interpreter.STATE_IDENTIFIER;
398
385
  function getCandidates(stateNode, receivedEventType) {
@@ -442,13 +429,7 @@ function getDelayedTransitions(stateNode) {
442
429
  stateNode.exit.push(cancel(eventType));
443
430
  return eventType;
444
431
  };
445
- const delayedTransitions = interpreter.isArray(afterConfig) ? afterConfig.map((transition, i) => {
446
- const eventType = mutateEntryExit(transition.delay, i);
447
- return {
448
- ...transition,
449
- event: eventType
450
- };
451
- }) : Object.keys(afterConfig).flatMap((delay, i) => {
432
+ const delayedTransitions = Object.keys(afterConfig).flatMap((delay, i) => {
452
433
  const configTransition = afterConfig[delay];
453
434
  const resolvedTransition = typeof configTransition === 'string' ? {
454
435
  target: configTransition
@@ -531,43 +512,23 @@ function formatTransitions(stateNode) {
531
512
  return transitions;
532
513
  }
533
514
  function formatInitialTransition(stateNode, _target) {
534
- if (typeof _target === 'string' || interpreter.isArray(_target)) {
535
- const targets = interpreter.toArray(_target).map(t => {
536
- // Resolve state string keys (which represent children)
537
- // to their state node
538
- const descStateNode = typeof t === 'string' ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
539
- if (!descStateNode) {
540
- throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
541
- }
542
- if (!isDescendant(descStateNode, stateNode)) {
543
- throw new Error(`Invalid initial target: state node #${descStateNode.id} is not a descendant of #${stateNode.id}`);
544
- }
545
- return descStateNode;
546
- });
547
- const resolvedTarget = resolveTarget(stateNode, targets);
548
- const transition = {
549
- source: stateNode,
550
- actions: [],
551
- eventType: null,
552
- reenter: false,
553
- target: resolvedTarget,
554
- toJSON: () => ({
555
- ...transition,
556
- source: `#${stateNode.id}`,
557
- target: resolvedTarget ? resolvedTarget.map(t => `#${t.id}`) : undefined
558
- })
559
- };
560
- return transition;
515
+ const resolvedTarget = typeof _target === 'string' ? stateNode.states[_target] : _target ? stateNode.states[_target.target] : undefined;
516
+ if (!resolvedTarget && _target) {
517
+ throw new Error(`Initial state node "${_target}" not found on parent state node #${stateNode.id}`);
561
518
  }
562
- return formatTransition(stateNode, '__INITIAL__', {
563
- target: interpreter.toArray(_target.target).map(t => {
564
- if (typeof t === 'string') {
565
- return isStateId(t) ? t : `${interpreter.STATE_DELIMITER}${t}`;
566
- }
567
- return t;
568
- }),
569
- actions: _target.actions
570
- });
519
+ const transition = {
520
+ source: stateNode,
521
+ actions: !_target || typeof _target === 'string' ? [] : interpreter.toArray(_target.actions),
522
+ eventType: null,
523
+ reenter: false,
524
+ target: resolvedTarget ? [resolvedTarget] : [],
525
+ toJSON: () => ({
526
+ ...transition,
527
+ source: `#${stateNode.id}`,
528
+ target: resolvedTarget ? [`#${resolvedTarget.id}`] : []
529
+ })
530
+ };
531
+ return transition;
571
532
  }
572
533
  function resolveTarget(stateNode, targets) {
573
534
  if (targets === undefined) {
@@ -610,6 +571,15 @@ function resolveHistoryTarget(stateNode) {
610
571
  function isHistoryNode(stateNode) {
611
572
  return stateNode.type === 'history';
612
573
  }
574
+ function getInitialStateNodesWithTheirAncestors(stateNode) {
575
+ const states = getInitialStateNodes(stateNode);
576
+ for (const initialState of states) {
577
+ for (const ancestor of getProperAncestors(initialState, stateNode)) {
578
+ states.add(ancestor);
579
+ }
580
+ }
581
+ return states;
582
+ }
613
583
  function getInitialStateNodes(stateNode) {
614
584
  const set = new Set();
615
585
  function iter(descStateNode) {
@@ -618,12 +588,7 @@ function getInitialStateNodes(stateNode) {
618
588
  }
619
589
  set.add(descStateNode);
620
590
  if (descStateNode.type === 'compound') {
621
- for (const targetStateNode of descStateNode.initial.target) {
622
- for (const a of getProperAncestors(targetStateNode, stateNode)) {
623
- set.add(a);
624
- }
625
- iter(targetStateNode);
626
- }
591
+ iter(descStateNode.initial.target[0]);
627
592
  } else if (descStateNode.type === 'parallel') {
628
593
  for (const child of getChildren(descStateNode)) {
629
594
  iter(child);
@@ -631,7 +596,7 @@ function getInitialStateNodes(stateNode) {
631
596
  }
632
597
  }
633
598
  iter(stateNode);
634
- return [...set];
599
+ return set;
635
600
  }
636
601
  /**
637
602
  * Returns the child state node from its relative `stateKey`, or throws.
@@ -865,6 +830,17 @@ function computeExitSet(transitions, configuration, historyValue) {
865
830
  }
866
831
  return [...statesToExit];
867
832
  }
833
+ function areConfigurationsEqual(previousConfiguration, nextConfigurationSet) {
834
+ if (previousConfiguration.length !== nextConfigurationSet.size) {
835
+ return false;
836
+ }
837
+ for (const node of previousConfiguration) {
838
+ if (!nextConfigurationSet.has(node)) {
839
+ return false;
840
+ }
841
+ }
842
+ return true;
843
+ }
868
844
 
869
845
  /**
870
846
  * https://www.w3.org/TR/scxml/#microstepProcedure
@@ -874,56 +850,36 @@ function computeExitSet(transitions, configuration, historyValue) {
874
850
  * @param currentState
875
851
  * @param mutConfiguration
876
852
  */
877
-
878
- function microstep(transitions, currentState, actorCtx, event, isInitial) {
879
- const mutConfiguration = new Set(currentState.configuration);
853
+ function microstep(transitions, currentState, actorCtx, event, isInitial, internalQueue) {
880
854
  if (!transitions.length) {
881
855
  return currentState;
882
856
  }
883
- const microstate = microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial);
884
- return cloneState(microstate, {
885
- value: {} // TODO: make optional
886
- });
887
- }
888
-
889
- function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
890
- const historyValue = {
891
- ...currentState.historyValue
892
- };
857
+ const mutConfiguration = new Set(currentState.configuration);
858
+ let historyValue = currentState.historyValue;
893
859
  const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
894
- const internalQueue = [...currentState._internalQueue];
895
- // TODO: this `cloneState` is really just a hack to prevent infinite loops
896
- // we need to take another look at how internal queue is managed
897
- let nextState = cloneState(currentState, {
898
- _internalQueue: []
899
- });
860
+ let nextState = currentState;
900
861
 
901
862
  // Exit states
902
863
  if (!isInitial) {
903
- nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
864
+ [nextState, historyValue] = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue, internalQueue);
904
865
  }
905
866
 
906
867
  // Execute transition content
907
- nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
868
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions), internalQueue);
908
869
 
909
870
  // Enter states
910
871
  nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
911
872
  const nextConfiguration = [...mutConfiguration];
912
- const done = isInFinalState(nextConfiguration);
913
- if (done) {
914
- nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
873
+ if (nextState.status === 'done') {
874
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
915
875
  }
916
876
  try {
917
- const output = done ? getOutput(nextConfiguration, nextState.context, event, actorCtx.self) : undefined;
918
- internalQueue.push(...nextState._internalQueue);
919
- return cloneState(currentState, {
877
+ if (historyValue === currentState.historyValue && areConfigurationsEqual(currentState.configuration, mutConfiguration)) {
878
+ return nextState;
879
+ }
880
+ return cloneState(nextState, {
920
881
  configuration: nextConfiguration,
921
- historyValue,
922
- _internalQueue: internalQueue,
923
- context: nextState.context,
924
- status: done ? 'done' : currentState.status,
925
- output,
926
- children: nextState.children
882
+ historyValue
927
883
  });
928
884
  } catch (e) {
929
885
  // TODO: Refactor this once proper error handling is implemented.
@@ -931,6 +887,13 @@ function microstepProcedure(transitions, currentState, mutConfiguration, event,
931
887
  throw e;
932
888
  }
933
889
  }
890
+ function getMachineOutput(state, event, actorCtx, rootNode, rootCompletionNode) {
891
+ if (!rootNode.output) {
892
+ return;
893
+ }
894
+ const doneStateEvent = interpreter.createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output && rootCompletionNode.parent ? interpreter.resolveOutput(rootCompletionNode.output, state.context, event, actorCtx.self) : undefined);
895
+ return interpreter.resolveOutput(rootNode.output, state.context, doneStateEvent, actorCtx.self);
896
+ }
934
897
  function enterStates(currentState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial) {
935
898
  let nextState = currentState;
936
899
  const statesToEnter = new Set();
@@ -941,6 +904,7 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
941
904
  if (isInitial) {
942
905
  statesForDefaultEntry.add(currentState.machine.root);
943
906
  }
907
+ const completedNodes = new Set();
944
908
  for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
945
909
  mutConfiguration.add(stateNodeToEnter);
946
910
  const actions = [];
@@ -951,26 +915,34 @@ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConf
951
915
  actions.push(invoke(invokeDef));
952
916
  }
953
917
  if (statesForDefaultEntry.has(stateNodeToEnter)) {
954
- for (const stateNode of statesForDefaultEntry) {
955
- const initialActions = stateNode.initial.actions;
956
- actions.push(...initialActions);
957
- }
918
+ const initialActions = stateNodeToEnter.initial.actions;
919
+ actions.push(...initialActions);
958
920
  }
959
- nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
921
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
960
922
  if (stateNodeToEnter.type === 'final') {
961
923
  const parent = stateNodeToEnter.parent;
962
- if (!parent.parent) {
924
+ if (completedNodes.has(parent)) {
963
925
  continue;
964
926
  }
965
- internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, nextState.context, event, actorCtx.self) : undefined));
966
- if (parent.parent) {
967
- const grandparent = parent.parent;
968
- if (grandparent.type === 'parallel') {
969
- if (getChildren(grandparent).every(parentNode => isInFinalState([...mutConfiguration], parentNode))) {
970
- internalQueue.push(interpreter.createDoneStateEvent(grandparent.id));
971
- }
927
+ completedNodes.add(parent);
928
+ let rootCompletionNode = parent?.type === 'parallel' ? parent : stateNodeToEnter;
929
+ let ancestorMarker = parent?.parent;
930
+ if (ancestorMarker) {
931
+ internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, nextState.context, event, actorCtx.self) : undefined));
932
+ while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutConfiguration, ancestorMarker)) {
933
+ completedNodes.add(ancestorMarker);
934
+ internalQueue.push(interpreter.createDoneStateEvent(ancestorMarker.id));
935
+ rootCompletionNode = ancestorMarker;
936
+ ancestorMarker = ancestorMarker.parent;
972
937
  }
973
938
  }
939
+ if (ancestorMarker) {
940
+ continue;
941
+ }
942
+ nextState = cloneState(nextState, {
943
+ status: 'done',
944
+ output: getMachineOutput(nextState, event, actorCtx, currentState.configuration[0].machine.root, rootCompletionNode)
945
+ });
974
946
  }
975
947
  }
976
948
  return nextState;
@@ -1016,13 +988,9 @@ function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEnt
1016
988
  statesToEnter.add(stateNode);
1017
989
  if (stateNode.type === 'compound') {
1018
990
  statesForDefaultEntry.add(stateNode);
1019
- const initialStates = stateNode.initial.target;
1020
- for (const initialState of initialStates) {
1021
- addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
1022
- }
1023
- for (const initialState of initialStates) {
1024
- addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
1025
- }
991
+ const [initialState] = stateNode.initial.target;
992
+ addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
993
+ addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
1026
994
  } else {
1027
995
  if (stateNode.type === 'parallel') {
1028
996
  for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
@@ -1047,10 +1015,11 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
1047
1015
  }
1048
1016
  }
1049
1017
  }
1050
- function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
1018
+ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue, internalQueue) {
1051
1019
  let nextState = currentState;
1052
1020
  const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
1053
1021
  statesToExit.sort((a, b) => b.order - a.order);
1022
+ let changedHistory;
1054
1023
 
1055
1024
  // From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates
1056
1025
  for (const exitStateNode of statesToExit) {
@@ -1063,14 +1032,17 @@ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration
1063
1032
  return sn.parent === exitStateNode;
1064
1033
  };
1065
1034
  }
1066
- historyValue[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
1035
+ changedHistory ??= {
1036
+ ...historyValue
1037
+ };
1038
+ changedHistory[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
1067
1039
  }
1068
1040
  }
1069
1041
  for (const s of statesToExit) {
1070
- nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))]);
1042
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))], internalQueue);
1071
1043
  mutConfiguration.delete(s);
1072
1044
  }
1073
- return nextState;
1045
+ return [nextState, changedHistory || historyValue];
1074
1046
  }
1075
1047
  function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
1076
1048
  const {
@@ -1135,9 +1107,10 @@ function resolveActionsAndContextWorker(currentState, event, actorCtx, actions,
1135
1107
  }
1136
1108
  return intermediateState;
1137
1109
  }
1138
- function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
1110
+ function resolveActionsAndContext(currentState, event, actorCtx, actions, internalQueue, deferredActorIds) {
1139
1111
  const retries = deferredActorIds ? [] : undefined;
1140
- const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, deferredActorIds && {
1112
+ const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, {
1113
+ internalQueue,
1141
1114
  deferredActorIds
1142
1115
  }, retries);
1143
1116
  retries?.forEach(([builtinAction, params]) => {
@@ -1145,13 +1118,13 @@ function resolveActionsAndContext(currentState, event, actorCtx, actions, deferr
1145
1118
  });
1146
1119
  return nextState;
1147
1120
  }
1148
- function macrostep(state, event, actorCtx) {
1121
+ function macrostep(state, event, actorCtx, internalQueue = []) {
1149
1122
  let nextState = state;
1150
1123
  const states = [];
1151
1124
 
1152
1125
  // Handle stop event
1153
1126
  if (event.type === interpreter.XSTATE_STOP) {
1154
- nextState = stopStep(event, nextState, actorCtx);
1127
+ nextState = stopChildren(nextState, event, actorCtx);
1155
1128
  states.push(nextState);
1156
1129
  return {
1157
1130
  state: nextState,
@@ -1164,44 +1137,37 @@ function macrostep(state, event, actorCtx) {
1164
1137
  // Determine the next state based on the next microstep
1165
1138
  if (nextEvent.type !== interpreter.XSTATE_INIT) {
1166
1139
  const transitions = selectTransitions(nextEvent, nextState);
1167
- nextState = microstep(transitions, state, actorCtx, nextEvent, false);
1140
+ nextState = microstep(transitions, state, actorCtx, nextEvent, false, internalQueue);
1168
1141
  states.push(nextState);
1169
1142
  }
1143
+ let shouldSelectEventlessTransitions = true;
1170
1144
  while (nextState.status === 'active') {
1171
- let enabledTransitions = selectEventlessTransitions(nextState, nextEvent);
1145
+ let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextState, nextEvent) : [];
1146
+
1147
+ // eventless transitions should always be selected after selecting *regular* transitions
1148
+ // by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case
1149
+ const previousState = enabledTransitions.length ? nextState : undefined;
1172
1150
  if (!enabledTransitions.length) {
1173
- if (!nextState._internalQueue.length) {
1151
+ if (!internalQueue.length) {
1174
1152
  break;
1175
- } else {
1176
- nextEvent = nextState._internalQueue[0];
1177
- const transitions = selectTransitions(nextEvent, nextState);
1178
- nextState = microstep(transitions, nextState, actorCtx, nextEvent, false);
1179
- nextState._internalQueue.shift();
1180
- states.push(nextState);
1181
1153
  }
1182
- } else {
1183
- nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false);
1184
- states.push(nextState);
1154
+ nextEvent = internalQueue.shift();
1155
+ enabledTransitions = selectTransitions(nextEvent, nextState);
1185
1156
  }
1157
+ nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent, false, internalQueue);
1158
+ shouldSelectEventlessTransitions = nextState !== previousState;
1159
+ states.push(nextState);
1186
1160
  }
1187
1161
  if (nextState.status !== 'active') {
1188
- // Perform the stop step to ensure that child actors are stopped
1189
- stopStep(nextEvent, nextState, actorCtx);
1162
+ stopChildren(nextState, nextEvent, actorCtx);
1190
1163
  }
1191
1164
  return {
1192
1165
  state: nextState,
1193
1166
  microstates: states
1194
1167
  };
1195
1168
  }
1196
- function stopStep(event, nextState, actorCtx) {
1197
- const actions = [];
1198
- for (const stateNode of nextState.configuration.sort((a, b) => b.order - a.order)) {
1199
- actions.push(...stateNode.exit);
1200
- }
1201
- for (const child of Object.values(nextState.children)) {
1202
- actions.push(stop(child));
1203
- }
1204
- return resolveActionsAndContext(nextState, event, actorCtx, actions);
1169
+ function stopChildren(nextState, event, actorCtx) {
1170
+ return resolveActionsAndContext(nextState, event, actorCtx, Object.values(nextState.children).map(child => stop(child)), []);
1205
1171
  }
1206
1172
  function selectTransitions(event, nextState) {
1207
1173
  return nextState.machine.getTransitionData(nextState, event);
@@ -1307,11 +1273,9 @@ class State {
1307
1273
  this.error = void 0;
1308
1274
  this.context = void 0;
1309
1275
  this.historyValue = {};
1310
- this._internalQueue = void 0;
1311
1276
  this.configuration = void 0;
1312
1277
  this.children = void 0;
1313
1278
  this.context = config.context;
1314
- this._internalQueue = config._internalQueue ?? [];
1315
1279
  this.historyValue = config.historyValue || {};
1316
1280
  this.matches = this.matches.bind(this);
1317
1281
  this.toStrings = this.toStrings.bind(this);
@@ -1410,6 +1374,7 @@ function getPersistedState(state) {
1410
1374
  tags,
1411
1375
  machine,
1412
1376
  children,
1377
+ context,
1413
1378
  ...jsonValues
1414
1379
  } = state;
1415
1380
  const childrenJson = {};
@@ -1422,14 +1387,45 @@ function getPersistedState(state) {
1422
1387
  }
1423
1388
  return {
1424
1389
  ...jsonValues,
1390
+ // TODO: this makes `PersistedMachineState`'s type kind of a lie
1391
+ // it doesn't truly use `TContext` but rather some kind of a derived form of it
1392
+ context: persistContext(context),
1425
1393
  children: childrenJson
1426
1394
  };
1427
1395
  }
1396
+ function persistContext(contextPart) {
1397
+ let copy;
1398
+ for (const key in contextPart) {
1399
+ const value = contextPart[key];
1400
+ if (value && typeof value === 'object') {
1401
+ if ('sessionId' in value && 'send' in value && 'ref' in value) {
1402
+ copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
1403
+ ...contextPart
1404
+ };
1405
+ copy[key] = {
1406
+ xstate$$type: interpreter.$$ACTOR_TYPE,
1407
+ id: value.id
1408
+ };
1409
+ } else {
1410
+ const result = persistContext(value);
1411
+ if (result !== value) {
1412
+ copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
1413
+ ...contextPart
1414
+ };
1415
+ copy[key] = result;
1416
+ }
1417
+ }
1418
+ }
1419
+ }
1420
+ return copy ?? contextPart;
1421
+ }
1428
1422
 
1429
1423
  function resolveRaise(_, state, args, {
1430
1424
  event: eventOrExpr,
1431
1425
  id,
1432
1426
  delay
1427
+ }, {
1428
+ internalQueue
1433
1429
  }) {
1434
1430
  const delaysMap = state.machine.implementations.delays;
1435
1431
  if (typeof eventOrExpr === 'string') {
@@ -1443,9 +1439,10 @@ function resolveRaise(_, state, args, {
1443
1439
  } else {
1444
1440
  resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
1445
1441
  }
1446
- return [typeof resolvedDelay !== 'number' ? cloneState(state, {
1447
- _internalQueue: state._internalQueue.concat(resolvedEvent)
1448
- }) : state, {
1442
+ if (typeof resolvedDelay !== 'number') {
1443
+ internalQueue.push(resolvedEvent);
1444
+ }
1445
+ return [state, {
1449
1446
  event: resolvedEvent,
1450
1447
  id,
1451
1448
  delay: resolvedDelay
@@ -1487,10 +1484,10 @@ exports.getCandidates = getCandidates;
1487
1484
  exports.getConfiguration = getConfiguration;
1488
1485
  exports.getDelayedTransitions = getDelayedTransitions;
1489
1486
  exports.getInitialConfiguration = getInitialConfiguration;
1487
+ exports.getInitialStateNodes = getInitialStateNodes;
1490
1488
  exports.getPersistedState = getPersistedState;
1491
1489
  exports.getStateNodeByPath = getStateNodeByPath;
1492
1490
  exports.getStateNodes = getStateNodes;
1493
- exports.isAtomicStateNode = isAtomicStateNode;
1494
1491
  exports.isInFinalState = isInFinalState;
1495
1492
  exports.isStateId = isStateId;
1496
1493
  exports.macrostep = macrostep;