xstate 6.0.0-alpha.64 → 6.0.0-alpha.65

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 (60) hide show
  1. package/README.md +27 -0
  2. package/dist/{createActor-521c8805.development.cjs.js → createActor-1df42c9e.development.cjs.js} +205 -31
  3. package/dist/{createActor-8493caa9.esm.js → createActor-4629a290.esm.js} +133 -28
  4. package/dist/{createActor-bd2527dc.development.esm.js → createActor-8f57b47b.development.esm.js} +205 -31
  5. package/dist/{createActor-29adb8a4.cjs.js → createActor-b987e971.cjs.js} +133 -28
  6. package/dist/declarations/src/State.d.ts +25 -3
  7. package/dist/declarations/src/StateMachine.d.ts +20 -7
  8. package/dist/declarations/src/actors/promise.d.ts +5 -5
  9. package/dist/declarations/src/createMachine.d.ts +5 -3
  10. package/dist/declarations/src/createMachineFromConfig.d.ts +13 -2
  11. package/dist/declarations/src/eventTypes.d.ts +8 -0
  12. package/dist/declarations/src/graph/index.d.ts +1 -0
  13. package/dist/declarations/src/graph/types.d.ts +20 -2
  14. package/dist/declarations/src/machineVersions.d.ts +2 -2
  15. package/dist/declarations/src/serialize.d.ts +7 -2
  16. package/dist/declarations/src/setup.d.ts +60 -19
  17. package/dist/declarations/src/types.d.ts +44 -23
  18. package/dist/declarations/src/types.v6.d.ts +9 -7
  19. package/dist/declarations/src/utils.d.ts +9 -0
  20. package/dist/{effectDescriptor-6dbc400a.cjs.js → effectDescriptor-4cf24593.cjs.js} +1 -1
  21. package/dist/{effectDescriptor-85ea06c9.esm.js → effectDescriptor-973fc1ba.esm.js} +1 -1
  22. package/dist/{effectDescriptor-62b53c6d.development.cjs.js → effectDescriptor-b2b7deaa.development.cjs.js} +1 -1
  23. package/dist/{effectDescriptor-f76948fc.development.esm.js → effectDescriptor-c4671afc.development.esm.js} +1 -1
  24. package/dist/{index-5587e13b.cjs.js → index-0cf33789.development.cjs.js} +29 -14
  25. package/dist/{index-b0dc2b39.esm.js → index-15382daf.development.esm.js} +29 -14
  26. package/dist/{index-90ebf5ae.development.esm.js → index-52ad3d45.esm.js} +29 -14
  27. package/dist/{index-2afc57c3.development.cjs.js → index-f201d440.cjs.js} +29 -14
  28. package/dist/xstate-actors.cjs.js +2 -2
  29. package/dist/xstate-actors.development.cjs.js +2 -2
  30. package/dist/xstate-actors.development.esm.js +2 -2
  31. package/dist/xstate-actors.esm.js +2 -2
  32. package/dist/xstate-actors.umd.min.js +1 -1
  33. package/dist/xstate-actors.umd.min.js.map +1 -1
  34. package/dist/xstate-durable.cjs.js +2 -2
  35. package/dist/xstate-durable.development.cjs.js +2 -2
  36. package/dist/xstate-durable.development.esm.js +2 -2
  37. package/dist/xstate-durable.esm.js +2 -2
  38. package/dist/xstate-durable.umd.min.js +1 -1
  39. package/dist/xstate-durable.umd.min.js.map +1 -1
  40. package/dist/xstate-graph.cjs.js +8 -4
  41. package/dist/xstate-graph.cjs.mjs +1 -0
  42. package/dist/xstate-graph.development.cjs.js +8 -4
  43. package/dist/xstate-graph.development.cjs.mjs +1 -0
  44. package/dist/xstate-graph.development.esm.js +8 -4
  45. package/dist/xstate-graph.esm.js +8 -4
  46. package/dist/xstate-graph.umd.min.js +1 -1
  47. package/dist/xstate-graph.umd.min.js.map +1 -1
  48. package/dist/xstate-validation.cjs.js +24 -7
  49. package/dist/xstate-validation.development.cjs.js +24 -7
  50. package/dist/xstate-validation.development.esm.js +24 -7
  51. package/dist/xstate-validation.esm.js +24 -7
  52. package/dist/xstate-validation.umd.min.js +1 -1
  53. package/dist/xstate-validation.umd.min.js.map +1 -1
  54. package/dist/xstate.cjs.js +475 -257
  55. package/dist/xstate.development.cjs.js +497 -260
  56. package/dist/xstate.development.esm.js +499 -262
  57. package/dist/xstate.esm.js +477 -259
  58. package/dist/xstate.umd.min.js +1 -1
  59. package/dist/xstate.umd.min.js.map +1 -1
  60. package/package.json +1 -1
