UNPKG

28.2 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var actors_dist_xstateActors = require('../actors/dist/xstate-actors.cjs.js');
6var guards_dist_xstateGuards = require('./raise-40b1a1f5.cjs.js');
7var log = require('./log-11d3f771.cjs.js');
8require('../dev/dist/xstate-dev.cjs.js');
9
10class SimulatedClock {
11 constructor() {
12 this.timeouts = new Map();
13 this._now = 0;
14 this._id = 0;
15 this._flushing = false;
16 this._flushingInvalidated = false;
17 }
18 now() {
19 return this._now;
20 }
21 getId() {
22 return this._id++;
23 }
24 setTimeout(fn, timeout) {
25 this._flushingInvalidated = this._flushing;
26 const id = this.getId();
27 this.timeouts.set(id, {
28 start: this.now(),
29 timeout,
30 fn
31 });
32 return id;
33 }
34 clearTimeout(id) {
35 this._flushingInvalidated = this._flushing;
36 this.timeouts.delete(id);
37 }
38 set(time) {
39 if (this._now > time) {
40 throw new Error('Unable to travel back in time');
41 }
42 this._now = time;
43 this.flushTimeouts();
44 }
45 flushTimeouts() {
46 if (this._flushing) {
47 this._flushingInvalidated = true;
48 return;
49 }
50 this._flushing = true;
51 const sorted = [...this.timeouts].sort(([_idA, timeoutA], [_idB, timeoutB]) => {
52 const endA = timeoutA.start + timeoutA.timeout;
53 const endB = timeoutB.start + timeoutB.timeout;
54 return endB > endA ? -1 : 1;
55 });
56 for (const [id, timeout] of sorted) {
57 if (this._flushingInvalidated) {
58 this._flushingInvalidated = false;
59 this._flushing = false;
60 this.flushTimeouts();
61 return;
62 }
63 if (this.now() - timeout.start >= timeout.timeout) {
64 this.timeouts.delete(id);
65 timeout.fn.call(null);
66 }
67 }
68 this._flushing = false;
69 }
70 increment(ms) {
71 this._now += ms;
72 this.flushTimeouts();
73 }
74}
75
76const cache = new WeakMap();
77function memo(object, key, fn) {
78 let memoizedData = cache.get(object);
79 if (!memoizedData) {
80 memoizedData = {
81 [key]: fn()
82 };
83 cache.set(object, memoizedData);
84 } else if (!(key in memoizedData)) {
85 memoizedData[key] = fn();
86 }
87 return memoizedData[key];
88}
89
90const EMPTY_OBJECT = {};
91const toSerializableAction = action => {
92 if (typeof action === 'string') {
93 return {
94 type: action
95 };
96 }
97 if (typeof action === 'function') {
98 if ('resolve' in action) {
99 return {
100 type: action.type
101 };
102 }
103 return {
104 type: action.name
105 };
106 }
107 return action;
108};
109class StateNode {
110 constructor(
111 /**
112 * The raw config used to create the machine.
113 */
114 config, options) {
115 this.config = config;
116 /**
117 * The relative key of the state node, which represents its location in the overall state value.
118 */
119 this.key = void 0;
120 /**
121 * The unique ID of the state node.
122 */
123 this.id = void 0;
124 /**
125 * The type of this state node:
126 *
127 * - `'atomic'` - no child state nodes
128 * - `'compound'` - nested child state nodes (XOR)
129 * - `'parallel'` - orthogonal nested child state nodes (AND)
130 * - `'history'` - history state node
131 * - `'final'` - final state node
132 */
133 this.type = void 0;
134 /**
135 * The string path from the root machine node to this node.
136 */
137 this.path = void 0;
138 /**
139 * The child state nodes.
140 */
141 this.states = void 0;
142 /**
143 * The type of history on this state node. Can be:
144 *
145 * - `'shallow'` - recalls only top-level historical state value
146 * - `'deep'` - recalls historical state value at all levels
147 */
148 this.history = void 0;
149 /**
150 * The action(s) to be executed upon entering the state node.
151 */
152 this.entry = void 0;
153 /**
154 * The action(s) to be executed upon exiting the state node.
155 */
156 this.exit = void 0;
157 /**
158 * The parent state node.
159 */
160 this.parent = void 0;
161 /**
162 * The root machine node.
163 */
164 this.machine = void 0;
165 /**
166 * The meta data associated with this state node, which will be returned in State instances.
167 */
168 this.meta = void 0;
169 /**
170 * The output data sent with the "xstate.done.state._id_" event if this is a final state node.
171 */
172 this.output = void 0;
173 /**
174 * The order this state node appears. Corresponds to the implicit document order.
175 */
176 this.order = -1;
177 this.description = void 0;
178 this.tags = [];
179 this.transitions = void 0;
180 this.always = void 0;
181 this.parent = options._parent;
182 this.key = options._key;
183 this.machine = options._machine;
184 this.path = this.parent ? this.parent.path.concat(this.key) : [];
185 this.id = this.config.id || [this.machine.id, ...this.path].join(guards_dist_xstateGuards.STATE_DELIMITER);
186 this.type = this.config.type || (this.config.states && Object.keys(this.config.states).length ? 'compound' : this.config.history ? 'history' : 'atomic');
187 this.description = this.config.description;
188 this.order = this.machine.idMap.size;
189 this.machine.idMap.set(this.id, this);
190 this.states = this.config.states ? guards_dist_xstateGuards.mapValues(this.config.states, (stateConfig, key) => {
191 const stateNode = new StateNode(stateConfig, {
192 _parent: this,
193 _key: key,
194 _machine: this.machine
195 });
196 return stateNode;
197 }) : EMPTY_OBJECT;
198 if (this.type === 'compound' && !this.config.initial) {
199 throw new Error(`No initial state specified for compound state node "#${this.id}". Try adding { initial: "${Object.keys(this.states)[0]}" } to the state config.`);
200 }
201
202 // History config
203 this.history = this.config.history === true ? 'shallow' : this.config.history || false;
204 this.entry = guards_dist_xstateGuards.toArray(this.config.entry).slice();
205 this.exit = guards_dist_xstateGuards.toArray(this.config.exit).slice();
206 this.meta = this.config.meta;
207 this.output = this.type === 'final' || !this.parent ? this.config.output : undefined;
208 this.tags = guards_dist_xstateGuards.toArray(config.tags).slice();
209 }
210
211 /** @internal */
212 _initialize() {
213 this.transitions = guards_dist_xstateGuards.formatTransitions(this);
214 if (this.config.always) {
215 this.always = guards_dist_xstateGuards.toTransitionConfigArray(this.config.always).map(t => guards_dist_xstateGuards.formatTransition(this, guards_dist_xstateGuards.NULL_EVENT, t));
216 }
217 Object.keys(this.states).forEach(key => {
218 this.states[key]._initialize();
219 });
220 }
221
222 /**
223 * The well-structured state node definition.
224 */
225 get definition() {
226 return {
227 id: this.id,
228 key: this.key,
229 version: this.machine.version,
230 type: this.type,
231 initial: this.initial ? {
232 target: this.initial.target,
233 source: this,
234 actions: this.initial.actions.map(toSerializableAction),
235 eventType: null,
236 reenter: false,
237 toJSON: () => ({
238 target: this.initial.target.map(t => `#${t.id}`),
239 source: `#${this.id}`,
240 actions: this.initial.actions.map(toSerializableAction),
241 eventType: null
242 })
243 } : undefined,
244 history: this.history,
245 states: guards_dist_xstateGuards.mapValues(this.states, state => {
246 return state.definition;
247 }),
248 on: this.on,
249 transitions: [...this.transitions.values()].flat().map(t => ({
250 ...t,
251 actions: t.actions.map(toSerializableAction)
252 })),
253 entry: this.entry.map(toSerializableAction),
254 exit: this.exit.map(toSerializableAction),
255 meta: this.meta,
256 order: this.order || -1,
257 output: this.output,
258 invoke: this.invoke,
259 description: this.description,
260 tags: this.tags
261 };
262 }
263
264 /** @internal */
265 toJSON() {
266 return this.definition;
267 }
268
269 /**
270 * The logic invoked as actors by this state node.
271 */
272 get invoke() {
273 return memo(this, 'invoke', () => guards_dist_xstateGuards.toArray(this.config.invoke).map((invokeConfig, i) => {
274 const {
275 src,
276 systemId
277 } = invokeConfig;
278 const resolvedId = invokeConfig.id ?? guards_dist_xstateGuards.createInvokeId(this.id, i);
279 const resolvedSrc = typeof src === 'string' ? src : `xstate.invoke.${guards_dist_xstateGuards.createInvokeId(this.id, i)}`;
280 return {
281 ...invokeConfig,
282 src: resolvedSrc,
283 id: resolvedId,
284 systemId: systemId,
285 toJSON() {
286 const {
287 onDone,
288 onError,
289 ...invokeDefValues
290 } = invokeConfig;
291 return {
292 ...invokeDefValues,
293 type: 'xstate.invoke',
294 src: resolvedSrc,
295 id: resolvedId
296 };
297 }
298 };
299 }));
300 }
301
302 /**
303 * The mapping of events to transitions.
304 */
305 get on() {
306 return memo(this, 'on', () => {
307 const transitions = this.transitions;
308 return [...transitions].flatMap(([descriptor, t]) => t.map(t => [descriptor, t])).reduce((map, [descriptor, transition]) => {
309 map[descriptor] = map[descriptor] || [];
310 map[descriptor].push(transition);
311 return map;
312 }, {});
313 });
314 }
315 get after() {
316 return memo(this, 'delayedTransitions', () => guards_dist_xstateGuards.getDelayedTransitions(this));
317 }
318 get initial() {
319 return memo(this, 'initial', () => guards_dist_xstateGuards.formatInitialTransition(this, this.config.initial));
320 }
321
322 /** @internal */
323 next(snapshot, event) {
324 const eventType = event.type;
325 const actions = [];
326 let selectedTransition;
327 const candidates = memo(this, `candidates-${eventType}`, () => guards_dist_xstateGuards.getCandidates(this, eventType));
328 for (const candidate of candidates) {
329 const {
330 guard
331 } = candidate;
332 const resolvedContext = snapshot.context;
333 let guardPassed = false;
334 try {
335 guardPassed = !guard || guards_dist_xstateGuards.evaluateGuard(guard, resolvedContext, event, snapshot);
336 } catch (err) {
337 const guardType = typeof guard === 'string' ? guard : typeof guard === 'object' ? guard.type : undefined;
338 throw new Error(`Unable to evaluate guard ${guardType ? `'${guardType}' ` : ''}in transition for event '${eventType}' in state node '${this.id}':\n${err.message}`);
339 }
340 if (guardPassed) {
341 actions.push(...candidate.actions);
342 selectedTransition = candidate;
343 break;
344 }
345 }
346 return selectedTransition ? [selectedTransition] : undefined;
347 }
348
349 /**
350 * All the event types accepted by this state node and its descendants.
351 */
352 get events() {
353 return memo(this, 'events', () => {
354 const {
355 states
356 } = this;
357 const events = new Set(this.ownEvents);
358 if (states) {
359 for (const stateId of Object.keys(states)) {
360 const state = states[stateId];
361 if (state.states) {
362 for (const event of state.events) {
363 events.add(`${event}`);
364 }
365 }
366 }
367 }
368 return Array.from(events);
369 });
370 }
371
372 /**
373 * All the events that have transitions directly from this state node.
374 *
375 * Excludes any inert events.
376 */
377 get ownEvents() {
378 const events = new Set([...this.transitions.keys()].filter(descriptor => {
379 return this.transitions.get(descriptor).some(transition => !(!transition.target && !transition.actions.length && !transition.reenter));
380 }));
381 return Array.from(events);
382 }
383}
384
385const STATE_IDENTIFIER = '#';
386class StateMachine {
387 constructor(
388 /**
389 * The raw config used to create the machine.
390 */
391 config, implementations) {
392 this.config = config;
393 /**
394 * The machine's own version.
395 */
396 this.version = void 0;
397 this.schemas = void 0;
398 this.implementations = void 0;
399 /** @internal */
400 this.__xstatenode = true;
401 /** @internal */
402 this.idMap = new Map();
403 this.root = void 0;
404 this.id = void 0;
405 this.states = void 0;
406 this.events = void 0;
407 /**
408 * @deprecated an internal property that was acting as a "phantom" type, it's not used by anything right now but it's kept around for compatibility reasons
409 **/
410 this.__TResolvedTypesMeta = void 0;
411 this.id = config.id || '(machine)';
412 this.implementations = {
413 actors: implementations?.actors ?? {},
414 actions: implementations?.actions ?? {},
415 delays: implementations?.delays ?? {},
416 guards: implementations?.guards ?? {}
417 };
418 this.version = this.config.version;
419 this.schemas = this.config.schemas;
420 this.transition = this.transition.bind(this);
421 this.getInitialSnapshot = this.getInitialSnapshot.bind(this);
422 this.getPersistedSnapshot = this.getPersistedSnapshot.bind(this);
423 this.restoreSnapshot = this.restoreSnapshot.bind(this);
424 this.start = this.start.bind(this);
425 this.root = new StateNode(config, {
426 _key: this.id,
427 _machine: this
428 });
429 this.root._initialize();
430 this.states = this.root.states; // TODO: remove!
431 this.events = this.root.events;
432 }
433
434 /**
435 * Clones this state machine with the provided implementations
436 * and merges the `context` (if provided).
437 *
438 * @param implementations Options (`actions`, `guards`, `actors`, `delays`, `context`)
439 * to recursively merge with the existing options.
440 *
441 * @returns A new `StateMachine` instance with the provided implementations.
442 */
443 provide(implementations) {
444 const {
445 actions,
446 guards,
447 actors,
448 delays
449 } = this.implementations;
450 return new StateMachine(this.config, {
451 actions: {
452 ...actions,
453 ...implementations.actions
454 },
455 guards: {
456 ...guards,
457 ...implementations.guards
458 },
459 actors: {
460 ...actors,
461 ...implementations.actors
462 },
463 delays: {
464 ...delays,
465 ...implementations.delays
466 }
467 });
468 }
469 resolveState(config) {
470 const resolvedStateValue = guards_dist_xstateGuards.resolveStateValue(this.root, config.value);
471 const nodeSet = guards_dist_xstateGuards.getAllStateNodes(guards_dist_xstateGuards.getStateNodes(this.root, resolvedStateValue));
472 return guards_dist_xstateGuards.createMachineSnapshot({
473 _nodes: [...nodeSet],
474 context: config.context || {},
475 children: {},
476 status: guards_dist_xstateGuards.isInFinalState(nodeSet, this.root) ? 'done' : config.status || 'active',
477 output: config.output,
478 error: config.error,
479 historyValue: config.historyValue
480 }, this);
481 }
482
483 /**
484 * Determines the next snapshot given the current `snapshot` and received `event`.
485 * Calculates a full macrostep from all microsteps.
486 *
487 * @param snapshot The current snapshot
488 * @param event The received event
489 */
490 transition(snapshot, event, actorScope) {
491 return guards_dist_xstateGuards.macrostep(snapshot, event, actorScope).snapshot;
492 }
493
494 /**
495 * Determines the next state given the current `state` and `event`.
496 * Calculates a microstep.
497 *
498 * @param state The current state
499 * @param event The received event
500 */
501 microstep(snapshot, event, actorScope) {
502 return guards_dist_xstateGuards.macrostep(snapshot, event, actorScope).microstates;
503 }
504 getTransitionData(snapshot, event) {
505 return guards_dist_xstateGuards.transitionNode(this.root, snapshot.value, snapshot, event) || [];
506 }
507
508 /**
509 * The initial state _before_ evaluating any microsteps.
510 * This "pre-initial" state is provided to initial actions executed in the initial state.
511 */
512 getPreInitialState(actorScope, initEvent, internalQueue) {
513 const {
514 context
515 } = this.config;
516 const preInitial = guards_dist_xstateGuards.createMachineSnapshot({
517 context: typeof context !== 'function' && context ? context : {},
518 _nodes: [this.root],
519 children: {},
520 status: 'active'
521 }, this);
522 if (typeof context === 'function') {
523 const assignment = ({
524 spawn,
525 event,
526 self
527 }) => context({
528 spawn,
529 input: event.input,
530 self
531 });
532 return guards_dist_xstateGuards.resolveActionsAndContext(preInitial, initEvent, actorScope, [log.assign(assignment)], internalQueue);
533 }
534 return preInitial;
535 }
536
537 /**
538 * Returns the initial `State` instance, with reference to `self` as an `ActorRef`.
539 */
540 getInitialSnapshot(actorScope, input) {
541 const initEvent = guards_dist_xstateGuards.createInitEvent(input); // TODO: fix;
542 const internalQueue = [];
543 const preInitialState = this.getPreInitialState(actorScope, initEvent, internalQueue);
544 const nextState = guards_dist_xstateGuards.microstep([{
545 target: [...guards_dist_xstateGuards.getInitialStateNodes(this.root)],
546 source: this.root,
547 reenter: true,
548 actions: [],
549 eventType: null,
550 toJSON: null // TODO: fix
551 }], preInitialState, actorScope, initEvent, true, internalQueue);
552 const {
553 snapshot: macroState
554 } = guards_dist_xstateGuards.macrostep(nextState, initEvent, actorScope, internalQueue);
555 return macroState;
556 }
557 start(snapshot) {
558 Object.values(snapshot.children).forEach(child => {
559 if (child.getSnapshot().status === 'active') {
560 child.start();
561 }
562 });
563 }
564 getStateNodeById(stateId) {
565 const fullPath = guards_dist_xstateGuards.toStatePath(stateId);
566 const relativePath = fullPath.slice(1);
567 const resolvedStateId = guards_dist_xstateGuards.isStateId(fullPath[0]) ? fullPath[0].slice(STATE_IDENTIFIER.length) : fullPath[0];
568 const stateNode = this.idMap.get(resolvedStateId);
569 if (!stateNode) {
570 throw new Error(`Child state node '#${resolvedStateId}' does not exist on machine '${this.id}'`);
571 }
572 return guards_dist_xstateGuards.getStateNodeByPath(stateNode, relativePath);
573 }
574 get definition() {
575 return this.root.definition;
576 }
577 toJSON() {
578 return this.definition;
579 }
580 getPersistedSnapshot(snapshot, options) {
581 return guards_dist_xstateGuards.getPersistedSnapshot(snapshot, options);
582 }
583 restoreSnapshot(snapshot, _actorScope) {
584 const children = {};
585 const snapshotChildren = snapshot.children;
586 Object.keys(snapshotChildren).forEach(actorId => {
587 const actorData = snapshotChildren[actorId];
588 const childState = actorData.snapshot;
589 const src = actorData.src;
590 const logic = typeof src === 'string' ? guards_dist_xstateGuards.resolveReferencedActor(this, src) : src;
591 if (!logic) {
592 return;
593 }
594 const actorRef = guards_dist_xstateGuards.createActor(logic, {
595 id: actorId,
596 parent: _actorScope.self,
597 syncSnapshot: actorData.syncSnapshot,
598 snapshot: childState,
599 src,
600 systemId: actorData.systemId
601 });
602 children[actorId] = actorRef;
603 });
604 const restoredSnapshot = guards_dist_xstateGuards.createMachineSnapshot({
605 ...snapshot,
606 children,
607 _nodes: Array.from(guards_dist_xstateGuards.getAllStateNodes(guards_dist_xstateGuards.getStateNodes(this.root, snapshot.value)))
608 }, this);
609 let seen = new Set();
610 function reviveContext(contextPart, children) {
611 if (seen.has(contextPart)) {
612 return;
613 }
614 seen.add(contextPart);
615 for (let key in contextPart) {
616 const value = contextPart[key];
617 if (value && typeof value === 'object') {
618 if ('xstate$$type' in value && value.xstate$$type === guards_dist_xstateGuards.$$ACTOR_TYPE) {
619 contextPart[key] = children[value.id];
620 continue;
621 }
622 reviveContext(value, children);
623 }
624 }
625 }
626 reviveContext(restoredSnapshot.context, children);
627 return restoredSnapshot;
628 }
629}
630
631const defaultWaitForOptions = {
632 timeout: Infinity // much more than 10 seconds
633};
634
635/**
636 * Subscribes to an actor ref and waits for its emitted value to satisfy
637 * a predicate, and then resolves with that value.
638 * Will throw if the desired state is not reached after an optional timeout.
639 * (defaults to Infinity).
640 *
641 * @example
642 * ```js
643 * const state = await waitFor(someService, state => {
644 * return state.hasTag('loaded');
645 * });
646 *
647 * state.hasTag('loaded'); // true
648 * ```
649 *
650 * @param actorRef The actor ref to subscribe to
651 * @param predicate Determines if a value matches the condition to wait for
652 * @param options
653 * @returns A promise that eventually resolves to the emitted value
654 * that matches the condition
655 */
656function waitFor(actorRef, predicate, options) {
657 const resolvedOptions = {
658 ...defaultWaitForOptions,
659 ...options
660 };
661 return new Promise((res, rej) => {
662 let done = false;
663 const handle = resolvedOptions.timeout === Infinity ? undefined : setTimeout(() => {
664 sub.unsubscribe();
665 rej(new Error(`Timeout of ${resolvedOptions.timeout} ms exceeded`));
666 }, resolvedOptions.timeout);
667 const dispose = () => {
668 clearTimeout(handle);
669 done = true;
670 sub?.unsubscribe();
671 };
672 function checkEmitted(emitted) {
673 if (predicate(emitted)) {
674 dispose();
675 res(emitted);
676 }
677 }
678 let sub; // avoid TDZ when disposing synchronously
679
680 // See if the current snapshot already matches the predicate
681 checkEmitted(actorRef.getSnapshot());
682 if (done) {
683 return;
684 }
685 sub = actorRef.subscribe({
686 next: checkEmitted,
687 error: err => {
688 dispose();
689 rej(err);
690 },
691 complete: () => {
692 dispose();
693 rej(new Error(`Actor terminated without satisfying predicate`));
694 }
695 });
696 if (done) {
697 sub.unsubscribe();
698 }
699 });
700}
701
702// this is not 100% accurate since we can't make parallel regions required in the result
703// `TTestValue` doesn't encode this information anyhow for us to be able to do that
704// this is fine for most practical use cases anyway though
705/**
706 * Creates a state machine (statechart) with the given configuration.
707 *
708 * The state machine represents the pure logic of a state machine actor.
709 *
710 * @param config The state machine configuration.
711 * @param options DEPRECATED: use `setup({ ... })` or `machine.provide({ ... })` to provide machine implementations instead.
712 *
713 * @example
714 ```ts
715 import { createMachine } from 'xstate';
716
717 const lightMachine = createMachine({
718 id: 'light',
719 initial: 'green',
720 states: {
721 green: {
722 on: {
723 TIMER: { target: 'yellow' }
724 }
725 },
726 yellow: {
727 on: {
728 TIMER: { target: 'red' }
729 }
730 },
731 red: {
732 on: {
733 TIMER: { target: 'green' }
734 }
735 }
736 }
737 });
738
739 const lightActor = createActor(lightMachine);
740 lightActor.start();
741
742 lightActor.send({ type: 'TIMER' });
743 ```
744 */
745function createMachine(config, implementations) {
746 return new StateMachine(config, implementations);
747}
748
749/** @internal */
750function createInertActorScope(actorLogic) {
751 const self = guards_dist_xstateGuards.createActor(actorLogic);
752 const inertActorScope = {
753 self,
754 defer: () => {},
755 id: '',
756 logger: () => {},
757 sessionId: '',
758 stopChild: () => {},
759 system: self.system,
760 emit: () => {}
761 };
762 return inertActorScope;
763}
764function getInitialSnapshot(actorLogic, ...[input]) {
765 const actorScope = createInertActorScope(actorLogic);
766 return actorLogic.getInitialSnapshot(actorScope, input);
767}
768
769/**
770 * Determines the next snapshot for the given `actorLogic` based on
771 * the given `snapshot` and `event`.
772 *
773 * If the `snapshot` is `undefined`, the initial snapshot of the
774 * `actorLogic` is used.
775 *
776 * @example
777 ```ts
778 import { getNextSnapshot } from 'xstate';
779 import { trafficLightMachine } from './trafficLightMachine.ts';
780
781 const nextSnapshot = getNextSnapshot(
782 trafficLightMachine, // actor logic
783 undefined, // snapshot (or initial state if undefined)
784 { type: 'TIMER' }); // event object
785
786 console.log(nextSnapshot.value);
787 // => 'yellow'
788
789 const nextSnapshot2 = getNextSnapshot(
790 trafficLightMachine, // actor logic
791 nextSnapshot, // snapshot
792 { type: 'TIMER' }); // event object
793
794 console.log(nextSnapshot2.value);
795 // =>'red'
796 ```
797 */
798function getNextSnapshot(actorLogic, snapshot, event) {
799 const inertActorScope = createInertActorScope(actorLogic);
800 inertActorScope.self._snapshot = snapshot;
801 return actorLogic.transition(snapshot, event, inertActorScope);
802}
803
804// at the moment we allow extra actors - ones that are not specified by `children`
805// this could be reconsidered in the future
806function setup({
807 schemas,
808 actors,
809 actions,
810 guards,
811 delays
812}) {
813 return {
814 createMachine: config => createMachine({
815 ...config,
816 schemas
817 }, {
818 actors,
819 actions,
820 guards,
821 delays
822 })
823 };
824}
825
826/**
827 * Returns a promise that resolves to the `output` of the actor when it is done.
828 *
829 * @example
830 * ```ts
831 * const machine = createMachine({
832 * // ...
833 * output: {
834 * count: 42
835 * }
836 * });
837 *
838 * const actor = createActor(machine);
839 *
840 * actor.start();
841 *
842 * const output = await toPromise(actor);
843 *
844 * console.log(output);
845 * // logs { count: 42 }
846 * ```
847 */
848function toPromise(actor) {
849 return new Promise((resolve, reject) => {
850 actor.subscribe({
851 complete: () => {
852 resolve(actor.getSnapshot().output);
853 },
854 error: reject
855 });
856 });
857}
858
859/**
860 * Asserts that the given event object is of the specified type or types.
861 * Throws an error if the event object is not of the specified types.
862 @example
863
864 ```ts
865 // ...
866 entry: ({ event }) => {
867 assertEvent(event, 'doNothing');
868 // event is { type: 'doNothing' }
869 },
870 // ...
871 exit: ({ event }) => {
872 assertEvent(event, 'greet');
873 // event is { type: 'greet'; message: string }
874
875 assertEvent(event, ['greet', 'notify']);
876 // event is { type: 'greet'; message: string }
877 // or { type: 'notify'; message: string; level: 'info' | 'error' }
878 },
879 ```
880 */
881function assertEvent(event, type) {
882 const types = guards_dist_xstateGuards.toArray(type);
883 if (!types.includes(event.type)) {
884 const typesText = types.length === 1 ? `type "${types[0]}"` : `one of types "${types.join('", "')}"`;
885 throw new Error(`Expected event ${JSON.stringify(event)} to have ${typesText}`);
886 }
887}
888
889exports.createEmptyActor = actors_dist_xstateActors.createEmptyActor;
890exports.fromCallback = actors_dist_xstateActors.fromCallback;
891exports.fromEventObservable = actors_dist_xstateActors.fromEventObservable;
892exports.fromObservable = actors_dist_xstateActors.fromObservable;
893exports.fromPromise = actors_dist_xstateActors.fromPromise;
894exports.fromTransition = actors_dist_xstateActors.fromTransition;
895exports.Actor = guards_dist_xstateGuards.Actor;
896exports.__unsafe_getAllOwnEventDescriptors = guards_dist_xstateGuards.getAllOwnEventDescriptors;
897exports.and = guards_dist_xstateGuards.and;
898exports.cancel = guards_dist_xstateGuards.cancel;
899exports.createActor = guards_dist_xstateGuards.createActor;
900exports.getStateNodes = guards_dist_xstateGuards.getStateNodes;
901exports.interpret = guards_dist_xstateGuards.interpret;
902exports.isMachineSnapshot = guards_dist_xstateGuards.isMachineSnapshot;
903exports.matchesState = guards_dist_xstateGuards.matchesState;
904exports.not = guards_dist_xstateGuards.not;
905exports.or = guards_dist_xstateGuards.or;
906exports.pathToStateValue = guards_dist_xstateGuards.pathToStateValue;
907exports.raise = guards_dist_xstateGuards.raise;
908exports.spawnChild = guards_dist_xstateGuards.spawnChild;
909exports.stateIn = guards_dist_xstateGuards.stateIn;
910exports.stop = guards_dist_xstateGuards.stop;
911exports.stopChild = guards_dist_xstateGuards.stopChild;
912exports.toObserver = guards_dist_xstateGuards.toObserver;
913exports.SpecialTargets = log.SpecialTargets;
914exports.assign = log.assign;
915exports.emit = log.emit;
916exports.enqueueActions = log.enqueueActions;
917exports.forwardTo = log.forwardTo;
918exports.log = log.log;
919exports.sendParent = log.sendParent;
920exports.sendTo = log.sendTo;
921exports.SimulatedClock = SimulatedClock;
922exports.StateMachine = StateMachine;
923exports.StateNode = StateNode;
924exports.assertEvent = assertEvent;
925exports.createMachine = createMachine;
926exports.getInitialSnapshot = getInitialSnapshot;
927exports.getNextSnapshot = getNextSnapshot;
928exports.setup = setup;
929exports.toPromise = toPromise;
930exports.waitFor = waitFor;