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