@@ -527,7 +527,8 @@ function withActorScope(args, actorScope) {
527
527
  }
528
528
 
529
529
  function execCustomEffect() {
530
- return this.action?.(...this.args);
530
+ const result = this.action?.(...this.args);
531
+ return result;
531
532
  }
532
533
  function execEmitEffect(runtime = this.source.system) {
533
534
  return runtime.emitEvent(this.source, this.event);
@@ -1049,6 +1050,13 @@ function createTransitionEnqueue(actorScope, actions, internalEvents, actorSubsc
1049
1050
  props[key] = guard(props[key]);
1050
1051
  }
1051
1052
  const enqueue = createEnqueueObject(props, guard((action, ...args) => {
1053
+ // A named action is `undefined` when it has no implementation. Skip it:
1054
+ // an `{ action, args }` record without a function would be emitted as
1055
+ // an event. Speculative passes (`can()`, conflict resolution) run with
1056
+ // `createActors: false`; warn only when the transition really runs.
1057
+ if (typeof action !== 'function') {
1058
+ return;
1059
+ }
1052
1060
  pushBuiltInAction(actions, action, ...args);
1053
1061
  }));
1054
1062
  enqueueClosers.set(enqueue, () => {
@@ -2266,6 +2274,10 @@ function getDelayedTransitions(stateNode) {
2266
2274
  }));
2267
2275
  }
2268
2276
  function formatTransition(stateNode, descriptor, transitionConfig) {
2277
+ const removedKey = getRemovedTransitionKey(transitionConfig);
2278
+ if (removedKey) {
2279
+ throw new Error(`Transition "${descriptor || 'always'}" in state "${stateNode.id}" uses ${removedKey}, which was removed in v6. Use a transition function.`);
2280
+ }
2269
2281
  const normalizedTarget = normalizeTarget(transitionConfig.target);
2270
2282
  const reenter = transitionConfig.reenter ?? false;
2271
2283
  const target = resolveTarget(stateNode, normalizedTarget);
@@ -2276,14 +2288,46 @@ function formatTransition(stateNode, descriptor, transitionConfig) {
2276
2288
  source: stateNode,
2277
2289
  reenter,
2278
2290
  eventType: descriptor,
2279
- toJSON: () => ({
2280
- ...transition,
2281
- source: `#${stateNode.id}`,
2282
- target: target ? target.map(t => `#${t.id}`) : undefined
2283
- })
2291
+ toJSON: () => transitionDefinitionToJSON(transition)
2284
2292
  };
2285
2293
  return transition;
2286
2294
  }
