1 | 'use strict';
|
2 |
|
3 | var dev_dist_xstateDev = require('../dev/dist/xstate-dev.cjs.js');
|
4 |
|
5 | class Mailbox {
|
6 | constructor(_process) {
|
7 | this._process = _process;
|
8 | this._active = false;
|
9 | this._current = null;
|
10 | this._last = null;
|
11 | }
|
12 | start() {
|
13 | this._active = true;
|
14 | this.flush();
|
15 | }
|
16 | clear() {
|
17 |
|
18 |
|
19 | if (this._current) {
|
20 | this._current.next = null;
|
21 | this._last = this._current;
|
22 | }
|
23 | }
|
24 | enqueue(event) {
|
25 | const enqueued = {
|
26 | value: event,
|
27 | next: null
|
28 | };
|
29 | if (this._current) {
|
30 | this._last.next = enqueued;
|
31 | this._last = enqueued;
|
32 | return;
|
33 | }
|
34 | this._current = enqueued;
|
35 | this._last = enqueued;
|
36 | if (this._active) {
|
37 | this.flush();
|
38 | }
|
39 | }
|
40 | flush() {
|
41 | while (this._current) {
|
42 |
|
43 |
|
44 | const consumed = this._current;
|
45 | this._process(consumed.value);
|
46 | this._current = consumed.next;
|
47 | }
|
48 | this._last = null;
|
49 | }
|
50 | }
|
51 |
|
52 | const STATE_DELIMITER = '.';
|
53 | const TARGETLESS_KEY = '';
|
54 | const NULL_EVENT = '';
|
55 | const STATE_IDENTIFIER = '#';
|
56 | const WILDCARD = '*';
|
57 | const XSTATE_INIT = 'xstate.init';
|
58 | const XSTATE_ERROR = 'xstate.error';
|
59 | const XSTATE_STOP = 'xstate.stop';
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 | function createAfterEvent(delayRef, id) {
|
69 | return {
|
70 | type: `xstate.after.${delayRef}.${id}`
|
71 | };
|
72 | }
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | function createDoneStateEvent(id, output) {
|
82 | return {
|
83 | type: `xstate.done.state.${id}`,
|
84 | output
|
85 | };
|
86 | }
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | function createDoneActorEvent(invokeId, output) {
|
98 | return {
|
99 | type: `xstate.done.actor.${invokeId}`,
|
100 | output
|
101 | };
|
102 | }
|
103 | function createErrorActorEvent(id, error) {
|
104 | return {
|
105 | type: `xstate.error.actor.${id}`,
|
106 | error
|
107 | };
|
108 | }
|
109 | function createInitEvent(input) {
|
110 | return {
|
111 | type: XSTATE_INIT,
|
112 | input
|
113 | };
|
114 | }
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | function reportUnhandledError(err) {
|
124 | setTimeout(() => {
|
125 | throw err;
|
126 | });
|
127 | }
|
128 |
|
129 | const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
130 |
|
131 | function createScheduledEventId(actorRef, id) {
|
132 | return `${actorRef.sessionId}.${id}`;
|
133 | }
|
134 | let idCounter = 0;
|
135 | function createSystem(rootActor, options) {
|
136 | const children = new Map();
|
137 | const keyedActors = new Map();
|
138 | const reverseKeyedActors = new WeakMap();
|
139 | const inspectionObservers = new Set();
|
140 | const timerMap = {};
|
141 | const {
|
142 | clock,
|
143 | logger
|
144 | } = options;
|
145 | const scheduler = {
|
146 | schedule: (source, target, event, delay, id = Math.random().toString(36).slice(2)) => {
|
147 | const scheduledEvent = {
|
148 | source,
|
149 | target,
|
150 | event,
|
151 | delay,
|
152 | id,
|
153 | startedAt: Date.now()
|
154 | };
|
155 | const scheduledEventId = createScheduledEventId(source, id);
|
156 | system._snapshot._scheduledEvents[scheduledEventId] = scheduledEvent;
|
157 | const timeout = clock.setTimeout(() => {
|
158 | delete timerMap[scheduledEventId];
|
159 | delete system._snapshot._scheduledEvents[scheduledEventId];
|
160 | system._relay(source, target, event);
|
161 | }, delay);
|
162 | timerMap[scheduledEventId] = timeout;
|
163 | },
|
164 | cancel: (source, id) => {
|
165 | const scheduledEventId = createScheduledEventId(source, id);
|
166 | const timeout = timerMap[scheduledEventId];
|
167 | delete timerMap[scheduledEventId];
|
168 | delete system._snapshot._scheduledEvents[scheduledEventId];
|
169 | clock.clearTimeout(timeout);
|
170 | },
|
171 | cancelAll: actorRef => {
|
172 | for (const scheduledEventId in system._snapshot._scheduledEvents) {
|
173 | const scheduledEvent = system._snapshot._scheduledEvents[scheduledEventId];
|
174 | if (scheduledEvent.source === actorRef) {
|
175 | scheduler.cancel(actorRef, scheduledEvent.id);
|
176 | }
|
177 | }
|
178 | }
|
179 | };
|
180 | const sendInspectionEvent = event => {
|
181 | if (!inspectionObservers.size) {
|
182 | return;
|
183 | }
|
184 | const resolvedInspectionEvent = {
|
185 | ...event,
|
186 | rootId: rootActor.sessionId
|
187 | };
|
188 | inspectionObservers.forEach(observer => observer.next?.(resolvedInspectionEvent));
|
189 | };
|
190 | const system = {
|
191 | _snapshot: {
|
192 | _scheduledEvents: (options?.snapshot && options.snapshot.scheduler) ?? {}
|
193 | },
|
194 | _bookId: () => `x:${idCounter++}`,
|
195 | _register: (sessionId, actorRef) => {
|
196 | children.set(sessionId, actorRef);
|
197 | return sessionId;
|
198 | },
|
199 | _unregister: actorRef => {
|
200 | children.delete(actorRef.sessionId);
|
201 | const systemId = reverseKeyedActors.get(actorRef);
|
202 | if (systemId !== undefined) {
|
203 | keyedActors.delete(systemId);
|
204 | reverseKeyedActors.delete(actorRef);
|
205 | }
|
206 | },
|
207 | get: systemId => {
|
208 | return keyedActors.get(systemId);
|
209 | },
|
210 | _set: (systemId, actorRef) => {
|
211 | const existing = keyedActors.get(systemId);
|
212 | if (existing && existing !== actorRef) {
|
213 | throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
214 | }
|
215 | keyedActors.set(systemId, actorRef);
|
216 | reverseKeyedActors.set(actorRef, systemId);
|
217 | },
|
218 | inspect: observer => {
|
219 | inspectionObservers.add(observer);
|
220 | },
|
221 | _sendInspectionEvent: sendInspectionEvent,
|
222 | _relay: (source, target, event) => {
|
223 | system._sendInspectionEvent({
|
224 | type: '@xstate.event',
|
225 | sourceRef: source,
|
226 | actorRef: target,
|
227 | event
|
228 | });
|
229 | target._send(event);
|
230 | },
|
231 | scheduler,
|
232 | getSnapshot: () => {
|
233 | return {
|
234 | _scheduledEvents: {
|
235 | ...system._snapshot._scheduledEvents
|
236 | }
|
237 | };
|
238 | },
|
239 | start: () => {
|
240 | const scheduledEvents = system._snapshot._scheduledEvents;
|
241 | system._snapshot._scheduledEvents = {};
|
242 | for (const scheduledId in scheduledEvents) {
|
243 | const {
|
244 | source,
|
245 | target,
|
246 | event,
|
247 | delay,
|
248 | id
|
249 | } = scheduledEvents[scheduledId];
|
250 | scheduler.schedule(source, target, event, delay, id);
|
251 | }
|
252 | },
|
253 | _clock: clock,
|
254 | _logger: logger
|
255 | };
|
256 | return system;
|
257 | }
|
258 |
|
259 | function matchesState(parentStateId, childStateId) {
|
260 | const parentStateValue = toStateValue(parentStateId);
|
261 | const childStateValue = toStateValue(childStateId);
|
262 | if (typeof childStateValue === 'string') {
|
263 | if (typeof parentStateValue === 'string') {
|
264 | return childStateValue === parentStateValue;
|
265 | }
|
266 |
|
267 |
|
268 | return false;
|
269 | }
|
270 | if (typeof parentStateValue === 'string') {
|
271 | return parentStateValue in childStateValue;
|
272 | }
|
273 | return Object.keys(parentStateValue).every(key => {
|
274 | if (!(key in childStateValue)) {
|
275 | return false;
|
276 | }
|
277 | return matchesState(parentStateValue[key], childStateValue[key]);
|
278 | });
|
279 | }
|
280 | function toStatePath(stateId) {
|
281 | if (isArray(stateId)) {
|
282 | return stateId;
|
283 | }
|
284 | let result = [];
|
285 | let segment = '';
|
286 | for (let i = 0; i < stateId.length; i++) {
|
287 | const char = stateId.charCodeAt(i);
|
288 | switch (char) {
|
289 |
|
290 | case 92:
|
291 |
|
292 | segment += stateId[i + 1];
|
293 |
|
294 | i++;
|
295 | continue;
|
296 |
|
297 | case 46:
|
298 | result.push(segment);
|
299 | segment = '';
|
300 | continue;
|
301 | }
|
302 | segment += stateId[i];
|
303 | }
|
304 | result.push(segment);
|
305 | return result;
|
306 | }
|
307 | function toStateValue(stateValue) {
|
308 | if (isMachineSnapshot(stateValue)) {
|
309 | return stateValue.value;
|
310 | }
|
311 | if (typeof stateValue !== 'string') {
|
312 | return stateValue;
|
313 | }
|
314 | const statePath = toStatePath(stateValue);
|
315 | return pathToStateValue(statePath);
|
316 | }
|
317 | function pathToStateValue(statePath) {
|
318 | if (statePath.length === 1) {
|
319 | return statePath[0];
|
320 | }
|
321 | const value = {};
|
322 | let marker = value;
|
323 | for (let i = 0; i < statePath.length - 1; i++) {
|
324 | if (i === statePath.length - 2) {
|
325 | marker[statePath[i]] = statePath[i + 1];
|
326 | } else {
|
327 | const previous = marker;
|
328 | marker = {};
|
329 | previous[statePath[i]] = marker;
|
330 | }
|
331 | }
|
332 | return value;
|
333 | }
|
334 | function mapValues(collection, iteratee) {
|
335 | const result = {};
|
336 | const collectionKeys = Object.keys(collection);
|
337 | for (let i = 0; i < collectionKeys.length; i++) {
|
338 | const key = collectionKeys[i];
|
339 | result[key] = iteratee(collection[key], key, collection, i);
|
340 | }
|
341 | return result;
|
342 | }
|
343 | function toArrayStrict(value) {
|
344 | if (isArray(value)) {
|
345 | return value;
|
346 | }
|
347 | return [value];
|
348 | }
|
349 | function toArray(value) {
|
350 | if (value === undefined) {
|
351 | return [];
|
352 | }
|
353 | return toArrayStrict(value);
|
354 | }
|
355 | function resolveOutput(mapper, context, event, self) {
|
356 | if (typeof mapper === 'function') {
|
357 | return mapper({
|
358 | context,
|
359 | event,
|
360 | self
|
361 | });
|
362 | }
|
363 | return mapper;
|
364 | }
|
365 | function isArray(value) {
|
366 | return Array.isArray(value);
|
367 | }
|
368 | function isErrorActorEvent(event) {
|
369 | return event.type.startsWith('xstate.error.actor');
|
370 | }
|
371 | function toTransitionConfigArray(configLike) {
|
372 | return toArrayStrict(configLike).map(transitionLike => {
|
373 | if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
|
374 | return {
|
375 | target: transitionLike
|
376 | };
|
377 | }
|
378 | return transitionLike;
|
379 | });
|
380 | }
|
381 | function normalizeTarget(target) {
|
382 | if (target === undefined || target === TARGETLESS_KEY) {
|
383 | return undefined;
|
384 | }
|
385 | return toArray(target);
|
386 | }
|
387 | function toObserver(nextHandler, errorHandler, completionHandler) {
|
388 | const isObserver = typeof nextHandler === 'object';
|
389 | const self = isObserver ? nextHandler : undefined;
|
390 | return {
|
391 | next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),
|
392 | error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),
|
393 | complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self)
|
394 | };
|
395 | }
|
396 | function createInvokeId(stateNodeId, index) {
|
397 | return `${index}.${stateNodeId}`;
|
398 | }
|
399 | function resolveReferencedActor(machine, src) {
|
400 | const match = src.match(/^xstate\.invoke\.(\d+)\.(.*)/);
|
401 | if (!match) {
|
402 | return machine.implementations.actors[src];
|
403 | }
|
404 | const [, indexStr, nodeId] = match;
|
405 | const node = machine.getStateNodeById(nodeId);
|
406 | const invokeConfig = node.config.invoke;
|
407 | return (Array.isArray(invokeConfig) ? invokeConfig[indexStr] : invokeConfig).src;
|
408 | }
|
409 | function getAllOwnEventDescriptors(snapshot) {
|
410 | return [...new Set([...snapshot._nodes.flatMap(sn => sn.ownEvents)])];
|
411 | }
|
412 |
|
413 | const $$ACTOR_TYPE = 1;
|
414 |
|
415 | let ProcessingStatus = function (ProcessingStatus) {
|
416 | ProcessingStatus[ProcessingStatus["NotStarted"] = 0] = "NotStarted";
|
417 | ProcessingStatus[ProcessingStatus["Running"] = 1] = "Running";
|
418 | ProcessingStatus[ProcessingStatus["Stopped"] = 2] = "Stopped";
|
419 | return ProcessingStatus;
|
420 | }({});
|
421 | const defaultOptions = {
|
422 | clock: {
|
423 | setTimeout: (fn, ms) => {
|
424 | return setTimeout(fn, ms);
|
425 | },
|
426 | clearTimeout: id => {
|
427 | return clearTimeout(id);
|
428 | }
|
429 | },
|
430 | logger: console.log.bind(console),
|
431 | devTools: false
|
432 | };
|
433 |
|
434 |
|
435 |
|
436 |
|
437 | class Actor {
|
438 | |
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 | constructor(logic, options) {
|
445 | this.logic = logic;
|
446 | |
447 |
|
448 |
|
449 | this._snapshot = void 0;
|
450 | |
451 |
|
452 |
|
453 | this.clock = void 0;
|
454 | this.options = void 0;
|
455 | |
456 |
|
457 |
|
458 | this.id = void 0;
|
459 | this.mailbox = new Mailbox(this._process.bind(this));
|
460 | this.observers = new Set();
|
461 | this.eventListeners = new Map();
|
462 | this.logger = void 0;
|
463 |
|
464 | this._processingStatus = ProcessingStatus.NotStarted;
|
465 |
|
466 | this._parent = void 0;
|
467 |
|
468 | this._syncSnapshot = void 0;
|
469 | this.ref = void 0;
|
470 |
|
471 | this._actorScope = void 0;
|
472 | this._systemId = void 0;
|
473 | |
474 |
|
475 |
|
476 | this.sessionId = void 0;
|
477 | |
478 |
|
479 |
|
480 | this.system = void 0;
|
481 | this._doneEvent = void 0;
|
482 | this.src = void 0;
|
483 |
|
484 | this._deferred = [];
|
485 | const resolvedOptions = {
|
486 | ...defaultOptions,
|
487 | ...options
|
488 | };
|
489 | const {
|
490 | clock,
|
491 | logger,
|
492 | parent,
|
493 | syncSnapshot,
|
494 | id,
|
495 | systemId,
|
496 | inspect
|
497 | } = resolvedOptions;
|
498 | this.system = parent ? parent.system : createSystem(this, {
|
499 | clock,
|
500 | logger
|
501 | });
|
502 | if (inspect && !parent) {
|
503 |
|
504 | this.system.inspect(toObserver(inspect));
|
505 | }
|
506 | this.sessionId = this.system._bookId();
|
507 | this.id = id ?? this.sessionId;
|
508 | this.logger = options?.logger ?? this.system._logger;
|
509 | this.clock = options?.clock ?? this.system._clock;
|
510 | this._parent = parent;
|
511 | this._syncSnapshot = syncSnapshot;
|
512 | this.options = resolvedOptions;
|
513 | this.src = resolvedOptions.src ?? logic;
|
514 | this.ref = this;
|
515 | this._actorScope = {
|
516 | self: this,
|
517 | id: this.id,
|
518 | sessionId: this.sessionId,
|
519 | logger: this.logger,
|
520 | defer: fn => {
|
521 | this._deferred.push(fn);
|
522 | },
|
523 | system: this.system,
|
524 | stopChild: child => {
|
525 | if (child._parent !== this) {
|
526 | throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
527 | }
|
528 | child._stop();
|
529 | },
|
530 | emit: emittedEvent => {
|
531 | const listeners = this.eventListeners.get(emittedEvent.type);
|
532 | if (!listeners) {
|
533 | return;
|
534 | }
|
535 | for (const handler of Array.from(listeners)) {
|
536 | handler(emittedEvent);
|
537 | }
|
538 | }
|
539 | };
|
540 |
|
541 |
|
542 |
|
543 | this.send = this.send.bind(this);
|
544 | this.system._sendInspectionEvent({
|
545 | type: '@xstate.actor',
|
546 | actorRef: this
|
547 | });
|
548 | if (systemId) {
|
549 | this._systemId = systemId;
|
550 | this.system._set(systemId, this);
|
551 | }
|
552 | this._initState(options?.snapshot ?? options?.state);
|
553 | if (systemId && this._snapshot.status !== 'active') {
|
554 | this.system._unregister(this);
|
555 | }
|
556 | }
|
557 | _initState(persistedState) {
|
558 | try {
|
559 | this._snapshot = persistedState ? this.logic.restoreSnapshot ? this.logic.restoreSnapshot(persistedState, this._actorScope) : persistedState : this.logic.getInitialSnapshot(this._actorScope, this.options?.input);
|
560 | } catch (err) {
|
561 |
|
562 |
|
563 |
|
564 | this._snapshot = {
|
565 | status: 'error',
|
566 | output: undefined,
|
567 | error: err
|
568 | };
|
569 | }
|
570 | }
|
571 | update(snapshot, event) {
|
572 |
|
573 | this._snapshot = snapshot;
|
574 |
|
575 |
|
576 | let deferredFn;
|
577 | while (deferredFn = this._deferred.shift()) {
|
578 | try {
|
579 | deferredFn();
|
580 | } catch (err) {
|
581 |
|
582 |
|
583 |
|
584 |
|
585 |
|
586 | this._deferred.length = 0;
|
587 | this._snapshot = {
|
588 | ...snapshot,
|
589 | status: 'error',
|
590 | error: err
|
591 | };
|
592 | }
|
593 | }
|
594 | switch (this._snapshot.status) {
|
595 | case 'active':
|
596 | for (const observer of this.observers) {
|
597 | try {
|
598 | observer.next?.(snapshot);
|
599 | } catch (err) {
|
600 | reportUnhandledError(err);
|
601 | }
|
602 | }
|
603 | break;
|
604 | case 'done':
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 |
|
611 | for (const observer of this.observers) {
|
612 | try {
|
613 | observer.next?.(snapshot);
|
614 | } catch (err) {
|
615 | reportUnhandledError(err);
|
616 | }
|
617 | }
|
618 | this._stopProcedure();
|
619 | this._complete();
|
620 | this._doneEvent = createDoneActorEvent(this.id, this._snapshot.output);
|
621 | if (this._parent) {
|
622 | this.system._relay(this, this._parent, this._doneEvent);
|
623 | }
|
624 | break;
|
625 | case 'error':
|
626 | this._error(this._snapshot.error);
|
627 | break;
|
628 | }
|
629 | this.system._sendInspectionEvent({
|
630 | type: '@xstate.snapshot',
|
631 | actorRef: this,
|
632 | event,
|
633 | snapshot
|
634 | });
|
635 | }
|
636 |
|
637 | |
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 |
|
644 |
|
645 |
|
646 |
|
647 |
|
648 |
|
649 |
|
650 |
|
651 |
|
652 |
|
653 |
|
654 |
|
655 |
|
656 |
|
657 |
|
658 |
|
659 |
|
660 |
|
661 |
|
662 |
|
663 |
|
664 |
|
665 |
|
666 |
|
667 |
|
668 |
|
669 |
|
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 |
|
676 |
|
677 |
|
678 |
|
679 |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 |
|
686 | subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
687 | const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
688 | if (this._processingStatus !== ProcessingStatus.Stopped) {
|
689 | this.observers.add(observer);
|
690 | } else {
|
691 | switch (this._snapshot.status) {
|
692 | case 'done':
|
693 | try {
|
694 | observer.complete?.();
|
695 | } catch (err) {
|
696 | reportUnhandledError(err);
|
697 | }
|
698 | break;
|
699 | case 'error':
|
700 | {
|
701 | const err = this._snapshot.error;
|
702 | if (!observer.error) {
|
703 | reportUnhandledError(err);
|
704 | } else {
|
705 | try {
|
706 | observer.error(err);
|
707 | } catch (err) {
|
708 | reportUnhandledError(err);
|
709 | }
|
710 | }
|
711 | break;
|
712 | }
|
713 | }
|
714 | }
|
715 | return {
|
716 | unsubscribe: () => {
|
717 | this.observers.delete(observer);
|
718 | }
|
719 | };
|
720 | }
|
721 | on(type, handler) {
|
722 | let listeners = this.eventListeners.get(type);
|
723 | if (!listeners) {
|
724 | listeners = new Set();
|
725 | this.eventListeners.set(type, listeners);
|
726 | }
|
727 | const wrappedHandler = handler.bind(undefined);
|
728 | listeners.add(wrappedHandler);
|
729 | return {
|
730 | unsubscribe: () => {
|
731 | listeners.delete(wrappedHandler);
|
732 | }
|
733 | };
|
734 | }
|
735 |
|
736 | |
737 |
|
738 |
|
739 | start() {
|
740 | if (this._processingStatus === ProcessingStatus.Running) {
|
741 |
|
742 | return this;
|
743 | }
|
744 | if (this._syncSnapshot) {
|
745 | this.subscribe({
|
746 | next: snapshot => {
|
747 | if (snapshot.status === 'active') {
|
748 | this.system._relay(this, this._parent, {
|
749 | type: `xstate.snapshot.${this.id}`,
|
750 | snapshot
|
751 | });
|
752 | }
|
753 | },
|
754 | error: () => {}
|
755 | });
|
756 | }
|
757 | this.system._register(this.sessionId, this);
|
758 | if (this._systemId) {
|
759 | this.system._set(this._systemId, this);
|
760 | }
|
761 | this._processingStatus = ProcessingStatus.Running;
|
762 |
|
763 |
|
764 | const initEvent = createInitEvent(this.options.input);
|
765 | this.system._sendInspectionEvent({
|
766 | type: '@xstate.event',
|
767 | sourceRef: this._parent,
|
768 | actorRef: this,
|
769 | event: initEvent
|
770 | });
|
771 | const status = this._snapshot.status;
|
772 | switch (status) {
|
773 | case 'done':
|
774 |
|
775 |
|
776 | this.update(this._snapshot, initEvent);
|
777 |
|
778 | return this;
|
779 | case 'error':
|
780 | this._error(this._snapshot.error);
|
781 | return this;
|
782 | }
|
783 | if (!this._parent) {
|
784 | this.system.start();
|
785 | }
|
786 | if (this.logic.start) {
|
787 | try {
|
788 | this.logic.start(this._snapshot, this._actorScope);
|
789 | } catch (err) {
|
790 | this._snapshot = {
|
791 | ...this._snapshot,
|
792 | status: 'error',
|
793 | error: err
|
794 | };
|
795 | this._error(err);
|
796 | return this;
|
797 | }
|
798 | }
|
799 |
|
800 |
|
801 |
|
802 |
|
803 | this.update(this._snapshot, initEvent);
|
804 | if (this.options.devTools) {
|
805 | this.attachDevTools();
|
806 | }
|
807 | this.mailbox.start();
|
808 | return this;
|
809 | }
|
810 | _process(event) {
|
811 | let nextState;
|
812 | let caughtError;
|
813 | try {
|
814 | nextState = this.logic.transition(this._snapshot, event, this._actorScope);
|
815 | } catch (err) {
|
816 |
|
817 | caughtError = {
|
818 | err
|
819 | };
|
820 | }
|
821 | if (caughtError) {
|
822 | const {
|
823 | err
|
824 | } = caughtError;
|
825 | this._snapshot = {
|
826 | ...this._snapshot,
|
827 | status: 'error',
|
828 | error: err
|
829 | };
|
830 | this._error(err);
|
831 | return;
|
832 | }
|
833 | this.update(nextState, event);
|
834 | if (event.type === XSTATE_STOP) {
|
835 | this._stopProcedure();
|
836 | this._complete();
|
837 | }
|
838 | }
|
839 | _stop() {
|
840 | if (this._processingStatus === ProcessingStatus.Stopped) {
|
841 | return this;
|
842 | }
|
843 | this.mailbox.clear();
|
844 | if (this._processingStatus === ProcessingStatus.NotStarted) {
|
845 | this._processingStatus = ProcessingStatus.Stopped;
|
846 | return this;
|
847 | }
|
848 | this.mailbox.enqueue({
|
849 | type: XSTATE_STOP
|
850 | });
|
851 | return this;
|
852 | }
|
853 |
|
854 | |
855 |
|
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 | try {
|
866 | observer.complete?.();
|
867 | } catch (err) {
|
868 | reportUnhandledError(err);
|
869 | }
|
870 | }
|
871 | this.observers.clear();
|
872 | }
|
873 | _reportError(err) {
|
874 | if (!this.observers.size) {
|
875 | if (!this._parent) {
|
876 | reportUnhandledError(err);
|
877 | }
|
878 | return;
|
879 | }
|
880 | let reportError = false;
|
881 | for (const observer of this.observers) {
|
882 | const errorListener = observer.error;
|
883 | reportError ||= !errorListener;
|
884 | try {
|
885 | errorListener?.(err);
|
886 | } catch (err2) {
|
887 | reportUnhandledError(err2);
|
888 | }
|
889 | }
|
890 | this.observers.clear();
|
891 | if (reportError) {
|
892 | reportUnhandledError(err);
|
893 | }
|
894 | }
|
895 | _error(err) {
|
896 | this._stopProcedure();
|
897 | this._reportError(err);
|
898 | if (this._parent) {
|
899 | this.system._relay(this, this._parent, createErrorActorEvent(this.id, err));
|
900 | }
|
901 | }
|
902 |
|
903 |
|
904 |
|
905 |
|
906 |
|
907 | _stopProcedure() {
|
908 | if (this._processingStatus !== ProcessingStatus.Running) {
|
909 |
|
910 | return this;
|
911 | }
|
912 |
|
913 |
|
914 | this.system.scheduler.cancelAll(this);
|
915 |
|
916 |
|
917 | this.mailbox.clear();
|
918 |
|
919 |
|
920 |
|
921 |
|
922 | this.mailbox = new Mailbox(this._process.bind(this));
|
923 | this._processingStatus = ProcessingStatus.Stopped;
|
924 | this.system._unregister(this);
|
925 | return this;
|
926 | }
|
927 |
|
928 | |
929 |
|
930 |
|
931 | _send(event) {
|
932 | if (this._processingStatus === ProcessingStatus.Stopped) {
|
933 | return;
|
934 | }
|
935 | this.mailbox.enqueue(event);
|
936 | }
|
937 |
|
938 | |
939 |
|
940 |
|
941 |
|
942 |
|
943 | send(event) {
|
944 | this.system._relay(undefined, this, event);
|
945 | }
|
946 | attachDevTools() {
|
947 | const {
|
948 | devTools
|
949 | } = this.options;
|
950 | if (devTools) {
|
951 | const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : dev_dist_xstateDev.devToolsAdapter;
|
952 | resolvedDevToolsAdapter(this);
|
953 | }
|
954 | }
|
955 | toJSON() {
|
956 | return {
|
957 | xstate$$type: $$ACTOR_TYPE,
|
958 | id: this.id
|
959 | };
|
960 | }
|
961 |
|
962 | |
963 |
|
964 |
|
965 |
|
966 |
|
967 |
|
968 |
|
969 |
|
970 |
|
971 |
|
972 |
|
973 |
|
974 |
|
975 | getPersistedSnapshot(options) {
|
976 | return this.logic.getPersistedSnapshot(this._snapshot, options);
|
977 | }
|
978 | [symbolObservable]() {
|
979 | return this;
|
980 | }
|
981 |
|
982 | |
983 |
|
984 |
|
985 |
|
986 |
|
987 |
|
988 |
|
989 |
|
990 |
|
991 |
|
992 |
|
993 |
|
994 |
|
995 |
|
996 | getSnapshot() {
|
997 | return this._snapshot;
|
998 | }
|
999 | }
|
1000 |
|
1001 |
|
1002 |
|
1003 |
|
1004 |
|
1005 |
|
1006 |
|
1007 |
|
1008 |
|
1009 |
|
1010 |
|
1011 |
|
1012 |
|
1013 |
|
1014 |
|
1015 |
|
1016 |
|
1017 |
|
1018 |
|
1019 |
|
1020 |
|
1021 |
|
1022 |
|
1023 |
|
1024 |
|
1025 |
|
1026 |
|
1027 |
|
1028 |
|
1029 |
|
1030 |
|
1031 |
|
1032 | function createActor(logic, ...[options]) {
|
1033 | return new Actor(logic, options);
|
1034 | }
|
1035 |
|
1036 |
|
1037 |
|
1038 |
|
1039 |
|
1040 |
|
1041 | const interpret = createActor;
|
1042 |
|
1043 |
|
1044 |
|
1045 |
|
1046 |
|
1047 | function resolveCancel(_, snapshot, actionArgs, actionParams, {
|
1048 | sendId
|
1049 | }) {
|
1050 | const resolvedSendId = typeof sendId === 'function' ? sendId(actionArgs, actionParams) : sendId;
|
1051 | return [snapshot, resolvedSendId];
|
1052 | }
|
1053 | function executeCancel(actorScope, resolvedSendId) {
|
1054 | actorScope.defer(() => {
|
1055 | actorScope.system.scheduler.cancel(actorScope.self, resolvedSendId);
|
1056 | });
|
1057 | }
|
1058 |
|
1059 |
|
1060 |
|
1061 |
|
1062 |
|
1063 |
|
1064 |
|
1065 |
|
1066 |
|
1067 |
|
1068 |
|
1069 |
|
1070 |
|
1071 |
|
1072 |
|
1073 |
|
1074 |
|
1075 |
|
1076 |
|
1077 |
|
1078 |
|
1079 |
|
1080 |
|
1081 |
|
1082 |
|
1083 |
|
1084 | function cancel(sendId) {
|
1085 | function cancel(args, params) {
|
1086 | }
|
1087 | cancel.type = 'xstate.cancel';
|
1088 | cancel.sendId = sendId;
|
1089 | cancel.resolve = resolveCancel;
|
1090 | cancel.execute = executeCancel;
|
1091 | return cancel;
|
1092 | }
|
1093 |
|
1094 | function resolveSpawn(actorScope, snapshot, actionArgs, _actionParams, {
|
1095 | id,
|
1096 | systemId,
|
1097 | src,
|
1098 | input,
|
1099 | syncSnapshot
|
1100 | }) {
|
1101 | const logic = typeof src === 'string' ? resolveReferencedActor(snapshot.machine, src) : src;
|
1102 | const resolvedId = typeof id === 'function' ? id(actionArgs) : id;
|
1103 | let actorRef;
|
1104 | if (logic) {
|
1105 | actorRef = createActor(logic, {
|
1106 | id: resolvedId,
|
1107 | src,
|
1108 | parent: actorScope.self,
|
1109 | syncSnapshot,
|
1110 | systemId,
|
1111 | input: typeof input === 'function' ? input({
|
1112 | context: snapshot.context,
|
1113 | event: actionArgs.event,
|
1114 | self: actorScope.self
|
1115 | }) : input
|
1116 | });
|
1117 | }
|
1118 | return [cloneMachineSnapshot(snapshot, {
|
1119 | children: {
|
1120 | ...snapshot.children,
|
1121 | [resolvedId]: actorRef
|
1122 | }
|
1123 | }), {
|
1124 | id,
|
1125 | actorRef
|
1126 | }];
|
1127 | }
|
1128 | function executeSpawn(actorScope, {
|
1129 | id,
|
1130 | actorRef
|
1131 | }) {
|
1132 | if (!actorRef) {
|
1133 | return;
|
1134 | }
|
1135 | actorScope.defer(() => {
|
1136 | if (actorRef._processingStatus === ProcessingStatus.Stopped) {
|
1137 | return;
|
1138 | }
|
1139 | actorRef.start();
|
1140 | });
|
1141 | }
|
1142 | function spawnChild(...[src, {
|
1143 | id,
|
1144 | systemId,
|
1145 | input,
|
1146 | syncSnapshot = false
|
1147 | } = {}]) {
|
1148 | function spawnChild(args, params) {
|
1149 | }
|
1150 | spawnChild.type = 'snapshot.spawnChild';
|
1151 | spawnChild.id = id;
|
1152 | spawnChild.systemId = systemId;
|
1153 | spawnChild.src = src;
|
1154 | spawnChild.input = input;
|
1155 | spawnChild.syncSnapshot = syncSnapshot;
|
1156 | spawnChild.resolve = resolveSpawn;
|
1157 | spawnChild.execute = executeSpawn;
|
1158 | return spawnChild;
|
1159 | }
|
1160 |
|
1161 | function resolveStop(_, snapshot, args, actionParams, {
|
1162 | actorRef
|
1163 | }) {
|
1164 | const actorRefOrString = typeof actorRef === 'function' ? actorRef(args, actionParams) : actorRef;
|
1165 | const resolvedActorRef = typeof actorRefOrString === 'string' ? snapshot.children[actorRefOrString] : actorRefOrString;
|
1166 | let children = snapshot.children;
|
1167 | if (resolvedActorRef) {
|
1168 | children = {
|
1169 | ...children
|
1170 | };
|
1171 | delete children[resolvedActorRef.id];
|
1172 | }
|
1173 | return [cloneMachineSnapshot(snapshot, {
|
1174 | children
|
1175 | }), resolvedActorRef];
|
1176 | }
|
1177 | function executeStop(actorScope, actorRef) {
|
1178 | if (!actorRef) {
|
1179 | return;
|
1180 | }
|
1181 |
|
1182 |
|
1183 |
|
1184 |
|
1185 | actorScope.system._unregister(actorRef);
|
1186 |
|
1187 |
|
1188 |
|
1189 | if (actorRef._processingStatus !== ProcessingStatus.Running) {
|
1190 | actorScope.stopChild(actorRef);
|
1191 | return;
|
1192 | }
|
1193 |
|
1194 |
|
1195 |
|
1196 |
|
1197 | actorScope.defer(() => {
|
1198 | actorScope.stopChild(actorRef);
|
1199 | });
|
1200 | }
|
1201 |
|
1202 |
|
1203 |
|
1204 |
|
1205 |
|
1206 | function stopChild(actorRef) {
|
1207 | function stop(args, params) {
|
1208 | }
|
1209 | stop.type = 'xstate.stopChild';
|
1210 | stop.actorRef = actorRef;
|
1211 | stop.resolve = resolveStop;
|
1212 | stop.execute = executeStop;
|
1213 | return stop;
|
1214 | }
|
1215 |
|
1216 |
|
1217 |
|
1218 |
|
1219 |
|
1220 |
|
1221 | const stop = stopChild;
|
1222 |
|
1223 | function checkStateIn(snapshot, _, {
|
1224 | stateValue
|
1225 | }) {
|
1226 | if (typeof stateValue === 'string' && isStateId(stateValue)) {
|
1227 | const target = snapshot.machine.getStateNodeById(stateValue);
|
1228 | return snapshot._nodes.some(sn => sn === target);
|
1229 | }
|
1230 | return snapshot.matches(stateValue);
|
1231 | }
|
1232 | function stateIn(stateValue) {
|
1233 | function stateIn(args, params) {
|
1234 | return false;
|
1235 | }
|
1236 | stateIn.check = checkStateIn;
|
1237 | stateIn.stateValue = stateValue;
|
1238 | return stateIn;
|
1239 | }
|
1240 | function checkNot(snapshot, {
|
1241 | context,
|
1242 | event
|
1243 | }, {
|
1244 | guards
|
1245 | }) {
|
1246 | return !evaluateGuard(guards[0], context, event, snapshot);
|
1247 | }
|
1248 |
|
1249 |
|
1250 |
|
1251 |
|
1252 |
|
1253 |
|
1254 |
|
1255 |
|
1256 |
|
1257 |
|
1258 |
|
1259 |
|
1260 |
|
1261 |
|
1262 |
|
1263 |
|
1264 |
|
1265 |
|
1266 |
|
1267 |
|
1268 |
|
1269 |
|
1270 |
|
1271 |
|
1272 |
|
1273 |
|
1274 |
|
1275 | function not(guard) {
|
1276 | function not(args, params) {
|
1277 | return false;
|
1278 | }
|
1279 | not.check = checkNot;
|
1280 | not.guards = [guard];
|
1281 | return not;
|
1282 | }
|
1283 | function checkAnd(snapshot, {
|
1284 | context,
|
1285 | event
|
1286 | }, {
|
1287 | guards
|
1288 | }) {
|
1289 | return guards.every(guard => evaluateGuard(guard, context, event, snapshot));
|
1290 | }
|
1291 |
|
1292 |
|
1293 |
|
1294 |
|
1295 |
|
1296 |
|
1297 |
|
1298 |
|
1299 |
|
1300 |
|
1301 |
|
1302 |
|
1303 |
|
1304 |
|
1305 |
|
1306 |
|
1307 |
|
1308 |
|
1309 |
|
1310 |
|
1311 |
|
1312 |
|
1313 |
|
1314 |
|
1315 |
|
1316 |
|
1317 |
|
1318 |
|
1319 |
|
1320 |
|
1321 |
|
1322 | function and(guards) {
|
1323 | function and(args, params) {
|
1324 | return false;
|
1325 | }
|
1326 | and.check = checkAnd;
|
1327 | and.guards = guards;
|
1328 | return and;
|
1329 | }
|
1330 | function checkOr(snapshot, {
|
1331 | context,
|
1332 | event
|
1333 | }, {
|
1334 | guards
|
1335 | }) {
|
1336 | return guards.some(guard => evaluateGuard(guard, context, event, snapshot));
|
1337 | }
|
1338 |
|
1339 |
|
1340 |
|
1341 |
|
1342 |
|
1343 |
|
1344 |
|
1345 |
|
1346 |
|
1347 |
|
1348 |
|
1349 |
|
1350 |
|
1351 |
|
1352 |
|
1353 |
|
1354 |
|
1355 |
|
1356 |
|
1357 |
|
1358 |
|
1359 |
|
1360 |
|
1361 |
|
1362 |
|
1363 |
|
1364 |
|
1365 |
|
1366 |
|
1367 |
|
1368 |
|
1369 | function or(guards) {
|
1370 | function or(args, params) {
|
1371 | return false;
|
1372 | }
|
1373 | or.check = checkOr;
|
1374 | or.guards = guards;
|
1375 | return or;
|
1376 | }
|
1377 |
|
1378 |
|
1379 | function evaluateGuard(guard, context, event, snapshot) {
|
1380 | const {
|
1381 | machine
|
1382 | } = snapshot;
|
1383 | const isInline = typeof guard === 'function';
|
1384 | const resolved = isInline ? guard : machine.implementations.guards[typeof guard === 'string' ? guard : guard.type];
|
1385 | if (!isInline && !resolved) {
|
1386 | throw new Error(`Guard '${typeof guard === 'string' ? guard : guard.type}' is not implemented.'.`);
|
1387 | }
|
1388 | if (typeof resolved !== 'function') {
|
1389 | return evaluateGuard(resolved, context, event, snapshot);
|
1390 | }
|
1391 | const guardArgs = {
|
1392 | context,
|
1393 | event
|
1394 | };
|
1395 | const guardParams = isInline || typeof guard === 'string' ? undefined : 'params' in guard ? typeof guard.params === 'function' ? guard.params({
|
1396 | context,
|
1397 | event
|
1398 | }) : guard.params : undefined;
|
1399 | if (!('check' in resolved)) {
|
1400 |
|
1401 |
|
1402 |
|
1403 | return resolved(guardArgs, guardParams);
|
1404 | }
|
1405 | const builtinGuard = resolved;
|
1406 | return builtinGuard.check(snapshot, guardArgs, resolved
|
1407 | );
|
1408 | }
|
1409 |
|
1410 | const isAtomicStateNode = stateNode => stateNode.type === 'atomic' || stateNode.type === 'final';
|
1411 | function getChildren(stateNode) {
|
1412 | return Object.values(stateNode.states).filter(sn => sn.type !== 'history');
|
1413 | }
|
1414 | function getProperAncestors(stateNode, toStateNode) {
|
1415 | const ancestors = [];
|
1416 | if (toStateNode === stateNode) {
|
1417 | return ancestors;
|
1418 | }
|
1419 |
|
1420 |
|
1421 | let m = stateNode.parent;
|
1422 | while (m && m !== toStateNode) {
|
1423 | ancestors.push(m);
|
1424 | m = m.parent;
|
1425 | }
|
1426 | return ancestors;
|
1427 | }
|
1428 | function getAllStateNodes(stateNodes) {
|
1429 | const nodeSet = new Set(stateNodes);
|
1430 | const adjList = getAdjList(nodeSet);
|
1431 |
|
1432 |
|
1433 | for (const s of nodeSet) {
|
1434 |
|
1435 | if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) {
|
1436 | getInitialStateNodesWithTheirAncestors(s).forEach(sn => nodeSet.add(sn));
|
1437 | } else {
|
1438 | if (s.type === 'parallel') {
|
1439 | for (const child of getChildren(s)) {
|
1440 | if (child.type === 'history') {
|
1441 | continue;
|
1442 | }
|
1443 | if (!nodeSet.has(child)) {
|
1444 | const initialStates = getInitialStateNodesWithTheirAncestors(child);
|
1445 | for (const initialStateNode of initialStates) {
|
1446 | nodeSet.add(initialStateNode);
|
1447 | }
|
1448 | }
|
1449 | }
|
1450 | }
|
1451 | }
|
1452 | }
|
1453 |
|
1454 |
|
1455 | for (const s of nodeSet) {
|
1456 | let m = s.parent;
|
1457 | while (m) {
|
1458 | nodeSet.add(m);
|
1459 | m = m.parent;
|
1460 | }
|
1461 | }
|
1462 | return nodeSet;
|
1463 | }
|
1464 | function getValueFromAdj(baseNode, adjList) {
|
1465 | const childStateNodes = adjList.get(baseNode);
|
1466 | if (!childStateNodes) {
|
1467 | return {};
|
1468 | }
|
1469 |
|
1470 | if (baseNode.type === 'compound') {
|
1471 | const childStateNode = childStateNodes[0];
|
1472 | if (childStateNode) {
|
1473 | if (isAtomicStateNode(childStateNode)) {
|
1474 | return childStateNode.key;
|
1475 | }
|
1476 | } else {
|
1477 | return {};
|
1478 | }
|
1479 | }
|
1480 | const stateValue = {};
|
1481 | for (const childStateNode of childStateNodes) {
|
1482 | stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList);
|
1483 | }
|
1484 | return stateValue;
|
1485 | }
|
1486 | function getAdjList(stateNodes) {
|
1487 | const adjList = new Map();
|
1488 | for (const s of stateNodes) {
|
1489 | if (!adjList.has(s)) {
|
1490 | adjList.set(s, []);
|
1491 | }
|
1492 | if (s.parent) {
|
1493 | if (!adjList.has(s.parent)) {
|
1494 | adjList.set(s.parent, []);
|
1495 | }
|
1496 | adjList.get(s.parent).push(s);
|
1497 | }
|
1498 | }
|
1499 | return adjList;
|
1500 | }
|
1501 | function getStateValue(rootNode, stateNodes) {
|
1502 | const config = getAllStateNodes(stateNodes);
|
1503 | return getValueFromAdj(rootNode, getAdjList(config));
|
1504 | }
|
1505 | function isInFinalState(stateNodeSet, stateNode) {
|
1506 | if (stateNode.type === 'compound') {
|
1507 | return getChildren(stateNode).some(s => s.type === 'final' && stateNodeSet.has(s));
|
1508 | }
|
1509 | if (stateNode.type === 'parallel') {
|
1510 | return getChildren(stateNode).every(sn => isInFinalState(stateNodeSet, sn));
|
1511 | }
|
1512 | return stateNode.type === 'final';
|
1513 | }
|
1514 | const isStateId = str => str[0] === STATE_IDENTIFIER;
|
1515 | function getCandidates(stateNode, receivedEventType) {
|
1516 | const candidates = stateNode.transitions.get(receivedEventType) || [...stateNode.transitions.keys()].filter(eventDescriptor => {
|
1517 |
|
1518 |
|
1519 | if (eventDescriptor === WILDCARD) {
|
1520 | return true;
|
1521 | }
|
1522 | if (!eventDescriptor.endsWith('.*')) {
|
1523 | return false;
|
1524 | }
|
1525 | const partialEventTokens = eventDescriptor.split('.');
|
1526 | const eventTokens = receivedEventType.split('.');
|
1527 | for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
|
1528 | const partialEventToken = partialEventTokens[tokenIndex];
|
1529 | const eventToken = eventTokens[tokenIndex];
|
1530 | if (partialEventToken === '*') {
|
1531 | const isLastToken = tokenIndex === partialEventTokens.length - 1;
|
1532 | return isLastToken;
|
1533 | }
|
1534 | if (partialEventToken !== eventToken) {
|
1535 | return false;
|
1536 | }
|
1537 | }
|
1538 | return true;
|
1539 | }).sort((a, b) => b.length - a.length).flatMap(key => stateNode.transitions.get(key));
|
1540 | return candidates;
|
1541 | }
|
1542 |
|
1543 |
|
1544 |
|
1545 |
|
1546 | function getDelayedTransitions(stateNode) {
|
1547 | const afterConfig = stateNode.config.after;
|
1548 | if (!afterConfig) {
|
1549 | return [];
|
1550 | }
|
1551 | const mutateEntryExit = (delay, i) => {
|
1552 | const afterEvent = createAfterEvent(delay, stateNode.id);
|
1553 | const eventType = afterEvent.type;
|
1554 | stateNode.entry.push(raise(afterEvent, {
|
1555 | id: eventType,
|
1556 | delay
|
1557 | }));
|
1558 | stateNode.exit.push(cancel(eventType));
|
1559 | return eventType;
|
1560 | };
|
1561 | const delayedTransitions = Object.keys(afterConfig).flatMap((delay, i) => {
|
1562 | const configTransition = afterConfig[delay];
|
1563 | const resolvedTransition = typeof configTransition === 'string' ? {
|
1564 | target: configTransition
|
1565 | } : configTransition;
|
1566 | const resolvedDelay = Number.isNaN(+delay) ? delay : +delay;
|
1567 | const eventType = mutateEntryExit(resolvedDelay);
|
1568 | return toArray(resolvedTransition).map(transition => ({
|
1569 | ...transition,
|
1570 | event: eventType,
|
1571 | delay: resolvedDelay
|
1572 | }));
|
1573 | });
|
1574 | return delayedTransitions.map(delayedTransition => {
|
1575 | const {
|
1576 | delay
|
1577 | } = delayedTransition;
|
1578 | return {
|
1579 | ...formatTransition(stateNode, delayedTransition.event, delayedTransition),
|
1580 | delay
|
1581 | };
|
1582 | });
|
1583 | }
|
1584 | function formatTransition(stateNode, descriptor, transitionConfig) {
|
1585 | const normalizedTarget = normalizeTarget(transitionConfig.target);
|
1586 | const reenter = transitionConfig.reenter ?? false;
|
1587 | const target = resolveTarget(stateNode, normalizedTarget);
|
1588 | const transition = {
|
1589 | ...transitionConfig,
|
1590 | actions: toArray(transitionConfig.actions),
|
1591 | guard: transitionConfig.guard,
|
1592 | target,
|
1593 | source: stateNode,
|
1594 | reenter,
|
1595 | eventType: descriptor,
|
1596 | toJSON: () => ({
|
1597 | ...transition,
|
1598 | source: `#${stateNode.id}`,
|
1599 | target: target ? target.map(t => `#${t.id}`) : undefined
|
1600 | })
|
1601 | };
|
1602 | return transition;
|
1603 | }
|
1604 | function formatTransitions(stateNode) {
|
1605 | const transitions = new Map();
|
1606 | if (stateNode.config.on) {
|
1607 | for (const descriptor of Object.keys(stateNode.config.on)) {
|
1608 | if (descriptor === NULL_EVENT) {
|
1609 | throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.');
|
1610 | }
|
1611 | const transitionsConfig = stateNode.config.on[descriptor];
|
1612 | transitions.set(descriptor, toTransitionConfigArray(transitionsConfig).map(t => formatTransition(stateNode, descriptor, t)));
|
1613 | }
|
1614 | }
|
1615 | if (stateNode.config.onDone) {
|
1616 | const descriptor = `xstate.done.state.${stateNode.id}`;
|
1617 | transitions.set(descriptor, toTransitionConfigArray(stateNode.config.onDone).map(t => formatTransition(stateNode, descriptor, t)));
|
1618 | }
|
1619 | for (const invokeDef of stateNode.invoke) {
|
1620 | if (invokeDef.onDone) {
|
1621 | const descriptor = `xstate.done.actor.${invokeDef.id}`;
|
1622 | transitions.set(descriptor, toTransitionConfigArray(invokeDef.onDone).map(t => formatTransition(stateNode, descriptor, t)));
|
1623 | }
|
1624 | if (invokeDef.onError) {
|
1625 | const descriptor = `xstate.error.actor.${invokeDef.id}`;
|
1626 | transitions.set(descriptor, toTransitionConfigArray(invokeDef.onError).map(t => formatTransition(stateNode, descriptor, t)));
|
1627 | }
|
1628 | if (invokeDef.onSnapshot) {
|
1629 | const descriptor = `xstate.snapshot.${invokeDef.id}`;
|
1630 | transitions.set(descriptor, toTransitionConfigArray(invokeDef.onSnapshot).map(t => formatTransition(stateNode, descriptor, t)));
|
1631 | }
|
1632 | }
|
1633 | for (const delayedTransition of stateNode.after) {
|
1634 | let existing = transitions.get(delayedTransition.eventType);
|
1635 | if (!existing) {
|
1636 | existing = [];
|
1637 | transitions.set(delayedTransition.eventType, existing);
|
1638 | }
|
1639 | existing.push(delayedTransition);
|
1640 | }
|
1641 | return transitions;
|
1642 | }
|
1643 | function formatInitialTransition(stateNode, _target) {
|
1644 | const resolvedTarget = typeof _target === 'string' ? stateNode.states[_target] : _target ? stateNode.states[_target.target] : undefined;
|
1645 | if (!resolvedTarget && _target) {
|
1646 | throw new Error(`Initial state node "${_target}" not found on parent state node #${stateNode.id}`);
|
1647 | }
|
1648 | const transition = {
|
1649 | source: stateNode,
|
1650 | actions: !_target || typeof _target === 'string' ? [] : toArray(_target.actions),
|
1651 | eventType: null,
|
1652 | reenter: false,
|
1653 | target: resolvedTarget ? [resolvedTarget] : [],
|
1654 | toJSON: () => ({
|
1655 | ...transition,
|
1656 | source: `#${stateNode.id}`,
|
1657 | target: resolvedTarget ? [`#${resolvedTarget.id}`] : []
|
1658 | })
|
1659 | };
|
1660 | return transition;
|
1661 | }
|
1662 | function resolveTarget(stateNode, targets) {
|
1663 | if (targets === undefined) {
|
1664 |
|
1665 | return undefined;
|
1666 | }
|
1667 | return targets.map(target => {
|
1668 | if (typeof target !== 'string') {
|
1669 | return target;
|
1670 | }
|
1671 | if (isStateId(target)) {
|
1672 | return stateNode.machine.getStateNodeById(target);
|
1673 | }
|
1674 | const isInternalTarget = target[0] === STATE_DELIMITER;
|
1675 |
|
1676 |
|
1677 | if (isInternalTarget && !stateNode.parent) {
|
1678 | return getStateNodeByPath(stateNode, target.slice(1));
|
1679 | }
|
1680 | const resolvedTarget = isInternalTarget ? stateNode.key + target : target;
|
1681 | if (stateNode.parent) {
|
1682 | try {
|
1683 | const targetStateNode = getStateNodeByPath(stateNode.parent, resolvedTarget);
|
1684 | return targetStateNode;
|
1685 | } catch (err) {
|
1686 | throw new Error(`Invalid transition definition for state node '${stateNode.id}':\n${err.message}`);
|
1687 | }
|
1688 | } else {
|
1689 | throw new Error(`Invalid target: "${target}" is not a valid target from the root node. Did you mean ".${target}"?`);
|
1690 | }
|
1691 | });
|
1692 | }
|
1693 | function resolveHistoryDefaultTransition(stateNode) {
|
1694 | const normalizedTarget = normalizeTarget(stateNode.config.target);
|
1695 | if (!normalizedTarget) {
|
1696 | return stateNode.parent.initial;
|
1697 | }
|
1698 | return {
|
1699 | target: normalizedTarget.map(t => typeof t === 'string' ? getStateNodeByPath(stateNode.parent, t) : t)
|
1700 | };
|
1701 | }
|
1702 | function isHistoryNode(stateNode) {
|
1703 | return stateNode.type === 'history';
|
1704 | }
|
1705 | function getInitialStateNodesWithTheirAncestors(stateNode) {
|
1706 | const states = getInitialStateNodes(stateNode);
|
1707 | for (const initialState of states) {
|
1708 | for (const ancestor of getProperAncestors(initialState, stateNode)) {
|
1709 | states.add(ancestor);
|
1710 | }
|
1711 | }
|
1712 | return states;
|
1713 | }
|
1714 | function getInitialStateNodes(stateNode) {
|
1715 | const set = new Set();
|
1716 | function iter(descStateNode) {
|
1717 | if (set.has(descStateNode)) {
|
1718 | return;
|
1719 | }
|
1720 | set.add(descStateNode);
|
1721 | if (descStateNode.type === 'compound') {
|
1722 | iter(descStateNode.initial.target[0]);
|
1723 | } else if (descStateNode.type === 'parallel') {
|
1724 | for (const child of getChildren(descStateNode)) {
|
1725 | iter(child);
|
1726 | }
|
1727 | }
|
1728 | }
|
1729 | iter(stateNode);
|
1730 | return set;
|
1731 | }
|
1732 | /**
|
1733 | * Returns the child state node from its relative `stateKey`, or throws.
|
1734 | */
|
1735 | function getStateNode(stateNode, stateKey) {
|
1736 | if (isStateId(stateKey)) {
|
1737 | return stateNode.machine.getStateNodeById(stateKey);
|
1738 | }
|
1739 | if (!stateNode.states) {
|
1740 | throw new Error(`Unable to retrieve child state '${stateKey}' from '${stateNode.id}'; no child states exist.`);
|
1741 | }
|
1742 | const result = stateNode.states[stateKey];
|
1743 | if (!result) {
|
1744 | throw new Error(`Child state '${stateKey}' does not exist on '${stateNode.id}'`);
|
1745 | }
|
1746 | return result;
|
1747 | }
|
1748 |
|
1749 |
|
1750 |
|
1751 |
|
1752 |
|
1753 |
|
1754 | function getStateNodeByPath(stateNode, statePath) {
|
1755 | if (typeof statePath === 'string' && isStateId(statePath)) {
|
1756 | try {
|
1757 | return stateNode.machine.getStateNodeById(statePath);
|
1758 | } catch (e) {
|
1759 |
|
1760 |
|
1761 | }
|
1762 | }
|
1763 | const arrayStatePath = toStatePath(statePath).slice();
|
1764 | let currentStateNode = stateNode;
|
1765 | while (arrayStatePath.length) {
|
1766 | const key = arrayStatePath.shift();
|
1767 | if (!key.length) {
|
1768 | break;
|
1769 | }
|
1770 | currentStateNode = getStateNode(currentStateNode, key);
|
1771 | }
|
1772 | return currentStateNode;
|
1773 | }
|
1774 |
|
1775 |
|
1776 |
|
1777 |
|
1778 |
|
1779 |
|
1780 | function getStateNodes(stateNode, stateValue) {
|
1781 | if (typeof stateValue === 'string') {
|
1782 | const childStateNode = stateNode.states[stateValue];
|
1783 | if (!childStateNode) {
|
1784 | throw new Error(`State '${stateValue}' does not exist on '${stateNode.id}'`);
|
1785 | }
|
1786 | return [stateNode, childStateNode];
|
1787 | }
|
1788 | const childStateKeys = Object.keys(stateValue);
|
1789 | const childStateNodes = childStateKeys.map(subStateKey => getStateNode(stateNode, subStateKey)).filter(Boolean);
|
1790 | return [stateNode.machine.root, stateNode].concat(childStateNodes, childStateKeys.reduce((allSubStateNodes, subStateKey) => {
|
1791 | const subStateNode = getStateNode(stateNode, subStateKey);
|
1792 | if (!subStateNode) {
|
1793 | return allSubStateNodes;
|
1794 | }
|
1795 | const subStateNodes = getStateNodes(subStateNode, stateValue[subStateKey]);
|
1796 | return allSubStateNodes.concat(subStateNodes);
|
1797 | }, []));
|
1798 | }
|
1799 | function transitionAtomicNode(stateNode, stateValue, snapshot, event) {
|
1800 | const childStateNode = getStateNode(stateNode, stateValue);
|
1801 | const next = childStateNode.next(snapshot, event);
|
1802 | if (!next || !next.length) {
|
1803 | return stateNode.next(snapshot, event);
|
1804 | }
|
1805 | return next;
|
1806 | }
|
1807 | function transitionCompoundNode(stateNode, stateValue, snapshot, event) {
|
1808 | const subStateKeys = Object.keys(stateValue);
|
1809 | const childStateNode = getStateNode(stateNode, subStateKeys[0]);
|
1810 | const next = transitionNode(childStateNode, stateValue[subStateKeys[0]], snapshot, event);
|
1811 | if (!next || !next.length) {
|
1812 | return stateNode.next(snapshot, event);
|
1813 | }
|
1814 | return next;
|
1815 | }
|
1816 | function transitionParallelNode(stateNode, stateValue, snapshot, event) {
|
1817 | const allInnerTransitions = [];
|
1818 | for (const subStateKey of Object.keys(stateValue)) {
|
1819 | const subStateValue = stateValue[subStateKey];
|
1820 | if (!subStateValue) {
|
1821 | continue;
|
1822 | }
|
1823 | const subStateNode = getStateNode(stateNode, subStateKey);
|
1824 | const innerTransitions = transitionNode(subStateNode, subStateValue, snapshot, event);
|
1825 | if (innerTransitions) {
|
1826 | allInnerTransitions.push(...innerTransitions);
|
1827 | }
|
1828 | }
|
1829 | if (!allInnerTransitions.length) {
|
1830 | return stateNode.next(snapshot, event);
|
1831 | }
|
1832 | return allInnerTransitions;
|
1833 | }
|
1834 | function transitionNode(stateNode, stateValue, snapshot, event) {
|
1835 |
|
1836 | if (typeof stateValue === 'string') {
|
1837 | return transitionAtomicNode(stateNode, stateValue, snapshot, event);
|
1838 | }
|
1839 |
|
1840 |
|
1841 | if (Object.keys(stateValue).length === 1) {
|
1842 | return transitionCompoundNode(stateNode, stateValue, snapshot, event);
|
1843 | }
|
1844 |
|
1845 |
|
1846 | return transitionParallelNode(stateNode, stateValue, snapshot, event);
|
1847 | }
|
1848 | function getHistoryNodes(stateNode) {
|
1849 | return Object.keys(stateNode.states).map(key => stateNode.states[key]).filter(sn => sn.type === 'history');
|
1850 | }
|
1851 | function isDescendant(childStateNode, parentStateNode) {
|
1852 | let marker = childStateNode;
|
1853 | while (marker.parent && marker.parent !== parentStateNode) {
|
1854 | marker = marker.parent;
|
1855 | }
|
1856 | return marker.parent === parentStateNode;
|
1857 | }
|
1858 | function hasIntersection(s1, s2) {
|
1859 | const set1 = new Set(s1);
|
1860 | const set2 = new Set(s2);
|
1861 | for (const item of set1) {
|
1862 | if (set2.has(item)) {
|
1863 | return true;
|
1864 | }
|
1865 | }
|
1866 | for (const item of set2) {
|
1867 | if (set1.has(item)) {
|
1868 | return true;
|
1869 | }
|
1870 | }
|
1871 | return false;
|
1872 | }
|
1873 | function removeConflictingTransitions(enabledTransitions, stateNodeSet, historyValue) {
|
1874 | const filteredTransitions = new Set();
|
1875 | for (const t1 of enabledTransitions) {
|
1876 | let t1Preempted = false;
|
1877 | const transitionsToRemove = new Set();
|
1878 | for (const t2 of filteredTransitions) {
|
1879 | if (hasIntersection(computeExitSet([t1], stateNodeSet, historyValue), computeExitSet([t2], stateNodeSet, historyValue))) {
|
1880 | if (isDescendant(t1.source, t2.source)) {
|
1881 | transitionsToRemove.add(t2);
|
1882 | } else {
|
1883 | t1Preempted = true;
|
1884 | break;
|
1885 | }
|
1886 | }
|
1887 | }
|
1888 | if (!t1Preempted) {
|
1889 | for (const t3 of transitionsToRemove) {
|
1890 | filteredTransitions.delete(t3);
|
1891 | }
|
1892 | filteredTransitions.add(t1);
|
1893 | }
|
1894 | }
|
1895 | return Array.from(filteredTransitions);
|
1896 | }
|
1897 | function findLeastCommonAncestor(stateNodes) {
|
1898 | const [head, ...tail] = stateNodes;
|
1899 | for (const ancestor of getProperAncestors(head, undefined)) {
|
1900 | if (tail.every(sn => isDescendant(sn, ancestor))) {
|
1901 | return ancestor;
|
1902 | }
|
1903 | }
|
1904 | }
|
1905 | function getEffectiveTargetStates(transition, historyValue) {
|
1906 | if (!transition.target) {
|
1907 | return [];
|
1908 | }
|
1909 | const targets = new Set();
|
1910 | for (const targetNode of transition.target) {
|
1911 | if (isHistoryNode(targetNode)) {
|
1912 | if (historyValue[targetNode.id]) {
|
1913 | for (const node of historyValue[targetNode.id]) {
|
1914 | targets.add(node);
|
1915 | }
|
1916 | } else {
|
1917 | for (const node of getEffectiveTargetStates(resolveHistoryDefaultTransition(targetNode), historyValue)) {
|
1918 | targets.add(node);
|
1919 | }
|
1920 | }
|
1921 | } else {
|
1922 | targets.add(targetNode);
|
1923 | }
|
1924 | }
|
1925 | return [...targets];
|
1926 | }
|
1927 | function getTransitionDomain(transition, historyValue) {
|
1928 | const targetStates = getEffectiveTargetStates(transition, historyValue);
|
1929 | if (!targetStates) {
|
1930 | return;
|
1931 | }
|
1932 | if (!transition.reenter && targetStates.every(target => target === transition.source || isDescendant(target, transition.source))) {
|
1933 | return transition.source;
|
1934 | }
|
1935 | const lca = findLeastCommonAncestor(targetStates.concat(transition.source));
|
1936 | if (lca) {
|
1937 | return lca;
|
1938 | }
|
1939 |
|
1940 |
|
1941 | if (transition.reenter) {
|
1942 | return;
|
1943 | }
|
1944 | return transition.source.machine.root;
|
1945 | }
|
1946 | function computeExitSet(transitions, stateNodeSet, historyValue) {
|
1947 | const statesToExit = new Set();
|
1948 | for (const t of transitions) {
|
1949 | if (t.target?.length) {
|
1950 | const domain = getTransitionDomain(t, historyValue);
|
1951 | if (t.reenter && t.source === domain) {
|
1952 | statesToExit.add(domain);
|
1953 | }
|
1954 | for (const stateNode of stateNodeSet) {
|
1955 | if (isDescendant(stateNode, domain)) {
|
1956 | statesToExit.add(stateNode);
|
1957 | }
|
1958 | }
|
1959 | }
|
1960 | }
|
1961 | return [...statesToExit];
|
1962 | }
|
1963 | function areStateNodeCollectionsEqual(prevStateNodes, nextStateNodeSet) {
|
1964 | if (prevStateNodes.length !== nextStateNodeSet.size) {
|
1965 | return false;
|
1966 | }
|
1967 | for (const node of prevStateNodes) {
|
1968 | if (!nextStateNodeSet.has(node)) {
|
1969 | return false;
|
1970 | }
|
1971 | }
|
1972 | return true;
|
1973 | }
|
1974 |
|
1975 |
|
1976 |
|
1977 |
|
1978 | function microstep(transitions, currentSnapshot, actorScope, event, isInitial, internalQueue) {
|
1979 | if (!transitions.length) {
|
1980 | return currentSnapshot;
|
1981 | }
|
1982 | const mutStateNodeSet = new Set(currentSnapshot._nodes);
|
1983 | let historyValue = currentSnapshot.historyValue;
|
1984 | const filteredTransitions = removeConflictingTransitions(transitions, mutStateNodeSet, historyValue);
|
1985 | let nextState = currentSnapshot;
|
1986 |
|
1987 |
|
1988 | if (!isInitial) {
|
1989 | [nextState, historyValue] = exitStates(nextState, event, actorScope, filteredTransitions, mutStateNodeSet, historyValue, internalQueue);
|
1990 | }
|
1991 |
|
1992 |
|
1993 | nextState = resolveActionsAndContext(nextState, event, actorScope, filteredTransitions.flatMap(t => t.actions), internalQueue);
|
1994 |
|
1995 |
|
1996 | nextState = enterStates(nextState, event, actorScope, filteredTransitions, mutStateNodeSet, internalQueue, historyValue, isInitial);
|
1997 | const nextStateNodes = [...mutStateNodeSet];
|
1998 | if (nextState.status === 'done') {
|
1999 | nextState = resolveActionsAndContext(nextState, event, actorScope, nextStateNodes.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
|
2000 | }
|
2001 | try {
|
2002 | if (historyValue === currentSnapshot.historyValue && areStateNodeCollectionsEqual(currentSnapshot._nodes, mutStateNodeSet)) {
|
2003 | return nextState;
|
2004 | }
|
2005 | return cloneMachineSnapshot(nextState, {
|
2006 | _nodes: nextStateNodes,
|
2007 | historyValue
|
2008 | });
|
2009 | } catch (e) {
|
2010 |
|
2011 |
|
2012 | throw e;
|
2013 | }
|
2014 | }
|
2015 | function getMachineOutput(snapshot, event, actorScope, rootNode, rootCompletionNode) {
|
2016 | if (rootNode.output === undefined) {
|
2017 | return;
|
2018 | }
|
2019 | const doneStateEvent = createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output !== undefined && rootCompletionNode.parent ? resolveOutput(rootCompletionNode.output, snapshot.context, event, actorScope.self) : undefined);
|
2020 | return resolveOutput(rootNode.output, snapshot.context, doneStateEvent, actorScope.self);
|
2021 | }
|
2022 | function enterStates(currentSnapshot, event, actorScope, filteredTransitions, mutStateNodeSet, internalQueue, historyValue, isInitial) {
|
2023 | let nextSnapshot = currentSnapshot;
|
2024 | const statesToEnter = new Set();
|
2025 |
|
2026 |
|
2027 |
|
2028 | const statesForDefaultEntry = new Set();
|
2029 | computeEntrySet(filteredTransitions, historyValue, statesForDefaultEntry, statesToEnter);
|
2030 |
|
2031 |
|
2032 | if (isInitial) {
|
2033 | statesForDefaultEntry.add(currentSnapshot.machine.root);
|
2034 | }
|
2035 | const completedNodes = new Set();
|
2036 | for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
|
2037 | mutStateNodeSet.add(stateNodeToEnter);
|
2038 | const actions = [];
|
2039 |
|
2040 |
|
2041 | actions.push(...stateNodeToEnter.entry);
|
2042 | for (const invokeDef of stateNodeToEnter.invoke) {
|
2043 | actions.push(spawnChild(invokeDef.src, {
|
2044 | ...invokeDef,
|
2045 | syncSnapshot: !!invokeDef.onSnapshot
|
2046 | }));
|
2047 | }
|
2048 | if (statesForDefaultEntry.has(stateNodeToEnter)) {
|
2049 | const initialActions = stateNodeToEnter.initial.actions;
|
2050 | actions.push(...initialActions);
|
2051 | }
|
2052 | nextSnapshot = resolveActionsAndContext(nextSnapshot, event, actorScope, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
|
2053 | if (stateNodeToEnter.type === 'final') {
|
2054 | const parent = stateNodeToEnter.parent;
|
2055 | let ancestorMarker = parent?.type === 'parallel' ? parent : parent?.parent;
|
2056 | let rootCompletionNode = ancestorMarker || stateNodeToEnter;
|
2057 | if (parent?.type === 'compound') {
|
2058 | internalQueue.push(createDoneStateEvent(parent.id, stateNodeToEnter.output !== undefined ? resolveOutput(stateNodeToEnter.output, nextSnapshot.context, event, actorScope.self) : undefined));
|
2059 | }
|
2060 | while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutStateNodeSet, ancestorMarker)) {
|
2061 | completedNodes.add(ancestorMarker);
|
2062 | internalQueue.push(createDoneStateEvent(ancestorMarker.id));
|
2063 | rootCompletionNode = ancestorMarker;
|
2064 | ancestorMarker = ancestorMarker.parent;
|
2065 | }
|
2066 | if (ancestorMarker) {
|
2067 | continue;
|
2068 | }
|
2069 | nextSnapshot = cloneMachineSnapshot(nextSnapshot, {
|
2070 | status: 'done',
|
2071 | output: getMachineOutput(nextSnapshot, event, actorScope, nextSnapshot.machine.root, rootCompletionNode)
|
2072 | });
|
2073 | }
|
2074 | }
|
2075 | return nextSnapshot;
|
2076 | }
|
2077 | function computeEntrySet(transitions, historyValue, statesForDefaultEntry, statesToEnter) {
|
2078 | for (const t of transitions) {
|
2079 | const domain = getTransitionDomain(t, historyValue);
|
2080 | for (const s of t.target || []) {
|
2081 | if (!isHistoryNode(s) && (
|
2082 |
|
2083 | t.source !== s ||
|
2084 |
|
2085 |
|
2086 | t.source !== domain ||
|
2087 |
|
2088 | t.reenter)) {
|
2089 | statesToEnter.add(s);
|
2090 | statesForDefaultEntry.add(s);
|
2091 | }
|
2092 | addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
|
2093 | }
|
2094 | const targetStates = getEffectiveTargetStates(t, historyValue);
|
2095 | for (const s of targetStates) {
|
2096 | const ancestors = getProperAncestors(s, domain);
|
2097 | if (domain?.type === 'parallel') {
|
2098 | ancestors.push(domain);
|
2099 | }
|
2100 | addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, ancestors, !t.source.parent && t.reenter ? undefined : domain);
|
2101 | }
|
2102 | }
|
2103 | }
|
2104 | function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEntry, statesToEnter) {
|
2105 | if (isHistoryNode(stateNode)) {
|
2106 | if (historyValue[stateNode.id]) {
|
2107 | const historyStateNodes = historyValue[stateNode.id];
|
2108 | for (const s of historyStateNodes) {
|
2109 | statesToEnter.add(s);
|
2110 | addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
|
2111 | }
|
2112 | for (const s of historyStateNodes) {
|
2113 | addProperAncestorStatesToEnter(s, stateNode.parent, statesToEnter, historyValue, statesForDefaultEntry);
|
2114 | }
|
2115 | } else {
|
2116 | const historyDefaultTransition = resolveHistoryDefaultTransition(stateNode);
|
2117 | for (const s of historyDefaultTransition.target) {
|
2118 | statesToEnter.add(s);
|
2119 | if (historyDefaultTransition === stateNode.parent?.initial) {
|
2120 | statesForDefaultEntry.add(stateNode.parent);
|
2121 | }
|
2122 | addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
|
2123 | }
|
2124 | for (const s of historyDefaultTransition.target) {
|
2125 | addProperAncestorStatesToEnter(s, stateNode.parent, statesToEnter, historyValue, statesForDefaultEntry);
|
2126 | }
|
2127 | }
|
2128 | } else {
|
2129 | if (stateNode.type === 'compound') {
|
2130 | const [initialState] = stateNode.initial.target;
|
2131 | if (!isHistoryNode(initialState)) {
|
2132 | statesToEnter.add(initialState);
|
2133 | statesForDefaultEntry.add(initialState);
|
2134 | }
|
2135 | addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
|
2136 | addProperAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
|
2137 | } else {
|
2138 | if (stateNode.type === 'parallel') {
|
2139 | for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
|
2140 | if (![...statesToEnter].some(s => isDescendant(s, child))) {
|
2141 | if (!isHistoryNode(child)) {
|
2142 | statesToEnter.add(child);
|
2143 | statesForDefaultEntry.add(child);
|
2144 | }
|
2145 | addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter);
|
2146 | }
|
2147 | }
|
2148 | }
|
2149 | }
|
2150 | }
|
2151 | }
|
2152 | function addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, ancestors, reentrancyDomain) {
|
2153 | for (const anc of ancestors) {
|
2154 | if (!reentrancyDomain || isDescendant(anc, reentrancyDomain)) {
|
2155 | statesToEnter.add(anc);
|
2156 | }
|
2157 | if (anc.type === 'parallel') {
|
2158 | for (const child of getChildren(anc).filter(sn => !isHistoryNode(sn))) {
|
2159 | if (![...statesToEnter].some(s => isDescendant(s, child))) {
|
2160 | statesToEnter.add(child);
|
2161 | addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter);
|
2162 | }
|
2163 | }
|
2164 | }
|
2165 | }
|
2166 | }
|
2167 | function addProperAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, historyValue, statesForDefaultEntry) {
|
2168 | addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, getProperAncestors(stateNode, toStateNode));
|
2169 | }
|
2170 | function exitStates(currentSnapshot, event, actorScope, transitions, mutStateNodeSet, historyValue, internalQueue) {
|
2171 | let nextSnapshot = currentSnapshot;
|
2172 | const statesToExit = computeExitSet(transitions, mutStateNodeSet, historyValue);
|
2173 | statesToExit.sort((a, b) => b.order - a.order);
|
2174 | let changedHistory;
|
2175 |
|
2176 |
|
2177 | for (const exitStateNode of statesToExit) {
|
2178 | for (const historyNode of getHistoryNodes(exitStateNode)) {
|
2179 | let predicate;
|
2180 | if (historyNode.history === 'deep') {
|
2181 | predicate = sn => isAtomicStateNode(sn) && isDescendant(sn, exitStateNode);
|
2182 | } else {
|
2183 | predicate = sn => {
|
2184 | return sn.parent === exitStateNode;
|
2185 | };
|
2186 | }
|
2187 | changedHistory ??= {
|
2188 | ...historyValue
|
2189 | };
|
2190 | changedHistory[historyNode.id] = Array.from(mutStateNodeSet).filter(predicate);
|
2191 | }
|
2192 | }
|
2193 | for (const s of statesToExit) {
|
2194 | nextSnapshot = resolveActionsAndContext(nextSnapshot, event, actorScope, [...s.exit, ...s.invoke.map(def => stopChild(def.id))], internalQueue);
|
2195 | mutStateNodeSet.delete(s);
|
2196 | }
|
2197 | return [nextSnapshot, changedHistory || historyValue];
|
2198 | }
|
2199 | function resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope, actions, extra, retries) {
|
2200 | const {
|
2201 | machine
|
2202 | } = currentSnapshot;
|
2203 | let intermediateSnapshot = currentSnapshot;
|
2204 | for (const action of actions) {
|
2205 | const isInline = typeof action === 'function';
|
2206 | const resolvedAction = isInline ? action :
|
2207 |
|
2208 |
|
2209 |
|
2210 | machine.implementations.actions[typeof action === 'string' ? action : action.type];
|
2211 | if (!resolvedAction) {
|
2212 | continue;
|
2213 | }
|
2214 | const actionArgs = {
|
2215 | context: intermediateSnapshot.context,
|
2216 | event,
|
2217 | self: actorScope.self,
|
2218 | system: actorScope.system
|
2219 | };
|
2220 | const actionParams = isInline || typeof action === 'string' ? undefined : 'params' in action ? typeof action.params === 'function' ? action.params({
|
2221 | context: intermediateSnapshot.context,
|
2222 | event
|
2223 | }) : action.params : undefined;
|
2224 | function executeAction() {
|
2225 | actorScope.system._sendInspectionEvent({
|
2226 | type: '@xstate.action',
|
2227 | actorRef: actorScope.self,
|
2228 | action: {
|
2229 | type: typeof action === 'string' ? action : typeof action === 'object' ? action.type : action.name || '(anonymous)',
|
2230 | params: actionParams
|
2231 | }
|
2232 | });
|
2233 | resolvedAction(actionArgs, actionParams);
|
2234 | }
|
2235 | if (!('resolve' in resolvedAction)) {
|
2236 | if (actorScope.self._processingStatus === ProcessingStatus.Running) {
|
2237 | executeAction();
|
2238 | } else {
|
2239 | actorScope.defer(() => {
|
2240 | executeAction();
|
2241 | });
|
2242 | }
|
2243 | continue;
|
2244 | }
|
2245 | const builtinAction = resolvedAction;
|
2246 | const [nextState, params, actions] = builtinAction.resolve(actorScope, intermediateSnapshot, actionArgs, actionParams, resolvedAction,
|
2247 |
|
2248 | extra);
|
2249 | intermediateSnapshot = nextState;
|
2250 | if ('retryResolve' in builtinAction) {
|
2251 | retries?.push([builtinAction, params]);
|
2252 | }
|
2253 | if ('execute' in builtinAction) {
|
2254 | if (actorScope.self._processingStatus === ProcessingStatus.Running) {
|
2255 | builtinAction.execute(actorScope, params);
|
2256 | } else {
|
2257 | actorScope.defer(builtinAction.execute.bind(null, actorScope, params));
|
2258 | }
|
2259 | }
|
2260 | if (actions) {
|
2261 | intermediateSnapshot = resolveAndExecuteActionsWithContext(intermediateSnapshot, event, actorScope, actions, extra, retries);
|
2262 | }
|
2263 | }
|
2264 | return intermediateSnapshot;
|
2265 | }
|
2266 | function resolveActionsAndContext(currentSnapshot, event, actorScope, actions, internalQueue, deferredActorIds) {
|
2267 | const retries = deferredActorIds ? [] : undefined;
|
2268 | const nextState = resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope, actions, {
|
2269 | internalQueue,
|
2270 | deferredActorIds
|
2271 | }, retries);
|
2272 | retries?.forEach(([builtinAction, params]) => {
|
2273 | builtinAction.retryResolve(actorScope, nextState, params);
|
2274 | });
|
2275 | return nextState;
|
2276 | }
|
2277 | function macrostep(snapshot, event, actorScope, internalQueue = []) {
|
2278 | let nextSnapshot = snapshot;
|
2279 | const microstates = [];
|
2280 | function addMicrostate(microstate, event, transitions) {
|
2281 | actorScope.system._sendInspectionEvent({
|
2282 | type: '@xstate.microstep',
|
2283 | actorRef: actorScope.self,
|
2284 | event,
|
2285 | snapshot: microstate,
|
2286 | _transitions: transitions
|
2287 | });
|
2288 | microstates.push(microstate);
|
2289 | }
|
2290 |
|
2291 |
|
2292 | if (event.type === XSTATE_STOP) {
|
2293 | nextSnapshot = cloneMachineSnapshot(stopChildren(nextSnapshot, event, actorScope), {
|
2294 | status: 'stopped'
|
2295 | });
|
2296 | addMicrostate(nextSnapshot, event, []);
|
2297 | return {
|
2298 | snapshot: nextSnapshot,
|
2299 | microstates
|
2300 | };
|
2301 | }
|
2302 | let nextEvent = event;
|
2303 |
|
2304 |
|
2305 |
|
2306 | if (nextEvent.type !== XSTATE_INIT) {
|
2307 | const currentEvent = nextEvent;
|
2308 | const isErr = isErrorActorEvent(currentEvent);
|
2309 | const transitions = selectTransitions(currentEvent, nextSnapshot);
|
2310 | if (isErr && !transitions.length) {
|
2311 |
|
2312 |
|
2313 |
|
2314 | nextSnapshot = cloneMachineSnapshot(snapshot, {
|
2315 | status: 'error',
|
2316 | error: currentEvent.error
|
2317 | });
|
2318 | addMicrostate(nextSnapshot, currentEvent, []);
|
2319 | return {
|
2320 | snapshot: nextSnapshot,
|
2321 | microstates
|
2322 | };
|
2323 | }
|
2324 | nextSnapshot = microstep(transitions, snapshot, actorScope, nextEvent, false,
|
2325 |
|
2326 | internalQueue);
|
2327 | addMicrostate(nextSnapshot, currentEvent, transitions);
|
2328 | }
|
2329 | let shouldSelectEventlessTransitions = true;
|
2330 | while (nextSnapshot.status === 'active') {
|
2331 | let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextSnapshot, nextEvent) : [];
|
2332 |
|
2333 |
|
2334 |
|
2335 | const previousState = enabledTransitions.length ? nextSnapshot : undefined;
|
2336 | if (!enabledTransitions.length) {
|
2337 | if (!internalQueue.length) {
|
2338 | break;
|
2339 | }
|
2340 | nextEvent = internalQueue.shift();
|
2341 | enabledTransitions = selectTransitions(nextEvent, nextSnapshot);
|
2342 | }
|
2343 | nextSnapshot = microstep(enabledTransitions, nextSnapshot, actorScope, nextEvent, false, internalQueue);
|
2344 | shouldSelectEventlessTransitions = nextSnapshot !== previousState;
|
2345 | addMicrostate(nextSnapshot, nextEvent, enabledTransitions);
|
2346 | }
|
2347 | if (nextSnapshot.status !== 'active') {
|
2348 | stopChildren(nextSnapshot, nextEvent, actorScope);
|
2349 | }
|
2350 | return {
|
2351 | snapshot: nextSnapshot,
|
2352 | microstates
|
2353 | };
|
2354 | }
|
2355 | function stopChildren(nextState, event, actorScope) {
|
2356 | return resolveActionsAndContext(nextState, event, actorScope, Object.values(nextState.children).map(child => stopChild(child)), []);
|
2357 | }
|
2358 | function selectTransitions(event, nextState) {
|
2359 | return nextState.machine.getTransitionData(nextState, event);
|
2360 | }
|
2361 | function selectEventlessTransitions(nextState, event) {
|
2362 | const enabledTransitionSet = new Set();
|
2363 | const atomicStates = nextState._nodes.filter(isAtomicStateNode);
|
2364 | for (const stateNode of atomicStates) {
|
2365 | loop: for (const s of [stateNode].concat(getProperAncestors(stateNode, undefined))) {
|
2366 | if (!s.always) {
|
2367 | continue;
|
2368 | }
|
2369 | for (const transition of s.always) {
|
2370 | if (transition.guard === undefined || evaluateGuard(transition.guard, nextState.context, event, nextState)) {
|
2371 | enabledTransitionSet.add(transition);
|
2372 | break loop;
|
2373 | }
|
2374 | }
|
2375 | }
|
2376 | }
|
2377 | return removeConflictingTransitions(Array.from(enabledTransitionSet), new Set(nextState._nodes), nextState.historyValue);
|
2378 | }
|
2379 |
|
2380 |
|
2381 |
|
2382 |
|
2383 |
|
2384 |
|
2385 | function resolveStateValue(rootNode, stateValue) {
|
2386 | const allStateNodes = getAllStateNodes(getStateNodes(rootNode, stateValue));
|
2387 | return getStateValue(rootNode, [...allStateNodes]);
|
2388 | }
|
2389 |
|
2390 | function isMachineSnapshot(value) {
|
2391 | return !!value && typeof value === 'object' && 'machine' in value && 'value' in value;
|
2392 | }
|
2393 | const machineSnapshotMatches = function matches(testValue) {
|
2394 | return matchesState(testValue, this.value);
|
2395 | };
|
2396 | const machineSnapshotHasTag = function hasTag(tag) {
|
2397 | return this.tags.has(tag);
|
2398 | };
|
2399 | const machineSnapshotCan = function can(event) {
|
2400 | const transitionData = this.machine.getTransitionData(this, event);
|
2401 | return !!transitionData?.length &&
|
2402 |
|
2403 | transitionData.some(t => t.target !== undefined || t.actions.length);
|
2404 | };
|
2405 | const machineSnapshotToJSON = function toJSON() {
|
2406 | const {
|
2407 | _nodes: nodes,
|
2408 | tags,
|
2409 | machine,
|
2410 | getMeta,
|
2411 | toJSON,
|
2412 | can,
|
2413 | hasTag,
|
2414 | matches,
|
2415 | ...jsonValues
|
2416 | } = this;
|
2417 | return {
|
2418 | ...jsonValues,
|
2419 | tags: Array.from(tags)
|
2420 | };
|
2421 | };
|
2422 | const machineSnapshotGetMeta = function getMeta() {
|
2423 | return this._nodes.reduce((acc, stateNode) => {
|
2424 | if (stateNode.meta !== undefined) {
|
2425 | acc[stateNode.id] = stateNode.meta;
|
2426 | }
|
2427 | return acc;
|
2428 | }, {});
|
2429 | };
|
2430 | function createMachineSnapshot(config, machine) {
|
2431 | return {
|
2432 | status: config.status,
|
2433 | output: config.output,
|
2434 | error: config.error,
|
2435 | machine,
|
2436 | context: config.context,
|
2437 | _nodes: config._nodes,
|
2438 | value: getStateValue(machine.root, config._nodes),
|
2439 | tags: new Set(config._nodes.flatMap(sn => sn.tags)),
|
2440 | children: config.children,
|
2441 | historyValue: config.historyValue || {},
|
2442 | matches: machineSnapshotMatches,
|
2443 | hasTag: machineSnapshotHasTag,
|
2444 | can: machineSnapshotCan,
|
2445 | getMeta: machineSnapshotGetMeta,
|
2446 | toJSON: machineSnapshotToJSON
|
2447 | };
|
2448 | }
|
2449 | function cloneMachineSnapshot(snapshot, config = {}) {
|
2450 | return createMachineSnapshot({
|
2451 | ...snapshot,
|
2452 | ...config
|
2453 | }, snapshot.machine);
|
2454 | }
|
2455 | function getPersistedSnapshot(snapshot, options) {
|
2456 | const {
|
2457 | _nodes: nodes,
|
2458 | tags,
|
2459 | machine,
|
2460 | children,
|
2461 | context,
|
2462 | can,
|
2463 | hasTag,
|
2464 | matches,
|
2465 | getMeta,
|
2466 | toJSON,
|
2467 | ...jsonValues
|
2468 | } = snapshot;
|
2469 | const childrenJson = {};
|
2470 | for (const id in children) {
|
2471 | const child = children[id];
|
2472 | childrenJson[id] = {
|
2473 | snapshot: child.getPersistedSnapshot(options),
|
2474 | src: child.src,
|
2475 | systemId: child._systemId,
|
2476 | syncSnapshot: child._syncSnapshot
|
2477 | };
|
2478 | }
|
2479 | const persisted = {
|
2480 | ...jsonValues,
|
2481 | context: persistContext(context),
|
2482 | children: childrenJson
|
2483 | };
|
2484 | return persisted;
|
2485 | }
|
2486 | function persistContext(contextPart) {
|
2487 | let copy;
|
2488 | for (const key in contextPart) {
|
2489 | const value = contextPart[key];
|
2490 | if (value && typeof value === 'object') {
|
2491 | if ('sessionId' in value && 'send' in value && 'ref' in value) {
|
2492 | copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
|
2493 | ...contextPart
|
2494 | };
|
2495 | copy[key] = {
|
2496 | xstate$$type: $$ACTOR_TYPE,
|
2497 | id: value.id
|
2498 | };
|
2499 | } else {
|
2500 | const result = persistContext(value);
|
2501 | if (result !== value) {
|
2502 | copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
|
2503 | ...contextPart
|
2504 | };
|
2505 | copy[key] = result;
|
2506 | }
|
2507 | }
|
2508 | }
|
2509 | }
|
2510 | return copy ?? contextPart;
|
2511 | }
|
2512 |
|
2513 | function resolveRaise(_, snapshot, args, actionParams, {
|
2514 | event: eventOrExpr,
|
2515 | id,
|
2516 | delay
|
2517 | }, {
|
2518 | internalQueue
|
2519 | }) {
|
2520 | const delaysMap = snapshot.machine.implementations.delays;
|
2521 | if (typeof eventOrExpr === 'string') {
|
2522 | throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
|
2523 | }
|
2524 | const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args, actionParams) : eventOrExpr;
|
2525 | let resolvedDelay;
|
2526 | if (typeof delay === 'string') {
|
2527 | const configDelay = delaysMap && delaysMap[delay];
|
2528 | resolvedDelay = typeof configDelay === 'function' ? configDelay(args, actionParams) : configDelay;
|
2529 | } else {
|
2530 | resolvedDelay = typeof delay === 'function' ? delay(args, actionParams) : delay;
|
2531 | }
|
2532 | if (typeof resolvedDelay !== 'number') {
|
2533 | internalQueue.push(resolvedEvent);
|
2534 | }
|
2535 | return [snapshot, {
|
2536 | event: resolvedEvent,
|
2537 | id,
|
2538 | delay: resolvedDelay
|
2539 | }];
|
2540 | }
|
2541 | function executeRaise(actorScope, params) {
|
2542 | const {
|
2543 | event,
|
2544 | delay,
|
2545 | id
|
2546 | } = params;
|
2547 | if (typeof delay === 'number') {
|
2548 | actorScope.defer(() => {
|
2549 | const self = actorScope.self;
|
2550 | actorScope.system.scheduler.schedule(self, self, event, delay, id);
|
2551 | });
|
2552 | return;
|
2553 | }
|
2554 | }
|
2555 |
|
2556 |
|
2557 |
|
2558 |
|
2559 |
|
2560 |
|
2561 | function raise(eventOrExpr, options) {
|
2562 | function raise(args, params) {
|
2563 | }
|
2564 | raise.type = 'xstate.raise';
|
2565 | raise.event = eventOrExpr;
|
2566 | raise.id = options?.id;
|
2567 | raise.delay = options?.delay;
|
2568 | raise.resolve = resolveRaise;
|
2569 | raise.execute = executeRaise;
|
2570 | return raise;
|
2571 | }
|
2572 |
|
2573 | exports.$$ACTOR_TYPE = $$ACTOR_TYPE;
|
2574 | exports.Actor = Actor;
|
2575 | exports.NULL_EVENT = NULL_EVENT;
|
2576 | exports.ProcessingStatus = ProcessingStatus;
|
2577 | exports.STATE_DELIMITER = STATE_DELIMITER;
|
2578 | exports.XSTATE_ERROR = XSTATE_ERROR;
|
2579 | exports.XSTATE_STOP = XSTATE_STOP;
|
2580 | exports.and = and;
|
2581 | exports.cancel = cancel;
|
2582 | exports.cloneMachineSnapshot = cloneMachineSnapshot;
|
2583 | exports.createActor = createActor;
|
2584 | exports.createErrorActorEvent = createErrorActorEvent;
|
2585 | exports.createInitEvent = createInitEvent;
|
2586 | exports.createInvokeId = createInvokeId;
|
2587 | exports.createMachineSnapshot = createMachineSnapshot;
|
2588 | exports.evaluateGuard = evaluateGuard;
|
2589 | exports.formatInitialTransition = formatInitialTransition;
|
2590 | exports.formatTransition = formatTransition;
|
2591 | exports.formatTransitions = formatTransitions;
|
2592 | exports.getAllOwnEventDescriptors = getAllOwnEventDescriptors;
|
2593 | exports.getAllStateNodes = getAllStateNodes;
|
2594 | exports.getCandidates = getCandidates;
|
2595 | exports.getDelayedTransitions = getDelayedTransitions;
|
2596 | exports.getInitialStateNodes = getInitialStateNodes;
|
2597 | exports.getPersistedSnapshot = getPersistedSnapshot;
|
2598 | exports.getStateNodeByPath = getStateNodeByPath;
|
2599 | exports.getStateNodes = getStateNodes;
|
2600 | exports.interpret = interpret;
|
2601 | exports.isInFinalState = isInFinalState;
|
2602 | exports.isMachineSnapshot = isMachineSnapshot;
|
2603 | exports.isStateId = isStateId;
|
2604 | exports.macrostep = macrostep;
|
2605 | exports.mapValues = mapValues;
|
2606 | exports.matchesState = matchesState;
|
2607 | exports.microstep = microstep;
|
2608 | exports.not = not;
|
2609 | exports.or = or;
|
2610 | exports.pathToStateValue = pathToStateValue;
|
2611 | exports.raise = raise;
|
2612 | exports.resolveActionsAndContext = resolveActionsAndContext;
|
2613 | exports.resolveReferencedActor = resolveReferencedActor;
|
2614 | exports.resolveStateValue = resolveStateValue;
|
2615 | exports.spawnChild = spawnChild;
|
2616 | exports.stateIn = stateIn;
|
2617 | exports.stop = stop;
|
2618 | exports.stopChild = stopChild;
|
2619 | exports.toArray = toArray;
|
2620 | exports.toObserver = toObserver;
|
2621 | exports.toStatePath = toStatePath;
|
2622 | exports.toTransitionConfigArray = toTransitionConfigArray;
|
2623 | exports.transitionNode = transitionNode;
|