xstate 5.0.0-beta.15 → 5.0.0-beta.17

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 (51) hide show
  1. package/actions/dist/xstate-actions.cjs.js +2 -7
  2. package/actions/dist/xstate-actions.cjs.mjs +2 -7
  3. package/actions/dist/xstate-actions.development.cjs.js +2 -7
  4. package/actions/dist/xstate-actions.development.esm.js +1 -1
  5. package/actions/dist/xstate-actions.esm.js +1 -1
  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/{actions-98f362b9.development.esm.js → actions-13190b25.development.esm.js} +1335 -1537
  15. package/dist/{actions-d71ac253.development.cjs.js → actions-40bd643f.development.cjs.js} +1336 -1546
  16. package/dist/{actions-6884fae8.esm.js → actions-4d6514d2.esm.js} +1310 -1539
  17. package/dist/{actions-81cc7f2b.cjs.js → actions-5fb9f10d.cjs.js} +1311 -1548
  18. package/dist/declarations/src/State.d.ts +1 -1
  19. package/dist/declarations/src/StateMachine.d.ts +2 -4
  20. package/dist/declarations/src/StateNode.d.ts +4 -4
  21. package/dist/declarations/src/actions/assign.d.ts +11 -2
  22. package/dist/declarations/src/actions/cancel.d.ts +14 -3
  23. package/dist/declarations/src/actions/choose.d.ts +11 -3
  24. package/dist/declarations/src/actions/log.d.ts +22 -3
  25. package/dist/declarations/src/actions/pure.d.ts +17 -3
  26. package/dist/declarations/src/actions/raise.d.ts +5 -2
  27. package/dist/declarations/src/actions/send.d.ts +64 -22
  28. package/dist/declarations/src/actions/stop.d.ts +14 -2
  29. package/dist/declarations/src/actions.d.ts +5 -11
  30. package/dist/declarations/src/constantPrefixes.d.ts +6 -0
  31. package/dist/declarations/src/interpreter.d.ts +8 -3
  32. package/dist/declarations/src/stateUtils.d.ts +4 -8
  33. package/dist/declarations/src/types.d.ts +38 -223
  34. package/dist/declarations/src/utils.d.ts +1 -6
  35. package/dist/xstate.cjs.js +61 -52
  36. package/dist/xstate.cjs.mjs +1 -1
  37. package/dist/xstate.development.cjs.js +61 -52
  38. package/dist/xstate.development.esm.js +61 -52
  39. package/dist/xstate.esm.js +61 -52
  40. package/dist/xstate.umd.min.js +1 -1
  41. package/dist/xstate.umd.min.js.map +1 -1
  42. package/guards/dist/xstate-guards.cjs.js +1 -1
  43. package/guards/dist/xstate-guards.development.cjs.js +1 -1
  44. package/guards/dist/xstate-guards.development.esm.js +1 -1
  45. package/guards/dist/xstate-guards.esm.js +1 -1
  46. package/guards/dist/xstate-guards.umd.min.js +1 -1
  47. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  48. package/package.json +1 -1
  49. package/actions/dynamicAction.ts +0 -42
  50. package/dist/declarations/src/actionTypes.d.ts +0 -16
  51. package/dist/declarations/src/constants.d.ts +0 -5
@@ -15,12 +15,6 @@ import { devToolsAdapter } from '../dev/dist/xstate-dev.esm.js';
15
15
 
16
16
  // TODO: narrow this to logic from machine
17
17
 
18
- // TODO: fix last param
19
-
20
- /**
21
- * Extracts action objects that have no extra properties.
22
- */
23
-
24
18
  /**
25
19
  * The string or object representing the state value relative to the parent state node.
26
20
  *
@@ -32,25 +26,15 @@ import { devToolsAdapter } from '../dev/dist/xstate-dev.esm.js';
32
26
 
33
27
  // TODO: possibly refactor this somehow, use even a simpler type, and maybe even make `machine.options` private or something
34
28
 
35
- let ActionTypes = /*#__PURE__*/function (ActionTypes) {
36
- ActionTypes["Stop"] = "xstate.stop";
37
- ActionTypes["Raise"] = "xstate.raise";
38
- ActionTypes["Send"] = "xstate.send";
39
- ActionTypes["Cancel"] = "xstate.cancel";
40
- ActionTypes["Assign"] = "xstate.assign";
41
- ActionTypes["After"] = "xstate.after";
42
- ActionTypes["DoneState"] = "done.state";
43
- ActionTypes["DoneInvoke"] = "done.invoke";
44
- ActionTypes["Log"] = "xstate.log";
45
- ActionTypes["Init"] = "xstate.init";
46
- ActionTypes["Invoke"] = "xstate.invoke";
47
- ActionTypes["ErrorExecution"] = "error.execution";
48
- ActionTypes["ErrorCommunication"] = "error.communication";
49
- ActionTypes["ErrorPlatform"] = "error.platform";
50
- ActionTypes["ErrorCustom"] = "xstate.error";
51
- ActionTypes["Pure"] = "xstate.pure";
52
- ActionTypes["Choose"] = "xstate.choose";
53
- return ActionTypes;
29
+ let ConstantPrefix = /*#__PURE__*/function (ConstantPrefix) {
30
+ ConstantPrefix["After"] = "xstate.after";
31
+ ConstantPrefix["DoneState"] = "done.state";
32
+ ConstantPrefix["DoneInvoke"] = "done.invoke";
33
+ ConstantPrefix["ErrorExecution"] = "error.execution";
34
+ ConstantPrefix["ErrorCommunication"] = "error.communication";
35
+ ConstantPrefix["ErrorPlatform"] = "error.platform";
36
+ ConstantPrefix["ErrorCustom"] = "xstate.error";
37
+ return ConstantPrefix;
54
38
  }({});
55
39
  let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
56
40
  SpecialTargets["Parent"] = "#_parent";
@@ -58,40 +42,19 @@ let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
58
42
  return SpecialTargets;
59
43
  }({});
60
44
 
