xstate 5.17.0 → 5.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/dist/xstate-actions.umd.min.js.map +1 -1
- package/dist/declarations/src/State.d.ts +8 -7
- package/dist/declarations/src/StateMachine.d.ts +2 -3
- package/dist/declarations/src/StateNode.d.ts +1 -0
- package/dist/declarations/src/createMachine.d.ts +3 -2
- package/dist/declarations/src/stateUtils.d.ts +1 -1
- package/dist/declarations/src/types.d.ts +15 -11
- package/dist/xstate.umd.min.js.map +1 -1
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xstate-guards.umd.min.js","sources":["../../src/constants.ts","../../src/stateUtils.ts","../../src/guards.ts"],"sourcesContent":["export const STATE_DELIMITER = '.';\nexport const TARGETLESS_KEY = '';\nexport const NULL_EVENT = '';\nexport const STATE_IDENTIFIER = '#';\nexport const WILDCARD = '*';\nexport const XSTATE_INIT = 'xstate.init';\nexport const XSTATE_ERROR = 'xstate.error';\nexport const XSTATE_STOP = 'xstate.stop';\n","import isDevelopment from '#is-development';\nimport { MachineSnapshot, cloneMachineSnapshot } from './State.ts';\nimport type { StateNode } from './StateNode.ts';\nimport { raise } from './actions.ts';\nimport { createAfterEvent, createDoneStateEvent } from './eventUtils.ts';\nimport { cancel } from './actions/cancel.ts';\nimport { spawnChild } from './actions/spawnChild.ts';\nimport { stopChild } from './actions/stopChild.ts';\nimport {\n XSTATE_INIT,\n NULL_EVENT,\n STATE_DELIMITER,\n STATE_IDENTIFIER,\n XSTATE_STOP,\n WILDCARD\n} from './constants.ts';\nimport { evaluateGuard } from './guards.ts';\nimport {\n ActionArgs,\n AnyEventObject,\n AnyHistoryValue,\n AnyMachineSnapshot,\n AnyStateNode,\n AnyTransitionDefinition,\n DelayExpr,\n DelayedTransitionDefinition,\n EventObject,\n HistoryValue,\n InitialTransitionConfig,\n InitialTransitionDefinition,\n MachineContext,\n StateValue,\n StateValueMap,\n TransitionDefinition,\n TODO,\n UnknownAction,\n ParameterizedObject,\n ActionFunction,\n AnyTransitionConfig,\n ProvidedActor,\n AnyActorScope\n} from './types.ts';\nimport {\n resolveOutput,\n normalizeTarget,\n toArray,\n toStatePath,\n toTransitionConfigArray,\n isErrorActorEvent\n} from './utils.ts';\nimport { ProcessingStatus } from './createActor.ts';\n\ntype StateNodeIterable<\n TContext extends MachineContext,\n TE extends EventObject\n> = Iterable<StateNode<TContext, TE>>;\ntype AnyStateNodeIterable = StateNodeIterable<any, any>;\n\ntype AdjList = Map<AnyStateNode, Array<AnyStateNode>>;\n\nconst isAtomicStateNode = (stateNode: StateNode<any, any>) =>\n stateNode.type === 'atomic' || stateNode.type === 'final';\n\nfunction getChildren<TContext extends MachineContext, TE extends EventObject>(\n stateNode: StateNode<TContext, TE>\n): Array<StateNode<TContext, TE>> {\n return Object.values(stateNode.states).filter((sn) => sn.type !== 'history');\n}\n\nfunction getProperAncestors(\n stateNode: AnyStateNode,\n toStateNode: AnyStateNode | undefined\n): Array<typeof stateNode> {\n const ancestors: Array<typeof stateNode> = [];\n\n if (toStateNode === stateNode) {\n return ancestors;\n }\n\n // add all ancestors\n let m = stateNode.parent;\n while (m && m !== toStateNode) {\n ancestors.push(m);\n m = m.parent;\n }\n\n return ancestors;\n}\n\nexport function getAllStateNodes(\n stateNodes: Iterable<AnyStateNode>\n): Set<AnyStateNode> {\n const nodeSet = new Set(stateNodes);\n\n const adjList = getAdjList(nodeSet);\n\n // add descendants\n for (const s of nodeSet) {\n // if previously active, add existing child nodes\n if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s)!.length)) {\n getInitialStateNodesWithTheirAncestors(s).forEach((sn) =>\n nodeSet.add(sn)\n );\n } else {\n if (s.type === 'parallel') {\n for (const child of getChildren(s)) {\n if (child.type === 'history') {\n continue;\n }\n\n if (!nodeSet.has(child)) {\n const initialStates = getInitialStateNodesWithTheirAncestors(child);\n for (const initialStateNode of initialStates) {\n nodeSet.add(initialStateNode);\n }\n }\n }\n }\n }\n }\n\n // add all ancestors\n for (const s of nodeSet) {\n let m = s.parent;\n\n while (m) {\n nodeSet.add(m);\n m = m.parent;\n }\n }\n\n return nodeSet;\n}\n\nfunction getValueFromAdj(baseNode: AnyStateNode, adjList: AdjList): StateValue {\n const childStateNodes = adjList.get(baseNode);\n\n if (!childStateNodes) {\n return {}; // todo: fix?\n }\n\n if (baseNode.type === 'compound') {\n const childStateNode = childStateNodes[0];\n if (childStateNode) {\n if (isAtomicStateNode(childStateNode)) {\n return childStateNode.key;\n }\n } else {\n return {};\n }\n }\n\n const stateValue: StateValue = {};\n for (const childStateNode of childStateNodes) {\n stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList);\n }\n\n return stateValue;\n}\n\nfunction getAdjList<TContext extends MachineContext, TE extends EventObject>(\n stateNodes: StateNodeIterable<TContext, TE>\n): AdjList {\n const adjList: AdjList = new Map();\n\n for (const s of stateNodes) {\n if (!adjList.has(s)) {\n adjList.set(s, []);\n }\n\n if (s.parent) {\n if (!adjList.has(s.parent)) {\n adjList.set(s.parent, []);\n }\n\n adjList.get(s.parent)!.push(s);\n }\n }\n\n return adjList;\n}\n\nexport function getStateValue(\n rootNode: AnyStateNode,\n stateNodes: AnyStateNodeIterable\n): StateValue {\n const config = getAllStateNodes(stateNodes);\n return getValueFromAdj(rootNode, getAdjList(config));\n}\n\nexport function isInFinalState(\n stateNodeSet: Set<AnyStateNode>,\n stateNode: AnyStateNode\n): boolean {\n if (stateNode.type === 'compound') {\n return getChildren(stateNode).some(\n (s) => s.type === 'final' && stateNodeSet.has(s)\n );\n }\n if (stateNode.type === 'parallel') {\n return getChildren(stateNode).every((sn) =>\n isInFinalState(stateNodeSet, sn)\n );\n }\n\n return stateNode.type === 'final';\n}\n\nexport const isStateId = (str: string) => str[0] === STATE_IDENTIFIER;\n\nexport function getCandidates<TEvent extends EventObject>(\n stateNode: StateNode<any, TEvent>,\n receivedEventType: TEvent['type']\n): Array<TransitionDefinition<any, TEvent>> {\n const candidates =\n stateNode.transitions.get(receivedEventType) ||\n [...stateNode.transitions.keys()]\n .filter((eventDescriptor) => {\n // check if transition is a wildcard transition,\n // which matches any non-transient events\n if (eventDescriptor === WILDCARD) {\n return true;\n }\n\n if (!eventDescriptor.endsWith('.*')) {\n return false;\n }\n\n if (isDevelopment && /.*\\*.+/.test(eventDescriptor)) {\n console.warn(\n `Wildcards can only be the last token of an event descriptor (e.g., \"event.*\") or the entire event descriptor (\"*\"). Check the \"${eventDescriptor}\" event.`\n );\n }\n\n const partialEventTokens = eventDescriptor.split('.');\n const eventTokens = receivedEventType.split('.');\n\n for (\n let tokenIndex = 0;\n tokenIndex < partialEventTokens.length;\n tokenIndex++\n ) {\n const partialEventToken = partialEventTokens[tokenIndex];\n const eventToken = eventTokens[tokenIndex];\n\n if (partialEventToken === '*') {\n const isLastToken = tokenIndex === partialEventTokens.length - 1;\n\n if (isDevelopment && !isLastToken) {\n console.warn(\n `Infix wildcards in transition events are not allowed. Check the \"${eventDescriptor}\" transition.`\n );\n }\n\n return isLastToken;\n }\n\n if (partialEventToken !== eventToken) {\n return false;\n }\n }\n\n return true;\n })\n .sort((a, b) => b.length - a.length)\n .flatMap((key) => stateNode.transitions.get(key)!);\n\n return candidates;\n}\n\n/** All delayed transitions from the config. */\nexport function getDelayedTransitions(\n stateNode: AnyStateNode\n): Array<DelayedTransitionDefinition<MachineContext, EventObject>> {\n const afterConfig = stateNode.config.after;\n if (!afterConfig) {\n return [];\n }\n\n const mutateEntryExit = (delay: string | number, i: number) => {\n const afterEvent = createAfterEvent(delay, stateNode.id);\n const eventType = afterEvent.type;\n stateNode.entry.push(raise(afterEvent, { id: eventType, delay }));\n stateNode.exit.push(cancel(eventType));\n return eventType;\n };\n\n const delayedTransitions = Object.keys(afterConfig).flatMap((delay, i) => {\n const configTransition = afterConfig[delay];\n const resolvedTransition =\n typeof configTransition === 'string'\n ? { target: configTransition }\n : configTransition;\n const resolvedDelay = Number.isNaN(+delay) ? delay : +delay;\n const eventType = mutateEntryExit(resolvedDelay, i);\n return toArray(resolvedTransition).map((transition) => ({\n ...transition,\n event: eventType,\n delay: resolvedDelay\n }));\n });\n return delayedTransitions.map((delayedTransition) => {\n const { delay } = delayedTransition;\n return {\n ...formatTransition(\n stateNode,\n delayedTransition.event,\n delayedTransition\n ),\n delay\n };\n });\n}\n\nexport function formatTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n descriptor: string,\n transitionConfig: AnyTransitionConfig\n): AnyTransitionDefinition {\n const normalizedTarget = normalizeTarget(transitionConfig.target);\n const reenter = transitionConfig.reenter ?? false;\n const target = resolveTarget(stateNode, normalizedTarget);\n\n // TODO: should this be part of a lint rule instead?\n if (isDevelopment && (transitionConfig as any).cond) {\n throw new Error(\n `State \"${stateNode.id}\" has declared \\`cond\\` for one of its transitions. This property has been renamed to \\`guard\\`. Please update your code.`\n );\n }\n const transition = {\n ...transitionConfig,\n actions: toArray(transitionConfig.actions),\n guard: transitionConfig.guard as never,\n target,\n source: stateNode,\n reenter,\n eventType: descriptor,\n toJSON: () => ({\n ...transition,\n source: `#${stateNode.id}`,\n target: target ? target.map((t) => `#${t.id}`) : undefined\n })\n };\n\n return transition;\n}\n\nexport function formatTransitions<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode\n): Map<string, TransitionDefinition<TContext, TEvent>[]> {\n const transitions = new Map<\n string,\n TransitionDefinition<TContext, AnyEventObject>[]\n >();\n if (stateNode.config.on) {\n for (const descriptor of Object.keys(stateNode.config.on)) {\n if (descriptor === NULL_EVENT) {\n throw new Error(\n 'Null events (\"\") cannot be specified as a transition key. Use `always: { ... }` instead.'\n );\n }\n const transitionsConfig = stateNode.config.on[descriptor];\n transitions.set(\n descriptor,\n toTransitionConfigArray(transitionsConfig).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n }\n if (stateNode.config.onDone) {\n const descriptor = `xstate.done.state.${stateNode.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(stateNode.config.onDone).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n for (const invokeDef of stateNode.invoke) {\n if (invokeDef.onDone) {\n const descriptor = `xstate.done.actor.${invokeDef.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(invokeDef.onDone).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n if (invokeDef.onError) {\n const descriptor = `xstate.error.actor.${invokeDef.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(invokeDef.onError).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n if (invokeDef.onSnapshot) {\n const descriptor = `xstate.snapshot.${invokeDef.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(invokeDef.onSnapshot).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n }\n for (const delayedTransition of stateNode.after) {\n let existing = transitions.get(delayedTransition.eventType);\n if (!existing) {\n existing = [];\n transitions.set(delayedTransition.eventType, existing);\n }\n existing.push(delayedTransition);\n }\n return transitions as Map<string, TransitionDefinition<TContext, any>[]>;\n}\n\nexport function formatInitialTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n _target:\n | string\n | undefined\n | InitialTransitionConfig<TContext, TEvent, TODO, TODO, TODO, TODO>\n): InitialTransitionDefinition<TContext, TEvent> {\n const resolvedTarget =\n typeof _target === 'string'\n ? stateNode.states[_target]\n : _target\n ? stateNode.states[_target.target]\n : undefined;\n if (!resolvedTarget && _target) {\n throw new Error(\n `Initial state node \"${_target}\" not found on parent state node #${stateNode.id}`\n );\n }\n const transition: InitialTransitionDefinition<TContext, TEvent> = {\n source: stateNode,\n actions:\n !_target || typeof _target === 'string' ? [] : toArray(_target.actions),\n eventType: null as any,\n reenter: false,\n target: resolvedTarget ? [resolvedTarget] : [],\n toJSON: () => ({\n ...transition,\n source: `#${stateNode.id}`,\n target: resolvedTarget ? [`#${resolvedTarget.id}`] : []\n })\n };\n\n return transition;\n}\n\nfunction resolveTarget(\n stateNode: AnyStateNode,\n targets: ReadonlyArray<string | AnyStateNode> | undefined\n): ReadonlyArray<AnyStateNode> | undefined {\n if (targets === undefined) {\n // an undefined target signals that the state node should not transition from that state when receiving that event\n return undefined;\n }\n return targets.map((target) => {\n if (typeof target !== 'string') {\n return target;\n }\n if (isStateId(target)) {\n return stateNode.machine.getStateNodeById(target);\n }\n\n const isInternalTarget = target[0] === STATE_DELIMITER;\n // If internal target is defined on machine,\n // do not include machine key on target\n if (isInternalTarget && !stateNode.parent) {\n return getStateNodeByPath(stateNode, target.slice(1));\n }\n const resolvedTarget = isInternalTarget ? stateNode.key + target : target;\n if (stateNode.parent) {\n try {\n const targetStateNode = getStateNodeByPath(\n stateNode.parent,\n resolvedTarget\n );\n return targetStateNode;\n } catch (err: any) {\n throw new Error(\n `Invalid transition definition for state node '${stateNode.id}':\\n${err.message}`\n );\n }\n } else {\n throw new Error(\n `Invalid target: \"${target}\" is not a valid target from the root node. Did you mean \".${target}\"?`\n );\n }\n });\n}\n\nfunction resolveHistoryDefaultTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateNode: AnyStateNode & { type: 'history' }) {\n const normalizedTarget = normalizeTarget<TContext, TEvent>(\n stateNode.config.target\n );\n if (!normalizedTarget) {\n return stateNode.parent!.initial;\n }\n return {\n target: normalizedTarget.map((t) =>\n typeof t === 'string' ? getStateNodeByPath(stateNode.parent!, t) : t\n )\n };\n}\n\nfunction isHistoryNode(\n stateNode: AnyStateNode\n): stateNode is AnyStateNode & { type: 'history' } {\n return stateNode.type === 'history';\n}\n\nfunction getInitialStateNodesWithTheirAncestors(stateNode: AnyStateNode) {\n const states = getInitialStateNodes(stateNode);\n for (const initialState of states) {\n for (const ancestor of getProperAncestors(initialState, stateNode)) {\n states.add(ancestor);\n }\n }\n return states;\n}\n\nexport function getInitialStateNodes(stateNode: AnyStateNode) {\n const set = new Set<AnyStateNode>();\n\n function iter(descStateNode: AnyStateNode): void {\n if (set.has(descStateNode)) {\n return;\n }\n set.add(descStateNode);\n if (descStateNode.type === 'compound') {\n iter(descStateNode.initial.target[0]);\n } else if (descStateNode.type === 'parallel') {\n for (const child of getChildren(descStateNode)) {\n iter(child);\n }\n }\n }\n\n iter(stateNode);\n\n return set;\n}\n/** Returns the child state node from its relative `stateKey`, or throws. */\nfunction getStateNode(stateNode: AnyStateNode, stateKey: string): AnyStateNode {\n if (isStateId(stateKey)) {\n return stateNode.machine.getStateNodeById(stateKey);\n }\n if (!stateNode.states) {\n throw new Error(\n `Unable to retrieve child state '${stateKey}' from '${stateNode.id}'; no child states exist.`\n );\n }\n const result = stateNode.states[stateKey];\n if (!result) {\n throw new Error(\n `Child state '${stateKey}' does not exist on '${stateNode.id}'`\n );\n }\n return result;\n}\n\n/**\n * Returns the relative state node from the given `statePath`, or throws.\n *\n * @param statePath The string or string array relative path to the state node.\n */\nexport function getStateNodeByPath(\n stateNode: AnyStateNode,\n statePath: string | string[]\n): AnyStateNode {\n if (typeof statePath === 'string' && isStateId(statePath)) {\n try {\n return stateNode.machine.getStateNodeById(statePath);\n } catch (e) {\n // try individual paths\n // throw e;\n }\n }\n const arrayStatePath = toStatePath(statePath).slice();\n let currentStateNode: AnyStateNode = stateNode;\n while (arrayStatePath.length) {\n const key = arrayStatePath.shift()!;\n if (!key.length) {\n break;\n }\n currentStateNode = getStateNode(currentStateNode, key);\n }\n return currentStateNode;\n}\n\n/**\n * Returns the state nodes represented by the current state value.\n *\n * @param stateValue The state value or State instance\n */\nexport function getStateNodes<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateNode: AnyStateNode, stateValue: StateValue): Array<AnyStateNode> {\n if (typeof stateValue === 'string') {\n const childStateNode = stateNode.states[stateValue];\n if (!childStateNode) {\n throw new Error(\n `State '${stateValue}' does not exist on '${stateNode.id}'`\n );\n }\n return [stateNode, childStateNode];\n }\n\n const childStateKeys = Object.keys(stateValue);\n const childStateNodes: Array<AnyStateNode> = childStateKeys\n .map((subStateKey) => getStateNode(stateNode, subStateKey))\n .filter(Boolean);\n\n return [stateNode.machine.root, stateNode].concat(\n childStateNodes,\n childStateKeys.reduce((allSubStateNodes, subStateKey) => {\n const subStateNode = getStateNode(stateNode, subStateKey);\n if (!subStateNode) {\n return allSubStateNodes;\n }\n const subStateNodes = getStateNodes(\n subStateNode,\n stateValue[subStateKey]!\n );\n\n return allSubStateNodes.concat(subStateNodes);\n }, [] as Array<AnyStateNode>)\n );\n}\n\nfunction transitionAtomicNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: string,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any // TMeta\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const childStateNode = getStateNode(stateNode, stateValue);\n const next = childStateNode.next(snapshot, event);\n\n if (!next || !next.length) {\n return stateNode.next(snapshot, event);\n }\n\n return next;\n}\n\nfunction transitionCompoundNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any // TMeta\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const subStateKeys = Object.keys(stateValue);\n\n const childStateNode = getStateNode(stateNode, subStateKeys[0]);\n const next = transitionNode(\n childStateNode,\n stateValue[subStateKeys[0]]!,\n snapshot,\n event\n );\n\n if (!next || !next.length) {\n return stateNode.next(snapshot, event);\n }\n\n return next;\n}\n\nfunction transitionParallelNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any // TMeta\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const allInnerTransitions: Array<TransitionDefinition<TContext, TEvent>> = [];\n\n for (const subStateKey of Object.keys(stateValue)) {\n const subStateValue = stateValue[subStateKey];\n\n if (!subStateValue) {\n continue;\n }\n\n const subStateNode = getStateNode(stateNode, subStateKey);\n const innerTransitions = transitionNode(\n subStateNode,\n subStateValue,\n snapshot,\n event\n );\n if (innerTransitions) {\n allInnerTransitions.push(...innerTransitions);\n }\n }\n if (!allInnerTransitions.length) {\n return stateNode.next(snapshot, event);\n }\n\n return allInnerTransitions;\n}\n\nexport function transitionNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValue,\n snapshot: MachineSnapshot<TContext, TEvent, any, any, any, any, any>,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n // leaf node\n if (typeof stateValue === 'string') {\n return transitionAtomicNode(stateNode, stateValue, snapshot, event);\n }\n\n // compound node\n if (Object.keys(stateValue).length === 1) {\n return transitionCompoundNode(stateNode, stateValue, snapshot, event);\n }\n\n // parallel node\n return transitionParallelNode(stateNode, stateValue, snapshot, event);\n}\n\nfunction getHistoryNodes(stateNode: AnyStateNode): Array<AnyStateNode> {\n return Object.keys(stateNode.states)\n .map((key) => stateNode.states[key])\n .filter((sn) => sn.type === 'history');\n}\n\nfunction isDescendant(\n childStateNode: AnyStateNode,\n parentStateNode: AnyStateNode\n): boolean {\n let marker = childStateNode;\n while (marker.parent && marker.parent !== parentStateNode) {\n marker = marker.parent;\n }\n\n return marker.parent === parentStateNode;\n}\n\nfunction getPathFromRootToNode(stateNode: AnyStateNode): Array<AnyStateNode> {\n const path: Array<AnyStateNode> = [];\n let marker = stateNode.parent;\n\n while (marker) {\n path.unshift(marker);\n marker = marker.parent;\n }\n\n return path;\n}\n\nfunction hasIntersection<T>(s1: Iterable<T>, s2: Iterable<T>): boolean {\n const set1 = new Set(s1);\n const set2 = new Set(s2);\n\n for (const item of set1) {\n if (set2.has(item)) {\n return true;\n }\n }\n for (const item of set2) {\n if (set1.has(item)) {\n return true;\n }\n }\n return false;\n}\n\nfunction removeConflictingTransitions(\n enabledTransitions: Array<AnyTransitionDefinition>,\n stateNodeSet: Set<AnyStateNode>,\n historyValue: AnyHistoryValue\n): Array<AnyTransitionDefinition> {\n const filteredTransitions = new Set<AnyTransitionDefinition>();\n\n for (const t1 of enabledTransitions) {\n let t1Preempted = false;\n const transitionsToRemove = new Set<AnyTransitionDefinition>();\n for (const t2 of filteredTransitions) {\n if (\n hasIntersection(\n computeExitSet([t1], stateNodeSet, historyValue),\n computeExitSet([t2], stateNodeSet, historyValue)\n )\n ) {\n if (isDescendant(t1.source, t2.source)) {\n transitionsToRemove.add(t2);\n } else {\n t1Preempted = true;\n break;\n }\n }\n }\n if (!t1Preempted) {\n for (const t3 of transitionsToRemove) {\n filteredTransitions.delete(t3);\n }\n filteredTransitions.add(t1);\n }\n }\n\n return Array.from(filteredTransitions);\n}\n\nfunction findLeastCommonAncestor(\n stateNodes: Array<AnyStateNode>\n): AnyStateNode | undefined {\n const [head, ...tail] = stateNodes;\n for (const ancestor of getProperAncestors(head, undefined)) {\n if (tail.every((sn) => isDescendant(sn, ancestor))) {\n return ancestor;\n }\n }\n}\n\nfunction getEffectiveTargetStates(\n transition: Pick<AnyTransitionDefinition, 'target'>,\n historyValue: AnyHistoryValue\n): Array<AnyStateNode> {\n if (!transition.target) {\n return [];\n }\n\n const targets = new Set<AnyStateNode>();\n\n for (const targetNode of transition.target) {\n if (isHistoryNode(targetNode)) {\n if (historyValue[targetNode.id]) {\n for (const node of historyValue[targetNode.id]) {\n targets.add(node);\n }\n } else {\n for (const node of getEffectiveTargetStates(\n resolveHistoryDefaultTransition(targetNode),\n historyValue\n )) {\n targets.add(node);\n }\n }\n } else {\n targets.add(targetNode);\n }\n }\n\n return [...targets];\n}\n\nfunction getTransitionDomain(\n transition: AnyTransitionDefinition,\n historyValue: AnyHistoryValue\n): AnyStateNode | undefined {\n const targetStates = getEffectiveTargetStates(transition, historyValue);\n\n if (!targetStates) {\n return;\n }\n\n if (\n !transition.reenter &&\n targetStates.every(\n (target) =>\n target === transition.source || isDescendant(target, transition.source)\n )\n ) {\n return transition.source;\n }\n\n const lca = findLeastCommonAncestor(targetStates.concat(transition.source));\n\n if (lca) {\n return lca;\n }\n\n // at this point we know that it's a root transition since LCA couldn't be found\n if (transition.reenter) {\n return;\n }\n\n return transition.source.machine.root;\n}\n\nfunction computeExitSet(\n transitions: AnyTransitionDefinition[],\n stateNodeSet: Set<AnyStateNode>,\n historyValue: AnyHistoryValue\n): Array<AnyStateNode> {\n const statesToExit = new Set<AnyStateNode>();\n\n for (const t of transitions) {\n if (t.target?.length) {\n const domain = getTransitionDomain(t, historyValue);\n\n if (t.reenter && t.source === domain) {\n statesToExit.add(domain);\n }\n\n for (const stateNode of stateNodeSet) {\n if (isDescendant(stateNode, domain!)) {\n statesToExit.add(stateNode);\n }\n }\n }\n }\n\n return [...statesToExit];\n}\n\nfunction areStateNodeCollectionsEqual(\n prevStateNodes: StateNode<any, any>[],\n nextStateNodeSet: Set<StateNode<any, any>>\n) {\n if (prevStateNodes.length !== nextStateNodeSet.size) {\n return false;\n }\n for (const node of prevStateNodes) {\n if (!nextStateNodeSet.has(node)) {\n return false;\n }\n }\n return true;\n}\n\n/** https://www.w3.org/TR/scxml/#microstepProcedure */\nexport function microstep<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n transitions: Array<AnyTransitionDefinition>,\n currentSnapshot: AnyMachineSnapshot,\n actorScope: AnyActorScope,\n event: AnyEventObject,\n isInitial: boolean,\n internalQueue: Array<AnyEventObject>\n): AnyMachineSnapshot {\n if (!transitions.length) {\n return currentSnapshot;\n }\n const mutStateNodeSet = new Set(currentSnapshot._nodes);\n let historyValue = currentSnapshot.historyValue;\n\n const filteredTransitions = removeConflictingTransitions(\n transitions,\n mutStateNodeSet,\n historyValue\n );\n\n let nextState = currentSnapshot;\n\n // Exit states\n if (!isInitial) {\n [nextState, historyValue] = exitStates(\n nextState,\n event,\n actorScope,\n filteredTransitions,\n mutStateNodeSet,\n historyValue,\n internalQueue\n );\n }\n\n // Execute transition content\n nextState = resolveActionsAndContext(\n nextState,\n event,\n actorScope,\n filteredTransitions.flatMap((t) => t.actions),\n internalQueue\n );\n\n // Enter states\n nextState = enterStates(\n nextState,\n event,\n actorScope,\n filteredTransitions,\n mutStateNodeSet,\n internalQueue,\n historyValue,\n isInitial\n );\n\n const nextStateNodes = [...mutStateNodeSet];\n\n if (nextState.status === 'done') {\n nextState = resolveActionsAndContext(\n nextState,\n event,\n actorScope,\n nextStateNodes\n .sort((a, b) => b.order - a.order)\n .flatMap((state) => state.exit),\n internalQueue\n );\n }\n\n try {\n if (\n historyValue === currentSnapshot.historyValue &&\n areStateNodeCollectionsEqual(currentSnapshot._nodes, mutStateNodeSet)\n ) {\n return nextState;\n }\n return cloneMachineSnapshot(nextState, {\n _nodes: nextStateNodes,\n historyValue\n });\n } catch (e) {\n // TODO: Refactor this once proper error handling is implemented.\n // See https://github.com/statelyai/rfcs/pull/4\n throw e;\n }\n}\n\nfunction getMachineOutput(\n snapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n rootNode: AnyStateNode,\n rootCompletionNode: AnyStateNode\n) {\n if (rootNode.output === undefined) {\n return;\n }\n const doneStateEvent = createDoneStateEvent(\n rootCompletionNode.id,\n rootCompletionNode.output !== undefined && rootCompletionNode.parent\n ? resolveOutput(\n rootCompletionNode.output,\n snapshot.context,\n event,\n actorScope.self\n )\n : undefined\n );\n return resolveOutput(\n rootNode.output,\n snapshot.context,\n doneStateEvent,\n actorScope.self\n );\n}\n\nfunction enterStates(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n filteredTransitions: AnyTransitionDefinition[],\n mutStateNodeSet: Set<AnyStateNode>,\n internalQueue: AnyEventObject[],\n historyValue: HistoryValue<any, any>,\n isInitial: boolean\n) {\n let nextSnapshot = currentSnapshot;\n const statesToEnter = new Set<AnyStateNode>();\n // those are states that were directly targeted or indirectly targeted by the explicit target\n // in other words, those are states for which initial actions should be executed\n // when we target `#deep_child` initial actions of its ancestors shouldn't be executed\n const statesForDefaultEntry = new Set<AnyStateNode>();\n computeEntrySet(\n filteredTransitions,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n\n // In the initial state, the root state node is \"entered\".\n if (isInitial) {\n statesForDefaultEntry.add(currentSnapshot.machine.root);\n }\n\n const completedNodes = new Set();\n\n for (const stateNodeToEnter of [...statesToEnter].sort(\n (a, b) => a.order - b.order\n )) {\n mutStateNodeSet.add(stateNodeToEnter);\n const actions: UnknownAction[] = [];\n\n // Add entry actions\n actions.push(...stateNodeToEnter.entry);\n\n for (const invokeDef of stateNodeToEnter.invoke) {\n actions.push(\n spawnChild(invokeDef.src, {\n ...invokeDef,\n syncSnapshot: !!invokeDef.onSnapshot\n })\n );\n }\n\n if (statesForDefaultEntry.has(stateNodeToEnter)) {\n const initialActions = stateNodeToEnter.initial!.actions;\n actions.push(...initialActions);\n }\n\n nextSnapshot = resolveActionsAndContext(\n nextSnapshot,\n event,\n actorScope,\n actions,\n internalQueue,\n stateNodeToEnter.invoke.map((invokeDef) => invokeDef.id)\n );\n\n if (stateNodeToEnter.type === 'final') {\n const parent = stateNodeToEnter.parent;\n\n let ancestorMarker =\n parent?.type === 'parallel' ? parent : parent?.parent;\n let rootCompletionNode = ancestorMarker || stateNodeToEnter;\n\n if (parent?.type === 'compound') {\n internalQueue.push(\n createDoneStateEvent(\n parent!.id,\n stateNodeToEnter.output !== undefined\n ? resolveOutput(\n stateNodeToEnter.output,\n nextSnapshot.context,\n event,\n actorScope.self\n )\n : undefined\n )\n );\n }\n while (\n ancestorMarker?.type === 'parallel' &&\n !completedNodes.has(ancestorMarker) &&\n isInFinalState(mutStateNodeSet, ancestorMarker)\n ) {\n completedNodes.add(ancestorMarker);\n internalQueue.push(createDoneStateEvent(ancestorMarker.id));\n rootCompletionNode = ancestorMarker;\n ancestorMarker = ancestorMarker.parent;\n }\n if (ancestorMarker) {\n continue;\n }\n\n nextSnapshot = cloneMachineSnapshot(nextSnapshot, {\n status: 'done',\n output: getMachineOutput(\n nextSnapshot,\n event,\n actorScope,\n nextSnapshot.machine.root,\n rootCompletionNode\n )\n });\n }\n }\n\n return nextSnapshot;\n}\n\nfunction computeEntrySet(\n transitions: Array<AnyTransitionDefinition>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>,\n statesToEnter: Set<AnyStateNode>\n) {\n for (const t of transitions) {\n const domain = getTransitionDomain(t, historyValue);\n\n for (const s of t.target || []) {\n if (\n !isHistoryNode(s) &&\n // if the target is different than the source then it will *definitely* be entered\n (t.source !== s ||\n // we know that the domain can't lie within the source\n // if it's different than the source then it's outside of it and it means that the target has to be entered as well\n t.source !== domain ||\n // reentering transitions always enter the target, even if it's the source itself\n t.reenter)\n ) {\n statesToEnter.add(s);\n statesForDefaultEntry.add(s);\n }\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n const targetStates = getEffectiveTargetStates(t, historyValue);\n for (const s of targetStates) {\n const ancestors = getProperAncestors(s, domain);\n if (domain?.type === 'parallel') {\n ancestors.push(domain!);\n }\n addAncestorStatesToEnter(\n statesToEnter,\n historyValue,\n statesForDefaultEntry,\n ancestors,\n !t.source.parent && t.reenter ? undefined : domain\n );\n }\n }\n}\n\nfunction addDescendantStatesToEnter<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>,\n statesToEnter: Set<AnyStateNode>\n) {\n if (isHistoryNode(stateNode)) {\n if (historyValue[stateNode.id]) {\n const historyStateNodes = historyValue[stateNode.id];\n for (const s of historyStateNodes) {\n statesToEnter.add(s);\n\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n for (const s of historyStateNodes) {\n addProperAncestorStatesToEnter(\n s,\n stateNode.parent!,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n }\n } else {\n const historyDefaultTransition = resolveHistoryDefaultTransition<\n TContext,\n TEvent\n >(stateNode);\n for (const s of historyDefaultTransition.target) {\n statesToEnter.add(s);\n\n if (historyDefaultTransition === stateNode.parent?.initial) {\n statesForDefaultEntry.add(stateNode.parent);\n }\n\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n\n for (const s of historyDefaultTransition.target) {\n addProperAncestorStatesToEnter(\n s,\n stateNode.parent!,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n }\n }\n } else {\n if (stateNode.type === 'compound') {\n const [initialState] = stateNode.initial.target;\n\n if (!isHistoryNode(initialState)) {\n statesToEnter.add(initialState);\n statesForDefaultEntry.add(initialState);\n }\n addDescendantStatesToEnter(\n initialState,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n\n addProperAncestorStatesToEnter(\n initialState,\n stateNode,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n } else {\n if (stateNode.type === 'parallel') {\n for (const child of getChildren(stateNode).filter(\n (sn) => !isHistoryNode(sn)\n )) {\n if (![...statesToEnter].some((s) => isDescendant(s, child))) {\n if (!isHistoryNode(child)) {\n statesToEnter.add(child);\n statesForDefaultEntry.add(child);\n }\n addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n }\n}\n\nfunction addAncestorStatesToEnter(\n statesToEnter: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>,\n ancestors: AnyStateNode[],\n reentrancyDomain?: AnyStateNode\n) {\n for (const anc of ancestors) {\n if (!reentrancyDomain || isDescendant(anc, reentrancyDomain)) {\n statesToEnter.add(anc);\n }\n if (anc.type === 'parallel') {\n for (const child of getChildren(anc).filter((sn) => !isHistoryNode(sn))) {\n if (![...statesToEnter].some((s) => isDescendant(s, child))) {\n statesToEnter.add(child);\n addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n}\n\nfunction addProperAncestorStatesToEnter(\n stateNode: AnyStateNode,\n toStateNode: AnyStateNode | undefined,\n statesToEnter: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>\n) {\n addAncestorStatesToEnter(\n statesToEnter,\n historyValue,\n statesForDefaultEntry,\n getProperAncestors(stateNode, toStateNode)\n );\n}\n\nfunction exitStates(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n transitions: AnyTransitionDefinition[],\n mutStateNodeSet: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n internalQueue: AnyEventObject[]\n) {\n let nextSnapshot = currentSnapshot;\n const statesToExit = computeExitSet(\n transitions,\n mutStateNodeSet,\n historyValue\n );\n\n statesToExit.sort((a, b) => b.order - a.order);\n\n let changedHistory: typeof historyValue | undefined;\n\n // From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates\n for (const exitStateNode of statesToExit) {\n for (const historyNode of getHistoryNodes(exitStateNode)) {\n let predicate: (sn: AnyStateNode) => boolean;\n if (historyNode.history === 'deep') {\n predicate = (sn) =>\n isAtomicStateNode(sn) && isDescendant(sn, exitStateNode);\n } else {\n predicate = (sn) => {\n return sn.parent === exitStateNode;\n };\n }\n changedHistory ??= { ...historyValue };\n changedHistory[historyNode.id] =\n Array.from(mutStateNodeSet).filter(predicate);\n }\n }\n\n for (const s of statesToExit) {\n nextSnapshot = resolveActionsAndContext(\n nextSnapshot,\n event,\n actorScope,\n [...s.exit, ...s.invoke.map((def) => stopChild(def.id))],\n internalQueue\n );\n mutStateNodeSet.delete(s);\n }\n return [nextSnapshot, changedHistory || historyValue] as const;\n}\n\ninterface BuiltinAction {\n (): void;\n resolve: (\n actorScope: AnyActorScope,\n snapshot: AnyMachineSnapshot,\n actionArgs: ActionArgs<any, any, any>,\n actionParams: ParameterizedObject['params'] | undefined,\n action: unknown,\n extra: unknown\n ) => [\n newState: AnyMachineSnapshot,\n params: unknown,\n actions?: UnknownAction[]\n ];\n retryResolve: (\n actorScope: AnyActorScope,\n snapshot: AnyMachineSnapshot,\n params: unknown\n ) => void;\n execute: (actorScope: AnyActorScope, params: unknown) => void;\n}\n\nexport let executingCustomAction:\n | ActionFunction<any, any, any, any, any, any, any, any, any>\n | false = false;\n\nfunction resolveAndExecuteActionsWithContext(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n actions: UnknownAction[],\n extra: {\n internalQueue: AnyEventObject[];\n deferredActorIds: string[] | undefined;\n },\n retries: (readonly [BuiltinAction, unknown])[] | undefined\n): AnyMachineSnapshot {\n const { machine } = currentSnapshot;\n let intermediateSnapshot = currentSnapshot;\n\n for (const action of actions) {\n const isInline = typeof action === 'function';\n const resolvedAction = isInline\n ? action\n : // the existing type of `.actions` assumes non-nullable `TExpressionAction`\n // it's fine to cast this here to get a common type and lack of errors in the rest of the code\n // our logic below makes sure that we call those 2 \"variants\" correctly\n (\n machine.implementations.actions as Record<\n string,\n ActionFunction<\n MachineContext,\n EventObject,\n EventObject,\n ParameterizedObject['params'] | undefined,\n ProvidedActor,\n ParameterizedObject,\n ParameterizedObject,\n string,\n EventObject\n >\n >\n )[typeof action === 'string' ? action : action.type];\n\n if (!resolvedAction) {\n continue;\n }\n\n const actionArgs = {\n context: intermediateSnapshot.context,\n event,\n self: actorScope.self,\n system: actorScope.system\n };\n\n const actionParams =\n isInline || typeof action === 'string'\n ? undefined\n : 'params' in action\n ? typeof action.params === 'function'\n ? action.params({ context: intermediateSnapshot.context, event })\n : action.params\n : undefined;\n\n function executeAction() {\n actorScope.system._sendInspectionEvent({\n type: '@xstate.action',\n actorRef: actorScope.self,\n action: {\n type:\n typeof action === 'string'\n ? action\n : typeof action === 'object'\n ? action.type\n : action.name || '(anonymous)',\n params: actionParams\n }\n });\n try {\n executingCustomAction = resolvedAction;\n resolvedAction(actionArgs, actionParams);\n } finally {\n executingCustomAction = false;\n }\n }\n\n if (!('resolve' in resolvedAction)) {\n if (actorScope.self._processingStatus === ProcessingStatus.Running) {\n executeAction();\n } else {\n actorScope.defer(() => {\n executeAction();\n });\n }\n continue;\n }\n\n const builtinAction = resolvedAction as BuiltinAction;\n\n const [nextState, params, actions] = builtinAction.resolve(\n actorScope,\n intermediateSnapshot,\n actionArgs,\n actionParams,\n resolvedAction, // this holds all params\n extra\n );\n intermediateSnapshot = nextState;\n\n if ('retryResolve' in builtinAction) {\n retries?.push([builtinAction, params]);\n }\n\n if ('execute' in builtinAction) {\n if (actorScope.self._processingStatus === ProcessingStatus.Running) {\n builtinAction.execute(actorScope, params);\n } else {\n actorScope.defer(builtinAction.execute.bind(null, actorScope, params));\n }\n }\n\n if (actions) {\n intermediateSnapshot = resolveAndExecuteActionsWithContext(\n intermediateSnapshot,\n event,\n actorScope,\n actions,\n extra,\n retries\n );\n }\n }\n\n return intermediateSnapshot;\n}\n\nexport function resolveActionsAndContext(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n actions: UnknownAction[],\n internalQueue: AnyEventObject[],\n deferredActorIds?: string[]\n): AnyMachineSnapshot {\n const retries: (readonly [BuiltinAction, unknown])[] | undefined =\n deferredActorIds ? [] : undefined;\n const nextState = resolveAndExecuteActionsWithContext(\n currentSnapshot,\n event,\n actorScope,\n actions,\n { internalQueue, deferredActorIds },\n retries\n );\n retries?.forEach(([builtinAction, params]) => {\n builtinAction.retryResolve(actorScope, nextState, params);\n });\n return nextState;\n}\n\nexport function macrostep(\n snapshot: AnyMachineSnapshot,\n event: EventObject,\n actorScope: AnyActorScope,\n internalQueue: AnyEventObject[] = []\n): {\n snapshot: typeof snapshot;\n microstates: Array<typeof snapshot>;\n} {\n if (isDevelopment && event.type === WILDCARD) {\n throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);\n }\n\n let nextSnapshot = snapshot;\n const microstates: AnyMachineSnapshot[] = [];\n\n function addMicrostate(\n microstate: AnyMachineSnapshot,\n event: AnyEventObject,\n transitions: AnyTransitionDefinition[]\n ) {\n actorScope.system._sendInspectionEvent({\n type: '@xstate.microstep',\n actorRef: actorScope.self,\n event,\n snapshot: microstate,\n _transitions: transitions\n });\n microstates.push(microstate);\n }\n\n // Handle stop event\n if (event.type === XSTATE_STOP) {\n nextSnapshot = cloneMachineSnapshot(\n stopChildren(nextSnapshot, event, actorScope),\n {\n status: 'stopped'\n }\n );\n addMicrostate(nextSnapshot, event, []);\n\n return {\n snapshot: nextSnapshot,\n microstates\n };\n }\n\n let nextEvent = event;\n\n // Assume the state is at rest (no raised events)\n // Determine the next state based on the next microstep\n if (nextEvent.type !== XSTATE_INIT) {\n const currentEvent = nextEvent;\n const isErr = isErrorActorEvent(currentEvent);\n\n const transitions = selectTransitions(currentEvent, nextSnapshot);\n\n if (isErr && !transitions.length) {\n // TODO: we should likely only allow transitions selected by very explicit descriptors\n // `*` shouldn't be matched, likely `xstate.error.*` shouldnt be either\n // similarly `xstate.error.actor.*` and `xstate.error.actor.todo.*` have to be considered too\n nextSnapshot = cloneMachineSnapshot<typeof snapshot>(snapshot, {\n status: 'error',\n error: currentEvent.error\n });\n addMicrostate(nextSnapshot, currentEvent, []);\n return {\n snapshot: nextSnapshot,\n microstates\n };\n }\n nextSnapshot = microstep(\n transitions,\n snapshot,\n actorScope,\n nextEvent,\n false, // isInitial\n internalQueue\n );\n addMicrostate(nextSnapshot, currentEvent, transitions);\n }\n\n let shouldSelectEventlessTransitions = true;\n\n while (nextSnapshot.status === 'active') {\n let enabledTransitions: AnyTransitionDefinition[] =\n shouldSelectEventlessTransitions\n ? selectEventlessTransitions(nextSnapshot, nextEvent)\n : [];\n\n // eventless transitions should always be selected after selecting *regular* transitions\n // by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case\n const previousState = enabledTransitions.length ? nextSnapshot : undefined;\n\n if (!enabledTransitions.length) {\n if (!internalQueue.length) {\n break;\n }\n nextEvent = internalQueue.shift()!;\n enabledTransitions = selectTransitions(nextEvent, nextSnapshot);\n }\n\n nextSnapshot = microstep(\n enabledTransitions,\n nextSnapshot,\n actorScope,\n nextEvent,\n false,\n internalQueue\n );\n shouldSelectEventlessTransitions = nextSnapshot !== previousState;\n addMicrostate(nextSnapshot, nextEvent, enabledTransitions);\n }\n\n if (nextSnapshot.status !== 'active') {\n stopChildren(nextSnapshot, nextEvent, actorScope);\n }\n\n return {\n snapshot: nextSnapshot,\n microstates\n };\n}\n\nfunction stopChildren(\n nextState: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope\n) {\n return resolveActionsAndContext(\n nextState,\n event,\n actorScope,\n Object.values(nextState.children).map((child: any) => stopChild(child)),\n []\n );\n}\n\nfunction selectTransitions(\n event: AnyEventObject,\n nextState: AnyMachineSnapshot\n): AnyTransitionDefinition[] {\n return nextState.machine.getTransitionData(nextState as any, event);\n}\n\nfunction selectEventlessTransitions(\n nextState: AnyMachineSnapshot,\n event: AnyEventObject\n): AnyTransitionDefinition[] {\n const enabledTransitionSet: Set<AnyTransitionDefinition> = new Set();\n const atomicStates = nextState._nodes.filter(isAtomicStateNode);\n\n for (const stateNode of atomicStates) {\n loop: for (const s of [stateNode].concat(\n getProperAncestors(stateNode, undefined)\n )) {\n if (!s.always) {\n continue;\n }\n for (const transition of s.always) {\n if (\n transition.guard === undefined ||\n evaluateGuard(transition.guard, nextState.context, event, nextState)\n ) {\n enabledTransitionSet.add(transition);\n break loop;\n }\n }\n }\n }\n\n return removeConflictingTransitions(\n Array.from(enabledTransitionSet),\n new Set(nextState._nodes),\n nextState.historyValue\n );\n}\n\n/**\n * Resolves a partial state value with its full representation in the state\n * node's machine.\n *\n * @param stateValue The partial state value to resolve.\n */\nexport function resolveStateValue(\n rootNode: AnyStateNode,\n stateValue: StateValue\n): StateValue {\n const allStateNodes = getAllStateNodes(getStateNodes(rootNode, stateValue));\n return getStateValue(rootNode, [...allStateNodes]);\n}\n\nfunction stateValuesEqual(\n a: StateValue | undefined,\n b: StateValue | undefined\n): boolean {\n if (a === b) {\n return true;\n }\n\n if (a === undefined || b === undefined) {\n return false;\n }\n\n if (typeof a === 'string' || typeof b === 'string') {\n return a === b;\n }\n\n const aKeys = Object.keys(a as StateValueMap);\n const bKeys = Object.keys(b as StateValueMap);\n\n return (\n aKeys.length === bKeys.length &&\n aKeys.every((key) => stateValuesEqual(a[key], b[key]))\n );\n}\n","import isDevelopment from '#is-development';\nimport type {\n EventObject,\n StateValue,\n MachineContext,\n ParameterizedObject,\n AnyMachineSnapshot,\n NoRequiredParams,\n WithDynamicParams,\n Identity,\n Elements,\n DoNotInfer\n} from './types.ts';\nimport { isStateId } from './stateUtils.ts';\n\ntype SingleGuardArg<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined,\n TGuardArg\n> = [TGuardArg] extends [{ type: string }]\n ? Identity<TGuardArg>\n : [TGuardArg] extends [string]\n ? TGuardArg\n : GuardPredicate<TContext, TExpressionEvent, TParams, ParameterizedObject>;\n\ntype NormalizeGuardArg<TGuardArg> = TGuardArg extends { type: string }\n ? Identity<TGuardArg> & { params: unknown }\n : TGuardArg extends string\n ? { type: TGuardArg; params: undefined }\n : '_out_TGuard' extends keyof TGuardArg\n ? TGuardArg['_out_TGuard'] & ParameterizedObject\n : never;\n\ntype NormalizeGuardArgArray<TArg extends unknown[]> = Elements<{\n [K in keyof TArg]: NormalizeGuardArg<TArg[K]>;\n}>;\n\nexport type GuardPredicate<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined,\n TGuard extends ParameterizedObject\n> = {\n (args: GuardArgs<TContext, TExpressionEvent>, params: TParams): boolean;\n _out_TGuard?: TGuard;\n};\n\nexport interface GuardArgs<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject\n> {\n context: TContext;\n event: TExpressionEvent;\n}\n\nexport type Guard<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined,\n TGuard extends ParameterizedObject\n> =\n | NoRequiredParams<TGuard>\n | WithDynamicParams<TContext, TExpressionEvent, TGuard>\n | GuardPredicate<TContext, TExpressionEvent, TParams, TGuard>;\n\nexport type UnknownGuard = UnknownReferencedGuard | UnknownInlineGuard;\n\ntype UnknownReferencedGuard = Guard<\n MachineContext,\n EventObject,\n ParameterizedObject['params'],\n ParameterizedObject\n>;\n\ntype UnknownInlineGuard = Guard<\n MachineContext,\n EventObject,\n undefined,\n ParameterizedObject\n>;\n\ninterface BuiltinGuard {\n (): boolean;\n check: (\n snapshot: AnyMachineSnapshot,\n guardArgs: GuardArgs<any, any>,\n params: unknown\n ) => boolean;\n}\n\nfunction checkStateIn(\n snapshot: AnyMachineSnapshot,\n _: GuardArgs<any, any>,\n { stateValue }: { stateValue: StateValue }\n) {\n if (typeof stateValue === 'string' && isStateId(stateValue)) {\n const target = snapshot.machine.getStateNodeById(stateValue);\n return snapshot._nodes.some((sn) => sn === target);\n }\n\n return snapshot.matches(stateValue);\n}\n\nexport function stateIn<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined\n>(\n stateValue: StateValue\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n TParams,\n any // TODO: recheck if we could replace this with something better here\n> {\n function stateIn(\n args: GuardArgs<TContext, TExpressionEvent>,\n params: TParams\n ) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n stateIn.check = checkStateIn;\n stateIn.stateValue = stateValue;\n\n return stateIn;\n}\n\nfunction checkNot(\n snapshot: AnyMachineSnapshot,\n { context, event }: GuardArgs<any, any>,\n { guards }: { guards: readonly UnknownGuard[] }\n) {\n return !evaluateGuard(guards[0], context, event, snapshot);\n}\n\n/**\n * Higher-order guard that evaluates to `true` if the `guard` passed to it\n * evaluates to `false`.\n *\n * @category Guards\n * @example\n *\n * ```ts\n * import { setup, not } from 'xstate';\n *\n * const machine = setup({\n * guards: {\n * someNamedGuard: () => false\n * }\n * }).createMachine({\n * on: {\n * someEvent: {\n * guard: not('someNamedGuard'),\n * actions: () => {\n * // will be executed if guard in `not(...)`\n * // evaluates to `false`\n * }\n * }\n * }\n * });\n * ```\n *\n * @returns A guard\n */\nexport function not<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TArg\n>(\n guard: SingleGuardArg<TContext, TExpressionEvent, unknown, TArg>\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n unknown,\n NormalizeGuardArg<DoNotInfer<TArg>>\n> {\n function not(args: GuardArgs<TContext, TExpressionEvent>, params: unknown) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n not.check = checkNot;\n not.guards = [guard];\n\n return not;\n}\n\nfunction checkAnd(\n snapshot: AnyMachineSnapshot,\n { context, event }: GuardArgs<any, any>,\n { guards }: { guards: readonly UnknownGuard[] }\n) {\n return guards.every((guard) =>\n evaluateGuard(guard, context, event, snapshot)\n );\n}\n\n/**\n * Higher-order guard that evaluates to `true` if all `guards` passed to it\n * evaluate to `true`.\n *\n * @category Guards\n * @example\n *\n * ```ts\n * import { setup, and } from 'xstate';\n *\n * const machine = setup({\n * guards: {\n * someNamedGuard: () => true\n * }\n * }).createMachine({\n * on: {\n * someEvent: {\n * guard: and([({ context }) => context.value > 0, 'someNamedGuard']),\n * actions: () => {\n * // will be executed if all guards in `and(...)`\n * // evaluate to true\n * }\n * }\n * }\n * });\n * ```\n *\n * @returns A guard action object\n */\nexport function and<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TArg extends unknown[]\n>(\n guards: readonly [\n ...{\n [K in keyof TArg]: SingleGuardArg<\n TContext,\n TExpressionEvent,\n unknown,\n TArg[K]\n >;\n }\n ]\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n unknown,\n NormalizeGuardArgArray<DoNotInfer<TArg>>\n> {\n function and(args: GuardArgs<TContext, TExpressionEvent>, params: unknown) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n and.check = checkAnd;\n and.guards = guards;\n\n return and;\n}\n\nfunction checkOr(\n snapshot: AnyMachineSnapshot,\n { context, event }: GuardArgs<any, any>,\n { guards }: { guards: readonly UnknownGuard[] }\n) {\n return guards.some((guard) => evaluateGuard(guard, context, event, snapshot));\n}\n\n/**\n * Higher-order guard that evaluates to `true` if any of the `guards` passed to\n * it evaluate to `true`.\n *\n * @category Guards\n * @example\n *\n * ```ts\n * import { setup, or } from 'xstate';\n *\n * const machine = setup({\n * guards: {\n * someNamedGuard: () => true\n * }\n * }).createMachine({\n * on: {\n * someEvent: {\n * guard: or([({ context }) => context.value > 0, 'someNamedGuard']),\n * actions: () => {\n * // will be executed if any of the guards in `or(...)`\n * // evaluate to true\n * }\n * }\n * }\n * });\n * ```\n *\n * @returns A guard action object\n */\nexport function or<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TArg extends unknown[]\n>(\n guards: readonly [\n ...{\n [K in keyof TArg]: SingleGuardArg<\n TContext,\n TExpressionEvent,\n unknown,\n TArg[K]\n >;\n }\n ]\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n unknown,\n NormalizeGuardArgArray<DoNotInfer<TArg>>\n> {\n function or(args: GuardArgs<TContext, TExpressionEvent>, params: unknown) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n or.check = checkOr;\n or.guards = guards;\n\n return or;\n}\n\n// TODO: throw on cycles (depth check should be enough)\nexport function evaluateGuard<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject\n>(\n guard: UnknownGuard | UnknownInlineGuard,\n context: TContext,\n event: TExpressionEvent,\n snapshot: AnyMachineSnapshot\n): boolean {\n const { machine } = snapshot;\n const isInline = typeof guard === 'function';\n\n const resolved = isInline\n ? guard\n : machine.implementations.guards[\n typeof guard === 'string' ? guard : guard.type\n ];\n\n if (!isInline && !resolved) {\n throw new Error(\n `Guard '${\n typeof guard === 'string' ? guard : guard.type\n }' is not implemented.'.`\n );\n }\n\n if (typeof resolved !== 'function') {\n return evaluateGuard(resolved!, context, event, snapshot);\n }\n\n const guardArgs = {\n context,\n event\n };\n\n const guardParams =\n isInline || typeof guard === 'string'\n ? undefined\n : 'params' in guard\n ? typeof guard.params === 'function'\n ? guard.params({ context, event })\n : guard.params\n : undefined;\n\n if (!('check' in resolved)) {\n // the existing type of `.guards` assumes non-nullable `TExpressionGuard`\n // inline guards expect `TExpressionGuard` to be set to `undefined`\n // it's fine to cast this here, our logic makes sure that we call those 2 \"variants\" correctly\n return resolved(guardArgs, guardParams as never);\n }\n\n const builtinGuard = resolved as unknown as BuiltinGuard;\n\n return builtinGuard.check(\n snapshot,\n guardArgs,\n resolved // this holds all params\n );\n}\n"],"names":["isStateId","str","checkStateIn","snapshot","_","stateValue","target","machine","getStateNodeById","_nodes","some","sn","matches","checkNot","context","event","guards","evaluateGuard","checkAnd","every","guard","checkOr","isInline","resolved","implementations","type","Error","guardArgs","guardParams","undefined","params","check","and","args","not","or","stateIn"],"mappings":"oPAGO,MC6MMA,EAAaC,GD7MM,MC6MUA,EAAI,GCrH9C,SAASC,EACPC,EACAC,GACAC,WAAEA,IAEF,GAA0B,iBAAfA,GAA2BL,EAAUK,GAAa,CAC3D,MAAMC,EAASH,EAASI,QAAQC,iBAAiBH,GACjD,OAAOF,EAASM,OAAOC,MAAMC,GAAOA,IAAOL,GAC7C,CAEA,OAAOH,EAASS,QAAQP,EAC1B,CA8BA,SAASQ,EACPV,GACAW,QAAEA,EAAOC,MAAEA,IACXC,OAAEA,IAEF,OAAQC,EAAcD,EAAO,GAAIF,EAASC,EAAOZ,EACnD,CAwDA,SAASe,EACPf,GACAW,QAAEA,EAAOC,MAAEA,IACXC,OAAEA,IAEF,OAAOA,EAAOG,OAAOC,GACnBH,EAAcG,EAAON,EAASC,EAAOZ,IAEzC,CAiEA,SAASkB,EACPlB,GACAW,QAAEA,EAAOC,MAAEA,IACXC,OAAEA,IAEF,OAAOA,EAAON,MAAMU,GAAUH,EAAcG,EAAON,EAASC,EAAOZ,IACrE,CAkEO,SAASc,EAIdG,EACAN,EACAC,EACAZ,GAEA,MAAMI,QAAEA,GAAYJ,EACdmB,EAA4B,mBAAVF,EAElBG,EAAWD,EACbF,EACAb,EAAQiB,gBAAgBR,OACL,iBAAVI,EAAqBA,EAAQA,EAAMK,MAGhD,IAAKH,IAAaC,EAChB,MAAM,IAAIG,MACP,UACkB,iBAAVN,EAAqBA,EAAQA,EAAMK,+BAKhD,GAAwB,mBAAbF,EACT,OAAON,EAAcM,EAAWT,EAASC,EAAOZ,GAGlD,MAAMwB,EAAY,CAChBb,UACAC,SAGIa,EACJN,GAA6B,iBAAVF,OACfS,EACA,WAAYT,EACc,mBAAjBA,EAAMU,OACXV,EAAMU,OAAO,CAAEhB,UAASC,UACxBK,EAAMU,YACRD,EAER,KAAM,UAAWN,GAIf,OAAOA,EAASI,EAAWC,GAK7B,OAFqBL,EAEDQ,MAClB5B,EACAwB,EACAJ,EAEJ,OApKO,SAKLP,GAgBA,SAASgB,EAAIC,EAA6CH,GAIxD,OAAO,CACT,CAKA,OAHAE,EAAID,MAAQb,EACZc,EAAIhB,OAASA,EAENgB,CACT,0BAhGO,SAKLZ,GAOA,SAASc,EAAID,EAA6CH,GAIxD,OAAO,CACT,CAKA,OAHAI,EAAIH,MAAQlB,EACZqB,EAAIlB,OAAS,CAACI,GAEPc,CACT,OAgHO,SAKLlB,GAgBA,SAASmB,EAAGF,EAA6CH,GAIvD,OAAO,CACT,CAKA,OAHAK,EAAGJ,MAAQV,EACXc,EAAGnB,OAASA,EAELmB,CACT,YAxOO,SAKL9B,GAOA,SAAS+B,EACPH,EACAH,GAKA,OAAO,CACT,CAKA,OAHAM,EAAQL,MAAQ7B,EAChBkC,EAAQ/B,WAAaA,EAEd+B,CACT"}
|
|
1
|
+
{"version":3,"file":"xstate-guards.umd.min.js","sources":["../../src/constants.ts","../../src/stateUtils.ts","../../src/guards.ts"],"sourcesContent":["export const STATE_DELIMITER = '.';\nexport const TARGETLESS_KEY = '';\nexport const NULL_EVENT = '';\nexport const STATE_IDENTIFIER = '#';\nexport const WILDCARD = '*';\nexport const XSTATE_INIT = 'xstate.init';\nexport const XSTATE_ERROR = 'xstate.error';\nexport const XSTATE_STOP = 'xstate.stop';\n","import isDevelopment from '#is-development';\nimport { MachineSnapshot, cloneMachineSnapshot } from './State.ts';\nimport type { StateNode } from './StateNode.ts';\nimport { raise } from './actions.ts';\nimport { createAfterEvent, createDoneStateEvent } from './eventUtils.ts';\nimport { cancel } from './actions/cancel.ts';\nimport { spawnChild } from './actions/spawnChild.ts';\nimport { stopChild } from './actions/stopChild.ts';\nimport {\n XSTATE_INIT,\n NULL_EVENT,\n STATE_DELIMITER,\n STATE_IDENTIFIER,\n XSTATE_STOP,\n WILDCARD\n} from './constants.ts';\nimport { evaluateGuard } from './guards.ts';\nimport {\n ActionArgs,\n AnyEventObject,\n AnyHistoryValue,\n AnyMachineSnapshot,\n AnyStateNode,\n AnyTransitionDefinition,\n DelayExpr,\n DelayedTransitionDefinition,\n EventObject,\n HistoryValue,\n InitialTransitionConfig,\n InitialTransitionDefinition,\n MachineContext,\n StateValue,\n StateValueMap,\n TransitionDefinition,\n TODO,\n UnknownAction,\n ParameterizedObject,\n ActionFunction,\n AnyTransitionConfig,\n ProvidedActor,\n AnyActorScope\n} from './types.ts';\nimport {\n resolveOutput,\n normalizeTarget,\n toArray,\n toStatePath,\n toTransitionConfigArray,\n isErrorActorEvent\n} from './utils.ts';\nimport { ProcessingStatus } from './createActor.ts';\n\ntype StateNodeIterable<\n TContext extends MachineContext,\n TE extends EventObject\n> = Iterable<StateNode<TContext, TE>>;\ntype AnyStateNodeIterable = StateNodeIterable<any, any>;\n\ntype AdjList = Map<AnyStateNode, Array<AnyStateNode>>;\n\nconst isAtomicStateNode = (stateNode: StateNode<any, any>) =>\n stateNode.type === 'atomic' || stateNode.type === 'final';\n\nfunction getChildren<TContext extends MachineContext, TE extends EventObject>(\n stateNode: StateNode<TContext, TE>\n): Array<StateNode<TContext, TE>> {\n return Object.values(stateNode.states).filter((sn) => sn.type !== 'history');\n}\n\nfunction getProperAncestors(\n stateNode: AnyStateNode,\n toStateNode: AnyStateNode | undefined\n): Array<typeof stateNode> {\n const ancestors: Array<typeof stateNode> = [];\n\n if (toStateNode === stateNode) {\n return ancestors;\n }\n\n // add all ancestors\n let m = stateNode.parent;\n while (m && m !== toStateNode) {\n ancestors.push(m);\n m = m.parent;\n }\n\n return ancestors;\n}\n\nexport function getAllStateNodes(\n stateNodes: Iterable<AnyStateNode>\n): Set<AnyStateNode> {\n const nodeSet = new Set(stateNodes);\n\n const adjList = getAdjList(nodeSet);\n\n // add descendants\n for (const s of nodeSet) {\n // if previously active, add existing child nodes\n if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s)!.length)) {\n getInitialStateNodesWithTheirAncestors(s).forEach((sn) =>\n nodeSet.add(sn)\n );\n } else {\n if (s.type === 'parallel') {\n for (const child of getChildren(s)) {\n if (child.type === 'history') {\n continue;\n }\n\n if (!nodeSet.has(child)) {\n const initialStates = getInitialStateNodesWithTheirAncestors(child);\n for (const initialStateNode of initialStates) {\n nodeSet.add(initialStateNode);\n }\n }\n }\n }\n }\n }\n\n // add all ancestors\n for (const s of nodeSet) {\n let m = s.parent;\n\n while (m) {\n nodeSet.add(m);\n m = m.parent;\n }\n }\n\n return nodeSet;\n}\n\nfunction getValueFromAdj(baseNode: AnyStateNode, adjList: AdjList): StateValue {\n const childStateNodes = adjList.get(baseNode);\n\n if (!childStateNodes) {\n return {}; // todo: fix?\n }\n\n if (baseNode.type === 'compound') {\n const childStateNode = childStateNodes[0];\n if (childStateNode) {\n if (isAtomicStateNode(childStateNode)) {\n return childStateNode.key;\n }\n } else {\n return {};\n }\n }\n\n const stateValue: StateValue = {};\n for (const childStateNode of childStateNodes) {\n stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList);\n }\n\n return stateValue;\n}\n\nfunction getAdjList<TContext extends MachineContext, TE extends EventObject>(\n stateNodes: StateNodeIterable<TContext, TE>\n): AdjList {\n const adjList: AdjList = new Map();\n\n for (const s of stateNodes) {\n if (!adjList.has(s)) {\n adjList.set(s, []);\n }\n\n if (s.parent) {\n if (!adjList.has(s.parent)) {\n adjList.set(s.parent, []);\n }\n\n adjList.get(s.parent)!.push(s);\n }\n }\n\n return adjList;\n}\n\nexport function getStateValue(\n rootNode: AnyStateNode,\n stateNodes: AnyStateNodeIterable\n): StateValue {\n const config = getAllStateNodes(stateNodes);\n return getValueFromAdj(rootNode, getAdjList(config));\n}\n\nexport function isInFinalState(\n stateNodeSet: Set<AnyStateNode>,\n stateNode: AnyStateNode\n): boolean {\n if (stateNode.type === 'compound') {\n return getChildren(stateNode).some(\n (s) => s.type === 'final' && stateNodeSet.has(s)\n );\n }\n if (stateNode.type === 'parallel') {\n return getChildren(stateNode).every((sn) =>\n isInFinalState(stateNodeSet, sn)\n );\n }\n\n return stateNode.type === 'final';\n}\n\nexport const isStateId = (str: string) => str[0] === STATE_IDENTIFIER;\n\nexport function getCandidates<TEvent extends EventObject>(\n stateNode: StateNode<any, TEvent>,\n receivedEventType: TEvent['type']\n): Array<TransitionDefinition<any, TEvent>> {\n const candidates =\n stateNode.transitions.get(receivedEventType) ||\n [...stateNode.transitions.keys()]\n .filter((eventDescriptor) => {\n // check if transition is a wildcard transition,\n // which matches any non-transient events\n if (eventDescriptor === WILDCARD) {\n return true;\n }\n\n if (!eventDescriptor.endsWith('.*')) {\n return false;\n }\n\n if (isDevelopment && /.*\\*.+/.test(eventDescriptor)) {\n console.warn(\n `Wildcards can only be the last token of an event descriptor (e.g., \"event.*\") or the entire event descriptor (\"*\"). Check the \"${eventDescriptor}\" event.`\n );\n }\n\n const partialEventTokens = eventDescriptor.split('.');\n const eventTokens = receivedEventType.split('.');\n\n for (\n let tokenIndex = 0;\n tokenIndex < partialEventTokens.length;\n tokenIndex++\n ) {\n const partialEventToken = partialEventTokens[tokenIndex];\n const eventToken = eventTokens[tokenIndex];\n\n if (partialEventToken === '*') {\n const isLastToken = tokenIndex === partialEventTokens.length - 1;\n\n if (isDevelopment && !isLastToken) {\n console.warn(\n `Infix wildcards in transition events are not allowed. Check the \"${eventDescriptor}\" transition.`\n );\n }\n\n return isLastToken;\n }\n\n if (partialEventToken !== eventToken) {\n return false;\n }\n }\n\n return true;\n })\n .sort((a, b) => b.length - a.length)\n .flatMap((key) => stateNode.transitions.get(key)!);\n\n return candidates;\n}\n\n/** All delayed transitions from the config. */\nexport function getDelayedTransitions(\n stateNode: AnyStateNode\n): Array<DelayedTransitionDefinition<MachineContext, EventObject>> {\n const afterConfig = stateNode.config.after;\n if (!afterConfig) {\n return [];\n }\n\n const mutateEntryExit = (delay: string | number, i: number) => {\n const afterEvent = createAfterEvent(delay, stateNode.id);\n const eventType = afterEvent.type;\n stateNode.entry.push(raise(afterEvent, { id: eventType, delay }));\n stateNode.exit.push(cancel(eventType));\n return eventType;\n };\n\n const delayedTransitions = Object.keys(afterConfig).flatMap((delay, i) => {\n const configTransition = afterConfig[delay];\n const resolvedTransition =\n typeof configTransition === 'string'\n ? { target: configTransition }\n : configTransition;\n const resolvedDelay = Number.isNaN(+delay) ? delay : +delay;\n const eventType = mutateEntryExit(resolvedDelay, i);\n return toArray(resolvedTransition).map((transition) => ({\n ...transition,\n event: eventType,\n delay: resolvedDelay\n }));\n });\n return delayedTransitions.map((delayedTransition) => {\n const { delay } = delayedTransition;\n return {\n ...formatTransition(\n stateNode,\n delayedTransition.event,\n delayedTransition\n ),\n delay\n };\n });\n}\n\nexport function formatTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n descriptor: string,\n transitionConfig: AnyTransitionConfig\n): AnyTransitionDefinition {\n const normalizedTarget = normalizeTarget(transitionConfig.target);\n const reenter = transitionConfig.reenter ?? false;\n const target = resolveTarget(stateNode, normalizedTarget);\n\n // TODO: should this be part of a lint rule instead?\n if (isDevelopment && (transitionConfig as any).cond) {\n throw new Error(\n `State \"${stateNode.id}\" has declared \\`cond\\` for one of its transitions. This property has been renamed to \\`guard\\`. Please update your code.`\n );\n }\n const transition = {\n ...transitionConfig,\n actions: toArray(transitionConfig.actions),\n guard: transitionConfig.guard as never,\n target,\n source: stateNode,\n reenter,\n eventType: descriptor,\n toJSON: () => ({\n ...transition,\n source: `#${stateNode.id}`,\n target: target ? target.map((t) => `#${t.id}`) : undefined\n })\n };\n\n return transition;\n}\n\nexport function formatTransitions<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode\n): Map<string, TransitionDefinition<TContext, TEvent>[]> {\n const transitions = new Map<\n string,\n TransitionDefinition<TContext, AnyEventObject>[]\n >();\n if (stateNode.config.on) {\n for (const descriptor of Object.keys(stateNode.config.on)) {\n if (descriptor === NULL_EVENT) {\n throw new Error(\n 'Null events (\"\") cannot be specified as a transition key. Use `always: { ... }` instead.'\n );\n }\n const transitionsConfig = stateNode.config.on[descriptor];\n transitions.set(\n descriptor,\n toTransitionConfigArray(transitionsConfig).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n }\n if (stateNode.config.onDone) {\n const descriptor = `xstate.done.state.${stateNode.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(stateNode.config.onDone).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n for (const invokeDef of stateNode.invoke) {\n if (invokeDef.onDone) {\n const descriptor = `xstate.done.actor.${invokeDef.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(invokeDef.onDone).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n if (invokeDef.onError) {\n const descriptor = `xstate.error.actor.${invokeDef.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(invokeDef.onError).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n if (invokeDef.onSnapshot) {\n const descriptor = `xstate.snapshot.${invokeDef.id}`;\n transitions.set(\n descriptor,\n toTransitionConfigArray(invokeDef.onSnapshot).map((t) =>\n formatTransition(stateNode, descriptor, t)\n )\n );\n }\n }\n for (const delayedTransition of stateNode.after) {\n let existing = transitions.get(delayedTransition.eventType);\n if (!existing) {\n existing = [];\n transitions.set(delayedTransition.eventType, existing);\n }\n existing.push(delayedTransition);\n }\n return transitions as Map<string, TransitionDefinition<TContext, any>[]>;\n}\n\nexport function formatInitialTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n _target:\n | string\n | undefined\n | InitialTransitionConfig<TContext, TEvent, TODO, TODO, TODO, TODO>\n): InitialTransitionDefinition<TContext, TEvent> {\n const resolvedTarget =\n typeof _target === 'string'\n ? stateNode.states[_target]\n : _target\n ? stateNode.states[_target.target]\n : undefined;\n if (!resolvedTarget && _target) {\n throw new Error(\n `Initial state node \"${_target}\" not found on parent state node #${stateNode.id}`\n );\n }\n const transition: InitialTransitionDefinition<TContext, TEvent> = {\n source: stateNode,\n actions:\n !_target || typeof _target === 'string' ? [] : toArray(_target.actions),\n eventType: null as any,\n reenter: false,\n target: resolvedTarget ? [resolvedTarget] : [],\n toJSON: () => ({\n ...transition,\n source: `#${stateNode.id}`,\n target: resolvedTarget ? [`#${resolvedTarget.id}`] : []\n })\n };\n\n return transition;\n}\n\nfunction resolveTarget(\n stateNode: AnyStateNode,\n targets: ReadonlyArray<string | AnyStateNode> | undefined\n): ReadonlyArray<AnyStateNode> | undefined {\n if (targets === undefined) {\n // an undefined target signals that the state node should not transition from that state when receiving that event\n return undefined;\n }\n return targets.map((target) => {\n if (typeof target !== 'string') {\n return target;\n }\n if (isStateId(target)) {\n return stateNode.machine.getStateNodeById(target);\n }\n\n const isInternalTarget = target[0] === STATE_DELIMITER;\n // If internal target is defined on machine,\n // do not include machine key on target\n if (isInternalTarget && !stateNode.parent) {\n return getStateNodeByPath(stateNode, target.slice(1));\n }\n const resolvedTarget = isInternalTarget ? stateNode.key + target : target;\n if (stateNode.parent) {\n try {\n const targetStateNode = getStateNodeByPath(\n stateNode.parent,\n resolvedTarget\n );\n return targetStateNode;\n } catch (err: any) {\n throw new Error(\n `Invalid transition definition for state node '${stateNode.id}':\\n${err.message}`\n );\n }\n } else {\n throw new Error(\n `Invalid target: \"${target}\" is not a valid target from the root node. Did you mean \".${target}\"?`\n );\n }\n });\n}\n\nfunction resolveHistoryDefaultTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateNode: AnyStateNode & { type: 'history' }) {\n const normalizedTarget = normalizeTarget<TContext, TEvent>(\n stateNode.config.target\n );\n if (!normalizedTarget) {\n return stateNode.parent!.initial;\n }\n return {\n target: normalizedTarget.map((t) =>\n typeof t === 'string' ? getStateNodeByPath(stateNode.parent!, t) : t\n )\n };\n}\n\nfunction isHistoryNode(\n stateNode: AnyStateNode\n): stateNode is AnyStateNode & { type: 'history' } {\n return stateNode.type === 'history';\n}\n\nfunction getInitialStateNodesWithTheirAncestors(stateNode: AnyStateNode) {\n const states = getInitialStateNodes(stateNode);\n for (const initialState of states) {\n for (const ancestor of getProperAncestors(initialState, stateNode)) {\n states.add(ancestor);\n }\n }\n return states;\n}\n\nexport function getInitialStateNodes(stateNode: AnyStateNode) {\n const set = new Set<AnyStateNode>();\n\n function iter(descStateNode: AnyStateNode): void {\n if (set.has(descStateNode)) {\n return;\n }\n set.add(descStateNode);\n if (descStateNode.type === 'compound') {\n iter(descStateNode.initial.target[0]);\n } else if (descStateNode.type === 'parallel') {\n for (const child of getChildren(descStateNode)) {\n iter(child);\n }\n }\n }\n\n iter(stateNode);\n\n return set;\n}\n/** Returns the child state node from its relative `stateKey`, or throws. */\nfunction getStateNode(stateNode: AnyStateNode, stateKey: string): AnyStateNode {\n if (isStateId(stateKey)) {\n return stateNode.machine.getStateNodeById(stateKey);\n }\n if (!stateNode.states) {\n throw new Error(\n `Unable to retrieve child state '${stateKey}' from '${stateNode.id}'; no child states exist.`\n );\n }\n const result = stateNode.states[stateKey];\n if (!result) {\n throw new Error(\n `Child state '${stateKey}' does not exist on '${stateNode.id}'`\n );\n }\n return result;\n}\n\n/**\n * Returns the relative state node from the given `statePath`, or throws.\n *\n * @param statePath The string or string array relative path to the state node.\n */\nexport function getStateNodeByPath(\n stateNode: AnyStateNode,\n statePath: string | string[]\n): AnyStateNode {\n if (typeof statePath === 'string' && isStateId(statePath)) {\n try {\n return stateNode.machine.getStateNodeById(statePath);\n } catch (e) {\n // try individual paths\n // throw e;\n }\n }\n const arrayStatePath = toStatePath(statePath).slice();\n let currentStateNode: AnyStateNode = stateNode;\n while (arrayStatePath.length) {\n const key = arrayStatePath.shift()!;\n if (!key.length) {\n break;\n }\n currentStateNode = getStateNode(currentStateNode, key);\n }\n return currentStateNode;\n}\n\n/**\n * Returns the state nodes represented by the current state value.\n *\n * @param stateValue The state value or State instance\n */\nexport function getStateNodes<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateNode: AnyStateNode, stateValue: StateValue): Array<AnyStateNode> {\n if (typeof stateValue === 'string') {\n const childStateNode = stateNode.states[stateValue];\n if (!childStateNode) {\n throw new Error(\n `State '${stateValue}' does not exist on '${stateNode.id}'`\n );\n }\n return [stateNode, childStateNode];\n }\n\n const childStateKeys = Object.keys(stateValue);\n const childStateNodes: Array<AnyStateNode> = childStateKeys\n .map((subStateKey) => getStateNode(stateNode, subStateKey))\n .filter(Boolean);\n\n return [stateNode.machine.root, stateNode].concat(\n childStateNodes,\n childStateKeys.reduce((allSubStateNodes, subStateKey) => {\n const subStateNode = getStateNode(stateNode, subStateKey);\n if (!subStateNode) {\n return allSubStateNodes;\n }\n const subStateNodes = getStateNodes(\n subStateNode,\n stateValue[subStateKey]!\n );\n\n return allSubStateNodes.concat(subStateNodes);\n }, [] as Array<AnyStateNode>)\n );\n}\n\nfunction transitionAtomicNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: string,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any, // TMeta\n any // TStateSchema\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const childStateNode = getStateNode(stateNode, stateValue);\n const next = childStateNode.next(snapshot, event);\n\n if (!next || !next.length) {\n return stateNode.next(snapshot, event);\n }\n\n return next;\n}\n\nfunction transitionCompoundNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any, // TMeta\n any // TStateSchema\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const subStateKeys = Object.keys(stateValue);\n\n const childStateNode = getStateNode(stateNode, subStateKeys[0]);\n const next = transitionNode(\n childStateNode,\n stateValue[subStateKeys[0]]!,\n snapshot,\n event\n );\n\n if (!next || !next.length) {\n return stateNode.next(snapshot, event);\n }\n\n return next;\n}\n\nfunction transitionParallelNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any, // TMeta\n any // TStateSchema\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const allInnerTransitions: Array<TransitionDefinition<TContext, TEvent>> = [];\n\n for (const subStateKey of Object.keys(stateValue)) {\n const subStateValue = stateValue[subStateKey];\n\n if (!subStateValue) {\n continue;\n }\n\n const subStateNode = getStateNode(stateNode, subStateKey);\n const innerTransitions = transitionNode(\n subStateNode,\n subStateValue,\n snapshot,\n event\n );\n if (innerTransitions) {\n allInnerTransitions.push(...innerTransitions);\n }\n }\n if (!allInnerTransitions.length) {\n return stateNode.next(snapshot, event);\n }\n\n return allInnerTransitions;\n}\n\nexport function transitionNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValue,\n snapshot: MachineSnapshot<\n TContext,\n TEvent,\n any,\n any,\n any,\n any,\n any,\n any // TStateSchema\n >,\n event: TEvent\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n // leaf node\n if (typeof stateValue === 'string') {\n return transitionAtomicNode(stateNode, stateValue, snapshot, event);\n }\n\n // compound node\n if (Object.keys(stateValue).length === 1) {\n return transitionCompoundNode(stateNode, stateValue, snapshot, event);\n }\n\n // parallel node\n return transitionParallelNode(stateNode, stateValue, snapshot, event);\n}\n\nfunction getHistoryNodes(stateNode: AnyStateNode): Array<AnyStateNode> {\n return Object.keys(stateNode.states)\n .map((key) => stateNode.states[key])\n .filter((sn) => sn.type === 'history');\n}\n\nfunction isDescendant(\n childStateNode: AnyStateNode,\n parentStateNode: AnyStateNode\n): boolean {\n let marker = childStateNode;\n while (marker.parent && marker.parent !== parentStateNode) {\n marker = marker.parent;\n }\n\n return marker.parent === parentStateNode;\n}\n\nfunction getPathFromRootToNode(stateNode: AnyStateNode): Array<AnyStateNode> {\n const path: Array<AnyStateNode> = [];\n let marker = stateNode.parent;\n\n while (marker) {\n path.unshift(marker);\n marker = marker.parent;\n }\n\n return path;\n}\n\nfunction hasIntersection<T>(s1: Iterable<T>, s2: Iterable<T>): boolean {\n const set1 = new Set(s1);\n const set2 = new Set(s2);\n\n for (const item of set1) {\n if (set2.has(item)) {\n return true;\n }\n }\n for (const item of set2) {\n if (set1.has(item)) {\n return true;\n }\n }\n return false;\n}\n\nfunction removeConflictingTransitions(\n enabledTransitions: Array<AnyTransitionDefinition>,\n stateNodeSet: Set<AnyStateNode>,\n historyValue: AnyHistoryValue\n): Array<AnyTransitionDefinition> {\n const filteredTransitions = new Set<AnyTransitionDefinition>();\n\n for (const t1 of enabledTransitions) {\n let t1Preempted = false;\n const transitionsToRemove = new Set<AnyTransitionDefinition>();\n for (const t2 of filteredTransitions) {\n if (\n hasIntersection(\n computeExitSet([t1], stateNodeSet, historyValue),\n computeExitSet([t2], stateNodeSet, historyValue)\n )\n ) {\n if (isDescendant(t1.source, t2.source)) {\n transitionsToRemove.add(t2);\n } else {\n t1Preempted = true;\n break;\n }\n }\n }\n if (!t1Preempted) {\n for (const t3 of transitionsToRemove) {\n filteredTransitions.delete(t3);\n }\n filteredTransitions.add(t1);\n }\n }\n\n return Array.from(filteredTransitions);\n}\n\nfunction findLeastCommonAncestor(\n stateNodes: Array<AnyStateNode>\n): AnyStateNode | undefined {\n const [head, ...tail] = stateNodes;\n for (const ancestor of getProperAncestors(head, undefined)) {\n if (tail.every((sn) => isDescendant(sn, ancestor))) {\n return ancestor;\n }\n }\n}\n\nfunction getEffectiveTargetStates(\n transition: Pick<AnyTransitionDefinition, 'target'>,\n historyValue: AnyHistoryValue\n): Array<AnyStateNode> {\n if (!transition.target) {\n return [];\n }\n\n const targets = new Set<AnyStateNode>();\n\n for (const targetNode of transition.target) {\n if (isHistoryNode(targetNode)) {\n if (historyValue[targetNode.id]) {\n for (const node of historyValue[targetNode.id]) {\n targets.add(node);\n }\n } else {\n for (const node of getEffectiveTargetStates(\n resolveHistoryDefaultTransition(targetNode),\n historyValue\n )) {\n targets.add(node);\n }\n }\n } else {\n targets.add(targetNode);\n }\n }\n\n return [...targets];\n}\n\nfunction getTransitionDomain(\n transition: AnyTransitionDefinition,\n historyValue: AnyHistoryValue\n): AnyStateNode | undefined {\n const targetStates = getEffectiveTargetStates(transition, historyValue);\n\n if (!targetStates) {\n return;\n }\n\n if (\n !transition.reenter &&\n targetStates.every(\n (target) =>\n target === transition.source || isDescendant(target, transition.source)\n )\n ) {\n return transition.source;\n }\n\n const lca = findLeastCommonAncestor(targetStates.concat(transition.source));\n\n if (lca) {\n return lca;\n }\n\n // at this point we know that it's a root transition since LCA couldn't be found\n if (transition.reenter) {\n return;\n }\n\n return transition.source.machine.root;\n}\n\nfunction computeExitSet(\n transitions: AnyTransitionDefinition[],\n stateNodeSet: Set<AnyStateNode>,\n historyValue: AnyHistoryValue\n): Array<AnyStateNode> {\n const statesToExit = new Set<AnyStateNode>();\n\n for (const t of transitions) {\n if (t.target?.length) {\n const domain = getTransitionDomain(t, historyValue);\n\n if (t.reenter && t.source === domain) {\n statesToExit.add(domain);\n }\n\n for (const stateNode of stateNodeSet) {\n if (isDescendant(stateNode, domain!)) {\n statesToExit.add(stateNode);\n }\n }\n }\n }\n\n return [...statesToExit];\n}\n\nfunction areStateNodeCollectionsEqual(\n prevStateNodes: StateNode<any, any>[],\n nextStateNodeSet: Set<StateNode<any, any>>\n) {\n if (prevStateNodes.length !== nextStateNodeSet.size) {\n return false;\n }\n for (const node of prevStateNodes) {\n if (!nextStateNodeSet.has(node)) {\n return false;\n }\n }\n return true;\n}\n\n/** https://www.w3.org/TR/scxml/#microstepProcedure */\nexport function microstep<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n transitions: Array<AnyTransitionDefinition>,\n currentSnapshot: AnyMachineSnapshot,\n actorScope: AnyActorScope,\n event: AnyEventObject,\n isInitial: boolean,\n internalQueue: Array<AnyEventObject>\n): AnyMachineSnapshot {\n if (!transitions.length) {\n return currentSnapshot;\n }\n const mutStateNodeSet = new Set(currentSnapshot._nodes);\n let historyValue = currentSnapshot.historyValue;\n\n const filteredTransitions = removeConflictingTransitions(\n transitions,\n mutStateNodeSet,\n historyValue\n );\n\n let nextState = currentSnapshot;\n\n // Exit states\n if (!isInitial) {\n [nextState, historyValue] = exitStates(\n nextState,\n event,\n actorScope,\n filteredTransitions,\n mutStateNodeSet,\n historyValue,\n internalQueue\n );\n }\n\n // Execute transition content\n nextState = resolveActionsAndContext(\n nextState,\n event,\n actorScope,\n filteredTransitions.flatMap((t) => t.actions),\n internalQueue\n );\n\n // Enter states\n nextState = enterStates(\n nextState,\n event,\n actorScope,\n filteredTransitions,\n mutStateNodeSet,\n internalQueue,\n historyValue,\n isInitial\n );\n\n const nextStateNodes = [...mutStateNodeSet];\n\n if (nextState.status === 'done') {\n nextState = resolveActionsAndContext(\n nextState,\n event,\n actorScope,\n nextStateNodes\n .sort((a, b) => b.order - a.order)\n .flatMap((state) => state.exit),\n internalQueue\n );\n }\n\n try {\n if (\n historyValue === currentSnapshot.historyValue &&\n areStateNodeCollectionsEqual(currentSnapshot._nodes, mutStateNodeSet)\n ) {\n return nextState;\n }\n return cloneMachineSnapshot(nextState, {\n _nodes: nextStateNodes,\n historyValue\n });\n } catch (e) {\n // TODO: Refactor this once proper error handling is implemented.\n // See https://github.com/statelyai/rfcs/pull/4\n throw e;\n }\n}\n\nfunction getMachineOutput(\n snapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n rootNode: AnyStateNode,\n rootCompletionNode: AnyStateNode\n) {\n if (rootNode.output === undefined) {\n return;\n }\n const doneStateEvent = createDoneStateEvent(\n rootCompletionNode.id,\n rootCompletionNode.output !== undefined && rootCompletionNode.parent\n ? resolveOutput(\n rootCompletionNode.output,\n snapshot.context,\n event,\n actorScope.self\n )\n : undefined\n );\n return resolveOutput(\n rootNode.output,\n snapshot.context,\n doneStateEvent,\n actorScope.self\n );\n}\n\nfunction enterStates(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n filteredTransitions: AnyTransitionDefinition[],\n mutStateNodeSet: Set<AnyStateNode>,\n internalQueue: AnyEventObject[],\n historyValue: HistoryValue<any, any>,\n isInitial: boolean\n) {\n let nextSnapshot = currentSnapshot;\n const statesToEnter = new Set<AnyStateNode>();\n // those are states that were directly targeted or indirectly targeted by the explicit target\n // in other words, those are states for which initial actions should be executed\n // when we target `#deep_child` initial actions of its ancestors shouldn't be executed\n const statesForDefaultEntry = new Set<AnyStateNode>();\n computeEntrySet(\n filteredTransitions,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n\n // In the initial state, the root state node is \"entered\".\n if (isInitial) {\n statesForDefaultEntry.add(currentSnapshot.machine.root);\n }\n\n const completedNodes = new Set();\n\n for (const stateNodeToEnter of [...statesToEnter].sort(\n (a, b) => a.order - b.order\n )) {\n mutStateNodeSet.add(stateNodeToEnter);\n const actions: UnknownAction[] = [];\n\n // Add entry actions\n actions.push(...stateNodeToEnter.entry);\n\n for (const invokeDef of stateNodeToEnter.invoke) {\n actions.push(\n spawnChild(invokeDef.src, {\n ...invokeDef,\n syncSnapshot: !!invokeDef.onSnapshot\n })\n );\n }\n\n if (statesForDefaultEntry.has(stateNodeToEnter)) {\n const initialActions = stateNodeToEnter.initial!.actions;\n actions.push(...initialActions);\n }\n\n nextSnapshot = resolveActionsAndContext(\n nextSnapshot,\n event,\n actorScope,\n actions,\n internalQueue,\n stateNodeToEnter.invoke.map((invokeDef) => invokeDef.id)\n );\n\n if (stateNodeToEnter.type === 'final') {\n const parent = stateNodeToEnter.parent;\n\n let ancestorMarker =\n parent?.type === 'parallel' ? parent : parent?.parent;\n let rootCompletionNode = ancestorMarker || stateNodeToEnter;\n\n if (parent?.type === 'compound') {\n internalQueue.push(\n createDoneStateEvent(\n parent!.id,\n stateNodeToEnter.output !== undefined\n ? resolveOutput(\n stateNodeToEnter.output,\n nextSnapshot.context,\n event,\n actorScope.self\n )\n : undefined\n )\n );\n }\n while (\n ancestorMarker?.type === 'parallel' &&\n !completedNodes.has(ancestorMarker) &&\n isInFinalState(mutStateNodeSet, ancestorMarker)\n ) {\n completedNodes.add(ancestorMarker);\n internalQueue.push(createDoneStateEvent(ancestorMarker.id));\n rootCompletionNode = ancestorMarker;\n ancestorMarker = ancestorMarker.parent;\n }\n if (ancestorMarker) {\n continue;\n }\n\n nextSnapshot = cloneMachineSnapshot(nextSnapshot, {\n status: 'done',\n output: getMachineOutput(\n nextSnapshot,\n event,\n actorScope,\n nextSnapshot.machine.root,\n rootCompletionNode\n )\n });\n }\n }\n\n return nextSnapshot;\n}\n\nfunction computeEntrySet(\n transitions: Array<AnyTransitionDefinition>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>,\n statesToEnter: Set<AnyStateNode>\n) {\n for (const t of transitions) {\n const domain = getTransitionDomain(t, historyValue);\n\n for (const s of t.target || []) {\n if (\n !isHistoryNode(s) &&\n // if the target is different than the source then it will *definitely* be entered\n (t.source !== s ||\n // we know that the domain can't lie within the source\n // if it's different than the source then it's outside of it and it means that the target has to be entered as well\n t.source !== domain ||\n // reentering transitions always enter the target, even if it's the source itself\n t.reenter)\n ) {\n statesToEnter.add(s);\n statesForDefaultEntry.add(s);\n }\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n const targetStates = getEffectiveTargetStates(t, historyValue);\n for (const s of targetStates) {\n const ancestors = getProperAncestors(s, domain);\n if (domain?.type === 'parallel') {\n ancestors.push(domain!);\n }\n addAncestorStatesToEnter(\n statesToEnter,\n historyValue,\n statesForDefaultEntry,\n ancestors,\n !t.source.parent && t.reenter ? undefined : domain\n );\n }\n }\n}\n\nfunction addDescendantStatesToEnter<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>,\n statesToEnter: Set<AnyStateNode>\n) {\n if (isHistoryNode(stateNode)) {\n if (historyValue[stateNode.id]) {\n const historyStateNodes = historyValue[stateNode.id];\n for (const s of historyStateNodes) {\n statesToEnter.add(s);\n\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n for (const s of historyStateNodes) {\n addProperAncestorStatesToEnter(\n s,\n stateNode.parent!,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n }\n } else {\n const historyDefaultTransition = resolveHistoryDefaultTransition<\n TContext,\n TEvent\n >(stateNode);\n for (const s of historyDefaultTransition.target) {\n statesToEnter.add(s);\n\n if (historyDefaultTransition === stateNode.parent?.initial) {\n statesForDefaultEntry.add(stateNode.parent);\n }\n\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n\n for (const s of historyDefaultTransition.target) {\n addProperAncestorStatesToEnter(\n s,\n stateNode.parent!,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n }\n }\n } else {\n if (stateNode.type === 'compound') {\n const [initialState] = stateNode.initial.target;\n\n if (!isHistoryNode(initialState)) {\n statesToEnter.add(initialState);\n statesForDefaultEntry.add(initialState);\n }\n addDescendantStatesToEnter(\n initialState,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n\n addProperAncestorStatesToEnter(\n initialState,\n stateNode,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n } else {\n if (stateNode.type === 'parallel') {\n for (const child of getChildren(stateNode).filter(\n (sn) => !isHistoryNode(sn)\n )) {\n if (![...statesToEnter].some((s) => isDescendant(s, child))) {\n if (!isHistoryNode(child)) {\n statesToEnter.add(child);\n statesForDefaultEntry.add(child);\n }\n addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n }\n}\n\nfunction addAncestorStatesToEnter(\n statesToEnter: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>,\n ancestors: AnyStateNode[],\n reentrancyDomain?: AnyStateNode\n) {\n for (const anc of ancestors) {\n if (!reentrancyDomain || isDescendant(anc, reentrancyDomain)) {\n statesToEnter.add(anc);\n }\n if (anc.type === 'parallel') {\n for (const child of getChildren(anc).filter((sn) => !isHistoryNode(sn))) {\n if (![...statesToEnter].some((s) => isDescendant(s, child))) {\n statesToEnter.add(child);\n addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n}\n\nfunction addProperAncestorStatesToEnter(\n stateNode: AnyStateNode,\n toStateNode: AnyStateNode | undefined,\n statesToEnter: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>\n) {\n addAncestorStatesToEnter(\n statesToEnter,\n historyValue,\n statesForDefaultEntry,\n getProperAncestors(stateNode, toStateNode)\n );\n}\n\nfunction exitStates(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n transitions: AnyTransitionDefinition[],\n mutStateNodeSet: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n internalQueue: AnyEventObject[]\n) {\n let nextSnapshot = currentSnapshot;\n const statesToExit = computeExitSet(\n transitions,\n mutStateNodeSet,\n historyValue\n );\n\n statesToExit.sort((a, b) => b.order - a.order);\n\n let changedHistory: typeof historyValue | undefined;\n\n // From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates\n for (const exitStateNode of statesToExit) {\n for (const historyNode of getHistoryNodes(exitStateNode)) {\n let predicate: (sn: AnyStateNode) => boolean;\n if (historyNode.history === 'deep') {\n predicate = (sn) =>\n isAtomicStateNode(sn) && isDescendant(sn, exitStateNode);\n } else {\n predicate = (sn) => {\n return sn.parent === exitStateNode;\n };\n }\n changedHistory ??= { ...historyValue };\n changedHistory[historyNode.id] =\n Array.from(mutStateNodeSet).filter(predicate);\n }\n }\n\n for (const s of statesToExit) {\n nextSnapshot = resolveActionsAndContext(\n nextSnapshot,\n event,\n actorScope,\n [...s.exit, ...s.invoke.map((def) => stopChild(def.id))],\n internalQueue\n );\n mutStateNodeSet.delete(s);\n }\n return [nextSnapshot, changedHistory || historyValue] as const;\n}\n\ninterface BuiltinAction {\n (): void;\n resolve: (\n actorScope: AnyActorScope,\n snapshot: AnyMachineSnapshot,\n actionArgs: ActionArgs<any, any, any>,\n actionParams: ParameterizedObject['params'] | undefined,\n action: unknown,\n extra: unknown\n ) => [\n newState: AnyMachineSnapshot,\n params: unknown,\n actions?: UnknownAction[]\n ];\n retryResolve: (\n actorScope: AnyActorScope,\n snapshot: AnyMachineSnapshot,\n params: unknown\n ) => void;\n execute: (actorScope: AnyActorScope, params: unknown) => void;\n}\n\nexport let executingCustomAction:\n | ActionFunction<any, any, any, any, any, any, any, any, any>\n | false = false;\n\nfunction resolveAndExecuteActionsWithContext(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n actions: UnknownAction[],\n extra: {\n internalQueue: AnyEventObject[];\n deferredActorIds: string[] | undefined;\n },\n retries: (readonly [BuiltinAction, unknown])[] | undefined\n): AnyMachineSnapshot {\n const { machine } = currentSnapshot;\n let intermediateSnapshot = currentSnapshot;\n\n for (const action of actions) {\n const isInline = typeof action === 'function';\n const resolvedAction = isInline\n ? action\n : // the existing type of `.actions` assumes non-nullable `TExpressionAction`\n // it's fine to cast this here to get a common type and lack of errors in the rest of the code\n // our logic below makes sure that we call those 2 \"variants\" correctly\n (\n machine.implementations.actions as Record<\n string,\n ActionFunction<\n MachineContext,\n EventObject,\n EventObject,\n ParameterizedObject['params'] | undefined,\n ProvidedActor,\n ParameterizedObject,\n ParameterizedObject,\n string,\n EventObject\n >\n >\n )[typeof action === 'string' ? action : action.type];\n\n if (!resolvedAction) {\n continue;\n }\n\n const actionArgs = {\n context: intermediateSnapshot.context,\n event,\n self: actorScope.self,\n system: actorScope.system\n };\n\n const actionParams =\n isInline || typeof action === 'string'\n ? undefined\n : 'params' in action\n ? typeof action.params === 'function'\n ? action.params({ context: intermediateSnapshot.context, event })\n : action.params\n : undefined;\n\n function executeAction() {\n actorScope.system._sendInspectionEvent({\n type: '@xstate.action',\n actorRef: actorScope.self,\n action: {\n type:\n typeof action === 'string'\n ? action\n : typeof action === 'object'\n ? action.type\n : action.name || '(anonymous)',\n params: actionParams\n }\n });\n try {\n executingCustomAction = resolvedAction;\n resolvedAction(actionArgs, actionParams);\n } finally {\n executingCustomAction = false;\n }\n }\n\n if (!('resolve' in resolvedAction)) {\n if (actorScope.self._processingStatus === ProcessingStatus.Running) {\n executeAction();\n } else {\n actorScope.defer(() => {\n executeAction();\n });\n }\n continue;\n }\n\n const builtinAction = resolvedAction as BuiltinAction;\n\n const [nextState, params, actions] = builtinAction.resolve(\n actorScope,\n intermediateSnapshot,\n actionArgs,\n actionParams,\n resolvedAction, // this holds all params\n extra\n );\n intermediateSnapshot = nextState;\n\n if ('retryResolve' in builtinAction) {\n retries?.push([builtinAction, params]);\n }\n\n if ('execute' in builtinAction) {\n if (actorScope.self._processingStatus === ProcessingStatus.Running) {\n builtinAction.execute(actorScope, params);\n } else {\n actorScope.defer(builtinAction.execute.bind(null, actorScope, params));\n }\n }\n\n if (actions) {\n intermediateSnapshot = resolveAndExecuteActionsWithContext(\n intermediateSnapshot,\n event,\n actorScope,\n actions,\n extra,\n retries\n );\n }\n }\n\n return intermediateSnapshot;\n}\n\nexport function resolveActionsAndContext(\n currentSnapshot: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope,\n actions: UnknownAction[],\n internalQueue: AnyEventObject[],\n deferredActorIds?: string[]\n): AnyMachineSnapshot {\n const retries: (readonly [BuiltinAction, unknown])[] | undefined =\n deferredActorIds ? [] : undefined;\n const nextState = resolveAndExecuteActionsWithContext(\n currentSnapshot,\n event,\n actorScope,\n actions,\n { internalQueue, deferredActorIds },\n retries\n );\n retries?.forEach(([builtinAction, params]) => {\n builtinAction.retryResolve(actorScope, nextState, params);\n });\n return nextState;\n}\n\nexport function macrostep(\n snapshot: AnyMachineSnapshot,\n event: EventObject,\n actorScope: AnyActorScope,\n internalQueue: AnyEventObject[] = []\n): {\n snapshot: typeof snapshot;\n microstates: Array<typeof snapshot>;\n} {\n if (isDevelopment && event.type === WILDCARD) {\n throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);\n }\n\n let nextSnapshot = snapshot;\n const microstates: AnyMachineSnapshot[] = [];\n\n function addMicrostate(\n microstate: AnyMachineSnapshot,\n event: AnyEventObject,\n transitions: AnyTransitionDefinition[]\n ) {\n actorScope.system._sendInspectionEvent({\n type: '@xstate.microstep',\n actorRef: actorScope.self,\n event,\n snapshot: microstate,\n _transitions: transitions\n });\n microstates.push(microstate);\n }\n\n // Handle stop event\n if (event.type === XSTATE_STOP) {\n nextSnapshot = cloneMachineSnapshot(\n stopChildren(nextSnapshot, event, actorScope),\n {\n status: 'stopped'\n }\n );\n addMicrostate(nextSnapshot, event, []);\n\n return {\n snapshot: nextSnapshot,\n microstates\n };\n }\n\n let nextEvent = event;\n\n // Assume the state is at rest (no raised events)\n // Determine the next state based on the next microstep\n if (nextEvent.type !== XSTATE_INIT) {\n const currentEvent = nextEvent;\n const isErr = isErrorActorEvent(currentEvent);\n\n const transitions = selectTransitions(currentEvent, nextSnapshot);\n\n if (isErr && !transitions.length) {\n // TODO: we should likely only allow transitions selected by very explicit descriptors\n // `*` shouldn't be matched, likely `xstate.error.*` shouldnt be either\n // similarly `xstate.error.actor.*` and `xstate.error.actor.todo.*` have to be considered too\n nextSnapshot = cloneMachineSnapshot<typeof snapshot>(snapshot, {\n status: 'error',\n error: currentEvent.error\n });\n addMicrostate(nextSnapshot, currentEvent, []);\n return {\n snapshot: nextSnapshot,\n microstates\n };\n }\n nextSnapshot = microstep(\n transitions,\n snapshot,\n actorScope,\n nextEvent,\n false, // isInitial\n internalQueue\n );\n addMicrostate(nextSnapshot, currentEvent, transitions);\n }\n\n let shouldSelectEventlessTransitions = true;\n\n while (nextSnapshot.status === 'active') {\n let enabledTransitions: AnyTransitionDefinition[] =\n shouldSelectEventlessTransitions\n ? selectEventlessTransitions(nextSnapshot, nextEvent)\n : [];\n\n // eventless transitions should always be selected after selecting *regular* transitions\n // by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case\n const previousState = enabledTransitions.length ? nextSnapshot : undefined;\n\n if (!enabledTransitions.length) {\n if (!internalQueue.length) {\n break;\n }\n nextEvent = internalQueue.shift()!;\n enabledTransitions = selectTransitions(nextEvent, nextSnapshot);\n }\n\n nextSnapshot = microstep(\n enabledTransitions,\n nextSnapshot,\n actorScope,\n nextEvent,\n false,\n internalQueue\n );\n shouldSelectEventlessTransitions = nextSnapshot !== previousState;\n addMicrostate(nextSnapshot, nextEvent, enabledTransitions);\n }\n\n if (nextSnapshot.status !== 'active') {\n stopChildren(nextSnapshot, nextEvent, actorScope);\n }\n\n return {\n snapshot: nextSnapshot,\n microstates\n };\n}\n\nfunction stopChildren(\n nextState: AnyMachineSnapshot,\n event: AnyEventObject,\n actorScope: AnyActorScope\n) {\n return resolveActionsAndContext(\n nextState,\n event,\n actorScope,\n Object.values(nextState.children).map((child: any) => stopChild(child)),\n []\n );\n}\n\nfunction selectTransitions(\n event: AnyEventObject,\n nextState: AnyMachineSnapshot\n): AnyTransitionDefinition[] {\n return nextState.machine.getTransitionData(nextState as any, event);\n}\n\nfunction selectEventlessTransitions(\n nextState: AnyMachineSnapshot,\n event: AnyEventObject\n): AnyTransitionDefinition[] {\n const enabledTransitionSet: Set<AnyTransitionDefinition> = new Set();\n const atomicStates = nextState._nodes.filter(isAtomicStateNode);\n\n for (const stateNode of atomicStates) {\n loop: for (const s of [stateNode].concat(\n getProperAncestors(stateNode, undefined)\n )) {\n if (!s.always) {\n continue;\n }\n for (const transition of s.always) {\n if (\n transition.guard === undefined ||\n evaluateGuard(transition.guard, nextState.context, event, nextState)\n ) {\n enabledTransitionSet.add(transition);\n break loop;\n }\n }\n }\n }\n\n return removeConflictingTransitions(\n Array.from(enabledTransitionSet),\n new Set(nextState._nodes),\n nextState.historyValue\n );\n}\n\n/**\n * Resolves a partial state value with its full representation in the state\n * node's machine.\n *\n * @param stateValue The partial state value to resolve.\n */\nexport function resolveStateValue(\n rootNode: AnyStateNode,\n stateValue: StateValue\n): StateValue {\n const allStateNodes = getAllStateNodes(getStateNodes(rootNode, stateValue));\n return getStateValue(rootNode, [...allStateNodes]);\n}\n\nfunction stateValuesEqual(\n a: StateValue | undefined,\n b: StateValue | undefined\n): boolean {\n if (a === b) {\n return true;\n }\n\n if (a === undefined || b === undefined) {\n return false;\n }\n\n if (typeof a === 'string' || typeof b === 'string') {\n return a === b;\n }\n\n const aKeys = Object.keys(a as StateValueMap);\n const bKeys = Object.keys(b as StateValueMap);\n\n return (\n aKeys.length === bKeys.length &&\n aKeys.every((key) => stateValuesEqual(a[key], b[key]))\n );\n}\n","import isDevelopment from '#is-development';\nimport type {\n EventObject,\n StateValue,\n MachineContext,\n ParameterizedObject,\n AnyMachineSnapshot,\n NoRequiredParams,\n WithDynamicParams,\n Identity,\n Elements,\n DoNotInfer\n} from './types.ts';\nimport { isStateId } from './stateUtils.ts';\n\ntype SingleGuardArg<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined,\n TGuardArg\n> = [TGuardArg] extends [{ type: string }]\n ? Identity<TGuardArg>\n : [TGuardArg] extends [string]\n ? TGuardArg\n : GuardPredicate<TContext, TExpressionEvent, TParams, ParameterizedObject>;\n\ntype NormalizeGuardArg<TGuardArg> = TGuardArg extends { type: string }\n ? Identity<TGuardArg> & { params: unknown }\n : TGuardArg extends string\n ? { type: TGuardArg; params: undefined }\n : '_out_TGuard' extends keyof TGuardArg\n ? TGuardArg['_out_TGuard'] & ParameterizedObject\n : never;\n\ntype NormalizeGuardArgArray<TArg extends unknown[]> = Elements<{\n [K in keyof TArg]: NormalizeGuardArg<TArg[K]>;\n}>;\n\nexport type GuardPredicate<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined,\n TGuard extends ParameterizedObject\n> = {\n (args: GuardArgs<TContext, TExpressionEvent>, params: TParams): boolean;\n _out_TGuard?: TGuard;\n};\n\nexport interface GuardArgs<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject\n> {\n context: TContext;\n event: TExpressionEvent;\n}\n\nexport type Guard<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined,\n TGuard extends ParameterizedObject\n> =\n | NoRequiredParams<TGuard>\n | WithDynamicParams<TContext, TExpressionEvent, TGuard>\n | GuardPredicate<TContext, TExpressionEvent, TParams, TGuard>;\n\nexport type UnknownGuard = UnknownReferencedGuard | UnknownInlineGuard;\n\ntype UnknownReferencedGuard = Guard<\n MachineContext,\n EventObject,\n ParameterizedObject['params'],\n ParameterizedObject\n>;\n\ntype UnknownInlineGuard = Guard<\n MachineContext,\n EventObject,\n undefined,\n ParameterizedObject\n>;\n\ninterface BuiltinGuard {\n (): boolean;\n check: (\n snapshot: AnyMachineSnapshot,\n guardArgs: GuardArgs<any, any>,\n params: unknown\n ) => boolean;\n}\n\nfunction checkStateIn(\n snapshot: AnyMachineSnapshot,\n _: GuardArgs<any, any>,\n { stateValue }: { stateValue: StateValue }\n) {\n if (typeof stateValue === 'string' && isStateId(stateValue)) {\n const target = snapshot.machine.getStateNodeById(stateValue);\n return snapshot._nodes.some((sn) => sn === target);\n }\n\n return snapshot.matches(stateValue);\n}\n\nexport function stateIn<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TParams extends ParameterizedObject['params'] | undefined\n>(\n stateValue: StateValue\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n TParams,\n any // TODO: recheck if we could replace this with something better here\n> {\n function stateIn(\n args: GuardArgs<TContext, TExpressionEvent>,\n params: TParams\n ) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n stateIn.check = checkStateIn;\n stateIn.stateValue = stateValue;\n\n return stateIn;\n}\n\nfunction checkNot(\n snapshot: AnyMachineSnapshot,\n { context, event }: GuardArgs<any, any>,\n { guards }: { guards: readonly UnknownGuard[] }\n) {\n return !evaluateGuard(guards[0], context, event, snapshot);\n}\n\n/**\n * Higher-order guard that evaluates to `true` if the `guard` passed to it\n * evaluates to `false`.\n *\n * @category Guards\n * @example\n *\n * ```ts\n * import { setup, not } from 'xstate';\n *\n * const machine = setup({\n * guards: {\n * someNamedGuard: () => false\n * }\n * }).createMachine({\n * on: {\n * someEvent: {\n * guard: not('someNamedGuard'),\n * actions: () => {\n * // will be executed if guard in `not(...)`\n * // evaluates to `false`\n * }\n * }\n * }\n * });\n * ```\n *\n * @returns A guard\n */\nexport function not<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TArg\n>(\n guard: SingleGuardArg<TContext, TExpressionEvent, unknown, TArg>\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n unknown,\n NormalizeGuardArg<DoNotInfer<TArg>>\n> {\n function not(args: GuardArgs<TContext, TExpressionEvent>, params: unknown) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n not.check = checkNot;\n not.guards = [guard];\n\n return not;\n}\n\nfunction checkAnd(\n snapshot: AnyMachineSnapshot,\n { context, event }: GuardArgs<any, any>,\n { guards }: { guards: readonly UnknownGuard[] }\n) {\n return guards.every((guard) =>\n evaluateGuard(guard, context, event, snapshot)\n );\n}\n\n/**\n * Higher-order guard that evaluates to `true` if all `guards` passed to it\n * evaluate to `true`.\n *\n * @category Guards\n * @example\n *\n * ```ts\n * import { setup, and } from 'xstate';\n *\n * const machine = setup({\n * guards: {\n * someNamedGuard: () => true\n * }\n * }).createMachine({\n * on: {\n * someEvent: {\n * guard: and([({ context }) => context.value > 0, 'someNamedGuard']),\n * actions: () => {\n * // will be executed if all guards in `and(...)`\n * // evaluate to true\n * }\n * }\n * }\n * });\n * ```\n *\n * @returns A guard action object\n */\nexport function and<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TArg extends unknown[]\n>(\n guards: readonly [\n ...{\n [K in keyof TArg]: SingleGuardArg<\n TContext,\n TExpressionEvent,\n unknown,\n TArg[K]\n >;\n }\n ]\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n unknown,\n NormalizeGuardArgArray<DoNotInfer<TArg>>\n> {\n function and(args: GuardArgs<TContext, TExpressionEvent>, params: unknown) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n and.check = checkAnd;\n and.guards = guards;\n\n return and;\n}\n\nfunction checkOr(\n snapshot: AnyMachineSnapshot,\n { context, event }: GuardArgs<any, any>,\n { guards }: { guards: readonly UnknownGuard[] }\n) {\n return guards.some((guard) => evaluateGuard(guard, context, event, snapshot));\n}\n\n/**\n * Higher-order guard that evaluates to `true` if any of the `guards` passed to\n * it evaluate to `true`.\n *\n * @category Guards\n * @example\n *\n * ```ts\n * import { setup, or } from 'xstate';\n *\n * const machine = setup({\n * guards: {\n * someNamedGuard: () => true\n * }\n * }).createMachine({\n * on: {\n * someEvent: {\n * guard: or([({ context }) => context.value > 0, 'someNamedGuard']),\n * actions: () => {\n * // will be executed if any of the guards in `or(...)`\n * // evaluate to true\n * }\n * }\n * }\n * });\n * ```\n *\n * @returns A guard action object\n */\nexport function or<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject,\n TArg extends unknown[]\n>(\n guards: readonly [\n ...{\n [K in keyof TArg]: SingleGuardArg<\n TContext,\n TExpressionEvent,\n unknown,\n TArg[K]\n >;\n }\n ]\n): GuardPredicate<\n TContext,\n TExpressionEvent,\n unknown,\n NormalizeGuardArgArray<DoNotInfer<TArg>>\n> {\n function or(args: GuardArgs<TContext, TExpressionEvent>, params: unknown) {\n if (isDevelopment) {\n throw new Error(`This isn't supposed to be called`);\n }\n return false;\n }\n\n or.check = checkOr;\n or.guards = guards;\n\n return or;\n}\n\n// TODO: throw on cycles (depth check should be enough)\nexport function evaluateGuard<\n TContext extends MachineContext,\n TExpressionEvent extends EventObject\n>(\n guard: UnknownGuard | UnknownInlineGuard,\n context: TContext,\n event: TExpressionEvent,\n snapshot: AnyMachineSnapshot\n): boolean {\n const { machine } = snapshot;\n const isInline = typeof guard === 'function';\n\n const resolved = isInline\n ? guard\n : machine.implementations.guards[\n typeof guard === 'string' ? guard : guard.type\n ];\n\n if (!isInline && !resolved) {\n throw new Error(\n `Guard '${\n typeof guard === 'string' ? guard : guard.type\n }' is not implemented.'.`\n );\n }\n\n if (typeof resolved !== 'function') {\n return evaluateGuard(resolved!, context, event, snapshot);\n }\n\n const guardArgs = {\n context,\n event\n };\n\n const guardParams =\n isInline || typeof guard === 'string'\n ? undefined\n : 'params' in guard\n ? typeof guard.params === 'function'\n ? guard.params({ context, event })\n : guard.params\n : undefined;\n\n if (!('check' in resolved)) {\n // the existing type of `.guards` assumes non-nullable `TExpressionGuard`\n // inline guards expect `TExpressionGuard` to be set to `undefined`\n // it's fine to cast this here, our logic makes sure that we call those 2 \"variants\" correctly\n return resolved(guardArgs, guardParams as never);\n }\n\n const builtinGuard = resolved as unknown as BuiltinGuard;\n\n return builtinGuard.check(\n snapshot,\n guardArgs,\n resolved // this holds all params\n );\n}\n"],"names":["isStateId","str","checkStateIn","snapshot","_","stateValue","target","machine","getStateNodeById","_nodes","some","sn","matches","checkNot","context","event","guards","evaluateGuard","checkAnd","every","guard","checkOr","isInline","resolved","implementations","type","Error","guardArgs","guardParams","undefined","params","check","and","args","not","or","stateIn"],"mappings":"oPAGO,MC6MMA,EAAaC,GD7MM,MC6MUA,EAAI,GCrH9C,SAASC,EACPC,EACAC,GACAC,WAAEA,IAEF,GAA0B,iBAAfA,GAA2BL,EAAUK,GAAa,CAC3D,MAAMC,EAASH,EAASI,QAAQC,iBAAiBH,GACjD,OAAOF,EAASM,OAAOC,MAAMC,GAAOA,IAAOL,GAC7C,CAEA,OAAOH,EAASS,QAAQP,EAC1B,CA8BA,SAASQ,EACPV,GACAW,QAAEA,EAAOC,MAAEA,IACXC,OAAEA,IAEF,OAAQC,EAAcD,EAAO,GAAIF,EAASC,EAAOZ,EACnD,CAwDA,SAASe,EACPf,GACAW,QAAEA,EAAOC,MAAEA,IACXC,OAAEA,IAEF,OAAOA,EAAOG,OAAOC,GACnBH,EAAcG,EAAON,EAASC,EAAOZ,IAEzC,CAiEA,SAASkB,EACPlB,GACAW,QAAEA,EAAOC,MAAEA,IACXC,OAAEA,IAEF,OAAOA,EAAON,MAAMU,GAAUH,EAAcG,EAAON,EAASC,EAAOZ,IACrE,CAkEO,SAASc,EAIdG,EACAN,EACAC,EACAZ,GAEA,MAAMI,QAAEA,GAAYJ,EACdmB,EAA4B,mBAAVF,EAElBG,EAAWD,EACbF,EACAb,EAAQiB,gBAAgBR,OACL,iBAAVI,EAAqBA,EAAQA,EAAMK,MAGhD,IAAKH,IAAaC,EAChB,MAAM,IAAIG,MACP,UACkB,iBAAVN,EAAqBA,EAAQA,EAAMK,+BAKhD,GAAwB,mBAAbF,EACT,OAAON,EAAcM,EAAWT,EAASC,EAAOZ,GAGlD,MAAMwB,EAAY,CAChBb,UACAC,SAGIa,EACJN,GAA6B,iBAAVF,OACfS,EACA,WAAYT,EACc,mBAAjBA,EAAMU,OACXV,EAAMU,OAAO,CAAEhB,UAASC,UACxBK,EAAMU,YACRD,EAER,KAAM,UAAWN,GAIf,OAAOA,EAASI,EAAWC,GAK7B,OAFqBL,EAEDQ,MAClB5B,EACAwB,EACAJ,EAEJ,OApKO,SAKLP,GAgBA,SAASgB,EAAIC,EAA6CH,GAIxD,OAAO,CACT,CAKA,OAHAE,EAAID,MAAQb,EACZc,EAAIhB,OAASA,EAENgB,CACT,0BAhGO,SAKLZ,GAOA,SAASc,EAAID,EAA6CH,GAIxD,OAAO,CACT,CAKA,OAHAI,EAAIH,MAAQlB,EACZqB,EAAIlB,OAAS,CAACI,GAEPc,CACT,OAgHO,SAKLlB,GAgBA,SAASmB,EAAGF,EAA6CH,GAIvD,OAAO,CACT,CAKA,OAHAK,EAAGJ,MAAQV,EACXc,EAAGnB,OAASA,EAELmB,CACT,YAxOO,SAKL9B,GAOA,SAAS+B,EACPH,EACAH,GAKA,OAAO,CACT,CAKA,OAHAM,EAAQL,MAAQ7B,EAChBkC,EAAQ/B,WAAaA,EAEd+B,CACT"}
|