2295
+ function transitionDefinitionToJSON(transition) {
2296
+ const {
2297
+ definition: _,
2298
+ ...serializableTransition
2299
+ } = transition;
2300
+ return {
2301
+ ...serializableTransition,
2302
+ source: `#${transition.source.id}`,
2303
+ target: transition.target?.map(target => `#${target.id}`)
2304
+ };
2305
+ }
2306
+
2307
+ /**
2308
+ * Returns the v5 key of a transition object that v6 would misread, in every
2309
+ * build: `cond` is never read, so the transition would always be taken,
2310
+ * transition `actions` would not run as written, and only a function `guard`
2311
+ * can be called. Development builds explain each key earlier, in
2312
+ * `diagnoseAuthorConfig`. Compiled configs (JSON, SCXML) never set them.
2313
+ */
2314
+ function getRemovedTransitionKey(transitionConfig) {
2315
+ const {
2316
+ cond,
2317
+ actions,
2318
+ guard
2319
+ } = transitionConfig;
2320
+ if (cond !== undefined) {
2321
+ return '"cond"';
2322
+ }
2323
+ if (actions !== undefined) {
2324
+ return '"actions"';
2325
+ }
2326
+ if (guard !== undefined && typeof guard !== 'function') {
2327
+ return 'an object-form "guard"';
2328
+ }
2329
+ return undefined;
2330
+ }
2287
2331
  function isStateNodeDescendantOf(stateNode, ancestor) {
2288
2332
  for (let current = stateNode.parent; current; current = current.parent) {
2289
2333
  if (current === ancestor) {
@@ -2626,12 +2670,18 @@ function removeConflictingTransitions(enabledTransitions, stateNodeSet, snapshot
2626
2670
  }
2627
2671
  function createTransitionResultResolver(snapshot, event, actorScope, resolveActions, selectionResults) {
2628
2672
  let cache;
2629
- return transition => {
2630
- if (!transition.to) {
2631
- return getTransitionResult(transition, snapshot, event, actorScope, {
2632
- resolveActions,
2633
- selectionResult: selectionResults?.get(transition)
2634
- });
2673
+ return (transition, applied) => {
2674
+ if (!transition.to && !applied) {
2675
+ // An object transition's targets are static, so reading them must not
2676
+ // run its `context` and `input` mappers
2677
+ return {
2678
+ targets: transition.target,
2679
+ context: undefined,
2680
+ reenter: transition.reenter,
2681
+ actions: undefined,
2682
+ internalEvents: undefined,
2683
+ input: undefined
2684
+ };
2635
2685
  }
2636
2686
  let result = cache?.get(transition);
2637
2687
  if (!result) {
@@ -2859,13 +2909,20 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2859
2909
  children: args.children,
2860
2910
  actions: args.actions,
2861
2911
  actors: args.actors,
2912
+ guards: currentSnapshot.machine.sources.guards,
2913
+ delays: currentSnapshot.machine.sources.delays,
2862
2914
  input,
2863
2915
  stateNode
2864
2916
  }, actorScope) : {
2865
2917
  ...args,
2918
+ guards: currentSnapshot.machine.sources.guards,
2919
+ delays: currentSnapshot.machine.sources.delays,
2866
2920
  input,
2867
2921
  stateNode
2868
- }, enqueue), '_special' in transitionFn ? {
2922
+ },
2923
+ // This function runs during action resolution, where enqueued
2924
+ // effects are no longer collected.
2925
+ enqueue), '_special' in transitionFn ? {
2869
2926
  _special: true
2870
2927
  } : {});
2871
2928
  return [[wrappedAction], undefined, undefined];
@@ -2903,7 +2960,7 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2903
2960
  }
2904
2961
  for (const exitStateNode of statesToExit) {
2905
2962
  const stateInput = getStateInput(currentSnapshot, exitStateNode.id);
2906
- const [exitActions, nextContext, internalEvents] = exitStateNode.exit ? getStateActionsAndContext(exitStateNode.exit, nextState.context, currentSnapshot.children, stateInput, 'exit', exitStateNode) : [[], undefined, undefined];
2963
+ const [exitActions, nextContext, internalEvents] = exitStateNode.exit ? getStateActionsAndContext(exitStateNode.exit, nextState.context, nextState.children, stateInput, 'exit', exitStateNode) : [[], undefined, undefined];
2907
2964
  if (internalEvents?.length) {
2908
2965
  internalQueue.push(...internalEvents);
2909
2966
  }
@@ -2933,11 +2990,20 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2933
2990
  let context = nextState.context;
2934
2991
  const transitionActions = [];
2935
2992
  const internalEvents = [];
2993
+ const resolvedTransitions = [];
2936
2994
  for (const t of filteredTransitions) {
2937
- if (t.actions) {
2938
- transitionActions.push(...toArray(t.actions));
2995
+ const res = getCurrentTransitionResult(t, true);
2996
+ if (t.to) {
2997
+ const resolvedTransition = {
2998
+ ...t,
2999
+ target: res.targets,
3000
+ definition: t
3001
+ };
3002
+ resolvedTransition.toJSON = () => transitionDefinitionToJSON(resolvedTransition);
3003
+ resolvedTransitions.push(resolvedTransition);
3004
+ } else {
3005
+ resolvedTransitions.push(t);
2939
3006
  }
2940
- const res = getCurrentTransitionResult(t);
2941
3007
  if (res.context !== undefined) {
2942
3008
  context = mergeContextPatch(context, res.context);
2943
3009
  }
@@ -3093,7 +3159,7 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3093
3159
  const {
3094
3160
  targets,
3095
3161
  input
3096
- } = getCurrentTransitionResult(transition);
3162
+ } = getCurrentTransitionResult(transition, true);
3097
3163
  if (input && targets) {
3098
3164
  for (const targetNode of targets.filter(targetNode => enteredTargetsByTransition.get(transition)?.has(targetNode))) {
3099
3165
  stateInputMap[targetNode.id] = input;
@@ -3102,12 +3168,12 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3102
3168
  }
3103
3169
  }
3104
3170
  const completedNodes = new Set();
3105
- const children = {
3106
- ...nextState.children
3107
- };
3108
3171
  for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
3109
3172
  mutStateNodeSet.add(stateNodeToEnter);
3110
3173
  const actions = [];
3174
+ // Read the children for each state: the entry actions of the states
3175
+ // entered before this one may have spawned or stopped children.
3176
+ let children = nextState.children;
3111
3177
 
3112
3178
  // Final states are inert, so (as in SCXML) their invocations never
3113
3179
  // start.
@@ -3146,7 +3212,10 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3146
3212
  args: [actor]
3147
3213
  });
3148
3214
  if (invokeDef.id) {
3149
- children[invokeDef.id] = actor;
3215
+ children = {
3216
+ ...children,
3217
+ [invokeDef.id]: actor
3218
+ };
3150
3219
  }
3151
3220
  }
3152
3221
  if (invoked) {
@@ -3266,7 +3335,12 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3266
3335
  nextStateNodesToExit.forEach(stateNode => {
3267
3336
  if (stateNode.exit) {
3268
3337
  const stateInput = getStateInput(nextState, stateNode.id);
3269
- const [exitActions,, nextInternalEvents] = getStateActionsAndContext(stateNode.exit, nextState.context, nextState.children, stateInput, 'exit', stateNode);
3338
+ const [exitActions, nextContext, nextInternalEvents] = getStateActionsAndContext(stateNode.exit, nextState.context, nextState.children, stateInput, 'exit', stateNode);
3339
+ if (nextContext) {
3340
+ nextState = cloneMachineSnapshot(nextState, {
3341
+ context: nextContext
3342
+ });
3343
+ }
3270
3344
  allExitActions.push(...exitActions);
3271
3345
  if (nextInternalEvents?.length) {
3272
3346
  internalQueue.push(...nextInternalEvents);
@@ -3287,14 +3361,14 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3287
3361
  // If context was changed (e.g. by entry actions during self-transition),
3288
3362
  // clone to ensure reference inequality for eventless transition re-evaluation
3289
3363
  if (nextState.context !== originalContext) {
3290
- return [nextState === currentSnapshot ? cloneMachineSnapshot(nextState) : nextState, executableActions];
3364
+ return [nextState === currentSnapshot ? cloneMachineSnapshot(nextState) : nextState, executableActions, resolvedTransitions];
3291
3365
  }
3292
- return [nextState, executableActions];
3366
+ return [nextState, executableActions, resolvedTransitions];
3293
3367
  }
3294
3368
  return [cloneMachineSnapshot(nextState, {
3295
3369
  _nodes: nextStateNodes,
3296
3370
  historyValue
3297
- }), executableActions];
3371
+ }), executableActions, resolvedTransitions];
3298
3372
  }
3299
3373
  }