61
- // xstate-specific action types
62
- const stop$1 = ActionTypes.Stop;
63
- const raise$1 = ActionTypes.Raise;
64
- const send$1 = ActionTypes.Send;
65
- const cancel$1 = ActionTypes.Cancel;
66
- const assign$1 = ActionTypes.Assign;
67
- const after$1 = ActionTypes.After;
68
- const doneState = ActionTypes.DoneState;
69
- const log$1 = ActionTypes.Log;
70
- const init = ActionTypes.Init;
71
- const invoke$1 = ActionTypes.Invoke;
72
- const errorExecution = ActionTypes.ErrorExecution;
73
- const errorPlatform = ActionTypes.ErrorPlatform;
74
- const error$1 = ActionTypes.ErrorCustom;
75
- const choose$1 = ActionTypes.Choose;
76
- const pure$1 = ActionTypes.Pure;
77
-
78
- var actionTypes = /*#__PURE__*/Object.freeze({
45
+ const after$1 = ConstantPrefix.After;
46
+ const doneState = ConstantPrefix.DoneState;
47
+ const errorExecution = ConstantPrefix.ErrorExecution;
48
+ const errorPlatform = ConstantPrefix.ErrorPlatform;
49
+ const error$1 = ConstantPrefix.ErrorCustom;
50
+
51
+ var constantPrefixes = /*#__PURE__*/Object.freeze({
79
52
  __proto__: null,
80
- stop: stop$1,
81
- raise: raise$1,
82
- send: send$1,
83
- cancel: cancel$1,
84
- assign: assign$1,
85
53
  after: after$1,
86
54
  doneState: doneState,
87
- log: log$1,
88
- init: init,
89
- invoke: invoke$1,
90
55
  errorExecution: errorExecution,
91
56
  errorPlatform: errorPlatform,
92
- error: error$1,
93
- choose: choose$1,
94
- pure: pure$1
57
+ error: error$1
95
58
  });
96
59
 
97
60
  const STATE_DELIMITER = '.';
@@ -99,311 +62,90 @@ const TARGETLESS_KEY = '';
99
62
  const NULL_EVENT = '';
100
63
  const STATE_IDENTIFIER = '#';
101
64
  const WILDCARD = '*';
102
-
103
- function matchesState(parentStateId, childStateId) {
104
- const parentStateValue = toStateValue(parentStateId);
105
- const childStateValue = toStateValue(childStateId);
106
- if (isString(childStateValue)) {
107
- if (isString(parentStateValue)) {
108
- return childStateValue === parentStateValue;
109
- }
110
-
111
- // Parent more specific than child
112
- return false;
113
- }
114
- if (isString(parentStateValue)) {
115
- return parentStateValue in childStateValue;
116
- }
117
- return Object.keys(parentStateValue).every(key => {
118
- if (!(key in childStateValue)) {
119
- return false;
120
- }
121
- return matchesState(parentStateValue[key], childStateValue[key]);
122
- });
123
- }
124
- function toStatePath(stateId) {
125
- try {
126
- if (isArray(stateId)) {
127
- return stateId;
128
- }
129
- return stateId.toString().split(STATE_DELIMITER);
130
- } catch (e) {
131
- throw new Error(`'${stateId}' is not a valid state path.`);
132
- }
133
- }
134
- function isStateLike(state) {
135
- return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state;
136
- }
137
- function toStateValue(stateValue) {
138
- if (isStateLike(stateValue)) {
139
- return stateValue.value;
140
- }
141
- if (isArray(stateValue)) {
142
- return pathToStateValue(stateValue);
143
- }
144
- if (typeof stateValue !== 'string') {
145
- return stateValue;
146
- }
147
- const statePath = toStatePath(stateValue);
148
- return pathToStateValue(statePath);
149
- }
150
- function pathToStateValue(statePath) {
151
- if (statePath.length === 1) {
152
- return statePath[0];
153
- }
154
- const value = {};
155
- let marker = value;
156
- for (let i = 0; i < statePath.length - 1; i++) {
157
- if (i === statePath.length - 2) {
158
- marker[statePath[i]] = statePath[i + 1];
65
+ const INIT_TYPE = 'xstate.init';
66
+
67
+ function resolve$8(actorContext, state, args, {
68
+ to,
69
+ event: eventOrExpr,
70
+ id,
71
+ delay
72
+ }) {
73
+ const delaysMap = state.machine.implementations.delays;
74
+ if (typeof eventOrExpr === 'string') {
75
+ throw new Error(`Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`);
76
+ }
77
+ const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
78
+ let resolvedDelay;
79
+ if (typeof delay === 'string') {
80
+ const configDelay = delaysMap && delaysMap[delay];
81
+ resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
82
+ } else {
83
+ resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
84
+ }
85
+ const resolvedTarget = typeof to === 'function' ? to(args) : to;
86
+ let targetActorRef;
87
+ if (typeof resolvedTarget === 'string') {
88
+ if (resolvedTarget === SpecialTargets.Parent) {
89
+ targetActorRef = actorContext?.self._parent;
90
+ } else if (resolvedTarget === SpecialTargets.Internal) {
91
+ targetActorRef = actorContext?.self;
92
+ } else if (resolvedTarget.startsWith('#_')) {
93
+ // SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor
94
+ // #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session.
95
+ targetActorRef = state.children[resolvedTarget.slice(2)];
159
96
  } else {
160
- const previous = marker;
161
- marker = {};
162
- previous[statePath[i]] = marker;
97
+ targetActorRef = state.children[resolvedTarget];
163
98
  }
164
- }
165
- return value;
166
- }
167
- function mapValues(collection, iteratee) {
168
- const result = {};
169
- const collectionKeys = Object.keys(collection);
170
- for (let i = 0; i < collectionKeys.length; i++) {
171
- const key = collectionKeys[i];
172
- result[key] = iteratee(collection[key], key, collection, i);
173
- }
174
- return result;
175
- }
176
- function flatten(array) {
177
- return [].concat(...array);
178
- }
179
- function toArrayStrict(value) {
180
- if (isArray(value)) {
181
- return value;
182
- }
183
- return [value];
184
- }
185
- function toArray(value) {
186
- if (value === undefined) {
187
- return [];
188
- }
189
- return toArrayStrict(value);
190
- }
191
- function mapContext(mapper, context, event) {
192
- if (isFunction(mapper)) {
193
- return mapper({
194
- context,
195
- event
196
- });
197
- }
198
- const result = {};
199
- const args = {
200
- context,
201
- event
202
- };
203
- for (const key of Object.keys(mapper)) {
204
- const subMapper = mapper[key];
205
- if (isFunction(subMapper)) {
206
- result[key] = subMapper(args);
207
- } else {
208
- result[key] = subMapper;
99
+ if (!targetActorRef) {
100
+ throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${state.machine.id}'.`);
209
101
  }
102
+ } else {
103
+ targetActorRef = resolvedTarget || actorContext?.self;
210
104
  }
211
- return result;
105
+ return [state, {
106
+ to: targetActorRef,
107
+ event: resolvedEvent,
108
+ id,
109
+ delay: resolvedDelay
110
+ }];
212
111
  }
213
- function isPromiseLike(value) {
214
- if (value instanceof Promise) {
215
- return true;
112
+ function execute$5(actorContext, params) {
113
+ if (typeof params.delay === 'number') {
114
+ actorContext.self.delaySend(params);
115
+ return;
216
116
  }
217
- // Check if shape matches the Promise/A+ specification for a "thenable".
218
- if (value !== null && (isFunction(value) || typeof value === 'object') && isFunction(value.then)) {
219
- return true;
220
- }
221
- return false;
222
- }
223
- function isArray(value) {
224
- return Array.isArray(value);
225
- }
226
-
227
- // tslint:disable-next-line:ban-types
228
- function isFunction(value) {
229
- return typeof value === 'function';
230
- }
231
- function isString(value) {
232
- return typeof value === 'string';
233
- }
234
- function isErrorEvent(event) {
235
- return typeof event.type === 'string' && (event.type === errorExecution || event.type.startsWith(errorPlatform));
236
- }
237
- function toTransitionConfigArray(event, configLike) {
238
- const transitions = toArrayStrict(configLike).map(transitionLike => {
239
- if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
240
- return {
241
- target: transitionLike,
242
- event
243
- };
244
- }
245
- return {
246
- ...transitionLike,
247
- event
248
- };
117
+ const {
118
+ to,
119
+ event
120
+ } = params;
121
+ actorContext.defer(() => {
122
+ to.send(event.type === error$1 ? {
123
+ type: `${error(actorContext.self.id)}`,
124
+ data: event.data
125
+ } : event);
249
126
  });
250
- return transitions;
251
- }
252
- function normalizeTarget(target) {
253
- if (target === undefined || target === TARGETLESS_KEY) {
254
- return undefined;
255
- }
256
- return toArray(target);
257
- }
258
- function toInvokeConfig(invocable, id) {
259
- if (typeof invocable === 'object') {
260
- if ('src' in invocable) {
261
- return invocable;
262
- }
263
- if ('transition' in invocable) {
264
- return {
265
- id,
266
- src: invocable
267
- };
268
- }
269
- }
270
- return {
271
- id,
272
- src: invocable
273
- };
274
- }
275
- function toObserver(nextHandler, errorHandler, completionHandler) {
276
- const noop = () => {};
277
- const isObserver = typeof nextHandler === 'object';
278
- const self = isObserver ? nextHandler : null;
279
- return {
280
- next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
281
- error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
282
- complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
283
- };
284
- }
285
- function createInvokeId(stateNodeId, index) {
286
- return `${stateNodeId}:invocation[${index}]`;
287
- }
288
- function resolveReferencedActor(referenced) {
289
- return referenced ? 'transition' in referenced ? {
290
- src: referenced,
291
- input: undefined
292
- } : referenced : undefined;
293
- }
294
-
295
- function createDynamicAction(action, resolve) {
296
- return {
297
- type: action.type,
298
- params: action.params,
299
- resolve
300
- };
301
- }
302
- function isDynamicAction(action) {
303
- return typeof action === 'object' && action !== null && 'resolve' in action;
304
127
  }
305
128
 
306
129
  /**
307
- * Sends an event. This returns an action that will be read by an interpreter to
308
- * send the event in the next step, after the current step is finished executing.
309
- *
310
- * @deprecated Use the `sendTo(...)` action creator instead.
130
+ * Sends an event to an actor.
311
131
  *
312
- * @param eventOrExpr The event to send.
313
- * @param options Options to pass into the send event:
132
+ * @param actor The `ActorRef` to send the event to.
133
+ * @param event The event to send, or an expression that evaluates to the event to send
134
+ * @param options Send action options
314
135
  * - `id` - The unique send event identifier (used with `cancel()`).
315
136
  * - `delay` - The number of milliseconds to delay the sending of the event.
316
- * - `to` - The target of this event (by default, the machine the event was sent from).
317
137
  */
318
- function send(eventOrExpr, options) {
319
- return createDynamicAction({
320
- type: send$1,
321
- params: {
322
- to: options ? options.to : undefined,
323
- delay: options ? options.delay : undefined,
324
- event: eventOrExpr,
325
- id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
326
- }
327
- }, (event, {
328
- actorContext,
329
- state
330
- }) => {
331
- const params = {
332
- to: options ? options.to : undefined,
333
- delay: options ? options.delay : undefined,
334
- event: eventOrExpr,
335
- // TODO: don't auto-generate IDs here like that
336
- // there is too big chance of the ID collision
337
- id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
338
- };
339
- const args = {
340
- context: state.context,
341
- event,
342
- self: actorContext?.self ?? null,
343
- system: actorContext?.system
344
- };
345
- const delaysMap = state.machine.implementations.delays;
346
-
347
- // TODO: helper function for resolving Expr
348
- if (typeof eventOrExpr === 'string') {
349
- throw new Error(`Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`);
350
- }
351
- const resolvedEvent = isFunction(eventOrExpr) ? eventOrExpr(args) : eventOrExpr;
352
- let resolvedDelay;
353
- if (isString(params.delay)) {
354
- const configDelay = delaysMap && delaysMap[params.delay];
355
- resolvedDelay = isFunction(configDelay) ? configDelay(args) : configDelay;
356
- } else {
357
- resolvedDelay = isFunction(params.delay) ? params.delay(args) : params.delay;
358
- }
359
- const resolvedTarget = isFunction(params.to) ? params.to(args) : params.to;
360
- let targetActorRef;
361
- if (typeof resolvedTarget === 'string') {
362
- if (resolvedTarget === SpecialTargets.Parent) {
363
- targetActorRef = actorContext?.self._parent;
364
- } else if (resolvedTarget === SpecialTargets.Internal) {
365
- targetActorRef = actorContext?.self;
366
- } else if (resolvedTarget.startsWith('#_')) {
367
- // SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor
368
- // #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session.
369
- targetActorRef = state.children[resolvedTarget.slice(2)];
370
- } else {
371
- targetActorRef = state.children[resolvedTarget];
372
- }
373
- if (!targetActorRef) {
374
- throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${state.machine.id}'.`);
375
- }
376
- } else {
377
- targetActorRef = resolvedTarget || actorContext?.self;
378
- }
379
- const resolvedAction = {
380
- type: send$1,
381
- params: {
382
- ...params,
383
- to: targetActorRef,
384
- event: resolvedEvent,
385
- delay: resolvedDelay,
386
- internal: resolvedTarget === SpecialTargets.Internal
387
- },
388
- execute: actorCtx => {
389
- const sendAction = resolvedAction;
390
- if (typeof sendAction.params.delay === 'number') {
391
- actorCtx.self.delaySend(sendAction);
392
- return;
393
- } else {
394
- const target = sendAction.params.to;
395
- const sentEvent = sendAction.params.event;
396
- actorCtx.defer(() => {
397
- target.send(sentEvent.type === error$1 ? {
398
- type: `${error(actorCtx.self.id)}`,
399
- data: sentEvent.data
400
- } : sendAction.params.event);
401
- });
402
- }
403
- }
404
- };
405
- return [state, resolvedAction];
406
- });
138
+ function sendTo(to, eventOrExpr, options) {
139
+ function sendTo(_) {
140
+ }
141
+ sendTo.type = 'xstate.sendTo';
142
+ sendTo.to = to;
143
+ sendTo.event = eventOrExpr;
144
+ sendTo.id = options?.id;
145
+ sendTo.delay = options?.delay;
146
+ sendTo.resolve = resolve$8;
147
+ sendTo.execute = execute$5;
148
+ return sendTo;
407
149
  }
408
150
 
409
151
  /**
@@ -413,12 +155,8 @@ function send(eventOrExpr, options) {
413
155
  * @param options Options to pass into the send event.
414
156
  */
415
157
  function sendParent(event, options) {
416
- return send(event, {
417
- ...options,
418
- to: SpecialTargets.Parent
419
- });
158
+ return sendTo(SpecialTargets.Parent, event, options);
420
159
  }
421
-
422
160
  /**
423
161
  * Forwards (sends) an event to a specified service.
424
162
  *
@@ -426,12 +164,9 @@ function sendParent(event, options) {
426
164
  * @param options Options to pass into the send action creator.
427
165
  */
428
166
  function forwardTo(target, options) {
429
- return send(({
167
+ return sendTo(target, ({
430
168
  event
431
- }) => event, {
432
- ...options,
433
- to: target
434
- });
169
+ }) => event, options);
435
170
  }
436
171
 
437
172
  /**
@@ -445,27 +180,9 @@ function escalate(errorData, options) {
445
180
  return sendParent(arg => {
446
181
  return {
447
182
  type: error$1,
448
- data: isFunction(errorData) ? errorData(arg) : errorData
183
+ data: typeof errorData === 'function' ? errorData(arg) : errorData
449
184
  };
450
- }, {
451
- ...options,
452
- to: SpecialTargets.Parent
453
- });
454
- }
455
-
456
- /**
457
- * Sends an event to an actor.
458
- *
459
- * @param actor The `ActorRef` to send the event to.
460
- * @param event The event to send, or an expression that evaluates to the event to send
461
- * @param options Send action options
462
- * @returns An XState send action object
463
- */
464
- function sendTo(actor, event, options) {
465
- return send(event, {
466
- ...options,
467
- to: actor
468
- });
185
+ }, options);
469
186
  }
470
187
 
471
188
  const cache = new WeakMap();
@@ -482,6 +199,16 @@ function memo(object, key, fn) {
482
199
  return memoizedData[key];
483
200
  }
484
201
 
202
+ function resolve$7(_, state, actionArgs, {
203
+ sendId
204
+ }) {
205
+ const resolvedSendId = typeof sendId === 'function' ? sendId(actionArgs) : sendId;
206
+ return [state, resolvedSendId];
207
+ }
208
+ function execute$4(actorContext, resolvedSendId) {
209
+ actorContext.self.cancel(resolvedSendId);
210
+ }
211
+
485
212
  /**
486
213
  * Cancels an in-flight `send(...)` action. A canceled sent action will not
487
214
  * be executed, nor will its event be sent, unless it has already been sent
@@ -489,38 +216,16 @@ function memo(object, key, fn) {
489
216
  *
490
217
  * @param sendId The `id` of the `send(...)` action to cancel.
491
218
  */
492
-
493
219
  function cancel(sendId) {
494
- return createDynamicAction({
495
- type: cancel$1,
496
- params: {
497
- sendId
498
- }
499
- }, (event, {
500
- state,
501
- actorContext
502
- }) => {
503
- const resolvedSendId = isFunction(sendId) ? sendId({
504
- context: state.context,
505
- event,
506
- self: actorContext?.self ?? {},
507
- system: actorContext?.system
508
- }) : sendId;
509
- return [state, {
510
- type: 'xstate.cancel',
511
- params: {
512
- sendId: resolvedSendId
513
- },
514
- execute: actorCtx => {
515
- const interpreter = actorCtx.self;
516
- interpreter.cancel(resolvedSendId);
517
- }
518
- }];
519
- });
220
+ function cancel(_) {
221
+ }
222
+ cancel.type = 'xstate.cancel';
223
+ cancel.sendId = sendId;
224
+ cancel.resolve = resolve$7;
225
+ cancel.execute = execute$4;
226
+ return cancel;
520
227
  }
521
228
 
522
- const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
523
-
524
229
  class Mailbox {
525
230
  constructor(_process) {
526
231
  this._process = _process;
@@ -588,526 +293,150 @@ class Mailbox {
588
293
  }
589
294
  }
590
295
 
591
- function createSystem() {
592
- let sessionIdCounter = 0;
593
- const children = new Map();
594
- const keyedActors = new Map();
595
- const reverseKeyedActors = new WeakMap();
596
- const system = {
597
- _bookId: () => `x:${sessionIdCounter++}`,
598
- _register: (sessionId, actorRef) => {
599
- children.set(sessionId, actorRef);
600
- return sessionId;
601
- },
602
- _unregister: actorRef => {
603
- children.delete(actorRef.sessionId);
604
- const systemId = reverseKeyedActors.get(actorRef);
605
- if (systemId !== undefined) {
606
- keyedActors.delete(systemId);
607
- reverseKeyedActors.delete(actorRef);
608
- }
296
+ const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
297
+
298
+ /**
299
+ * Returns actor logic from a transition function and its initial state.
300
+ *
301
+ * A transition function is a function that takes the current state and an event and returns the next state.
302
+ *
303
+ * @param transition The transition function that returns the next state given the current state and event.
304
+ * @param initialState The initial state of the transition function.
305
+ * @returns Actor logic
306
+ */
307
+ function fromTransition(transition, initialState) {
308
+ const logic = {
309
+ config: transition,
310
+ transition: (state, event, actorContext) => {
311
+ return transition(state, event, actorContext);
609
312
  },
610
- get: systemId => {
611
- return keyedActors.get(systemId);
313
+ getInitialState: (_, input) => {
314
+ return typeof initialState === 'function' ? initialState({
315
+ input
316
+ }) : initialState;
612
317
  },
613
- _set: (systemId, actorRef) => {
614
- const existing = keyedActors.get(systemId);
615
- if (existing && existing !== actorRef) {
616
- throw new Error(`Actor with system ID '${systemId}' already exists.`);
617
- }
618
- keyedActors.set(systemId, actorRef);
619
- reverseKeyedActors.set(actorRef, systemId);
620
- }
318
+ getSnapshot: state => state,
319
+ getPersistedState: state => state,
320
+ restoreState: state => state
621
321
  };
622
- return system;
322
+ return logic;
623
323
  }
624
324
 
625
- let ActorStatus = /*#__PURE__*/function (ActorStatus) {
626
- ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
627
- ActorStatus[ActorStatus["Running"] = 1] = "Running";
628
- ActorStatus[ActorStatus["Stopped"] = 2] = "Stopped";
629
- return ActorStatus;
630
- }({});
631
- const defaultOptions = {
632
- deferEvents: true,
633
- clock: {
634
- setTimeout: (fn, ms) => {
635
- return setTimeout(fn, ms);
325
+ const resolveEventType = '$$xstate.resolve';
326
+ const rejectEventType = '$$xstate.reject';
327
+ function fromPromise(
328
+ // TODO: add types
329
+ promiseCreator) {
330
+ // TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
331
+ const logic = {
332
+ config: promiseCreator,
333
+ transition: (state, event) => {
334
+ if (state.status !== 'active') {
335
+ return state;
336
+ }
337
+ switch (event.type) {
338
+ case resolveEventType:
339
+ return {
340
+ ...state,
341
+ status: 'done',
342
+ data: event.data,
343
+ input: undefined
344
+ };
345
+ case rejectEventType:
346
+ return {
347
+ ...state,
348
+ status: 'error',
349
+ data: event.data,
350
+ input: undefined
351
+ };
352
+ case stopSignalType:
353
+ return {
354
+ ...state,
355
+ status: 'canceled',
356
+ input: undefined
357
+ };
358
+ default:
359
+ return state;
360
+ }
636
361
  },
637
- clearTimeout: id => {
638
- return clearTimeout(id);
639
- }
640
- },
641
- logger: console.log.bind(console),
642
- devTools: false
643
- };
644
- class Interpreter {
645
- /**
646
- * The current state of the interpreted logic.
647
- */
648
-
649
- /**
650
- * The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
651
- */
652
-
653
- /**
654
- * The unique identifier for this actor relative to its parent.
655
- */
656
-
657
- /**
658
- * Whether the service is started.
659
- */
660
-
661
- // Actor Ref
662
-
663
- // TODO: add typings for system
664
-
665
- /**
666
- * The globally unique process ID for this invocation.
667
- */
668
-
669
- /**
670
- * Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
671
- *
672
- * @param logic The logic to be interpreted
673
- * @param options Interpreter options
674
- */
675
- constructor(logic, options) {
676
- this.logic = logic;
677
- this._state = void 0;
678
- this.clock = void 0;
679
- this.options = void 0;
680
- this.id = void 0;
681
- this.mailbox = new Mailbox(this._process.bind(this));
682
- this.delayedEventsMap = {};
683
- this.observers = new Set();
684
- this.logger = void 0;
685
- this.status = ActorStatus.NotStarted;
686
- this._parent = void 0;
687
- this.ref = void 0;
688
- this._actorContext = void 0;
689
- this._systemId = void 0;
690
- this.sessionId = void 0;
691
- this.system = void 0;
692
- this._doneEvent = void 0;
693
- this.src = void 0;
694
- this._deferred = [];
695
- const resolvedOptions = {
696
- ...defaultOptions,
697
- ...options
698
- };
699
- const {
700
- clock,
701
- logger,
702
- parent,
703
- id,
704
- systemId
705
- } = resolvedOptions;
706
- const self = this;
707
- this.system = parent?.system ?? createSystem();
708
- if (systemId) {
709
- this._systemId = systemId;
710
- this.system._set(systemId, this);
711
- }
712
- this.sessionId = this.system._bookId();
713
- this.id = id ?? this.sessionId;
714
- this.logger = logger;
715
- this.clock = clock;
716
- this._parent = parent;
717
- this.options = resolvedOptions;
718
- this.src = resolvedOptions.src;
719
- this.ref = this;
720
- this._actorContext = {
362
+ start: (state, {
721
363
  self,
722
- id: this.id,
723
- sessionId: this.sessionId,
724
- logger: this.logger,
725
- defer: fn => {
726
- this._deferred.push(fn);
727
- },
728
- system: this.system,
729
- stopChild: child => {
730
- if (child._parent !== this) {
731
- throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
732
- }
733
- child._stop();
364
+ system
365
+ }) => {
366
+ // TODO: determine how to allow customizing this so that promises
367
+ // can be restarted if necessary
368
+ if (state.status !== 'active') {
369
+ return;
734
370
  }
735
- };
736
-
737
- // Ensure that the send method is bound to this interpreter instance
738
- // if destructured
739
- this.send = this.send.bind(this);
740
- this._initState();
741
- }
742
- _initState() {
743
- this._state = this.options.state ? this.logic.restoreState ? this.logic.restoreState(this.options.state, this._actorContext) : this.options.state : this.logic.getInitialState(this._actorContext, this.options?.input);
744
- }
745
-
746
- // array of functions to defer
371
+ const resolvedPromise = Promise.resolve(promiseCreator({
372
+ input: state.input,
373
+ system
374
+ }));
375
+ resolvedPromise.then(response => {
376
+ // TODO: remove this condition once dead letter queue lands
377
+ if (self._state.status !== 'active') {
378
+ return;
379
+ }
380
+ self.send({
381
+ type: resolveEventType,
382
+ data: response
383
+ });
384
+ }, errorData => {
385
+ // TODO: remove this condition once dead letter queue lands
386
+ if (self._state.status !== 'active') {
387
+ return;
388
+ }
389
+ self.send({
390
+ type: rejectEventType,
391
+ data: errorData
392
+ });
393
+ });
394
+ },
395
+ getInitialState: (_, input) => {
396
+ return {
397
+ status: 'active',
398
+ data: undefined,
399
+ input
400
+ };
401
+ },
402
+ getSnapshot: state => state.data,
403
+ getStatus: state => state,
404
+ getPersistedState: state => state,
405
+ restoreState: state => state
406
+ };
407
+ return logic;
408
+ }
747
409
 
748
- update(state) {
749
- // Update state
750
- this._state = state;
751
- const snapshot = this.getSnapshot();
410
+ // TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
411
+ function fromObservable(observableCreator) {
412
+ const nextEventType = '$$xstate.next';
413
+ const errorEventType = '$$xstate.error';
414
+ const completeEventType = '$$xstate.complete';
752
415
 
753
- // Execute deferred effects
754
- let deferredFn;
755
- while (deferredFn = this._deferred.shift()) {
756
- deferredFn();
757
- }
758
- for (const observer of this.observers) {
759
- observer.next?.(snapshot);
760
- }
761
- const status = this.logic.getStatus?.(state);
762
- switch (status?.status) {
763
- case 'done':
764
- this._stopProcedure();
765
- this._doneEvent = doneInvoke(this.id, status.data);
766
- this._parent?.send(this._doneEvent);
767
- this._complete();
768
- break;
769
- case 'error':
770
- this._stopProcedure();
771
- this._parent?.send(error(this.id, status.data));
772
- this._error(status.data);
773
- break;
774
- }
775
- }
776
- subscribe(nextListenerOrObserver, errorListener, completeListener) {
777
- const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
778
- this.observers.add(observer);
779
- if (this.status === ActorStatus.Stopped) {
780
- observer.complete?.();
781
- this.observers.delete(observer);
782
- }
783
- return {
784
- unsubscribe: () => {
785
- this.observers.delete(observer);
786
- }
787
- };
788
- }
789
-
790
- /**
791
- * Starts the interpreter from the initial state
792
- */
793
- start() {
794
- if (this.status === ActorStatus.Running) {
795
- // Do not restart the service if it is already started
796
- return this;
797
- }
798
- this.system._register(this.sessionId, this);
799
- if (this._systemId) {
800
- this.system._set(this._systemId, this);
801
- }
802
- this.status = ActorStatus.Running;
803
- if (this.logic.start) {
804
- this.logic.start(this._state, this._actorContext);
805
- }
806
-
807
- // TODO: this notifies all subscribers but usually this is redundant
808
- // there is no real change happening here
809
- // we need to rethink if this needs to be refactored
810
- this.update(this._state);
811
- if (this.options.devTools) {
812
- this.attachDevTools();
813
- }
814
- this.mailbox.start();
815
- return this;
816
- }
817
- _process(event) {
818
- try {
819
- const nextState = this.logic.transition(this._state, event, this._actorContext);
820
- this.update(nextState);
821
- if (event.type === stopSignalType) {
822
- this._stopProcedure();
823
- this._complete();
824
- }
825
- } catch (err) {
826
- // TODO: properly handle errors
827
- if (this.observers.size > 0) {
828
- this.observers.forEach(observer => {
829
- observer.error?.(err);
830
- });
831
- this.stop();
832
- } else {
833
- throw err;
834
- }
835
- }
836
- }
837
- _stop() {
838
- if (this.status === ActorStatus.Stopped) {
839
- return this;
840
- }
841
- this.mailbox.clear();
842
- if (this.status === ActorStatus.NotStarted) {
843
- this.status = ActorStatus.Stopped;
844
- return this;
845
- }
846
- this.mailbox.enqueue({
847
- type: stopSignalType
848
- });
849
- return this;
850
- }
851
-
852
- /**
853
- * Stops the interpreter and unsubscribe all listeners.
854
- */
855
- stop() {
856
- if (this._parent) {
857
- throw new Error('A non-root actor cannot be stopped directly.');
858
- }
859
- return this._stop();
860
- }
861
- _complete() {
862
- for (const observer of this.observers) {
863
- observer.complete?.();
864
- }
865
- this.observers.clear();
866
- }
867
- _error(data) {
868
- for (const observer of this.observers) {
869
- observer.error?.(data);
870
- }
871
- this.observers.clear();
872
- }
873
- _stopProcedure() {
874
- if (this.status !== ActorStatus.Running) {
875
- // Interpreter already stopped; do nothing
876
- return this;
877
- }
878
-
879
- // Cancel all delayed events
880
- for (const key of Object.keys(this.delayedEventsMap)) {
881
- this.clock.clearTimeout(this.delayedEventsMap[key]);
882
- }
883
-
884
- // TODO: mailbox.reset
885
- this.mailbox.clear();
886
- // TODO: after `stop` we must prepare ourselves for receiving events again
887
- // events sent *after* stop signal must be queued
888
- // it seems like this should be the common behavior for all of our consumers
889
- // so perhaps this should be unified somehow for all of them
890
- this.mailbox = new Mailbox(this._process.bind(this));
891
- this.status = ActorStatus.Stopped;
892
- this.system._unregister(this);
893
- return this;
894
- }
895
-
896
- /**
897
- * Sends an event to the running interpreter to trigger a transition.
898
- *
899
- * @param event The event to send
900
- */
901
- send(event) {
902
- if (typeof event === 'string') {
903
- throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
904
- }
905
- if (this.status === ActorStatus.Stopped) {
906
- return;
907
- }
908
- if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
909
- throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
910
- // tslint:disable-next-line:max-line-length
911
- }". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
912
- }
913
- this.mailbox.enqueue(event);
914
- }
915
-
916
- // TODO: make private (and figure out a way to do this within the machine)
917
- delaySend(sendAction) {
918
- this.delayedEventsMap[sendAction.params.id] = this.clock.setTimeout(() => {
919
- if ('to' in sendAction.params && sendAction.params.to) {
920
- sendAction.params.to.send(sendAction.params.event);
921
- } else {
922
- this.send(sendAction.params.event);
923
- }
924
- }, sendAction.params.delay);
925
- }
926
-
927
- // TODO: make private (and figure out a way to do this within the machine)
928
- cancel(sendId) {
929
- this.clock.clearTimeout(this.delayedEventsMap[sendId]);
930
- delete this.delayedEventsMap[sendId];
931
- }
932
- attachDevTools() {
933
- const {
934
- devTools
935
- } = this.options;
936
- if (devTools) {
937
- const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
938
- resolvedDevToolsAdapter(this);
939
- }
940
- }
941
- toJSON() {
942
- return {
943
- id: this.id
944
- };
945
- }
946
- getPersistedState() {
947
- return this.logic.getPersistedState?.(this._state);
948
- }
949
- [symbolObservable]() {
950
- return this;
951
- }
952
- getSnapshot() {
953
- return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
954
- }
955
- }
956
-
957
- /**
958
- * Creates a new Interpreter instance for the given machine with the provided options, if any.
959
- *
960
- * @param machine The machine to interpret
961
- * @param options Interpreter options
962
- */
963
-
964
- function interpret(logic, options) {
965
- const interpreter = new Interpreter(logic, options);
966
- return interpreter;
967
- }
968
-
969
- /**
970
- * Returns actor logic from a transition function and its initial state.
971
- *
972
- * A transition function is a function that takes the current state and an event and returns the next state.
973
- *
974
- * @param transition The transition function that returns the next state given the current state and event.
975
- * @param initialState The initial state of the transition function.
976
- * @returns Actor logic
977
- */
978
- function fromTransition(transition, initialState) {
979
- const logic = {
980
- config: transition,
981
- transition: (state, event, actorContext) => {
982
- return transition(state, event, actorContext);
983
- },
984
- getInitialState: (_, input) => {
985
- return typeof initialState === 'function' ? initialState({
986
- input
987
- }) : initialState;
988
- },
989
- getSnapshot: state => state,
990
- getPersistedState: state => state,
991
- restoreState: state => state
992
- };
993
- return logic;
994
- }
995
-
996
- const resolveEventType = '$$xstate.resolve';
997
- const rejectEventType = '$$xstate.reject';
998
- function fromPromise(
999
- // TODO: add types
1000
- promiseCreator) {
1001
- // TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
416
+ // TODO: add event types
1002
417
  const logic = {
1003
- config: promiseCreator,
1004
- transition: (state, event) => {
418
+ config: observableCreator,
419
+ transition: (state, event, {
420
+ self,
421
+ id,
422
+ defer
423
+ }) => {
1005
424
  if (state.status !== 'active') {
1006
425
  return state;
1007
426
  }
1008
427
  switch (event.type) {
1009
- case resolveEventType:
428
+ case nextEventType:
429
+ // match the exact timing of events sent by machines
430
+ // send actions are not executed immediately
431
+ defer(() => {
432
+ self._parent?.send({
433
+ type: `xstate.snapshot.${id}`,
434
+ data: event.data
435
+ });
436
+ });
1010
437
  return {
1011
438
  ...state,
1012
- status: 'done',
1013
- data: event.data,
1014
- input: undefined
1015
- };
1016
- case rejectEventType:
1017
- return {
1018
- ...state,
1019
- status: 'error',
1020
- data: event.data,
1021
- input: undefined
1022
- };
1023
- case stopSignalType:
1024
- return {
1025
- ...state,
1026
- status: 'canceled',
1027
- input: undefined
1028
- };
1029
- default:
1030
- return state;
1031
- }
1032
- },
1033
- start: (state, {
1034
- self,
1035
- system
1036
- }) => {
1037
- // TODO: determine how to allow customizing this so that promises
1038
- // can be restarted if necessary
1039
- if (state.status !== 'active') {
1040
- return;
1041
- }
1042
- const resolvedPromise = Promise.resolve(promiseCreator({
1043
- input: state.input,
1044
- system
1045
- }));
1046
- resolvedPromise.then(response => {
1047
- // TODO: remove this condition once dead letter queue lands
1048
- if (self._state.status !== 'active') {
1049
- return;
1050
- }
1051
- self.send({
1052
- type: resolveEventType,
1053
- data: response
1054
- });
1055
- }, errorData => {
1056
- // TODO: remove this condition once dead letter queue lands
1057
- if (self._state.status !== 'active') {
1058
- return;
1059
- }
1060
- self.send({
1061
- type: rejectEventType,
1062
- data: errorData
1063
- });
1064
- });
1065
- },
1066
- getInitialState: (_, input) => {
1067
- return {
1068
- status: 'active',
1069
- data: undefined,
1070
- input
1071
- };
1072
- },
1073
- getSnapshot: state => state.data,
1074
- getStatus: state => state,
1075
- getPersistedState: state => state,
1076
- restoreState: state => state
1077
- };
1078
- return logic;
1079
- }
1080
-
1081
- // TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
1082
- function fromObservable(observableCreator) {
1083
- const nextEventType = '$$xstate.next';
1084
- const errorEventType = '$$xstate.error';
1085
- const completeEventType = '$$xstate.complete';
1086
-
1087
- // TODO: add event types
1088
- const logic = {
1089
- config: observableCreator,
1090
- transition: (state, event, {
1091
- self,
1092
- id,
1093
- defer
1094
- }) => {
1095
- if (state.status !== 'active') {
1096
- return state;
1097
- }
1098
- switch (event.type) {
1099
- case nextEventType:
1100
- // match the exact timing of events sent by machines
1101
- // send actions are not executed immediately
1102
- defer(() => {
1103
- self._parent?.send({
1104
- type: `xstate.snapshot.${id}`,
1105
- data: event.data
1106
- });
1107
- });
1108
- return {
1109
- ...state,
1110
- data: event.data
439
+ data: event.data
1111
440
  };
1112
441
  case errorEventType:
1113
442
  return {
@@ -1297,205 +626,759 @@ function fromEventObservable(lazyObservable) {
1297
626
  return logic;
1298
627
  }
1299
628
 
1300
- function fromCallback(invokeCallback) {
1301
- const logic = {
1302
- config: invokeCallback,
1303
- start: (_state, {
1304
- self
1305
- }) => {
1306
- self.send({
1307
- type: startSignalType
1308
- });
1309
- },
1310
- transition: (state, event, {
1311
- self,
1312
- id,
1313
- system
1314
- }) => {
1315
- if (event.type === startSignalType) {
1316
- const sender = eventForParent => {
1317
- if (state.canceled) {
1318
- return;
1319
- }
1320
- self._parent?.send(eventForParent);
1321
- };
1322
- const receiver = newListener => {
1323
- state.receivers.add(newListener);
1324
- };
1325
- state.dispose = invokeCallback(sender, receiver, {
1326
- input: state.input,
1327
- system
1328
- });
1329
- if (isPromiseLike(state.dispose)) {
1330
- state.dispose.then(resolved => {
1331
- self._parent?.send(doneInvoke(id, resolved));
1332
- state.canceled = true;
1333
- }, errorData => {
1334
- state.canceled = true;
1335
- self._parent?.send(error(id, errorData));
1336
- });
1337
- }
1338
- return state;
1339
- }
1340
- if (event.type === stopSignalType) {
1341
- state.canceled = true;
1342
- if (isFunction(state.dispose)) {
1343
- state.dispose();
1344
- }
1345
- return state;
1346
- }
1347
- if (isSignal(event)) {
1348
- // TODO: unrecognized signal
1349
- return state;
1350
- }
1351
- state.receivers.forEach(receiver => receiver(event));
1352
- return state;
1353
- },
1354
- getInitialState: (_, input) => {
1355
- return {
1356
- canceled: false,
1357
- receivers: new Set(),
1358
- dispose: undefined,
1359
- input
1360
- };
1361
- },
1362
- getSnapshot: () => undefined,
1363
- getPersistedState: ({
1364
- input
1365
- }) => input
1366
- };
1367
- return logic;
1368
- }
629
+ function matchesState(parentStateId, childStateId) {
630
+ const parentStateValue = toStateValue(parentStateId);
631
+ const childStateValue = toStateValue(childStateId);
632
+ if (typeof childStateValue === 'string') {
633
+ if (typeof parentStateValue === 'string') {
634
+ return childStateValue === parentStateValue;
635
+ }
636
+
637
+ // Parent more specific than child
638
+ return false;
639
+ }
640
+ if (typeof parentStateValue === 'string') {
641
+ return parentStateValue in childStateValue;
642
+ }
643
+ return Object.keys(parentStateValue).every(key => {
644
+ if (!(key in childStateValue)) {
645
+ return false;
646
+ }
647
+ return matchesState(parentStateValue[key], childStateValue[key]);
648
+ });
649
+ }
650
+ function toStatePath(stateId) {
651
+ try {
652
+ if (isArray(stateId)) {
653
+ return stateId;
654
+ }
655
+ return stateId.toString().split(STATE_DELIMITER);
656
+ } catch (e) {
657
+ throw new Error(`'${stateId}' is not a valid state path.`);
658
+ }
659
+ }
660
+ function isStateLike(state) {
661
+ return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state;
662
+ }
663
+ function toStateValue(stateValue) {
664
+ if (isStateLike(stateValue)) {
665
+ return stateValue.value;
666
+ }
667
+ if (isArray(stateValue)) {
668
+ return pathToStateValue(stateValue);
669
+ }
670
+ if (typeof stateValue !== 'string') {
671
+ return stateValue;
672
+ }
673
+ const statePath = toStatePath(stateValue);
674
+ return pathToStateValue(statePath);
675
+ }
676
+ function pathToStateValue(statePath) {
677
+ if (statePath.length === 1) {
678
+ return statePath[0];
679
+ }
680
+ const value = {};
681
+ let marker = value;
682
+ for (let i = 0; i < statePath.length - 1; i++) {
683
+ if (i === statePath.length - 2) {
684
+ marker[statePath[i]] = statePath[i + 1];
685
+ } else {
686
+ const previous = marker;
687
+ marker = {};
688
+ previous[statePath[i]] = marker;
689
+ }
690
+ }
691
+ return value;
692
+ }
693
+ function mapValues(collection, iteratee) {
694
+ const result = {};
695
+ const collectionKeys = Object.keys(collection);
696
+ for (let i = 0; i < collectionKeys.length; i++) {
697
+ const key = collectionKeys[i];
698
+ result[key] = iteratee(collection[key], key, collection, i);
699
+ }
700
+ return result;
701
+ }
702
+ function flatten(array) {
703
+ return [].concat(...array);
704
+ }
705
+ function toArrayStrict(value) {
706
+ if (isArray(value)) {
707
+ return value;
708
+ }
709
+ return [value];
710
+ }
711
+ function toArray(value) {
712
+ if (value === undefined) {
713
+ return [];
714
+ }
715
+ return toArrayStrict(value);
716
+ }
717
+ function mapContext(mapper, context, event) {
718
+ if (typeof mapper === 'function') {
719
+ return mapper({
720
+ context,
721
+ event
722
+ });
723
+ }
724
+ const result = {};
725
+ const args = {
726
+ context,
727
+ event
728
+ };
729
+ for (const key of Object.keys(mapper)) {
730
+ const subMapper = mapper[key];
731
+ if (typeof subMapper === 'function') {
732
+ result[key] = subMapper(args);
733
+ } else {
734
+ result[key] = subMapper;
735
+ }
736
+ }
737
+ return result;
738
+ }
739
+ function isPromiseLike(value) {
740
+ if (value instanceof Promise) {
741
+ return true;
742
+ }
743
+ // Check if shape matches the Promise/A+ specification for a "thenable".
744
+ if (value !== null && (typeof value === 'function' || typeof value === 'object') && typeof value.then === 'function') {
745
+ return true;
746
+ }
747
+ return false;
748
+ }
749
+ function isArray(value) {
750
+ return Array.isArray(value);
751
+ }
752
+ function isErrorEvent(event) {
753
+ return typeof event.type === 'string' && (event.type === errorExecution || event.type.startsWith(errorPlatform));
754
+ }
755
+ function toTransitionConfigArray(configLike) {
756
+ return toArrayStrict(configLike).map(transitionLike => {
757
+ if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
758
+ return {
759
+ target: transitionLike
760
+ };
761
+ }
762
+ return transitionLike;
763
+ });
764
+ }
765
+ function normalizeTarget(target) {
766
+ if (target === undefined || target === TARGETLESS_KEY) {
767
+ return undefined;
768
+ }
769
+ return toArray(target);
770
+ }
771
+ function toInvokeConfig(invocable, id) {
772
+ if (typeof invocable === 'object') {
773
+ if ('src' in invocable) {
774
+ return invocable;
775
+ }
776
+ if ('transition' in invocable) {
777
+ return {
778
+ id,
779
+ src: invocable
780
+ };
781
+ }
782
+ }
783
+ return {
784
+ id,
785
+ src: invocable
786
+ };
787
+ }
788
+ function toObserver(nextHandler, errorHandler, completionHandler) {
789
+ const noop = () => {};
790
+ const isObserver = typeof nextHandler === 'object';
791
+ const self = isObserver ? nextHandler : null;
792
+ return {
793
+ next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
794
+ error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
795
+ complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
796
+ };
797
+ }
798
+ function createInvokeId(stateNodeId, index) {
799
+ return `${stateNodeId}:invocation[${index}]`;
800
+ }
801
+ function resolveReferencedActor(referenced) {
802
+ return referenced ? 'transition' in referenced ? {
803
+ src: referenced,
804
+ input: undefined
805
+ } : referenced : undefined;
806
+ }
807
+
808
+ function fromCallback(invokeCallback) {
809
+ const logic = {
810
+ config: invokeCallback,
811
+ start: (_state, {
812
+ self
813
+ }) => {
814
+ self.send({
815
+ type: startSignalType
816
+ });
817
+ },
818
+ transition: (state, event, {
819
+ self,
820
+ id,
821
+ system
822
+ }) => {
823
+ if (event.type === startSignalType) {
824
+ const sender = eventForParent => {
825
+ if (state.canceled) {
826
+ return;
827
+ }
828
+ self._parent?.send(eventForParent);
829
+ };
830
+ const receiver = newListener => {
831
+ state.receivers.add(newListener);
832
+ };
833
+ state.dispose = invokeCallback(sender, receiver, {
834
+ input: state.input,
835
+ system
836
+ });
837
+ if (isPromiseLike(state.dispose)) {
838
+ state.dispose.then(resolved => {
839
+ self._parent?.send(doneInvoke(id, resolved));
840
+ state.canceled = true;
841
+ }, errorData => {
842
+ state.canceled = true;
843
+ self._parent?.send(error(id, errorData));
844
+ });
845
+ }
846
+ return state;
847
+ }
848
+ if (event.type === stopSignalType) {
849
+ state.canceled = true;
850
+ if (typeof state.dispose === 'function') {
851
+ state.dispose();
852
+ }
853
+ return state;
854
+ }
855
+ if (isSignal(event)) {
856
+ // TODO: unrecognized signal
857
+ return state;
858
+ }
859
+ state.receivers.forEach(receiver => receiver(event));
860
+ return state;
861
+ },
862
+ getInitialState: (_, input) => {
863
+ return {
864
+ canceled: false,
865
+ receivers: new Set(),
866
+ dispose: undefined,
867
+ input
868
+ };
869
+ },
870
+ getSnapshot: () => undefined,
871
+ getPersistedState: ({
872
+ input
873
+ }) => input
874
+ };
875
+ return logic;
876
+ }
877
+
878
+ const startSignalType = 'xstate.init';
879
+ const stopSignalType = 'xstate.stop';
880
+ const startSignal = {
881
+ type: 'xstate.init'
882
+ };
883
+ const stopSignal = {
884
+ type: 'xstate.stop'
885
+ };
886
+ /**
887
+ * An object that expresses the actor logic in reaction to received events,
888
+ * as well as an optionally emitted stream of values.
889
+ *
890
+ * @template TReceived The received event
891
+ * @template TSnapshot The emitted value
892
+ */
893
+
894
+ function isSignal(event) {
895
+ return event.type === startSignalType || event.type === stopSignalType;
896
+ }
897
+ function isActorRef(item) {
898
+ return !!item && typeof item === 'object' && typeof item.send === 'function';
899
+ }
900
+
901
+ // TODO: refactor the return type, this could be written in a better way
902
+ // but it's best to avoid unneccessary breaking changes now
903
+ // @deprecated use `interpret(actorLogic)` instead
904
+ function toActorRef(actorRefLike) {
905
+ return {
906
+ subscribe: () => ({
907
+ unsubscribe: () => void 0
908
+ }),
909
+ id: 'anonymous',
910
+ sessionId: '',
911
+ getSnapshot: () => undefined,
912
+ [symbolObservable]: function () {
913
+ return this;
914
+ },
915
+ status: ActorStatus.Running,
916
+ stop: () => void 0,
917
+ ...actorRefLike
918
+ };
919
+ }
920
+ const emptyLogic = fromTransition(_ => undefined, undefined);
921
+ function createEmptyActor() {
922
+ return interpret(emptyLogic);
923
+ }
924
+
925
+ function createSystem() {
926
+ let sessionIdCounter = 0;
927
+ const children = new Map();
928
+ const keyedActors = new Map();
929
+ const reverseKeyedActors = new WeakMap();
930
+ const system = {
931
+ _bookId: () => `x:${sessionIdCounter++}`,
932
+ _register: (sessionId, actorRef) => {
933
+ children.set(sessionId, actorRef);
934
+ return sessionId;
935
+ },
936
+ _unregister: actorRef => {
937
+ children.delete(actorRef.sessionId);
938
+ const systemId = reverseKeyedActors.get(actorRef);
939
+ if (systemId !== undefined) {
940
+ keyedActors.delete(systemId);
941
+ reverseKeyedActors.delete(actorRef);
942
+ }
943
+ },
944
+ get: systemId => {
945
+ return keyedActors.get(systemId);
946
+ },
947
+ _set: (systemId, actorRef) => {
948
+ const existing = keyedActors.get(systemId);
949
+ if (existing && existing !== actorRef) {
950
+ throw new Error(`Actor with system ID '${systemId}' already exists.`);
951
+ }
952
+ keyedActors.set(systemId, actorRef);
953
+ reverseKeyedActors.set(actorRef, systemId);
954
+ }
955
+ };
956
+ return system;
957
+ }
958
+
959
+ let ActorStatus = /*#__PURE__*/function (ActorStatus) {
960
+ ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
961
+ ActorStatus[ActorStatus["Running"] = 1] = "Running";
962
+ ActorStatus[ActorStatus["Stopped"] = 2] = "Stopped";
963
+ return ActorStatus;
964
+ }({});
965
+ const defaultOptions = {
966
+ deferEvents: true,
967
+ clock: {
968
+ setTimeout: (fn, ms) => {
969
+ return setTimeout(fn, ms);
970
+ },
971
+ clearTimeout: id => {
972
+ return clearTimeout(id);
973
+ }
974
+ },
975
+ logger: console.log.bind(console),
976
+ devTools: false
977
+ };
978
+ class Interpreter {
979
+ /**
980
+ * The current state of the interpreted logic.
981
+ */
982
+
983
+ /**
984
+ * The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
985
+ */
986
+
987
+ /**
988
+ * The unique identifier for this actor relative to its parent.
989
+ */
990
+
991
+ /**
992
+ * Whether the service is started.
993
+ */
994
+
995
+ // Actor Ref
996
+
997
+ // TODO: add typings for system
998
+
999
+ /**
1000
+ * The globally unique process ID for this invocation.
1001
+ */
1002
+
1003
+ /**
1004
+ * Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
1005
+ *
1006
+ * @param logic The logic to be interpreted
1007
+ * @param options Interpreter options
1008
+ */
1009
+ constructor(logic, options) {
1010
+ this.logic = logic;
1011
+ this._state = void 0;
1012
+ this.clock = void 0;
1013
+ this.options = void 0;
1014
+ this.id = void 0;
1015
+ this.mailbox = new Mailbox(this._process.bind(this));
1016
+ this.delayedEventsMap = {};
1017
+ this.observers = new Set();
1018
+ this.logger = void 0;
1019
+ this.status = ActorStatus.NotStarted;
1020
+ this._parent = void 0;
1021
+ this.ref = void 0;
1022
+ this._actorContext = void 0;
1023
+ this._systemId = void 0;
1024
+ this.sessionId = void 0;
1025
+ this.system = void 0;
1026
+ this._doneEvent = void 0;
1027
+ this.src = void 0;
1028
+ this._deferred = [];
1029
+ const resolvedOptions = {
1030
+ ...defaultOptions,
1031
+ ...options
1032
+ };
1033
+ const {
1034
+ clock,
1035
+ logger,
1036
+ parent,
1037
+ id,
1038
+ systemId
1039
+ } = resolvedOptions;
1040
+ const self = this;
1041
+ this.system = parent?.system ?? createSystem();
1042
+ if (systemId) {
1043
+ this._systemId = systemId;
1044
+ this.system._set(systemId, this);
1045
+ }
1046
+ this.sessionId = this.system._bookId();
1047
+ this.id = id ?? this.sessionId;
1048
+ this.logger = logger;
1049
+ this.clock = clock;
1050
+ this._parent = parent;
1051
+ this.options = resolvedOptions;
1052
+ this.src = resolvedOptions.src;
1053
+ this.ref = this;
1054
+ this._actorContext = {
1055
+ self,
1056
+ id: this.id,
1057
+ sessionId: this.sessionId,
1058
+ logger: this.logger,
1059
+ defer: fn => {
1060
+ this._deferred.push(fn);
1061
+ },
1062
+ system: this.system,
1063
+ stopChild: child => {
1064
+ if (child._parent !== this) {
1065
+ throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
1066
+ }
1067
+ child._stop();
1068
+ }
1069
+ };
1070
+
1071
+ // Ensure that the send method is bound to this interpreter instance
1072
+ // if destructured
1073
+ this.send = this.send.bind(this);
1074
+ this._initState();
1075
+ }
1076
+ _initState() {
1077
+ this._state = this.options.state ? this.logic.restoreState ? this.logic.restoreState(this.options.state, this._actorContext) : this.options.state : this.logic.getInitialState(this._actorContext, this.options?.input);
1078
+ }
1079
+
1080
+ // array of functions to defer
1081
+
1082
+ update(state) {
1083
+ // Update state
1084
+ this._state = state;
1085
+ const snapshot = this.getSnapshot();
1086
+
1087
+ // Execute deferred effects
1088
+ let deferredFn;
1089
+ while (deferredFn = this._deferred.shift()) {
1090
+ deferredFn();
1091
+ }
1092
+ for (const observer of this.observers) {
1093
+ observer.next?.(snapshot);
1094
+ }
1095
+ const status = this.logic.getStatus?.(state);
1096
+ switch (status?.status) {
1097
+ case 'done':
1098
+ this._stopProcedure();
1099
+ this._doneEvent = doneInvoke(this.id, status.data);
1100
+ this._parent?.send(this._doneEvent);
1101
+ this._complete();
1102
+ break;
1103
+ case 'error':
1104
+ this._stopProcedure();
1105
+ this._parent?.send(error(this.id, status.data));
1106
+ this._error(status.data);
1107
+ break;
1108
+ }
1109
+ }
1110
+ subscribe(nextListenerOrObserver, errorListener, completeListener) {
1111
+ const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
1112
+ this.observers.add(observer);
1113
+ if (this.status === ActorStatus.Stopped) {
1114
+ observer.complete?.();
1115
+ this.observers.delete(observer);
1116
+ }
1117
+ return {
1118
+ unsubscribe: () => {
1119
+ this.observers.delete(observer);
1120
+ }
1121
+ };
1122
+ }
1123
+
1124
+ /**
1125
+ * Starts the interpreter from the initial state
1126
+ */
1127
+ start() {
1128
+ if (this.status === ActorStatus.Running) {
1129
+ // Do not restart the service if it is already started
1130
+ return this;
1131
+ }
1132
+ this.system._register(this.sessionId, this);
1133
+ if (this._systemId) {
1134
+ this.system._set(this._systemId, this);
1135
+ }
1136
+ this.status = ActorStatus.Running;
1137
+ if (this.logic.start) {
1138
+ this.logic.start(this._state, this._actorContext);
1139
+ }
1140
+
1141
+ // TODO: this notifies all subscribers but usually this is redundant
1142
+ // there is no real change happening here
1143
+ // we need to rethink if this needs to be refactored
1144
+ this.update(this._state);
1145
+ if (this.options.devTools) {
1146
+ this.attachDevTools();
1147
+ }
1148
+ this.mailbox.start();
1149
+ return this;
1150
+ }
1151
+ _process(event) {
1152
+ try {
1153
+ const nextState = this.logic.transition(this._state, event, this._actorContext);
1154
+ this.update(nextState);
1155
+ if (event.type === stopSignalType) {
1156
+ this._stopProcedure();
1157
+ this._complete();
1158
+ }
1159
+ } catch (err) {
1160
+ // TODO: properly handle errors
1161
+ if (this.observers.size > 0) {
1162
+ this.observers.forEach(observer => {
1163
+ observer.error?.(err);
1164
+ });
1165
+ this.stop();
1166
+ } else {
1167
+ throw err;
1168
+ }
1169
+ }
1170
+ }
1171
+ _stop() {
1172
+ if (this.status === ActorStatus.Stopped) {
1173
+ return this;
1174
+ }
1175
+ this.mailbox.clear();
1176
+ if (this.status === ActorStatus.NotStarted) {
1177
+ this.status = ActorStatus.Stopped;
1178
+ return this;
1179
+ }
1180
+ this.mailbox.enqueue({
1181
+ type: stopSignalType
1182
+ });
1183
+ return this;
1184
+ }
1185
+
1186
+ /**
1187
+ * Stops the interpreter and unsubscribe all listeners.
1188
+ */
1189
+ stop() {
1190
+ if (this._parent) {
1191
+ throw new Error('A non-root actor cannot be stopped directly.');
1192
+ }
1193
+ return this._stop();
1194
+ }
1195
+ _complete() {
1196
+ for (const observer of this.observers) {
1197
+ observer.complete?.();
1198
+ }
1199
+ this.observers.clear();
1200
+ }
1201
+ _error(data) {
1202
+ for (const observer of this.observers) {
1203
+ observer.error?.(data);
1204
+ }
1205
+ this.observers.clear();
1206
+ }
1207
+ _stopProcedure() {
1208
+ if (this.status !== ActorStatus.Running) {
1209
+ // Interpreter already stopped; do nothing
1210
+ return this;
1211
+ }
1212
+
1213
+ // Cancel all delayed events
1214
+ for (const key of Object.keys(this.delayedEventsMap)) {
1215
+ this.clock.clearTimeout(this.delayedEventsMap[key]);
1216
+ }
1217
+
1218
+ // TODO: mailbox.reset
1219
+ this.mailbox.clear();
1220
+ // TODO: after `stop` we must prepare ourselves for receiving events again
1221
+ // events sent *after* stop signal must be queued
1222
+ // it seems like this should be the common behavior for all of our consumers
1223
+ // so perhaps this should be unified somehow for all of them
1224
+ this.mailbox = new Mailbox(this._process.bind(this));
1225
+ this.status = ActorStatus.Stopped;
1226
+ this.system._unregister(this);
1227
+ return this;
1228
+ }
1229
+
1230
+ /**
1231
+ * Sends an event to the running interpreter to trigger a transition.
1232
+ *
1233
+ * @param event The event to send
1234
+ */
1235
+ send(event) {
1236
+ if (typeof event === 'string') {
1237
+ throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
1238
+ }
1239
+ if (this.status === ActorStatus.Stopped) {
1240
+ return;
1241
+ }
1242
+ if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
1243
+ throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
1244
+ // tslint:disable-next-line:max-line-length
1245
+ }". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
1246
+ }
1247
+ this.mailbox.enqueue(event);
1248
+ }
1249
+
1250
+ // TODO: make private (and figure out a way to do this within the machine)
1251
+ delaySend({
1252
+ event,
1253
+ id,
1254
+ delay,
1255
+ to
1256
+ }) {
1257
+ const timerId = this.clock.setTimeout(() => {
1258
+ if (to) {
1259
+ to.send(event);
1260
+ } else {
1261
+ this.send(event);
1262
+ }
1263
+ }, delay);
1264
+
1265
+ // TODO: consider the rehydration story here
1266
+ if (id) {
1267
+ this.delayedEventsMap[id] = timerId;
1268
+ }
1269
+ }
1270
+
1271
+ // TODO: make private (and figure out a way to do this within the machine)
1272
+ cancel(sendId) {
1273
+ this.clock.clearTimeout(this.delayedEventsMap[sendId]);
1274
+ delete this.delayedEventsMap[sendId];
1275
+ }
1276
+ attachDevTools() {
1277
+ const {
1278
+ devTools
1279
+ } = this.options;
1280
+ if (devTools) {
1281
+ const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
1282
+ resolvedDevToolsAdapter(this);
1283
+ }
1284
+ }
1285
+ toJSON() {
1286
+ return {
1287
+ id: this.id
1288
+ };
1289
+ }
1290
+ getPersistedState() {
1291
+ return this.logic.getPersistedState?.(this._state);
1292
+ }
1293
+ [symbolObservable]() {
1294
+ return this;
1295
+ }
1296
+ getSnapshot() {
1297
+ return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
1298
+ }
1299
+ }
1369
1300
 
1370
- const startSignalType = 'xstate.init';
1371
- const stopSignalType = 'xstate.stop';
1372
- const startSignal = {
1373
- type: 'xstate.init'
1374
- };
1375
- const stopSignal = {
1376
- type: 'xstate.stop'
1377
- };
1378
1301
  /**
1379
- * An object that expresses the actor logic in reaction to received events,
1380
- * as well as an optionally emitted stream of values.
1302
+ * Creates a new Interpreter instance for the given machine with the provided options, if any.
1381
1303
  *
1382
- * @template TReceived The received event
1383
- * @template TSnapshot The emitted value
1304
+ * @param machine The machine to interpret
1305
+ * @param options Interpreter options
1384
1306
  */
1385
1307
 
1386
- function isSignal(event) {
1387
- return event.type === startSignalType || event.type === stopSignalType;
1388
- }
1389
- function isActorRef(item) {
1390
- return !!item && typeof item === 'object' && typeof item.send === 'function';
1391
- }
1392
-
1393
- // TODO: refactor the return type, this could be written in a better way
1394
- // but it's best to avoid unneccessary breaking changes now
1395
- // @deprecated use `interpret(actorLogic)` instead
1396
- function toActorRef(actorRefLike) {
1397
- return {
1398
- subscribe: () => ({
1399
- unsubscribe: () => void 0
1400
- }),
1401
- id: 'anonymous',
1402
- sessionId: '',
1403
- getSnapshot: () => undefined,
1404
- [symbolObservable]: function () {
1405
- return this;
1406
- },
1407
- status: ActorStatus.Running,
1408
- stop: () => void 0,
1409
- ...actorRefLike
1410
- };
1411
- }
1412
- const emptyLogic = fromTransition(_ => undefined, undefined);
1413
- function createEmptyActor() {
1414
- return interpret(emptyLogic);
1308
+ function interpret(logic, options) {
1309
+ const interpreter = new Interpreter(logic, options);
1310
+ return interpreter;
1415
1311
  }
1416
1312
 
1417
- function invoke(invokeDef) {
1418
- return createDynamicAction({
1419
- type: invoke$1,
1420
- params: invokeDef
1421
- }, (event, {
1422
- state,
1423
- actorContext
1424
- }) => {
1425
- const type = invoke$1;
1426
- const {
1313
+ function resolve$6(actorContext, state, actionArgs, {
1314
+ id,
1315
+ systemId,
1316
+ src,
1317
+ input
1318
+ }) {
1319
+ const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
1320
+ let actorRef;
1321
+ if (referenced) {
1322
+ // TODO: inline `input: undefined` should win over the referenced one
1323
+ const configuredInput = input || referenced.input;
1324
+ actorRef = interpret(referenced.src, {
1427
1325
  id,
1428
- src
1429
- } = invokeDef;
1430
- let resolvedInvokeAction;
1431
- if (isActorRef(src)) {
1432
- resolvedInvokeAction = {
1433
- type,
1434
- params: {
1435
- ...invokeDef,
1436
- ref: src
1437
- }
1438
- };
1439
- } else {
1440
- const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
1441
- if (!referenced) {
1442
- resolvedInvokeAction = {
1443
- type,
1444
- params: invokeDef
1445
- };
1446
- } else {
1447
- const input = 'input' in invokeDef ? invokeDef.input : referenced.input;
1448
- const ref = interpret(referenced.src, {
1449
- id,
1450
- src,
1451
- parent: actorContext?.self,
1452
- systemId: invokeDef.systemId,
1453
- input: typeof input === 'function' ? input({
1454
- context: state.context,
1455
- event,
1456
- self: actorContext?.self
1457
- }) : input
1458
- });
1459
- resolvedInvokeAction = {
1460
- type,
1461
- params: {
1462
- ...invokeDef,
1463
- ref
1464
- }
1465
- };
1466
- }
1467
- }
1468
- const actorRef = resolvedInvokeAction.params.ref;
1469
- const invokedState = cloneState(state, {
1470
- children: {
1471
- ...state.children,
1472
- [id]: actorRef
1473
- }
1326
+ src,
1327
+ parent: actorContext?.self,
1328
+ systemId,
1329
+ input: typeof configuredInput === 'function' ? configuredInput({
1330
+ context: state.context,
1331
+ event: actionArgs.event,
1332
+ self: actorContext?.self
1333
+ }) : configuredInput
1474
1334
  });
1475
- resolvedInvokeAction.execute = actorCtx => {
1476
- const parent = actorCtx.self;
1477
- const {
1478
- id,
1479
- ref
1480
- } = resolvedInvokeAction.params;
1481
- if (!ref) {
1482
- return;
1483
- }
1484
- actorCtx.defer(() => {
1485
- if (actorRef.status === ActorStatus.Stopped) {
1486
- return;
1487
- }
1488
- try {
1489
- actorRef.start?.();
1490
- } catch (err) {
1491
- parent.send(error(id, err));
1492
- return;
1493
- }
1494
- });
1495
- };
1496
- return [invokedState, resolvedInvokeAction];
1335
+ }
1336
+ return [cloneState(state, {
1337
+ children: {
1338
+ ...state.children,
1339
+ [id]: actorRef
1340
+ }
1341
+ }), {
1342
+ id,
1343
+ actorRef
1344
+ }];
1345
+ }
1346
+ function execute$3(actorContext, {
1347
+ id,
1348
+ actorRef
1349
+ }) {
1350
+ if (!actorRef) {
1351
+ return;
1352
+ }
1353
+ actorContext.defer(() => {
1354
+ if (actorRef.status === ActorStatus.Stopped) {
1355
+ return;
1356
+ }
1357
+ try {
1358
+ actorRef.start?.();
1359
+ } catch (err) {
1360
+ actorContext.self.send(error(id, err));
1361
+ return;
1362
+ }
1497
1363
  });
1498
1364
  }
1365
+ function invoke({
1366
+ id,
1367
+ systemId,
1368
+ src,
1369
+ input
1370
+ }) {
1371
+ function invoke(_) {
1372
+ }
1373
+ invoke.type = 'xstate.invoke';
1374
+ invoke.id = id;
1375
+ invoke.systemId = systemId;
1376
+ invoke.src = src;
1377
+ invoke.input = input;
1378
+ invoke.resolve = resolve$6;
1379
+ invoke.execute = execute$3;
1380
+ return invoke;
1381
+ }
1499
1382
 
1500
1383
  function stateIn(stateValue) {
1501
1384
  return {
@@ -1506,7 +1389,7 @@ function stateIn(stateValue) {
1506
1389
  predicate: ({
1507
1390
  state
1508
1391
  }) => {
1509
- if (isString(stateValue) && isStateId(stateValue)) {
1392
+ if (typeof stateValue === 'string' && isStateId(stateValue)) {
1510
1393
  return state.configuration.some(sn => sn.id === stateValue.slice(1));
1511
1394
  }
1512
1395
  return state.matches(stateValue);
@@ -1590,9 +1473,9 @@ function evaluateGuard(guard, context, event, state) {
1590
1473
  function toGuardDefinition(guardConfig, getPredicate) {
1591
1474
  // TODO: check for cycles and consider a refactor to more lazily evaluated guards
1592
1475
  // TODO: resolve this more recursively: https://github.com/statelyai/xstate/pull/4064#discussion_r1229915724
1593
- if (isString(guardConfig)) {
1476
+ if (typeof guardConfig === 'string') {
1594
1477
  const predicateOrDef = getPredicate?.(guardConfig);
1595
- if (isFunction(predicateOrDef)) {
1478
+ if (typeof predicateOrDef === 'function') {
1596
1479
  return {
1597
1480
  type: guardConfig,
1598
1481
  predicate: predicateOrDef,
@@ -1611,7 +1494,7 @@ function toGuardDefinition(guardConfig, getPredicate) {
1611
1494
  };
1612
1495
  }
1613
1496
  }
1614
- if (isFunction(guardConfig)) {
1497
+ if (typeof guardConfig === 'function') {
1615
1498
  return {
1616
1499
  type: guardConfig.name,
1617
1500
  predicate: guardConfig,
@@ -1622,7 +1505,7 @@ function toGuardDefinition(guardConfig, getPredicate) {
1622
1505
  };
1623
1506
  }
1624
1507
  const predicateOrDef = getPredicate?.(guardConfig.type);
1625
- if (isFunction(predicateOrDef)) {
1508
+ if (typeof predicateOrDef === 'function') {
1626
1509
  return {
1627
1510
  type: guardConfig.type,
1628
1511
  params: guardConfig.params || guardConfig,
@@ -1749,24 +1632,16 @@ function isInFinalState(configuration, stateNode = configuration[0].machine.root
1749
1632
  }
1750
1633
  const isStateId = str => str[0] === STATE_IDENTIFIER;
1751
1634
  function getCandidates(stateNode, receivedEventType) {
1752
- const candidates = stateNode.transitions.filter(transition => {
1753
- const {
1754
- eventType
1755
- } = transition;
1756
- // First, check the trivial case: event names are exactly equal
1757
- if (eventType === receivedEventType) {
1758
- return true;
1759
- }
1760
-
1761
- // Then, check if transition is a wildcard transition,
1635
+ const candidates = stateNode.transitions.get(receivedEventType) || [...stateNode.transitions.keys()].filter(descriptor => {
1636
+ // check if transition is a wildcard transition,
1762
1637
  // which matches any non-transient events
1763
- if (eventType === WILDCARD) {
1638
+ if (descriptor === WILDCARD) {
1764
1639
  return true;
1765
1640
  }
1766
- if (!eventType.endsWith('.*')) {
1641
+ if (!descriptor.endsWith('.*')) {
1767
1642
  return false;
1768
1643
  }
1769
- const partialEventTokens = eventType.split('.');
1644
+ const partialEventTokens = descriptor.split('.');
1770
1645
  const eventTokens = receivedEventType.split('.');
1771
1646
  for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
1772
1647
  const partialEventToken = partialEventTokens[tokenIndex];
@@ -1780,7 +1655,7 @@ function getCandidates(stateNode, receivedEventType) {
1780
1655
  }
1781
1656
  }
1782
1657
  return true;
1783
- });
1658
+ }).sort((a, b) => b.length - a.length).flatMap(key => stateNode.transitions.get(key));
1784
1659
  return candidates;
1785
1660
  }
1786
1661
 
@@ -1793,11 +1668,12 @@ function getDelayedTransitions(stateNode) {
1793
1668
  return [];
1794
1669
  }
1795
1670
  const mutateEntryExit = (delay, i) => {
1796
- const delayRef = isFunction(delay) ? `${stateNode.id}:delay[${i}]` : delay;
1671
+ const delayRef = typeof delay === 'function' ? `${stateNode.id}:delay[${i}]` : delay;
1797
1672
  const eventType = after(delayRef, stateNode.id);
1798
1673
  stateNode.entry.push(raise({
1799
1674
  type: eventType
1800
1675
  }, {
1676
+ id: eventType,
1801
1677
  delay
1802
1678
  }));
1803
1679
  stateNode.exit.push(cancel(eventType));
@@ -1811,7 +1687,7 @@ function getDelayedTransitions(stateNode) {
1811
1687
  };
1812
1688
  }) : Object.keys(afterConfig).flatMap((delay, i) => {
1813
1689
  const configTransition = afterConfig[delay];
1814
- const resolvedTransition = isString(configTransition) ? {
1690
+ const resolvedTransition = typeof configTransition === 'string' ? {
1815
1691
  target: configTransition
1816
1692
  } : configTransition;
1817
1693
  const resolvedDelay = !isNaN(+delay) ? +delay : delay;
@@ -1827,12 +1703,12 @@ function getDelayedTransitions(stateNode) {
1827
1703
  delay
1828
1704
  } = delayedTransition;
1829
1705
  return {
1830
- ...formatTransition(stateNode, delayedTransition),
1706
+ ...formatTransition(stateNode, delayedTransition.event, delayedTransition),
1831
1707
  delay
1832
1708
  };
1833
1709
  });
1834
1710
  }
1835
- function formatTransition(stateNode, transitionConfig) {
1711
+ function formatTransition(stateNode, descriptor, transitionConfig) {
1836
1712
  const normalizedTarget = normalizeTarget(transitionConfig.target);
1837
1713
  const reenter = transitionConfig.reenter ?? false;
1838
1714
  const {
@@ -1841,12 +1717,12 @@ function formatTransition(stateNode, transitionConfig) {
1841
1717
  const target = resolveTarget(stateNode, normalizedTarget);
1842
1718
  const transition = {
1843
1719
  ...transitionConfig,
1844
- actions: toActionObjects(toArray(transitionConfig.actions)),
1720
+ actions: toArray(transitionConfig.actions),
1845
1721
  guard: transitionConfig.guard ? toGuardDefinition(transitionConfig.guard, guardType => guards[guardType]) : undefined,
1846
1722
  target,
1847
1723
  source: stateNode,
1848
1724
  reenter,
1849
- eventType: transitionConfig.event,
1725
+ eventType: descriptor,
1850
1726
  toJSON: () => ({
1851
1727
  ...transition,
1852
1728
  source: `#${stateNode.id}`,
@@ -1856,52 +1732,50 @@ function formatTransition(stateNode, transitionConfig) {
1856
1732
  return transition;
1857
1733
  }
1858
1734
  function formatTransitions(stateNode) {
1859
- const transitionConfigs = [];
1860
- if (Array.isArray(stateNode.config.on)) {
1861
- transitionConfigs.push(...stateNode.config.on);
1862
- } else if (stateNode.config.on) {
1863
- const {
1864
- [WILDCARD]: wildcardConfigs = [],
1865
- ...namedTransitionConfigs
1866
- } = stateNode.config.on;
1867
- for (const eventType of Object.keys(namedTransitionConfigs)) {
1868
- if (eventType === NULL_EVENT) {
1735
+ const transitions = new Map();
1736
+ if (stateNode.config.on) {
1737
+ for (const descriptor of Object.keys(stateNode.config.on)) {
1738
+ if (descriptor === NULL_EVENT) {
1869
1739
  throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.');
1870
1740
  }
1871
- const eventTransitionConfigs = toTransitionConfigArray(eventType, namedTransitionConfigs[eventType]);
1872
- transitionConfigs.push(...eventTransitionConfigs);
1873
- // TODO: add dev-mode validation for unreachable transitions
1741
+ const transitionsConfig = stateNode.config.on[descriptor];
1742
+ transitions.set(descriptor, toTransitionConfigArray(transitionsConfig).map(t => formatTransition(stateNode, descriptor, t)));
1874
1743
  }
1875
-
1876
- transitionConfigs.push(...toTransitionConfigArray(WILDCARD, wildcardConfigs));
1877
1744
  }
1878
- const doneConfig = stateNode.config.onDone ? toTransitionConfigArray(String(done(stateNode.id)), stateNode.config.onDone) : [];
1879
- const invokeConfig = stateNode.invoke.flatMap(invokeDef => {
1880
- const settleTransitions = [];
1745
+ if (stateNode.config.onDone) {
1746
+ const descriptor = String(done(stateNode.id));
1747
+ transitions.set(descriptor, toTransitionConfigArray(stateNode.config.onDone).map(t => formatTransition(stateNode, descriptor, t)));
1748
+ }
1749
+ for (const invokeDef of stateNode.invoke) {
1881
1750
  if (invokeDef.onDone) {
1882
- settleTransitions.push(...toTransitionConfigArray(`done.invoke.${invokeDef.id}`, invokeDef.onDone));
1751
+ const descriptor = `done.invoke.${invokeDef.id}`;
1752
+ transitions.set(descriptor, toTransitionConfigArray(invokeDef.onDone).map(t => formatTransition(stateNode, descriptor, t)));
1883
1753
  }
1884
1754
  if (invokeDef.onError) {
1885
- settleTransitions.push(...toTransitionConfigArray(`error.platform.${invokeDef.id}`, invokeDef.onError));
1755
+ const descriptor = `error.platform.${invokeDef.id}`;
1756
+ transitions.set(descriptor, toTransitionConfigArray(invokeDef.onError).map(t => formatTransition(stateNode, descriptor, t)));
1886
1757
  }
1887
1758
  if (invokeDef.onSnapshot) {
1888
- settleTransitions.push(...toTransitionConfigArray(`xstate.snapshot.${invokeDef.id}`, invokeDef.onSnapshot));
1759
+ const descriptor = `xstate.snapshot.${invokeDef.id}`;
1760
+ transitions.set(descriptor, toTransitionConfigArray(invokeDef.onSnapshot).map(t => formatTransition(stateNode, descriptor, t)));
1889
1761
  }
1890
- return settleTransitions;
1891
- });
1892
- const delayedTransitions = stateNode.after;
1893
- const formattedTransitions = [...doneConfig, ...invokeConfig, ...transitionConfigs].flatMap(transitionConfig => toArray(transitionConfig).map(transition => formatTransition(stateNode, transition)));
1894
- for (const delayedTransition of delayedTransitions) {
1895
- formattedTransitions.push(delayedTransition);
1896
1762
  }
1897
- return formattedTransitions;
1763
+ for (const delayedTransition of stateNode.after) {
1764
+ let existing = transitions.get(delayedTransition.eventType);
1765
+ if (!existing) {
1766
+ existing = [];
1767
+ transitions.set(delayedTransition.eventType, existing);
1768
+ }
1769
+ existing.push(delayedTransition);
1770
+ }
1771
+ return transitions;
1898
1772
  }
1899
1773
  function formatInitialTransition(stateNode, _target) {
1900
- if (isString(_target) || isArray(_target)) {
1774
+ if (typeof _target === 'string' || isArray(_target)) {
1901
1775
  const targets = toArray(_target).map(t => {
1902
1776
  // Resolve state string keys (which represent children)
1903
1777
  // to their state node
1904
- const descStateNode = isString(t) ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
1778
+ const descStateNode = typeof t === 'string' ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
1905
1779
  if (!descStateNode) {
1906
1780
  throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
1907
1781
  }
@@ -1925,15 +1799,14 @@ function formatInitialTransition(stateNode, _target) {
1925
1799
  };
1926
1800
  return transition;
1927
1801
  }
1928
- return formatTransition(stateNode, {
1802
+ return formatTransition(stateNode, '__INITIAL__', {
1929
1803
  target: toArray(_target.target).map(t => {
1930
- if (isString(t)) {
1804
+ if (typeof t === 'string') {
1931
1805
  return isStateId(t) ? t : `${STATE_DELIMITER}${t}`;
1932
1806
  }
1933
1807
  return t;
1934
1808
  }),
1935
- actions: _target.actions,
1936
- event: null
1809
+ actions: _target.actions
1937
1810
  });
1938
1811
  }
1939
1812
  function resolveTarget(stateNode, targets) {
@@ -1942,7 +1815,7 @@ function resolveTarget(stateNode, targets) {
1942
1815
  return undefined;
1943
1816
  }
1944
1817
  return targets.map(target => {
1945
- if (!isString(target)) {
1818
+ if (typeof target !== 'string') {
1946
1819
  return target;
1947
1820
  }
1948
1821
  if (isStateId(target)) {
@@ -2050,7 +1923,7 @@ function getStateNodeByPath(stateNode, statePath) {
2050
1923
  */
2051
1924
  function getStateNodes(stateNode, state) {
2052
1925
  const stateValue = state instanceof State ? state.value : toStateValue(state);
2053
- if (isString(stateValue)) {
1926
+ if (typeof stateValue === 'string') {
2054
1927
  return [stateNode, stateNode.states[stateValue]];
2055
1928
  }
2056
1929
  const childStateKeys = Object.keys(stateValue);
@@ -2101,7 +1974,7 @@ function transitionParallelNode(stateNode, stateValue, state, event) {
2101
1974
  }
2102
1975
  function transitionNode(stateNode, stateValue, state, event) {
2103
1976
  // leaf node
2104
- if (isString(stateValue)) {
1977
+ if (typeof stateValue === 'string') {
2105
1978
  return transitionAtomicNode(stateNode, stateValue, state, event);
2106
1979
  }
2107
1980
 
@@ -2435,44 +2308,55 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
2435
2308
  const {
2436
2309
  machine
2437
2310
  } = currentState;
2438
- const raiseActions = [];
2439
- let intermediateState = currentState;
2440
- function handleAction(action) {
2441
- if (actorCtx?.self.status === ActorStatus.Running) {
2442
- action.execute?.(actorCtx);
2443
- } else {
2444
- actorCtx?.defer(() => action.execute?.(actorCtx));
2311
+ // TODO: this `cloneState` is really just a hack to prevent infinite loops
2312
+ // we need to take another look at how internal queue is managed
2313
+ let intermediateState = cloneState(currentState, {
2314
+ _internalQueue: []
2315
+ });
2316
+ for (const action of actions) {
2317
+ const resolved = typeof action === 'function' ? action : machine.implementations.actions[typeof action === 'string' ? action : action.type];
2318
+ if (!resolved) {
2319
+ continue;
2445
2320
  }
2446
- }
2447
- function resolveAction(actionObject) {
2448
- const executableActionObject = resolveActionObject(actionObject, machine.implementations.actions);
2449
- if (isDynamicAction(executableActionObject)) {
2450
- const [nextState, resolvedAction] = executableActionObject.resolve(event, {
2451
- state: intermediateState,
2452
- action: actionObject,
2453
- actorContext: actorCtx
2454
- });
2455
- const matchedActions = resolvedAction.params?.actions;
2456
- intermediateState = nextState;
2457
- if ((resolvedAction.type === raise$1 || resolvedAction.type === send$1 && resolvedAction.params.internal) && typeof resolvedAction.params.delay !== 'number') {
2458
- raiseActions.push(resolvedAction);
2321
+ const args = {
2322
+ context: intermediateState.context,
2323
+ event,
2324
+ self: actorCtx?.self,
2325
+ system: actorCtx?.system,
2326
+ // TODO: figure out story for `action` and inline actions
2327
+ // what those ones should receive?
2328
+ //
2329
+ // entry: ({ action }) => {}
2330
+ // exit: assign(({ action }) => {})
2331
+ action: typeof action === 'string' ? {
2332
+ type: action
2333
+ } : action
2334
+ };
2335
+ if (!('resolve' in resolved)) {
2336
+ if (actorCtx?.self.status === ActorStatus.Running) {
2337
+ resolved(args);
2338
+ } else {
2339
+ actorCtx?.defer(() => resolved(args));
2459
2340
  }
2341
+ continue;
2342
+ }
2343
+ const builtinAction = resolved;
2344
+ const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, args, resolved // this holds all params
2345
+ );
2460
2346
 
2461
- // TODO: remove the check; just handleAction
2462
- if (resolvedAction.type !== pure$1) {
2463
- handleAction(resolvedAction);
2347
+ intermediateState = nextState;
2348
+ if ('execute' in resolved) {
2349
+ if (actorCtx?.self.status === ActorStatus.Running) {
2350
+ builtinAction.execute(actorCtx, params);
2351
+ } else {
2352
+ actorCtx?.defer(builtinAction.execute.bind(null, actorCtx, params));
2464
2353
  }
2465
- toActionObjects(matchedActions).forEach(resolveAction);
2466
- return;
2467
2354
  }
2468
- handleAction(executableActionObject);
2469
- }
2470
- for (const actionObject of actions) {
2471
- resolveAction(actionObject);
2355
+ if (actions) {
2356
+ intermediateState = resolveActionsAndContext(actions, event, intermediateState, actorCtx);
2357
+ }
2472
2358
  }
2473
- return cloneState(intermediateState, {
2474
- _internalQueue: raiseActions.map(a => a.params.event)
2475
- });
2359
+ return intermediateState;
2476
2360
  }
2477
2361
  function macrostep(state, event, actorCtx) {
2478
2362
  let nextState = state;
@@ -2491,7 +2375,7 @@ function macrostep(state, event, actorCtx) {
2491
2375
 
2492
2376
  // Assume the state is at rest (no raised events)
2493
2377
  // Determine the next state based on the next microstep
2494
- if (nextEvent.type !== init) {
2378
+ if (nextEvent.type !== INIT_TYPE) {
2495
2379
  const transitions = selectTransitions(nextEvent, nextState);
2496
2380
  nextState = microstep(transitions, state, actorCtx, nextEvent, false);
2497
2381
  states.push(nextState);
@@ -2657,7 +2541,7 @@ class State {
2657
2541
  * @param delimiter The character(s) that separate each subpath in the string state node path.
2658
2542
  */
2659
2543
  toStrings(stateValue = this.value) {
2660
- if (isString(stateValue)) {
2544
+ if (typeof stateValue === 'string') {
2661
2545
  return [stateValue];
2662
2546
  }
2663
2547
  const valueKeys = Object.keys(stateValue);
@@ -2752,6 +2636,36 @@ function getPersistedState(state) {
2752
2636
  };
2753
2637
  }
2754
2638
 
2639
+ function resolve$5(_, state, args, {
2640
+ actorRef
2641
+ }) {
2642
+ const actorRefOrString = typeof actorRef === 'function' ? actorRef(args) : actorRef;
2643
+ const resolvedActorRef = typeof actorRefOrString === 'string' ? state.children[actorRefOrString] : actorRefOrString;
2644
+ let children = state.children;
2645
+ if (resolvedActorRef) {
2646
+ children = {
2647
+ ...children
2648
+ };
2649
+ delete children[resolvedActorRef.id];
2650
+ }
2651
+ return [cloneState(state, {
2652
+ children
2653
+ }), resolvedActorRef];
2654
+ }
2655
+ function execute$2(actorContext, actorRef) {
2656
+ if (!actorRef) {
2657
+ return;
2658
+ }
2659
+ if (actorRef.status !== ActorStatus.Running) {
2660
+ actorContext.stopChild(actorRef);
2661
+ return;
2662
+ }
2663
+ // TODO: recheck why this one has to be deferred
2664
+ actorContext.defer(() => {
2665
+ actorContext.stopChild(actorRef);
2666
+ });
2667
+ }
2668
+
2755
2669
  /**
2756
2670
  * Stops an actor.
2757
2671
  *
@@ -2759,58 +2673,37 @@ function getPersistedState(state) {
2759
2673
  */
2760
2674
 
2761
2675
  function stop(actorRef) {
2762
- const actor = actorRef;
2763
- return createDynamicAction({
2764
- type: stop$1,
2765
- params: {
2766
- actor
2767
- }
2768
- }, (event, {
2769
- state
2770
- }) => {
2771
- const actorRefOrString = isFunction(actor) ? actor({
2772
- context: state.context,
2773
- event
2774
- }) : actor;
2775
- const actorRef = typeof actorRefOrString === 'string' ? state.children[actorRefOrString] : actorRefOrString;
2776
- let children = state.children;
2777
- if (actorRef) {
2778
- children = {
2779
- ...children
2780
- };
2781
- delete children[actorRef.id];
2782
- }
2783
- return [cloneState(state, {
2784
- children
2785
- }), {
2786
- type: 'xstate.stop',
2787
- params: {
2788
- actor: actorRef
2789
- },
2790
- execute: actorCtx => {
2791
- if (!actorRef) {
2792
- return;
2793
- }
2794
- if (actorRef.status !== ActorStatus.Running) {
2795
- actorCtx.stopChild(actorRef);
2796
- return;
2797
- }
2798
- actorCtx.defer(() => {
2799
- actorCtx.stopChild(actorRef);
2800
- });
2801
- }
2802
- }];
2803
- });
2676
+ function stop(_) {
2677
+ }
2678
+ stop.type = 'xstate.stop';
2679
+ stop.actorRef = actorRef;
2680
+ stop.resolve = resolve$5;
2681
+ stop.execute = execute$2;
2682
+ return stop;
2683
+ }
2684
+
2685
+ function resolve$4(_, state, actionArgs, {
2686
+ value,
2687
+ label
2688
+ }) {
2689
+ return [state, {
2690
+ value: typeof value === 'function' ? value(actionArgs) : value,
2691
+ label
2692
+ }];
2693
+ }
2694
+ function execute$1({
2695
+ logger
2696
+ }, {
2697
+ value,
2698
+ label
2699
+ }) {
2700
+ if (label) {
2701
+ logger(label, value);
2702
+ } else {
2703
+ logger(value);
2704
+ }
2804
2705
  }
2805
2706
 
2806
- const defaultLogExpr = ({
2807
- context,
2808
- event
2809
- }) => ({
2810
- context,
2811
- event
2812
- });
2813
-
2814
2707
  /**
2815
2708
  *
2816
2709
  * @param expr The expression function to evaluate which will be logged.
@@ -2819,94 +2712,111 @@ const defaultLogExpr = ({
2819
2712
  * - `event` - the event that caused this action to be executed.
2820
2713
  * @param label The label to give to the logged expression.
2821
2714
  */
2822
-
2823
- function log(expr = defaultLogExpr, label) {
2824
- return createDynamicAction({
2825
- type: log$1,
2826
- params: {
2827
- label,
2828
- expr
2829
- }
2830
- }, (event, {
2831
- state,
2832
- actorContext
2833
- }) => {
2834
- const resolvedValue = typeof expr === 'function' ? expr({
2835
- context: state.context,
2836
- event,
2837
- self: actorContext?.self ?? {},
2838
- system: actorContext?.system
2839
- }) : expr;
2840
- return [state, {
2841
- type: 'xstate.log',
2842
- params: {
2843
- label,
2844
- value: resolvedValue
2845
- },
2846
- execute: actorCtx => {
2847
- if (label) {
2848
- actorCtx.logger?.(label, resolvedValue);
2849
- } else {
2850
- actorCtx.logger?.(resolvedValue);
2851
- }
2852
- }
2853
- }];
2854
- });
2855
- }
2856
-
2857
- function createSpawner(self, machine, context, event, mutCapturedActions) {
2858
- return (src, options = {}) => {
2715
+ function log(value = ({
2716
+ context,
2717
+ event
2718
+ }) => ({
2719
+ context,
2720
+ event
2721
+ }), label) {
2722
+ function log(_) {
2723
+ }
2724
+ log.type = 'xstate.log';
2725
+ log.value = value;
2726
+ log.label = label;
2727
+ log.resolve = resolve$4;
2728
+ log.execute = execute$1;
2729
+ return log;
2730
+ }
2731
+
2732
+ function createSpawner(actorContext, {
2733
+ machine,
2734
+ context
2735
+ }, event, spawnedChildren) {
2736
+ const spawn = (src, options = {}) => {
2859
2737
  const {
2860
2738
  systemId
2861
2739
  } = options;
2862
- if (isString(src)) {
2740
+ if (typeof src === 'string') {
2863
2741
  const referenced = resolveReferencedActor(machine.implementations.actors[src]);
2864
- if (referenced) {
2865
- const input = 'input' in options ? options.input : referenced.input;
2866
-
2867
- // TODO: this should also receive `src`
2868
- const actorRef = interpret(referenced.src, {
2869
- id: options.id,
2870
- parent: self,
2871
- input: typeof input === 'function' ? input({
2872
- context,
2873
- event,
2874
- self
2875
- }) : input
2876
- });
2877
- mutCapturedActions.push(invoke({
2878
- id: actorRef.id,
2879
- // @ts-ignore TODO: fix types
2880
- src: actorRef,
2881
- // TODO
2882
- ref: actorRef,
2883
- meta: undefined,
2884
- input,
2885
- systemId
2886
- }));
2887
- return actorRef; // TODO: fix types
2742
+ if (!referenced) {
2743
+ throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
2888
2744
  }
2745
+ const input = 'input' in options ? options.input : referenced.input;
2889
2746
 
2890
- throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
2747
+ // TODO: this should also receive `src`
2748
+ const actor = interpret(referenced.src, {
2749
+ id: options.id,
2750
+ parent: actorContext.self,
2751
+ input: typeof input === 'function' ? input({
2752
+ context,
2753
+ event,
2754
+ self: actorContext.self
2755
+ }) : input,
2756
+ systemId
2757
+ });
2758
+ spawnedChildren[actor.id] = actor;
2759
+ return actor;
2891
2760
  } else {
2892
2761
  // TODO: this should also receive `src`
2893
- const actorRef = interpret(src, {
2762
+ return interpret(src, {
2894
2763
  id: options.id,
2895
- parent: self,
2764
+ parent: actorContext.self,
2896
2765
  input: options.input,
2897
2766
  systemId
2898
2767
  });
2899
- mutCapturedActions.push(invoke({
2900
- // @ts-ignore TODO: fix types
2901
- src: actorRef,
2902
- ref: actorRef,
2903
- id: actorRef.id,
2904
- meta: undefined,
2905
- input: options.input
2906
- }));
2907
- return actorRef; // TODO: fix types
2908
2768
  }
2909
2769
  };
2770
+ return (src, options) => {
2771
+ const actorRef = spawn(src, options);
2772
+ spawnedChildren[actorRef.id] = actorRef;
2773
+ actorContext.defer(() => {
2774
+ if (actorRef.status === ActorStatus.Stopped) {
2775
+ return;
2776
+ }
2777
+ try {
2778
+ actorRef.start?.();
2779
+ } catch (err) {
2780
+ actorContext.self.send(error(actorRef.id, err));
2781
+ return;
2782
+ }
2783
+ });
2784
+ return actorRef;
2785
+ };
2786
+ }
2787
+
2788
+ function resolve$3(actorContext, state, actionArgs, {
2789
+ assignment
2790
+ }) {
2791
+ if (!state.context) {
2792
+ throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
2793
+ }
2794
+ const spawnedChildren = {};
2795
+ const assignArgs = {
2796
+ context: state.context,
2797
+ event: actionArgs.event,
2798
+ action: actionArgs.action,
2799
+ spawn: createSpawner(actorContext, state, actionArgs.event, spawnedChildren),
2800
+ self: actorContext?.self,
2801
+ system: actorContext?.system
2802
+ };
2803
+ let partialUpdate = {};
2804
+ if (typeof assignment === 'function') {
2805
+ partialUpdate = assignment(assignArgs);
2806
+ } else {
2807
+ for (const key of Object.keys(assignment)) {
2808
+ const propAssignment = assignment[key];
2809
+ partialUpdate[key] = typeof propAssignment === 'function' ? propAssignment(assignArgs) : propAssignment;
2810
+ }
2811
+ }
2812
+ const updatedContext = Object.assign({}, state.context, partialUpdate);
2813
+ return [cloneState(state, {
2814
+ context: updatedContext,
2815
+ children: Object.keys(spawnedChildren).length ? {
2816
+ ...state.children,
2817
+ ...spawnedChildren
2818
+ } : state.children
2819
+ })];
2910
2820
  }
2911
2821
 
2912
2822
  /**
@@ -2915,48 +2825,44 @@ function createSpawner(self, machine, context, event, mutCapturedActions) {
2915
2825
  * @param assignment An object that represents the partial context to update.
2916
2826
  */
2917
2827
  function assign(assignment) {
2918
- return createDynamicAction({
2919
- type: assign$1,
2920
- params: {
2921
- assignment
2922
- }
2923
- }, (event, {
2924
- state,
2925
- action,
2926
- actorContext
2927
- }) => {
2928
- const capturedActions = [];
2929
- if (!state.context) {
2930
- throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
2931
- }
2932
- const args = {
2933
- context: state.context,
2934
- event,
2935
- action,
2936
- spawn: createSpawner(actorContext?.self, state.machine, state.context, event, capturedActions),
2937
- self: actorContext?.self ?? {},
2938
- system: actorContext?.system
2939
- };
2940
- let partialUpdate = {};
2941
- if (isFunction(assignment)) {
2942
- partialUpdate = assignment(args);
2943
- } else {
2944
- for (const key of Object.keys(assignment)) {
2945
- const propAssignment = assignment[key];
2946
- partialUpdate[key] = isFunction(propAssignment) ? propAssignment(args) : propAssignment;
2947
- }
2948
- }
2949
- const updatedContext = Object.assign({}, state.context, partialUpdate);
2950
- return [cloneState(state, {
2951
- context: updatedContext
2952
- }), {
2953
- type: assign$1,
2954
- params: {
2955
- context: updatedContext,
2956
- actions: capturedActions
2957
- }
2958
- }];
2959
- });
2828
+ function assign(_) {
2829
+ }
2830
+ assign.type = 'xstate.assign';
2831
+ assign.assignment = assignment;
2832
+ assign.resolve = resolve$3;
2833
+ return assign;
2834
+ }
2835
+
2836
+ function resolve$2(_, state, args, {
2837
+ event: eventOrExpr,
2838
+ id,
2839
+ delay
2840
+ }) {
2841
+ const delaysMap = state.machine.implementations.delays;
2842
+ if (typeof eventOrExpr === 'string') {
2843
+ throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
2844
+ }
2845
+ const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
2846
+ let resolvedDelay;
2847
+ if (typeof delay === 'string') {
2848
+ const configDelay = delaysMap && delaysMap[delay];
2849
+ resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
2850
+ } else {
2851
+ resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
2852
+ }
2853
+ return [typeof resolvedDelay !== 'number' ? cloneState(state, {
2854
+ _internalQueue: state._internalQueue.concat(resolvedEvent)
2855
+ }) : state, {
2856
+ event: resolvedEvent,
2857
+ id,
2858
+ delay: resolvedDelay
2859
+ }];
2860
+ }
2861
+ function execute(actorContext, params) {
2862
+ if (typeof params.delay === 'number') {
2863
+ actorContext.self.delaySend(params);
2864
+ return;
2865
+ }
2960
2866
  }
2961
2867
 
2962
2868
  /**
@@ -2967,186 +2873,51 @@ function assign(assignment) {
2967
2873
  */
2968
2874
 
2969
2875
  function raise(eventOrExpr, options) {
2970
- return createDynamicAction({
2971
- type: raise$1,
2972
- params: {
2973
- delay: options ? options.delay : undefined,
2974
- event: eventOrExpr,
2975
- id: options && options.id !== undefined ? options.id : typeof eventOrExpr === 'function' ? eventOrExpr.name : eventOrExpr.type
2976
- }
2977
- }, (event, {
2978
- state,
2979
- actorContext
2980
- }) => {
2981
- const params = {
2982
- delay: options ? options.delay : undefined,
2983
- event: eventOrExpr,
2984
- id: options && options.id !== undefined ? options.id : typeof eventOrExpr === 'function' ? eventOrExpr.name : eventOrExpr.type
2985
- };
2986
- const args = {
2987
- context: state.context,
2988
- event,
2989
- self: actorContext?.self ?? {},
2990
- system: actorContext?.system
2991
- };
2992
- const delaysMap = state.machine.implementations.delays;
2993
-
2994
- // TODO: helper function for resolving Expr
2995
- if (typeof eventOrExpr === 'string') {
2996
- throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
2997
- }
2998
- const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
2999
- let resolvedDelay;
3000
- if (typeof params.delay === 'string') {
3001
- const configDelay = delaysMap && delaysMap[params.delay];
3002
- resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
3003
- } else {
3004
- resolvedDelay = typeof params.delay === 'function' ? params.delay(args) : params.delay;
3005
- }
3006
- const resolvedAction = {
3007
- type: raise$1,
3008
- params: {
3009
- ...params,
3010
- event: resolvedEvent,
3011
- delay: resolvedDelay
3012
- },
3013
- execute: actorCtx => {
3014
- if (typeof resolvedAction.params.delay === 'number') {
3015
- actorCtx.self.delaySend(resolvedAction);
3016
- return;
3017
- }
3018
- }
3019
- };
3020
- return [state, resolvedAction];
3021
- });
2876
+ function raise(_) {
2877
+ }
2878
+ raise.type = 'xstate.raise';
2879
+ raise.event = eventOrExpr;
2880
+ raise.id = options?.id;
2881
+ raise.delay = options?.delay;
2882
+ raise.resolve = resolve$2;
2883
+ raise.execute = execute;
2884
+ return raise;
2885
+ }
2886
+
2887
+ function resolve$1(_, state, actionArgs, {
2888
+ branches
2889
+ }) {
2890
+ const matchedActions = branches.find(condition => {
2891
+ const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.implementations.guards[guardType]);
2892
+ return !guard || evaluateGuard(guard, state.context, actionArgs.event, state);
2893
+ })?.actions;
2894
+ return [state, undefined, toArray(matchedActions)];
2895
+ }
2896
+ function choose(branches) {
2897
+ function choose(_) {
2898
+ }
2899
+ choose.type = 'xstate.choose';
2900
+ choose.branches = branches;
2901
+ choose.resolve = resolve$1;
2902
+ return choose;
2903
+ }
2904
+
2905
+ function resolve(_, state, args, {
2906
+ get
2907
+ }) {
2908
+ return [state, undefined, toArray(get({
2909
+ context: state.context,
2910
+ event: args.event
2911
+ }))];
3022
2912
  }
3023
-
3024
- function choose(guards) {
3025
- return createDynamicAction({
3026
- type: choose$1,
3027
- params: {
3028
- guards
3029
- }
3030
- }, (event, {
3031
- state
3032
- }) => {
3033
- const matchedActions = guards.find(condition => {
3034
- const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.implementations.guards[guardType]);
3035
- return !guard || evaluateGuard(guard, state.context, event, state);
3036
- })?.actions;
3037
- return [state, {
3038
- type: choose$1,
3039
- params: {
3040
- actions: toActionObjects(matchedActions)
3041
- }
3042
- }];
3043
- });
3044
- }
3045
-
3046
2913
  function pure(getActions) {
3047
- return createDynamicAction({
3048
- type: pure$1,
3049
- params: {
3050
- get: getActions
3051
- }
3052
- }, (event, {
3053
- state
3054
- }) => {
3055
- return [state, {
3056
- type: pure$1,
3057
- params: {
3058
- actions: toArray(toActionObjects(getActions({
3059
- context: state.context,
3060
- event
3061
- }))) ?? []
3062
- }
3063
- }];
3064
- });
3065
- }
3066
-
3067
- const initEvent = {
3068
- type: init
3069
- };
3070
- function resolveActionObject(actionObject, actionFunctionMap) {
3071
- if (isDynamicAction(actionObject)) {
3072
- return actionObject;
3073
- }
3074
- const dereferencedAction = actionFunctionMap[actionObject.type];
3075
- if (typeof dereferencedAction === 'function') {
3076
- return createDynamicAction({
3077
- type: 'xstate.function',
3078
- params: actionObject.params ?? {}
3079
- }, (event, {
3080
- state
3081
- }) => {
3082
- const a = {
3083
- type: actionObject.type,
3084
- params: actionObject.params,
3085
- execute: actorCtx => {
3086
- return dereferencedAction({
3087
- context: state.context,
3088
- event,
3089
- action: a,
3090
- system: actorCtx.system,
3091
- self: actorCtx.self
3092
- });
3093
- }
3094
- };
3095
- return [state, a];
3096
- });
3097
- } else if (dereferencedAction) {
3098
- return dereferencedAction;
3099
- } else {
3100
- return actionObject;
3101
- }
3102
- }
3103
- function toActionObject(action) {
3104
- if (isDynamicAction(action)) {
3105
- return action;
2914
+ function pure(_) {
3106
2915
  }
3107
- if (typeof action === 'string') {
3108
- return {
3109
- type: action,
3110
- params: {}
3111
- };
3112
- }
3113
- if (typeof action === 'function') {
3114
- const type = 'xstate.function';
3115
- return createDynamicAction({
3116
- type,
3117
- params: {}
3118
- }, (event, {
3119
- state
3120
- }) => {
3121
- const actionObject = {
3122
- type,
3123
- params: {
3124
- function: action
3125
- },
3126
- execute: actorCtx => {
3127
- return action({
3128
- context: state.context,
3129
- event: event,
3130
- action: actionObject,
3131
- self: actorCtx.self,
3132
- system: actorCtx.system
3133
- });
3134
- }
3135
- };
3136
- return [state, actionObject];
3137
- });
3138
- }
3139
-
3140
- // action is already a BaseActionObject
3141
- return action;
2916
+ pure.type = 'xstate.pure';
2917
+ pure.get = getActions;
2918
+ pure.resolve = resolve;
2919
+ return pure;
3142
2920
  }
3143
- const toActionObjects = action => {
3144
- if (!action) {
3145
- return [];
3146
- }
3147
- const actions = isArray(action) ? action : [action];
3148
- return actions.map(toActionObject);
3149
- };
3150
2921
 
3151
2922
  /**
3152
2923
  * Returns an event type that represents an implicit event that
@@ -3157,7 +2928,7 @@ const toActionObjects = action => {
3157
2928
  */
3158
2929
  function after(delayRef, id) {
3159
2930
  const idSuffix = id ? `#${id}` : '';
3160
- return `${ActionTypes.After}(${delayRef})${idSuffix}`;
2931
+ return `${ConstantPrefix.After}(${delayRef})${idSuffix}`;
3161
2932
  }
3162
2933
 
3163
2934
  /**
@@ -3168,7 +2939,7 @@ function after(delayRef, id) {
3168
2939
  * @param output The data to pass into the event
3169
2940
  */
3170
2941
  function done(id, output) {
3171
- const type = `${ActionTypes.DoneState}.${id}`;
2942
+ const type = `${ConstantPrefix.DoneState}.${id}`;
3172
2943
  const eventObject = {
3173
2944
  type,
3174
2945
  output
@@ -3187,7 +2958,7 @@ function done(id, output) {
3187
2958
  * @param output The data to pass into the event
3188
2959
  */
3189
2960
  function doneInvoke(invokeId, output) {
3190
- const type = `${ActionTypes.DoneInvoke}.${invokeId}`;
2961
+ const type = `${ConstantPrefix.DoneInvoke}.${invokeId}`;
3191
2962
  const eventObject = {
3192
2963
  type,
3193
2964
  output
@@ -3196,7 +2967,7 @@ function doneInvoke(invokeId, output) {
3196
2967
  return eventObject;
3197
2968
  }
3198
2969
  function error(id, data) {
3199
- const type = `${ActionTypes.ErrorPlatform}.${id}`;
2970
+ const type = `${ConstantPrefix.ErrorPlatform}.${id}`;
3200
2971
  const eventObject = {
3201
2972
  type,
3202
2973
  data
@@ -3206,9 +2977,9 @@ function error(id, data) {
3206
2977
  }
3207
2978
  function createInitEvent(input) {
3208
2979
  return {
3209
- type: init,
2980
+ type: INIT_TYPE,
3210
2981
  input
3211
2982
  };
3212
2983
  }
3213
2984
 
3214
- export { pathToStateValue as $, resolveActionsAndContext as A, microstep as B, isAtomicStateNode as C, error as D, isStateId as E, getStateNodeByPath as F, getPersistedState as G, resolveReferencedActor as H, interpret as I, createInitEvent as J, initEvent as K, matchesState as L, sendTo as M, NULL_EVENT as N, sendParent as O, forwardTo as P, Interpreter as Q, ActorStatus as R, STATE_DELIMITER as S, doneInvoke as T, assign as U, cancel as V, choose as W, log as X, pure as Y, raise as Z, stop as _, toArray as a, toObserver as a0, fromPromise as a1, fromObservable as a2, fromCallback as a3, fromEventObservable as a4, fromTransition as a5, stateIn as a6, not as a7, and as a8, or as a9, ActionTypes as aa, SpecialTargets as ab, startSignalType as ac, stopSignalType as ad, startSignal as ae, stopSignal as af, isSignal as ag, isActorRef as ah, toActorRef as ai, createEmptyActor as aj, toGuardDefinition as ak, actionTypes as al, resolveActionObject as am, toActionObject as an, after as ao, done as ap, send as aq, escalate as ar, toTransitionConfigArray as b, formatTransition as c, memo as d, evaluateGuard as e, formatTransitions as f, flatten as g, createInvokeId as h, isString as i, invoke$1 as j, getDelayedTransitions as k, formatInitialTransition as l, mapValues as m, getCandidates as n, toInvokeConfig as o, createSpawner as p, getConfiguration as q, getStateNodes as r, resolveStateValue as s, toActionObjects as t, isInFinalState as u, State as v, isErrorEvent as w, macrostep as x, transitionNode as y, getInitialConfiguration as z };
2985
+ export { fromEventObservable as $, isAtomicStateNode as A, error as B, isStateId as C, getStateNodeByPath as D, getPersistedState as E, resolveReferencedActor as F, interpret as G, matchesState as H, sendTo as I, sendParent as J, forwardTo as K, Interpreter as L, ActorStatus as M, NULL_EVENT as N, doneInvoke as O, cancel as P, choose as Q, log as R, STATE_DELIMITER as S, pure as T, raise as U, stop as V, pathToStateValue as W, toObserver as X, fromPromise as Y, fromObservable as Z, fromCallback as _, toTransitionConfigArray as a, fromTransition as a0, stateIn as a1, not as a2, and as a3, or as a4, ConstantPrefix as a5, SpecialTargets as a6, startSignalType as a7, stopSignalType as a8, startSignal as a9, stopSignal as aa, isSignal as ab, isActorRef as ac, toActorRef as ad, createEmptyActor as ae, toGuardDefinition as af, constantPrefixes as ag, after as ah, done as ai, escalate as aj, formatTransition as b, memo as c, flatten as d, evaluateGuard as e, formatTransitions as f, createInvokeId as g, getDelayedTransitions as h, formatInitialTransition as i, getCandidates as j, toInvokeConfig as k, getConfiguration as l, mapValues as m, getStateNodes as n, isInFinalState as o, State as p, isErrorEvent as q, resolveStateValue as r, macrostep as s, toArray as t, transitionNode as u, getInitialConfiguration as v, resolveActionsAndContext as w, assign as x, createInitEvent as y, microstep as z };