UNPKG

28.6 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var actors_dist_xstateActors = require('../actors/dist/xstate-actors.development.cjs.js');
6var guards_dist_xstateGuards = require('./raise-52a00e8f.development.cjs.js');
7var log = require('./log-6380a394.development.cjs.js');
8require('../dev/dist/xstate-dev.development.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 if (!('output' in this.root) && Object.values(this.states).some(state => state.type === 'final' && 'output' in state)) {
433 console.warn('Missing `machine.output` declaration (top-level final state with output detected)');
434 }
435 }
436
437 /**
438 * Clones this state machine with the provided implementations
439 * and merges the `context` (if provided).
440 *
441 * @param implementations Options (`actions`, `guards`, `actors`, `delays`, `context`)
442 * to recursively merge with the existing options.
443 *
444 * @returns A new `StateMachine` instance with the provided implementations.
445 */
446 provide(implementations) {
447 const {
448 actions,
449 guards,
450 actors,
451 delays
452 } = this.implementations;
453 return new StateMachine(this.config, {
454 actions: {
455 ...actions,
456 ...implementations.actions
457 },
458 guards: {
459 ...guards,
460 ...implementations.guards
461 },
462 actors: {
463 ...actors,
464 ...implementations.actors
465 },
466 delays: {
467 ...delays,
468 ...implementations.delays
469 }
470 });
471 }
472 resolveState(config) {
473 const resolvedStateValue = guards_dist_xstateGuards.resolveStateValue(this.root, config.value);
474 const nodeSet = guards_dist_xstateGuards.getAllStateNodes(guards_dist_xstateGuards.getStateNodes(this.root, resolvedStateValue));
475 return guards_dist_xstateGuards.createMachineSnapshot({
476 _nodes: [...nodeSet],
477 context: config.context || {},
478 children: {},
479 status: guards_dist_xstateGuards.isInFinalState(nodeSet, this.root) ? 'done' : config.status || 'active',
480 output: config.output,
481 error: config.error,
482 historyValue: config.historyValue
483 }, this);
484 }
485
486 /**
487 * Determines the next snapshot given the current `snapshot` and received `event`.
488 * Calculates a full macrostep from all microsteps.
489 *
490 * @param snapshot The current snapshot
491 * @param event The received event
492 */
493 transition(snapshot, event, actorScope) {
494 return guards_dist_xstateGuards.macrostep(snapshot, event, actorScope).snapshot;
495 }
496
497 /**
498 * Determines the next state given the current `state` and `event`.
499 * Calculates a microstep.
500 *
501 * @param state The current state
502 * @param event The received event
503 */
504 microstep(snapshot, event, actorScope) {
505 return guards_dist_xstateGuards.macrostep(snapshot, event, actorScope).microstates;
506 }
507 getTransitionData(snapshot, event) {
508 return guards_dist_xstateGuards.transitionNode(this.root, snapshot.value, snapshot, event) || [];
509 }
510
511 /**
512 * The initial state _before_ evaluating any microsteps.
513 * This "pre-initial" state is provided to initial actions executed in the initial state.
514 */
515 getPreInitialState(actorScope, initEvent, internalQueue) {
516 const {
517 context
518 } = this.config;
519 const preInitial = guards_dist_xstateGuards.createMachineSnapshot({
520 context: typeof context !== 'function' && context ? context : {},
521 _nodes: [this.root],
522 children: {},
523 status: 'active'
524 }, this);
525 if (typeof context === 'function') {
526 const assignment = ({
527 spawn,
528 event,
529 self
530 }) => context({
531 spawn,
532 input: event.input,
533 self
534 });
535 return guards_dist_xstateGuards.resolveActionsAndContext(preInitial, initEvent, actorScope, [log.assign(assignment)], internalQueue);
536 }
537 return preInitial;
538 }
539
540 /**
541 * Returns the initial `State` instance, with reference to `self` as an `ActorRef`.
542 */
543 getInitialSnapshot(actorScope, input) {
544 const initEvent = guards_dist_xstateGuards.createInitEvent(input); // TODO: fix;
545 const internalQueue = [];
546 const preInitialState = this.getPreInitialState(actorScope, initEvent, internalQueue);
547 const nextState = guards_dist_xstateGuards.microstep([{
548 target: [...guards_dist_xstateGuards.getInitialStateNodes(this.root)],
549 source: this.root,
550 reenter: true,
551 actions: [],
552 eventType: null,
553 toJSON: null // TODO: fix
554 }], preInitialState, actorScope, initEvent, true, internalQueue);
555 const {
556 snapshot: macroState
557 } = guards_dist_xstateGuards.macrostep(nextState, initEvent, actorScope, internalQueue);
558 return macroState;
559 }
560 start(snapshot) {
561 Object.values(snapshot.children).forEach(child => {
562 if (child.getSnapshot().status === 'active') {
563 child.start();
564 }
565 });
566 }
567 getStateNodeById(stateId) {
568 const fullPath = guards_dist_xstateGuards.toStatePath(stateId);
569 const relativePath = fullPath.slice(1);
570 const resolvedStateId = guards_dist_xstateGuards.isStateId(fullPath[0]) ? fullPath[0].slice(STATE_IDENTIFIER.length) : fullPath[0];
571 const stateNode = this.idMap.get(resolvedStateId);
572 if (!stateNode) {
573 throw new Error(`Child state node '#${resolvedStateId}' does not exist on machine '${this.id}'`);
574 }
575 return guards_dist_xstateGuards.getStateNodeByPath(stateNode, relativePath);
576 }
577 get definition() {
578 return this.root.definition;
579 }
580 toJSON() {
581 return this.definition;
582 }
583 getPersistedSnapshot(snapshot, options) {
584 return guards_dist_xstateGuards.getPersistedSnapshot(snapshot, options);
585 }
586 restoreSnapshot(snapshot, _actorScope) {
587 const children = {};
588 const snapshotChildren = snapshot.children;
589 Object.keys(snapshotChildren).forEach(actorId => {
590 const actorData = snapshotChildren[actorId];
591 const childState = actorData.snapshot;
592 const src = actorData.src;
593 const logic = typeof src === 'string' ? guards_dist_xstateGuards.resolveReferencedActor(this, src) : src;
594 if (!logic) {
595 return;
596 }
597 const actorRef = guards_dist_xstateGuards.createActor(logic, {
598 id: actorId,
599 parent: _actorScope.self,
600 syncSnapshot: actorData.syncSnapshot,
601 snapshot: childState,
602 src,
603 systemId: actorData.systemId
604 });
605 children[actorId] = actorRef;
606 });
607 const restoredSnapshot = guards_dist_xstateGuards.createMachineSnapshot({
608 ...snapshot,
609 children,
610 _nodes: Array.from(guards_dist_xstateGuards.getAllStateNodes(guards_dist_xstateGuards.getStateNodes(this.root, snapshot.value)))
611 }, this);
612 let seen = new Set();
613 function reviveContext(contextPart, children) {
614 if (seen.has(contextPart)) {
615 return;
616 }
617 seen.add(contextPart);
618 for (let key in contextPart) {
619 const value = contextPart[key];
620 if (value && typeof value === 'object') {
621 if ('xstate$$type' in value && value.xstate$$type === guards_dist_xstateGuards.$$ACTOR_TYPE) {
622 contextPart[key] = children[value.id];
623 continue;
624 }
625 reviveContext(value, children);
626 }
627 }
628 }
629 reviveContext(restoredSnapshot.context, children);
630 return restoredSnapshot;
631 }
632}
633
634const defaultWaitForOptions = {
635 timeout: Infinity // much more than 10 seconds
636};
637
638/**
639 * Subscribes to an actor ref and waits for its emitted value to satisfy
640 * a predicate, and then resolves with that value.
641 * Will throw if the desired state is not reached after an optional timeout.
642 * (defaults to Infinity).
643 *
644 * @example
645 * ```js
646 * const state = await waitFor(someService, state => {
647 * return state.hasTag('loaded');
648 * });
649 *
650 * state.hasTag('loaded'); // true
651 * ```
652 *
653 * @param actorRef The actor ref to subscribe to
654 * @param predicate Determines if a value matches the condition to wait for
655 * @param options
656 * @returns A promise that eventually resolves to the emitted value
657 * that matches the condition
658 */
659function waitFor(actorRef, predicate, options) {
660 const resolvedOptions = {
661 ...defaultWaitForOptions,
662 ...options
663 };
664 return new Promise((res, rej) => {
665 let done = false;
666 if (resolvedOptions.timeout < 0) {
667 console.error('`timeout` passed to `waitFor` is negative and it will reject its internal promise immediately.');
668 }
669 const handle = resolvedOptions.timeout === Infinity ? undefined : setTimeout(() => {
670 sub.unsubscribe();
671 rej(new Error(`Timeout of ${resolvedOptions.timeout} ms exceeded`));
672 }, resolvedOptions.timeout);
673 const dispose = () => {
674 clearTimeout(handle);
675 done = true;
676 sub?.unsubscribe();
677 };
678 function checkEmitted(emitted) {
679 if (predicate(emitted)) {
680 dispose();
681 res(emitted);
682 }
683 }
684 let sub; // avoid TDZ when disposing synchronously
685
686 // See if the current snapshot already matches the predicate
687 checkEmitted(actorRef.getSnapshot());
688 if (done) {
689 return;
690 }
691 sub = actorRef.subscribe({
692 next: checkEmitted,
693 error: err => {
694 dispose();
695 rej(err);
696 },
697 complete: () => {
698 dispose();
699 rej(new Error(`Actor terminated without satisfying predicate`));
700 }
701 });
702 if (done) {
703 sub.unsubscribe();
704 }
705 });
706}
707
708// this is not 100% accurate since we can't make parallel regions required in the result
709// `TTestValue` doesn't encode this information anyhow for us to be able to do that
710// this is fine for most practical use cases anyway though
711/**
712 * Creates a state machine (statechart) with the given configuration.
713 *
714 * The state machine represents the pure logic of a state machine actor.
715 *
716 * @param config The state machine configuration.
717 * @param options DEPRECATED: use `setup({ ... })` or `machine.provide({ ... })` to provide machine implementations instead.
718 *
719 * @example
720 ```ts
721 import { createMachine } from 'xstate';
722
723 const lightMachine = createMachine({
724 id: 'light',
725 initial: 'green',
726 states: {
727 green: {
728 on: {
729 TIMER: { target: 'yellow' }
730 }
731 },
732 yellow: {
733 on: {
734 TIMER: { target: 'red' }
735 }
736 },
737 red: {
738 on: {
739 TIMER: { target: 'green' }
740 }
741 }
742 }
743 });
744
745 const lightActor = createActor(lightMachine);
746 lightActor.start();
747
748 lightActor.send({ type: 'TIMER' });
749 ```
750 */
751function createMachine(config, implementations) {
752 return new StateMachine(config, implementations);
753}
754
755/** @internal */
756function createInertActorScope(actorLogic) {
757 const self = guards_dist_xstateGuards.createActor(actorLogic);
758 const inertActorScope = {
759 self,
760 defer: () => {},
761 id: '',
762 logger: () => {},
763 sessionId: '',
764 stopChild: () => {},
765 system: self.system,
766 emit: () => {}
767 };
768 return inertActorScope;
769}
770function getInitialSnapshot(actorLogic, ...[input]) {
771 const actorScope = createInertActorScope(actorLogic);
772 return actorLogic.getInitialSnapshot(actorScope, input);
773}
774
775/**
776 * Determines the next snapshot for the given `actorLogic` based on
777 * the given `snapshot` and `event`.
778 *
779 * If the `snapshot` is `undefined`, the initial snapshot of the
780 * `actorLogic` is used.
781 *
782 * @example
783 ```ts
784 import { getNextSnapshot } from 'xstate';
785 import { trafficLightMachine } from './trafficLightMachine.ts';
786
787 const nextSnapshot = getNextSnapshot(
788 trafficLightMachine, // actor logic
789 undefined, // snapshot (or initial state if undefined)
790 { type: 'TIMER' }); // event object
791
792 console.log(nextSnapshot.value);
793 // => 'yellow'
794
795 const nextSnapshot2 = getNextSnapshot(
796 trafficLightMachine, // actor logic
797 nextSnapshot, // snapshot
798 { type: 'TIMER' }); // event object
799
800 console.log(nextSnapshot2.value);
801 // =>'red'
802 ```
803 */
804function getNextSnapshot(actorLogic, snapshot, event) {
805 const inertActorScope = createInertActorScope(actorLogic);
806 inertActorScope.self._snapshot = snapshot;
807 return actorLogic.transition(snapshot, event, inertActorScope);
808}
809
810// at the moment we allow extra actors - ones that are not specified by `children`
811// this could be reconsidered in the future
812function setup({
813 schemas,
814 actors,
815 actions,
816 guards,
817 delays
818}) {
819 return {
820 createMachine: config => createMachine({
821 ...config,
822 schemas
823 }, {
824 actors,
825 actions,
826 guards,
827 delays
828 })
829 };
830}
831
832/**
833 * Returns a promise that resolves to the `output` of the actor when it is done.
834 *
835 * @example
836 * ```ts
837 * const machine = createMachine({
838 * // ...
839 * output: {
840 * count: 42
841 * }
842 * });
843 *
844 * const actor = createActor(machine);
845 *
846 * actor.start();
847 *
848 * const output = await toPromise(actor);
849 *
850 * console.log(output);
851 * // logs { count: 42 }
852 * ```
853 */
854function toPromise(actor) {
855 return new Promise((resolve, reject) => {
856 actor.subscribe({
857 complete: () => {
858 resolve(actor.getSnapshot().output);
859 },
860 error: reject
861 });
862 });
863}
864
865/**
866 * Asserts that the given event object is of the specified type or types.
867 * Throws an error if the event object is not of the specified types.
868 @example
869
870 ```ts
871 // ...
872 entry: ({ event }) => {
873 assertEvent(event, 'doNothing');
874 // event is { type: 'doNothing' }
875 },
876 // ...
877 exit: ({ event }) => {
878 assertEvent(event, 'greet');
879 // event is { type: 'greet'; message: string }
880
881 assertEvent(event, ['greet', 'notify']);
882 // event is { type: 'greet'; message: string }
883 // or { type: 'notify'; message: string; level: 'info' | 'error' }
884 },
885 ```
886 */
887function assertEvent(event, type) {
888 const types = guards_dist_xstateGuards.toArray(type);
889 if (!types.includes(event.type)) {
890 const typesText = types.length === 1 ? `type "${types[0]}"` : `one of types "${types.join('", "')}"`;
891 throw new Error(`Expected event ${JSON.stringify(event)} to have ${typesText}`);
892 }
893}
894
895exports.createEmptyActor = actors_dist_xstateActors.createEmptyActor;
896exports.fromCallback = actors_dist_xstateActors.fromCallback;
897exports.fromEventObservable = actors_dist_xstateActors.fromEventObservable;
898exports.fromObservable = actors_dist_xstateActors.fromObservable;
899exports.fromPromise = actors_dist_xstateActors.fromPromise;
900exports.fromTransition = actors_dist_xstateActors.fromTransition;
901exports.Actor = guards_dist_xstateGuards.Actor;
902exports.__unsafe_getAllOwnEventDescriptors = guards_dist_xstateGuards.getAllOwnEventDescriptors;
903exports.and = guards_dist_xstateGuards.and;
904exports.cancel = guards_dist_xstateGuards.cancel;
905exports.createActor = guards_dist_xstateGuards.createActor;
906exports.getStateNodes = guards_dist_xstateGuards.getStateNodes;
907exports.interpret = guards_dist_xstateGuards.interpret;
908exports.isMachineSnapshot = guards_dist_xstateGuards.isMachineSnapshot;
909exports.matchesState = guards_dist_xstateGuards.matchesState;
910exports.not = guards_dist_xstateGuards.not;
911exports.or = guards_dist_xstateGuards.or;
912exports.pathToStateValue = guards_dist_xstateGuards.pathToStateValue;
913exports.raise = guards_dist_xstateGuards.raise;
914exports.spawnChild = guards_dist_xstateGuards.spawnChild;
915exports.stateIn = guards_dist_xstateGuards.stateIn;
916exports.stop = guards_dist_xstateGuards.stop;
917exports.stopChild = guards_dist_xstateGuards.stopChild;
918exports.toObserver = guards_dist_xstateGuards.toObserver;
919exports.SpecialTargets = log.SpecialTargets;
920exports.assign = log.assign;
921exports.emit = log.emit;
922exports.enqueueActions = log.enqueueActions;
923exports.forwardTo = log.forwardTo;
924exports.log = log.log;
925exports.sendParent = log.sendParent;
926exports.sendTo = log.sendTo;
927exports.SimulatedClock = SimulatedClock;
928exports.StateMachine = StateMachine;
929exports.StateNode = StateNode;
930exports.assertEvent = assertEvent;
931exports.createMachine = createMachine;
932exports.getInitialSnapshot = getInitialSnapshot;
933exports.getNextSnapshot = getNextSnapshot;
934exports.setup = setup;
935exports.toPromise = toPromise;
936exports.waitFor = waitFor;