3300
3374
 
@@ -3404,6 +3478,15 @@ class InfiniteTransitionError extends Error {
3404
3478
  }
3405
3479
  }
3406
3480
  function macrostep(snapshot, event, actorScope, internalQueue, initialMicrosteps = []) {
3481
+ // A done, error or stopped snapshot processes no events, as in an actor:
3482
+ // every event is unhandled. The initial macrostep passes `initialMicrosteps`
3483
+ // and may start from a snapshot that is already done.
3484
+ if (snapshot.status !== 'active' && !initialMicrosteps.length) {
3485
+ return {
3486
+ snapshot,
3487
+ microsteps: [[snapshot, [], []]]
3488
+ };
3489
+ }
3407
3490
  let nextSnapshot = snapshot;
3408
3491
  const microsteps = initialMicrosteps.slice();
3409
3492
  // Whether a transition handled the external event. A handled event always
@@ -3472,6 +3555,7 @@ function macrostep(snapshot, event, actorScope, internalQueue, initialMicrosteps
3472
3555
  };
3473
3556
  }
3474
3557
  function addMicrostep(step, transitions) {
3558
+ transitions = step[2] ?? transitions;
3475
3559
  // collect microsteps; their transitions are surfaced on the enclosing
3476
3560
  // '@xstate.transition' event via its `microsteps[]` facet (there is no
3477
3561
  // standalone microstep event) and returned by `getMicrosteps()`
@@ -3882,6 +3966,17 @@ function isMachineSnapshot(value) {
3882
3966
  return !!value && typeof value === 'object' && 'machine' in value && 'value' in value;
3883
3967
  }
3884
3968
 
3969
+ /**
3970
+ * The values that `snapshot.matches(...)` accepts for a state value: a state
3971
+ * key, a dot-delimited path to a descendant state, or a partial state value.
3972
+ * Non-literal state values accept any value.
3973
+ */
3974
+
3975
+ /**
3976
+ * `unknown` if `matches(...)` accepts `TTestStateValue` for `TStateValue`,
3977
+ * otherwise `never`. Non-literal test values are always accepted.
3978
+ */
3979
+
3885
3980
  /** @public */
3886
3981
 
3887
3982
  const machineSnapshotMatches = function matches(testValue) {
@@ -4382,7 +4477,14 @@ function getAllOwnEventDescriptors(snapshot) {
4382
4477
  return [...new Set([...snapshot.nodes.flatMap(sn => sn.ownEvents)])];
4383
4478
  }
4384
4479
 
4385
- /** @internal Events synthesized from active transition descriptors. */
4480
+ /**
4481
+ * Returns one event per transition of the active state nodes of `snapshot`,
4482
+ * including the internal events for invoked actors (`xstate.done.actor`,
4483
+ * `xstate.error.actor`) and delayed transitions (`xstate.after`). Graph
4484
+ * traversal sends these when the `events` option is not given.
4485
+ *
4486
+ * @public
4487
+ */
4386
4488
  function getAllOwnEvents(snapshot) {
4387
4489
  const events = snapshot.nodes.flatMap(stateNode => [...stateNode.transitions.values()].flatMap(transitions => transitions.map(transition => {
4388
4490
  const event = {
@@ -5931,7 +6033,10 @@ class Actor {
5931
6033
  const [nextSnapshot, effects] = nextState;
5932
6034
  if (nextSnapshot === previousSnapshot && !effects.length &&
5933
6035
  // State machine snapshots only; other logic may ignore events freely.
5934
- 'machine' in previousSnapshot && !event.type.startsWith('xstate.')) {
6036
+ 'machine' in previousSnapshot && (
6037
+ // `xstate.route` is sent by users, so a route that matches nothing is
6038
+ // reported like any other unhandled event.
6039
+ !event.type.startsWith('xstate.') || event.type === 'xstate.route')) {
5935
6040
  this._reportUnhandledEvent(event);
5936
6041
  }
5937
6042
  snapshot = nextSnapshot;