xstate 6.0.0-alpha.47 → 6.0.0-alpha.49

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 (84) hide show
  1. package/README.md +30 -1
  2. package/dist/{StateMachine-7046f677.cjs.js → StateMachine-0adb3a70.cjs.js} +15 -12
  3. package/dist/{StateMachine-70c06bdd.development.cjs.js → StateMachine-29450e6d.development.cjs.js} +15 -12
  4. package/dist/{StateMachine-74929087.esm.js → StateMachine-2af31c11.esm.js} +10 -7
  5. package/dist/{StateMachine-ee10f67e.development.esm.js → StateMachine-faf50c5c.development.esm.js} +10 -7
  6. package/dist/{createActor-915ea40c.esm.js → createActor-268165d4.esm.js} +79 -23
  7. package/dist/{createActor-ff132afa.development.esm.js → createActor-88709f74.development.esm.js} +79 -23
  8. package/dist/{createActor-6736cbbe.development.cjs.js → createActor-a1e0dffb.development.cjs.js} +78 -25
  9. package/dist/{createActor-bfe8b6bd.cjs.js → createActor-b4dd05ae.cjs.js} +78 -25
  10. package/dist/declarations/src/createMachineFromConfig.d.ts +5 -77
  11. package/dist/declarations/src/fsm/createFSMActor.d.ts +67 -0
  12. package/dist/declarations/src/fsm/index.d.ts +2 -0
  13. package/dist/declarations/src/fsm.d.ts +5 -4
  14. package/dist/declarations/src/scxml/index.d.ts +1 -0
  15. package/dist/declarations/src/scxml/runtime.d.ts +251 -0
  16. package/dist/declarations/src/scxml/scxml.d.ts +19 -0
  17. package/dist/declarations/src/types.d.ts +1 -0
  18. package/dist/{effectDescriptor-8be60443.esm.js → effectDescriptor-30c9a744.esm.js} +1 -1
  19. package/dist/{effectDescriptor-fbe67d5a.development.esm.js → effectDescriptor-39d22100.development.esm.js} +1 -1
  20. package/dist/{effectDescriptor-3c699328.development.cjs.js → effectDescriptor-7ff6802f.development.cjs.js} +1 -1
  21. package/dist/{effectDescriptor-a7e2d4d1.cjs.js → effectDescriptor-be348e50.cjs.js} +1 -1
  22. package/dist/fsm-7a2e9697.cjs.js +777 -0
  23. package/dist/fsm-b804b3e9.esm.js +775 -0
  24. package/dist/fsm-c1316948.development.cjs.js +777 -0
  25. package/dist/fsm-e18a7cb4.development.esm.js +775 -0
  26. package/dist/types-3c3455f7.esm.js +185 -0
  27. package/dist/types-adda3842.development.esm.js +185 -0
  28. package/dist/types-b3fea5bd.development.cjs.js +189 -0
  29. package/dist/types-fbabaeee.cjs.js +189 -0
  30. package/dist/validation-05f1d517.esm.js +8 -0
  31. package/dist/validation-4561b43c.cjs.js +10 -0
  32. package/dist/validation-e69470ad.development.esm.js +8 -0
  33. package/dist/validation-f2714a35.development.cjs.js +10 -0
  34. package/dist/xstate-actors.cjs.js +934 -9
  35. package/dist/xstate-actors.development.cjs.js +934 -9
  36. package/dist/xstate-actors.development.esm.js +932 -2
  37. package/dist/xstate-actors.esm.js +932 -2
  38. package/dist/xstate-durable.cjs.js +2 -2
  39. package/dist/xstate-durable.development.cjs.js +2 -2
  40. package/dist/xstate-durable.development.esm.js +2 -2
  41. package/dist/xstate-durable.esm.js +2 -2
  42. package/dist/xstate-fsm.cjs.d.mts +2 -0
  43. package/dist/xstate-fsm.cjs.d.ts +2 -0
  44. package/dist/xstate-fsm.cjs.js +409 -0
  45. package/dist/xstate-fsm.cjs.mjs +5 -0
  46. package/dist/xstate-fsm.development.cjs.js +409 -0
  47. package/dist/xstate-fsm.development.cjs.mjs +5 -0
  48. package/dist/xstate-fsm.development.esm.js +403 -0
  49. package/dist/xstate-fsm.esm.js +403 -0
  50. package/dist/xstate-fsm.umd.min.js +2 -0
  51. package/dist/xstate-fsm.umd.min.js.map +1 -0
  52. package/dist/xstate-graph.cjs.js +4 -3
  53. package/dist/xstate-graph.development.cjs.js +4 -3
  54. package/dist/xstate-graph.development.esm.js +4 -3
  55. package/dist/xstate-graph.esm.js +4 -3
  56. package/dist/xstate-graph.umd.min.js +1 -1
  57. package/dist/xstate-graph.umd.min.js.map +1 -1
  58. package/dist/xstate-scxml.cjs.d.mts +2 -0
  59. package/dist/xstate-scxml.cjs.d.ts +2 -0
  60. package/dist/xstate-scxml.cjs.js +2387 -0
  61. package/dist/xstate-scxml.cjs.mjs +3 -0
  62. package/dist/xstate-scxml.development.cjs.js +2387 -0
  63. package/dist/xstate-scxml.development.cjs.mjs +3 -0
  64. package/dist/xstate-scxml.development.esm.js +2383 -0
  65. package/dist/xstate-scxml.esm.js +2383 -0
  66. package/dist/xstate-scxml.umd.min.js +26 -0
  67. package/dist/xstate-scxml.umd.min.js.map +1 -0
  68. package/dist/xstate-validation.cjs.js +1 -1
  69. package/dist/xstate-validation.development.cjs.js +1 -1
  70. package/dist/xstate-validation.development.esm.js +1 -1
  71. package/dist/xstate-validation.esm.js +1 -1
  72. package/dist/xstate.cjs.js +143 -1412
  73. package/dist/xstate.development.cjs.js +143 -1412
  74. package/dist/xstate.development.esm.js +143 -1411
  75. package/dist/xstate.esm.js +143 -1411
  76. package/dist/xstate.umd.min.js +1 -1
  77. package/dist/xstate.umd.min.js.map +1 -1
  78. package/fsm/package.json +8 -0
  79. package/package.json +37 -3
  80. package/scxml/package.json +8 -0
  81. package/dist/index-0f498ef2.development.cjs.js +0 -946
  82. package/dist/index-70d56425.development.esm.js +0 -937
  83. package/dist/index-b051c924.esm.js +0 -937
  84. package/dist/index-b3fe59bc.cjs.js +0 -946
@@ -0,0 +1,775 @@
1
+ import { l as listenerLogic, s as subscriptionLogic, H as XSTATE_INIT, I as withActorScope, X as XSTATE_STOP, J as XSTATE_TIMER, K as isLazyActorScope } from './createActor-268165d4.esm.js';
2
+
3
+ const allocations = new WeakMap();
4
+ function beginFSMEffects(scope, snapshot) {
5
+ allocations.set(scope, {
6
+ ids: new Set(Object.keys(snapshot.children)),
7
+ counters: {
8
+ ...snapshot._nextActorIds
9
+ }
10
+ });
11
+ }
12
+ function execute(runtime = this.source?.system ?? this.actor?.system) {
13
+ switch (this.type) {
14
+ case '@xstate.spawn':
15
+ return runtime.spawnActor(this.source, this.actor);
16
+ case '@xstate.start':
17
+ return runtime.startActor(this.actor);
18
+ case '@xstate.stop':
19
+ return runtime.stopActor(this.actor);
20
+ case '@xstate.terminate':
21
+ return runtime.terminateActor(this.actor, this);
22
+ case '@xstate.raise':
23
+ case '@xstate.sendTo':
24
+ {
25
+ if (this.delay === undefined) {
26
+ return runtime.sendEvent(this.source, this.target, this.event);
27
+ }
28
+ const timer = this.source.getSnapshot().timers[this.id];
29
+ if (timer && !runtime._clock.now) {
30
+ timer.startedAt = Date.now();
31
+ }
32
+ return runtime.scheduleTimer(this.source, this.id, this.delay);
33
+ }
34
+ case '@xstate.cancel':
35
+ return runtime.cancelTimer(this.source, this.id);
36
+ case '@xstate.emit':
37
+ return runtime.emitEvent(this.source, this.event);
38
+ default:
39
+ return this.action?.(...this.args);
40
+ }
41
+ }
42
+ function effect(type, fields = {}) {
43
+ return {
44
+ kind: 'builtin',
45
+ type,
46
+ params: undefined,
47
+ args: [],
48
+ exec: execute,
49
+ ...fields
50
+ };
51
+ }
52
+ function createFSMEnqueue(scope, effects, internalEvents) {
53
+ const enqueue = (action, ...args) => {
54
+ effects.push(effect(action.name || '(anonymous)', {
55
+ kind: 'action',
56
+ action,
57
+ args
58
+ }));
59
+ };
60
+ enqueue.cancel = id => {
61
+ effects.push(effect('@xstate.cancel', {
62
+ source: scope.self,
63
+ id
64
+ }));
65
+ };
66
+ enqueue.emit = event => {
67
+ effects.push(effect('@xstate.emit', {
68
+ kind: 'emit',
69
+ type: '@xstate.emit',
70
+ source: scope.self,
71
+ event
72
+ }));
73
+ };
74
+ enqueue.log = (...args) => {
75
+ enqueue(scope.logger, ...args);
76
+ };
77
+ enqueue.raise = (event, options) => {
78
+ if (typeof event === 'string') {
79
+ throw new Error('Only event objects may be used with raise');
80
+ }
81
+ if (options?.delay === undefined) {
82
+ internalEvents.push(event);
83
+ } else {
84
+ effects.push(effect('@xstate.raise', {
85
+ source: scope.self,
86
+ event,
87
+ id: options.id,
88
+ delay: options.delay
89
+ }));
90
+ }
91
+ };
92
+ enqueue.sendTo = (target, event, options) => {
93
+ if (!target) {
94
+ internalEvents.push({
95
+ type: 'xstate.error.communication',
96
+ error: {
97
+ message: 'Unable to send event to an undefined actor',
98
+ event
99
+ }
100
+ });
101
+ return;
102
+ }
103
+ effects.push(effect('@xstate.sendTo', {
104
+ source: scope.self,
105
+ target,
106
+ event,
107
+ id: options?.id,
108
+ delay: options?.delay
109
+ }));
110
+ };
111
+ const spawn = (logic, options = {}) => {
112
+ if (typeof logic === 'string') {
113
+ throw new Error(`Actor source "${logic}" not found`);
114
+ }
115
+ const allocation = allocations.get(scope);
116
+ let id = options.id;
117
+ let prefix;
118
+ let next;
119
+ if (id === undefined) {
120
+ prefix = logic.id ?? 'x';
121
+ if (prefix === '(machine)') {
122
+ prefix = 'x';
123
+ }
124
+ next = allocation.counters[prefix] ?? 0;
125
+ do {
126
+ id = `${prefix}:${next++}`;
127
+ } while (allocation.ids.has(id));
128
+ allocation.counters[prefix] = next;
129
+ }
130
+ if (allocation.ids.has(id)) {
131
+ throw new Error(`Actor with id "${id}" already exists`);
132
+ }
133
+ allocation.ids.add(id);
134
+ const actor = scope.system.createActorRef(logic, {
135
+ ...options,
136
+ id,
137
+ parent: scope.self
138
+ });
139
+ effects.push(effect('@xstate.spawn', {
140
+ source: scope.self,
141
+ actor,
142
+ id,
143
+ logic,
144
+ src: logic,
145
+ input: options.input,
146
+ childUpdate: {
147
+ type: 'add',
148
+ actor,
149
+ id,
150
+ prefix,
151
+ next
152
+ }
153
+ }));
154
+ return actor;
155
+ };
156
+ enqueue.spawn = spawn;
157
+ enqueue.stop = actor => {
158
+ if (actor) {
159
+ allocations.get(scope)?.ids.delete(actor.id);
160
+ effects.push(effect('@xstate.stop', {
161
+ source: scope.self,
162
+ actor,
163
+ id: actor.id,
164
+ childUpdate: {
165
+ type: 'remove',
166
+ actor: actor
167
+ }
168
+ }));
169
+ }
170
+ };
171
+ const attach = (logic, input) => {
172
+ const actor = scope.system.createActorRef(logic, {
173
+ input,
174
+ parent: scope.self
175
+ });
176
+ effects.push(effect('@xstate.spawn', {
177
+ source: scope.self,
178
+ actor,
179
+ id: actor.id,
180
+ logic,
181
+ src: logic,
182
+ input
183
+ }));
184
+ return actor;
185
+ };
186
+ enqueue.listen = (actor, eventType, mapper) => attach(listenerLogic, {
187
+ actor,
188
+ eventType,
189
+ mapper
190
+ });
191
+ enqueue.subscribeTo = (actor, mappers) => attach(subscriptionLogic, {
192
+ actor,
193
+ mappers: typeof mappers === 'function' ? {
194
+ snapshot: mappers
195
+ } : mappers
196
+ });
197
+ return enqueue;
198
+ }
199
+ function resolveFSMEffects(snapshot, effects, scope) {
200
+ let nextSnapshot = snapshot;
201
+ for (const current of effects) {
202
+ const update = current.childUpdate;
203
+ if (update?.type === 'add') {
204
+ nextSnapshot = {
205
+ ...nextSnapshot,
206
+ children: {
207
+ ...nextSnapshot.children,
208
+ [update.id]: update.actor
209
+ },
210
+ ...(update.prefix && {
211
+ _nextActorIds: {
212
+ ...nextSnapshot._nextActorIds,
213
+ [update.prefix]: Math.max(nextSnapshot._nextActorIds?.[update.prefix] ?? 0, update.next)
214
+ }
215
+ })
216
+ };
217
+ } else if (update?.type === 'remove') {
218
+ const children = {
219
+ ...nextSnapshot.children
220
+ };
221
+ let owned = update.actor._parent === scope.self;
222
+ for (const id of Object.keys(children)) {
223
+ if (children[id] === update.actor) {
224
+ owned = true;
225
+ delete children[id];
226
+ }
227
+ }
228
+ if (!owned) {
229
+ throw new Error(`Cannot stop non-child actor ${update.actor.id}`);
230
+ }
231
+ nextSnapshot = {
232
+ ...nextSnapshot,
233
+ children
234
+ };
235
+ }
236
+ if (current.type === '@xstate.cancel') {
237
+ if (nextSnapshot.timers[current.id]) {
238
+ const timers = {
239
+ ...nextSnapshot.timers
240
+ };
241
+ delete timers[current.id];
242
+ nextSnapshot = {
243
+ ...nextSnapshot,
244
+ timers
245
+ };
246
+ }
247
+ } else if ((current.type === '@xstate.raise' || current.type === '@xstate.sendTo') && current.delay !== undefined) {
248
+ const timer = current;
249
+ const generated = timer.id === undefined;
250
+ const id = timer.id ?? `xstate.timer.auto.${nextSnapshot._nextTimerId}`;
251
+ timer.id = id;
252
+ nextSnapshot = {
253
+ ...nextSnapshot,
254
+ timers: {
255
+ ...nextSnapshot.timers,
256
+ [id]: {
257
+ id,
258
+ delay: timer.delay,
259
+ type: timer.type,
260
+ event: timer.event,
261
+ target: timer.type === '@xstate.raise' || timer.target === scope.self ? 'self' : timer.target
262
+ }
263
+ },
264
+ _nextTimerId: generated ? nextSnapshot._nextTimerId + 1 : nextSnapshot._nextTimerId
265
+ };
266
+ }
267
+ }
268
+ return [nextSnapshot, effects];
269
+ }
270
+ function appendFSMStarts(effects) {
271
+ const ordered = [];
272
+ const attached = [];
273
+ const children = [];
274
+ for (const current of effects) {
275
+ if (current.type === '@xstate.stop') {
276
+ for (const starts of [attached, children]) {
277
+ const index = starts.findIndex(start => start.actor === current.actor);
278
+ if (index !== -1) {
279
+ ordered.push(starts.splice(index, 1)[0]);
280
+ }
281
+ }
282
+ }
283
+ ordered.push(current);
284
+ if (current.type !== '@xstate.spawn') {
285
+ continue;
286
+ }
287
+ const start = effect('@xstate.start', {
288
+ actor: current.actor,
289
+ id: current.id,
290
+ source: current.source
291
+ });
292
+ (current.logic === listenerLogic || current.logic === subscriptionLogic ? attached : children).push(start);
293
+ }
294
+ return ordered.concat(attached, children);
295
+ }
296
+ function createFSMSendEffect(scope, target, event) {
297
+ return effect('@xstate.sendTo', {
298
+ source: scope.self,
299
+ target,
300
+ event
301
+ });
302
+ }
303
+ function finalizeFSMEffects(scope, previous, result) {
304
+ const [snapshot, effects] = result;
305
+ if ((snapshot.status === 'done' || snapshot.status === 'error') && previous?.status !== 'done' && previous?.status !== 'error') {
306
+ effects.push(effect('@xstate.terminate', {
307
+ source: scope.self,
308
+ actor: scope.self,
309
+ id: scope.self.id,
310
+ status: snapshot.status,
311
+ output: snapshot.output,
312
+ error: snapshot.error
313
+ }));
314
+ }
315
+ return [snapshot, effects];
316
+ }
317
+
318
+ const emptySources = {
319
+ actions: {},
320
+ actors: {},
321
+ guards: {},
322
+ delays: {}
323
+ };
324
+ const emptyExecutableActions = [];
325
+ const emptyFSMActions = [];
326
+ function assertPersistableFSM(children, timers) {
327
+ if (Object.keys(children).length) {
328
+ throw new Error('FSM child persistence requires registered sources.');
329
+ }
330
+ for (const id in timers) {
331
+ if (timers[id].target !== 'self') {
332
+ throw new Error(`FSM timer '${id}' must target self to be persisted.`);
333
+ }
334
+ }
335
+ }
336
+ function toArray(value) {
337
+ return value === undefined ? [] : Array.isArray(value) ? value : [value];
338
+ }
339
+ function resolveContext(context, input) {
340
+ return typeof context === 'function' ? context({
341
+ input
342
+ }) : context ?? {};
343
+ }
344
+ function resolveTransitionContext(context, args) {
345
+ return typeof context === 'function' ? context(args) : context;
346
+ }
347
+ function resolveInput(input, context, event) {
348
+ return typeof input === 'function' ? input({
349
+ context,
350
+ event
351
+ }) : input;
352
+ }
353
+ function mergeContextPatch(context, patch) {
354
+ for (const key of Object.keys(patch)) {
355
+ if (!Object.prototype.hasOwnProperty.call(context, key) || !Object.is(context[key], patch[key])) {
356
+ return {
357
+ ...context,
358
+ ...patch
359
+ };
360
+ }
361
+ }
362
+ return context;
363
+ }
364
+ function createSnapshot(value, context, input, machine, stateInput) {
365
+ return {
366
+ status: 'active',
367
+ output: undefined,
368
+ error: undefined,
369
+ value,
370
+ context,
371
+ input,
372
+ children: {},
373
+ timers: {},
374
+ _nextTimerId: 0,
375
+ _stateInput: stateInput,
376
+ machine
377
+ };
378
+ }
379
+ function cloneSnapshot(snapshot, value, context, stateInput) {
380
+ return {
381
+ status: snapshot.status,
382
+ output: snapshot.output,
383
+ error: snapshot.error,
384
+ value,
385
+ context,
386
+ input: snapshot.input,
387
+ children: snapshot.children,
388
+ timers: snapshot.timers,
389
+ _nextTimerId: snapshot._nextTimerId,
390
+ // Carried across state changes: dropping these would let a later spawn
391
+ // reuse the id of a still-running child.
392
+ _nextActorIds: snapshot._nextActorIds,
393
+ _stateInput: stateInput,
394
+ machine: snapshot.machine
395
+ };
396
+ }
397
+ function stopSnapshot(snapshot) {
398
+ return {
399
+ status: 'stopped',
400
+ output: undefined,
401
+ error: undefined,
402
+ value: snapshot.value,
403
+ context: snapshot.context,
404
+ input: undefined,
405
+ children: snapshot.children,
406
+ timers: snapshot.timers,
407
+ _nextTimerId: snapshot._nextTimerId,
408
+ _nextActorIds: snapshot._nextActorIds,
409
+ _stateInput: snapshot._stateInput,
410
+ machine: snapshot.machine
411
+ };
412
+ }
413
+ function cleanupFSM(snapshot, actorScope) {
414
+ const effects = [];
415
+ const enqueue = createFSMEnqueue(actorScope, effects, []);
416
+ for (const child of Object.values(snapshot.children)) {
417
+ enqueue.stop(child);
418
+ }
419
+ for (const id of Object.keys(snapshot.timers)) {
420
+ enqueue.cancel(id);
421
+ }
422
+ return resolveFSMEffects(snapshot, effects, actorScope);
423
+ }
424
+ function completeFinalState(snapshot, event, actorScope, internalQueue, states, runStateActions) {
425
+ const completed = {
426
+ ...snapshot,
427
+ status: 'done',
428
+ output: undefined,
429
+ error: undefined
430
+ };
431
+ const [exited, exitEffects] = runStateActions(completed, event, actorScope, states[completed.value]?.exit, completed._stateInput, internalQueue);
432
+ const [cleaned, cleanupEffects] = cleanupFSM(exited, actorScope);
433
+ return [cleaned, [...exitEffects, ...cleanupEffects]];
434
+ }
435
+ function invalidStringTarget(path, target) {
436
+ throw new Error(`Invalid transition for "${path}": use { target: "${target}" } instead of a string target.`);
437
+ }
438
+ function assertNoStringTransitions(config) {
439
+ for (const [stateKey, stateConfig] of Object.entries(config.states)) {
440
+ for (const [eventType, transitionConfig] of Object.entries(stateConfig.on ?? {})) {
441
+ for (const transition of toArray(transitionConfig)) {
442
+ if (typeof transition === 'string') {
443
+ invalidStringTarget(`${stateKey}.${eventType}`, transition);
444
+ }
445
+ }
446
+ }
447
+ if (stateConfig.always) {
448
+ for (const transition of toArray(stateConfig.always)) {
449
+ if (typeof transition === 'string') {
450
+ invalidStringTarget(`${stateKey}.always`, transition);
451
+ }
452
+ }
453
+ }
454
+ }
455
+ }
456
+ function createFSM(config) {
457
+ const machine = {
458
+ id: config.id ?? '(fsm)',
459
+ sources: emptySources
460
+ };
461
+ assertNoStringTransitions(config);
462
+ const runActions = (snapshot, event, actorScope, actionsConfig, internalQueue) => {
463
+ if (!actionsConfig) {
464
+ return [snapshot, emptyExecutableActions];
465
+ }
466
+ const effects = [];
467
+ const enqueue = createFSMEnqueue(actorScope, effects, internalQueue);
468
+ let context = snapshot.context;
469
+ for (const action of toArray(actionsConfig)) {
470
+ const result = action(withActorScope({
471
+ context,
472
+ event: event,
473
+ input: snapshot._stateInput,
474
+ value: snapshot.value,
475
+ children: snapshot.children
476
+ }, actorScope), enqueue);
477
+ if (result?.context) {
478
+ context = mergeContextPatch(context, result.context);
479
+ }
480
+ }
481
+ return resolveFSMEffects(context === snapshot.context ? snapshot : cloneSnapshot(snapshot, snapshot.value, context, snapshot._stateInput), effects, actorScope);
482
+ };
483
+ const runStateActions = (snapshot, event, actorScope, actionsConfig, stateInput, internalQueue) => {
484
+ if (!actionsConfig) {
485
+ return [snapshot, emptyExecutableActions];
486
+ }
487
+ const actions = [];
488
+ const enq = createFSMEnqueue(actorScope, actions, internalQueue);
489
+ let context;
490
+ const actionCount = Array.isArray(actionsConfig) ? actionsConfig.length : 1;
491
+ for (let i = 0; i < actionCount; i++) {
492
+ const action = Array.isArray(actionsConfig) ? actionsConfig[i] : actionsConfig;
493
+ const result = action(withActorScope({
494
+ context: context ?? snapshot.context,
495
+ event: event,
496
+ input: stateInput,
497
+ value: snapshot.value,
498
+ children: snapshot.children
499
+ }, actorScope), enq);
500
+ if (result?.context !== undefined) {
501
+ const currentContext = context ?? snapshot.context;
502
+ const nextContext = mergeContextPatch(currentContext, result.context);
503
+ if (nextContext !== currentContext) {
504
+ context = nextContext;
505
+ }
506
+ }
507
+ }
508
+ const nextSnapshot = context !== undefined ? cloneSnapshot(snapshot, snapshot.value, context, snapshot._stateInput) : snapshot;
509
+ return resolveFSMEffects(nextSnapshot, actions, actorScope);
510
+ };
511
+ const selectTransition = (snapshot, event, actorScope, internalQueue) => {
512
+ const state = config.states[snapshot.value];
513
+ const transitionsConfig = event.type === '' ? state?.always : state?.on?.[event.type];
514
+ if (!transitionsConfig) {
515
+ return undefined;
516
+ }
517
+ const transitionCount = Array.isArray(transitionsConfig) ? transitionsConfig.length : 1;
518
+ for (let i = 0; i < transitionCount; i++) {
519
+ const transition = Array.isArray(transitionsConfig) ? transitionsConfig[i] : transitionsConfig;
520
+ const args = withActorScope({
521
+ context: snapshot.context,
522
+ event,
523
+ input: snapshot.input,
524
+ value: snapshot.value,
525
+ children: snapshot.children
526
+ }, actorScope);
527
+ if (typeof transition === 'function') {
528
+ const actions = [];
529
+ const enq = createFSMEnqueue(actorScope, actions, internalQueue);
530
+ const result = transition(args, enq);
531
+ if (!result) {
532
+ if (actions.length) {
533
+ return {
534
+ effects: actions
535
+ };
536
+ }
537
+ continue;
538
+ }
539
+ return {
540
+ target: result.target,
541
+ context: result.context,
542
+ input: result.input,
543
+ effects: actions
544
+ };
545
+ }
546
+ if ('guard' in transition && transition.guard && !transition.guard(args)) {
547
+ continue;
548
+ }
549
+ return {
550
+ target: transition.target,
551
+ context: resolveTransitionContext(transition.context, args),
552
+ input: transition.input,
553
+ actions: 'actions' in transition && transition.actions ? toArray(transition.actions) : emptyFSMActions
554
+ };
555
+ }
556
+ return undefined;
557
+ };
558
+ const transitionCore = (snapshot, event, actorScope) => {
559
+ if (snapshot.status !== 'active') {
560
+ return [snapshot, []];
561
+ }
562
+ if (event.type === XSTATE_STOP) {
563
+ const [cleaned, cleanupEffects] = cleanupFSM(snapshot, actorScope);
564
+ return [stopSnapshot(cleaned), cleanupEffects];
565
+ }
566
+ if (event.type === XSTATE_TIMER) {
567
+ const timer = snapshot.timers[event.id];
568
+ if (!timer) {
569
+ return [snapshot, emptyExecutableActions];
570
+ }
571
+ const timers = {
572
+ ...snapshot.timers
573
+ };
574
+ delete timers[timer.id];
575
+ const nextSnapshot = {
576
+ ...snapshot,
577
+ timers
578
+ };
579
+ if (timer.type === '@xstate.raise') {
580
+ return transitionCore(nextSnapshot, timer.event, actorScope);
581
+ }
582
+ const target = timer.target === 'self' ? actorScope.self : timer.target;
583
+ return [nextSnapshot, [createFSMSendEffect(actorScope, target, timer.event)]];
584
+ }
585
+ const stateConfig = config.states[snapshot.value];
586
+ const directTransition = event.type === '' ? stateConfig?.always : stateConfig?.on?.[event.type];
587
+ if (!directTransition) {
588
+ return [snapshot, emptyExecutableActions];
589
+ }
590
+ if (!Array.isArray(directTransition) && typeof directTransition !== 'function' && !('guard' in directTransition) && !('actions' in directTransition && directTransition.actions) && typeof directTransition.input !== 'function') {
591
+ const target = directTransition.target ?? snapshot.value;
592
+ const targetState = config.states[target];
593
+ const stateChanged = target !== snapshot.value;
594
+ if (targetState?.always || stateChanged && (stateConfig.exit || targetState?.entry || targetState?.type === 'final')) ; else {
595
+ const hasContext = directTransition.context !== undefined;
596
+ const hasInput = directTransition.input !== undefined;
597
+ const resolvedContext = !isLazyActorScope(actorScope) ? resolveTransitionContext(directTransition.context, {
598
+ context: snapshot.context,
599
+ event,
600
+ input: snapshot.input,
601
+ value: snapshot.value,
602
+ self: actorScope.self,
603
+ system: actorScope.system,
604
+ parent: actorScope.self._parent,
605
+ children: snapshot.children
606
+ }) : typeof directTransition.context === 'function' ? directTransition.context(withActorScope({
607
+ context: snapshot.context,
608
+ event,
609
+ input: snapshot.input,
610
+ value: snapshot.value,
611
+ children: snapshot.children
612
+ }, actorScope)) : directTransition.context;
613
+ const context = hasContext && resolvedContext ? mergeContextPatch(snapshot.context, resolvedContext) : snapshot.context;
614
+ if (!stateChanged && context === snapshot.context && !hasInput && snapshot._stateInput === undefined) {
615
+ return [snapshot, emptyExecutableActions];
616
+ }
617
+ return [cloneSnapshot(snapshot, target, context, hasInput ? resolveInput(directTransition.input, context, event) : undefined), emptyExecutableActions];
618
+ }
619
+ }
620
+ let selectedTransition;
621
+ if (typeof directTransition === 'function' && directTransition.length < 2 && !stateConfig?.exit) {
622
+ const result = directTransition(withActorScope({
623
+ context: snapshot.context,
624
+ event,
625
+ input: snapshot.input,
626
+ value: snapshot.value,
627
+ children: snapshot.children
628
+ }, actorScope), undefined);
629
+ if (!result) {
630
+ return [snapshot, emptyExecutableActions];
631
+ }
632
+ const target = result.target ?? snapshot.value;
633
+ const targetState = config.states[target];
634
+ if (!targetState?.entry && !targetState?.always && targetState?.type !== 'final') {
635
+ const hasContext = result.context !== undefined;
636
+ const hasInput = result.input !== undefined;
637
+ const context = hasContext && result.context ? mergeContextPatch(snapshot.context, result.context) : snapshot.context;
638
+ if (target === snapshot.value && context === snapshot.context && !hasInput && snapshot._stateInput === undefined) {
639
+ return [snapshot, emptyExecutableActions];
640
+ }
641
+ return [cloneSnapshot(snapshot, target, context, hasInput ? resolveInput(result.input, context, event) : undefined), emptyExecutableActions];
642
+ }
643
+ selectedTransition = {
644
+ target: result.target,
645
+ context: result.context,
646
+ input: result.input,
647
+ actions: emptyFSMActions
648
+ };
649
+ }
650
+ let nextSnapshot = snapshot;
651
+ const executableActions = [];
652
+ const internalQueue = [event];
653
+ let iterations = 0;
654
+ while (internalQueue.length) {
655
+ if (++iterations > 1000) {
656
+ throw new Error('FSM microstep count exceeded 1000');
657
+ }
658
+ const nextEvent = internalQueue.shift();
659
+ const selected = selectedTransition ?? selectTransition(nextSnapshot, nextEvent, actorScope, internalQueue);
660
+ selectedTransition = undefined;
661
+ if (!selected) {
662
+ continue;
663
+ }
664
+ const nextValue = selected.target ?? nextSnapshot.value;
665
+ const nextState = config.states[nextValue];
666
+ const stateChanged = nextValue !== nextSnapshot.value;
667
+ if (stateChanged) {
668
+ const [exited, exitActions] = runStateActions(nextSnapshot, nextEvent, actorScope, config.states[nextSnapshot.value]?.exit, nextSnapshot._stateInput, internalQueue);
669
+ nextSnapshot = exited;
670
+ executableActions.push(...exitActions);
671
+ }
672
+ let context = nextSnapshot.context;
673
+ if (selected.context !== undefined) {
674
+ context = mergeContextPatch(context, selected.context);
675
+ }
676
+ const hasInput = selected.input !== undefined;
677
+ const stateInput = hasInput ? resolveInput(selected.input, context, nextEvent) : undefined;
678
+ if (stateChanged || context !== nextSnapshot.context || hasInput || nextSnapshot._stateInput !== undefined) {
679
+ nextSnapshot = cloneSnapshot(nextSnapshot, nextValue, context, stateInput);
680
+ }
681
+ const transitionResult = selected.effects ? resolveFSMEffects(nextSnapshot, selected.effects, actorScope) : runActions(nextSnapshot, nextEvent, actorScope, selected.actions, internalQueue);
682
+ const [afterTransition, transitionActions] = transitionResult;
683
+ nextSnapshot = afterTransition;
684
+ executableActions.push(...transitionActions);
685
+ if (stateChanged) {
686
+ const [entered, entryActions] = runStateActions(nextSnapshot, nextEvent, actorScope, nextState?.entry, stateInput, internalQueue);
687
+ nextSnapshot = entered;
688
+ executableActions.push(...entryActions);
689
+ }
690
+ if (nextState?.type === 'final') {
691
+ const [completed, completionEffects] = completeFinalState(nextSnapshot, nextEvent, actorScope, internalQueue, config.states, runStateActions);
692
+ nextSnapshot = completed;
693
+ executableActions.push(...completionEffects);
694
+ break;
695
+ }
696
+ if (nextState?.always) {
697
+ internalQueue.unshift({
698
+ type: ''
699
+ });
700
+ }
701
+ }
702
+ return [nextSnapshot, executableActions];
703
+ };
704
+ const transition = (...args) => {
705
+ beginFSMEffects(args[2], args[0]);
706
+ const [nextSnapshot, effects] = transitionCore(...args);
707
+ return finalizeFSMEffects(args[2], args[0], [nextSnapshot, appendFSMStarts(effects)]);
708
+ };
709
+ const logic = {
710
+ id: config.id,
711
+ config,
712
+ transition,
713
+ initialTransition: (input, actorScope) => {
714
+ const initialState = config.states[config.initial];
715
+ const context = resolveContext(config.context, input);
716
+ const snapshot = createSnapshot(config.initial, context, input, machine);
717
+ beginFSMEffects(actorScope, snapshot);
718
+ const internalQueue = [];
719
+ let [nextSnapshot, actions] = runStateActions(snapshot, {
720
+ type: XSTATE_INIT
721
+ }, actorScope, initialState?.entry, undefined, internalQueue);
722
+ if (!actions.length) {
723
+ actions = [];
724
+ }
725
+ if (initialState?.type === 'final') {
726
+ const [completed, completionEffects] = completeFinalState(nextSnapshot, {
727
+ type: XSTATE_INIT
728
+ }, actorScope, internalQueue, config.states, runStateActions);
729
+ nextSnapshot = completed;
730
+ actions.push(...completionEffects);
731
+ } else {
732
+ if (initialState?.always) {
733
+ internalQueue.unshift({
734
+ type: ''
735
+ });
736
+ }
737
+ while (internalQueue.length) {
738
+ const [raisedSnapshot, raisedActions] = transitionCore(nextSnapshot, internalQueue.shift(), actorScope);
739
+ nextSnapshot = raisedSnapshot;
740
+ actions.push(...raisedActions);
741
+ }
742
+ }
743
+ return finalizeFSMEffects(actorScope, undefined, [nextSnapshot, appendFSMStarts(actions)]);
744
+ },
745
+ getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
746
+ getPersistedSnapshot: currentSnapshot => {
747
+ const {
748
+ machine: _,
749
+ children,
750
+ ...snapshot
751
+ } = currentSnapshot;
752
+ assertPersistableFSM(children, snapshot.timers);
753
+ return {
754
+ ...snapshot,
755
+ children: {}
756
+ };
757
+ },
758
+ restoreSnapshot: snapshot => {
759
+ const persisted = snapshot;
760
+ const children = persisted.children ?? {};
761
+ const timers = persisted.timers ?? {};
762
+ assertPersistableFSM(children, timers);
763
+ const restored = {
764
+ ...persisted,
765
+ children: {},
766
+ timers,
767
+ machine: machine
768
+ };
769
+ return restored;
770
+ }
771
+ };
772
+ return logic;
773
+ }
774
+
775
+ export { createFSM as c };