xstate 5.0.0-alpha.5 → 5.0.0-beta.7
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.cjs.dev.js +1 -1
- package/actions/dist/xstate-actions.cjs.prod.js +1 -1
- package/actions/dist/xstate-actions.esm.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js.map +1 -1
- package/actors/dist/xstate-actors.cjs.dev.js +1 -1
- package/actors/dist/xstate-actors.cjs.prod.js +1 -1
- package/actors/dist/xstate-actors.esm.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/{actions-96f799fc.cjs.dev.js → actions-0fcf4fd9.cjs.dev.js} +19 -16
- package/dist/{actions-2479953d.cjs.prod.js → actions-a1a641d3.cjs.prod.js} +19 -16
- package/dist/{actions-7678b87b.esm.js → actions-b334e916.esm.js} +19 -17
- package/dist/declarations/src/StateNode.d.ts +2 -2
- package/dist/declarations/src/actions.d.ts +4 -4
- package/dist/declarations/src/stateUtils.d.ts +6 -0
- package/dist/declarations/src/typegenTypes.d.ts +3 -3
- package/dist/declarations/src/types.d.ts +11 -11
- package/dist/xstate.cjs.dev.js +11 -9
- package/dist/xstate.cjs.prod.js +11 -9
- package/dist/xstate.esm.js +12 -10
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/guards/dist/xstate-guards.cjs.dev.js +1 -1
- package/guards/dist/xstate-guards.cjs.prod.js +1 -1
- package/guards/dist/xstate-guards.esm.js +1 -1
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var actors_dist_xstateActors = require('../../dist/actions-
|
|
5
|
+
var actors_dist_xstateActors = require('../../dist/actions-0fcf4fd9.cjs.dev.js');
|
|
6
6
|
require('../../dist/index-ebaab3c9.cjs.dev.js');
|
|
7
7
|
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var actors_dist_xstateActors = require('../../dist/actions-
|
|
5
|
+
var actors_dist_xstateActors = require('../../dist/actions-a1a641d3.cjs.prod.js');
|
|
6
6
|
require('../../dev/dist/xstate-dev.cjs.prod.js');
|
|
7
7
|
|
|
8
8
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { av as and, h as evaluateGuard, au as not, aw as or, at as stateIn, ax as toGuardDefinition } from '../../dist/actions-b334e916.esm.js';
|
|
2
2
|
import '../../dist/index-50bd0aff.esm.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xstate-guards.umd.min.js","sources":["../../src/utils.ts","../../src/guards.ts","../../src/constants.ts","../../src/stateUtils.ts"],"sourcesContent":["import { AnyActorBehavior, AnyState } from './index.ts';\nimport { errorExecution, errorPlatform } from './actionTypes.ts';\nimport { NULL_EVENT, STATE_DELIMITER, TARGETLESS_KEY } from './constants.ts';\nimport { IS_PRODUCTION } from './environment.ts';\nimport type { StateNode } from './StateNode.ts';\nimport type {\n ActorBehavior,\n EventObject,\n EventType,\n InvokeConfig,\n MachineContext,\n Mapper,\n Observer,\n PropertyMapper,\n SCXML,\n SCXMLErrorEvent,\n SingleOrArray,\n StateLike,\n StateValue,\n Subscribable,\n TransitionConfig,\n TransitionConfigTarget\n} from './types.ts';\n\nexport function keys<T extends object>(value: T): Array<keyof T & string> {\n return Object.keys(value) as Array<keyof T & string>;\n}\n\nexport function matchesState(\n parentStateId: StateValue,\n childStateId: StateValue,\n delimiter: string = STATE_DELIMITER\n): boolean {\n const parentStateValue = toStateValue(parentStateId, delimiter);\n const childStateValue = toStateValue(childStateId, delimiter);\n\n if (isString(childStateValue)) {\n if (isString(parentStateValue)) {\n return childStateValue === parentStateValue;\n }\n\n // Parent more specific than child\n return false;\n }\n\n if (isString(parentStateValue)) {\n return parentStateValue in childStateValue;\n }\n\n return Object.keys(parentStateValue).every((key) => {\n if (!(key in childStateValue)) {\n return false;\n }\n\n return matchesState(parentStateValue[key], childStateValue[key]);\n });\n}\n\nexport function toStatePath(\n stateId: string | string[],\n delimiter: string\n): string[] {\n try {\n if (isArray(stateId)) {\n return stateId;\n }\n\n return stateId.toString().split(delimiter);\n } catch (e) {\n throw new Error(`'${stateId}' is not a valid state path.`);\n }\n}\n\nexport function isStateLike(state: any): state is AnyState {\n return (\n typeof state === 'object' &&\n 'value' in state &&\n 'context' in state &&\n 'event' in state &&\n '_event' in state\n );\n}\n\nexport function toStateValue(\n stateValue: StateLike<any> | StateValue | string[],\n delimiter: string\n): StateValue {\n if (isStateLike(stateValue)) {\n return stateValue.value;\n }\n\n if (isArray(stateValue)) {\n return pathToStateValue(stateValue);\n }\n\n if (typeof stateValue !== 'string') {\n return stateValue as StateValue;\n }\n\n const statePath = toStatePath(stateValue as string, delimiter);\n\n return pathToStateValue(statePath);\n}\n\nexport function pathToStateValue(statePath: string[]): StateValue {\n if (statePath.length === 1) {\n return statePath[0];\n }\n\n const value = {};\n let marker = value;\n\n for (let i = 0; i < statePath.length - 1; i++) {\n if (i === statePath.length - 2) {\n marker[statePath[i]] = statePath[i + 1];\n } else {\n marker[statePath[i]] = {};\n marker = marker[statePath[i]];\n }\n }\n\n return value;\n}\n\nexport function mapValues<P, O extends Record<string, unknown>>(\n collection: O,\n iteratee: (item: O[keyof O], key: keyof O, collection: O, i: number) => P\n): { [key in keyof O]: P };\nexport function mapValues(\n collection: Record<string, unknown>,\n iteratee: (\n item: unknown,\n key: string,\n collection: Record<string, unknown>,\n i: number\n ) => unknown\n) {\n const result: Record<string, unknown> = {};\n\n const collectionKeys = Object.keys(collection);\n for (let i = 0; i < collectionKeys.length; i++) {\n const key = collectionKeys[i];\n result[key] = iteratee(collection[key], key, collection, i);\n }\n\n return result;\n}\n\nexport function mapFilterValues<T, P>(\n collection: { [key: string]: T },\n iteratee: (item: T, key: string, collection: { [key: string]: T }) => P,\n predicate: (item: T) => boolean\n): { [key: string]: P } {\n const result: { [key: string]: P } = {};\n\n for (const key of Object.keys(collection)) {\n const item = collection[key];\n\n if (!predicate(item)) {\n continue;\n }\n\n result[key] = iteratee(item, key, collection);\n }\n\n return result;\n}\n\n/**\n * Retrieves a value at the given path.\n * @param props The deep path to the prop of the desired value\n */\nexport function path<T extends Record<string, any>>(props: string[]): any {\n return (object: T): any => {\n let result: T = object;\n\n for (const prop of props) {\n result = result[prop as keyof typeof result];\n }\n\n return result;\n };\n}\n\nexport function toStatePaths(stateValue: StateValue | undefined): string[][] {\n if (!stateValue) {\n return [[]];\n }\n\n if (isString(stateValue)) {\n return [[stateValue]];\n }\n\n const result = flatten(\n Object.keys(stateValue).map((key) => {\n const subStateValue = stateValue[key];\n\n if (\n typeof subStateValue !== 'string' &&\n (!subStateValue || !Object.keys(subStateValue).length)\n ) {\n return [[key]];\n }\n\n return toStatePaths(stateValue[key]).map((subPath) => {\n return [key].concat(subPath);\n });\n })\n );\n\n return result;\n}\n\nexport function flatten<T>(array: Array<T | T[]>): T[] {\n return ([] as T[]).concat(...array);\n}\n\nexport function toArrayStrict<T>(value: T[] | T): T[] {\n if (isArray(value)) {\n return value;\n }\n return [value];\n}\n\nexport function toArray<T>(value: T[] | T | undefined): T[] {\n if (value === undefined) {\n return [];\n }\n return toArrayStrict(value);\n}\n\nexport function mapContext<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n mapper: Mapper<TContext, TEvent, any> | PropertyMapper<TContext, TEvent, any>,\n context: TContext,\n _event: SCXML.Event<TEvent>\n): any {\n if (isFunction(mapper)) {\n return mapper({ context, event: _event.data });\n }\n\n const result = {} as any;\n const args = { context, event: _event.data };\n\n for (const key of Object.keys(mapper)) {\n const subMapper = mapper[key];\n\n if (isFunction(subMapper)) {\n result[key] = subMapper(args);\n } else {\n result[key] = subMapper;\n }\n }\n\n return result;\n}\n\nexport function isBuiltInEvent(eventType: EventType): boolean {\n return /^(done|error)\\./.test(eventType);\n}\n\nexport function isPromiseLike(value: any): value is PromiseLike<any> {\n if (value instanceof Promise) {\n return true;\n }\n // Check if shape matches the Promise/A+ specification for a \"thenable\".\n if (\n value !== null &&\n (isFunction(value) || typeof value === 'object') &&\n isFunction(value.then)\n ) {\n return true;\n }\n return false;\n}\n\nexport function isBehavior(value: any): value is ActorBehavior<any, any> {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'transition' in value &&\n typeof value.transition === 'function'\n );\n}\n\nexport function partition<T, A extends T, B extends T>(\n items: T[],\n predicate: (item: T) => item is A\n): [A[], B[]] {\n const [truthy, falsy] = [[], []] as [A[], B[]];\n\n for (const item of items) {\n if (predicate(item)) {\n truthy.push(item);\n } else {\n falsy.push(item as B);\n }\n }\n\n return [truthy, falsy];\n}\n\n// tslint:disable-next-line:no-empty\nexport let warn: (\n condition: boolean | Error,\n message: string\n) => void = () => {};\n\nif (!IS_PRODUCTION) {\n warn = (condition: boolean | Error, message: string) => {\n const error = condition instanceof Error ? condition : undefined;\n if (!error && condition) {\n return;\n }\n\n if (console !== undefined) {\n const args: [string, ...any[]] = [`Warning: ${message}`];\n if (error) {\n args.push(error);\n }\n // tslint:disable-next-line:no-console\n console.warn.apply(console, args);\n }\n };\n}\n\nexport function isArray(value: any): value is any[] {\n return Array.isArray(value);\n}\n\n// tslint:disable-next-line:ban-types\nexport function isFunction(value: any): value is Function {\n return typeof value === 'function';\n}\n\nexport function isString(value: any): value is string {\n return typeof value === 'string';\n}\n\nexport function isObservable<T>(value: any): value is Subscribable<T> {\n try {\n return 'subscribe' in value && isFunction(value.subscribe);\n } catch (e) {\n return false;\n }\n}\n\nexport const uniqueId = (() => {\n let currentId = 0;\n\n return () => {\n currentId++;\n return currentId.toString(16);\n };\n})();\n\nexport function isSCXMLEvent<TEvent extends EventObject>(\n event: TEvent | SCXML.Event<TEvent>\n): event is SCXML.Event<TEvent> {\n return '$$type' in event && event.$$type === 'scxml';\n}\n\nexport function isSCXMLErrorEvent(\n event: SCXML.Event<any>\n): event is SCXMLErrorEvent {\n return (\n typeof event.name === 'string' &&\n (event.name === errorExecution || event.name.startsWith(errorPlatform))\n );\n}\n\nexport function toSCXMLEvent<TEvent extends EventObject>(\n event: TEvent | SCXML.Event<TEvent>,\n scxmlEvent?: Partial<SCXML.Event<TEvent>>\n): SCXML.Event<TEvent> {\n if (isSCXMLEvent(event)) {\n return event as SCXML.Event<TEvent>;\n }\n\n return {\n name: event.type,\n data: event,\n $$type: 'scxml',\n type: 'external',\n ...scxmlEvent\n };\n}\n\nexport function toTransitionConfigArray<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n event: TEvent['type'] | typeof NULL_EVENT | '*',\n configLike: SingleOrArray<\n TransitionConfig<TContext, TEvent> | TransitionConfigTarget\n >\n): Array<\n TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | typeof NULL_EVENT | '*';\n }\n> {\n const transitions = toArrayStrict(configLike).map((transitionLike) => {\n if (\n typeof transitionLike === 'undefined' ||\n typeof transitionLike === 'string'\n ) {\n return { target: transitionLike, event };\n }\n\n return { ...transitionLike, event };\n }) as Array<\n TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | typeof NULL_EVENT | '*';\n } // TODO: fix 'as' (remove)\n >;\n\n return transitions;\n}\n\nexport function normalizeTarget<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n target: SingleOrArray<string | StateNode<TContext, TEvent>> | undefined\n): Array<string | StateNode<TContext, TEvent>> | undefined {\n if (target === undefined || target === TARGETLESS_KEY) {\n return undefined;\n }\n return toArray(target);\n}\n\nexport function reportUnhandledExceptionOnInvocation(\n originalError: any,\n currentError: any,\n id: string\n) {\n if (!IS_PRODUCTION) {\n const originalStackTrace = originalError.stack\n ? ` Stacktrace was '${originalError.stack}'`\n : '';\n if (originalError === currentError) {\n // tslint:disable-next-line:no-console\n console.error(\n `Missing onError handler for invocation '${id}', error was '${originalError}'.${originalStackTrace}`\n );\n } else {\n const stackTrace = currentError.stack\n ? ` Stacktrace was '${currentError.stack}'`\n : '';\n // tslint:disable-next-line:no-console\n console.error(\n `Missing onError handler and/or unhandled exception/promise rejection for invocation '${id}'. ` +\n `Original error: '${originalError}'. ${originalStackTrace} Current error is '${currentError}'.${stackTrace}`\n );\n }\n }\n}\n\nexport function toInvokeConfig<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n invocable: InvokeConfig<TContext, TEvent> | string | ActorBehavior<any, any>,\n id: string\n): InvokeConfig<TContext, TEvent> {\n if (typeof invocable === 'object') {\n if ('src' in invocable) {\n return invocable;\n }\n\n if ('transition' in invocable) {\n return {\n id,\n src: invocable\n };\n }\n }\n\n return {\n id,\n src: invocable\n };\n}\n\nexport function toObserver<T>(\n nextHandler?: Observer<T> | ((value: T) => void),\n errorHandler?: (error: any) => void,\n completionHandler?: () => void\n): Observer<T> {\n const noop = () => {};\n const isObserver = typeof nextHandler === 'object';\n const self = isObserver ? nextHandler : null;\n\n return {\n next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),\n error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),\n complete: (\n (isObserver ? nextHandler.complete : completionHandler) || noop\n ).bind(self)\n };\n}\n\nexport function createInvokeId(stateNodeId: string, index: number): string {\n return `${stateNodeId}:invocation[${index}]`;\n}\n\nexport function resolveReferencedActor(\n referenced:\n | AnyActorBehavior\n | { src: AnyActorBehavior; input: Mapper<any, any, any> | any }\n | undefined\n) {\n return referenced\n ? 'transition' in referenced\n ? { src: referenced, input: undefined }\n : referenced\n : undefined;\n}\n","import type {\n EventObject,\n StateValue,\n BooleanGuardDefinition,\n GuardConfig,\n GuardDefinition,\n SCXML,\n GuardPredicate,\n MachineContext\n} from './types.ts';\nimport { isStateId } from './stateUtils.ts';\nimport { isFunction, isString } from './utils.ts';\nimport type { State } from './State.ts';\n\nexport function stateIn<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateValue: StateValue): GuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.guard:in',\n params: { stateValue },\n predicate: ({ state }) => {\n if (isString(stateValue) && isStateId(stateValue)) {\n return state.configuration.some((sn) => sn.id === stateValue.slice(1));\n }\n\n return state.matches(stateValue);\n }\n };\n}\n\nexport function not<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guard: GuardConfig<TContext, TEvent>\n): BooleanGuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.boolean',\n params: { op: 'not' },\n children: [toGuardDefinition(guard)],\n predicate: ({ evaluate, guard, context, _event, state }) => {\n return !evaluate(guard.children![0], context, _event, state);\n }\n };\n}\n\nexport function and<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guards: Array<GuardConfig<TContext, TEvent>>\n): BooleanGuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.boolean',\n params: { op: 'and' },\n children: guards.map((guard) => toGuardDefinition(guard)),\n predicate: ({ evaluate, guard, context, _event, state }) => {\n return guard.children!.every((childGuard) => {\n return evaluate(childGuard, context, _event, state);\n });\n }\n };\n}\n\nexport function or<TContext extends MachineContext, TEvent extends EventObject>(\n guards: Array<GuardConfig<TContext, TEvent>>\n): BooleanGuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.boolean',\n params: { op: 'or' },\n children: guards.map((guard) => toGuardDefinition(guard)),\n predicate: ({ evaluate, guard, context, _event, state }) => {\n return guard.children!.some((childGuard) => {\n return evaluate(childGuard, context, _event, state);\n });\n }\n };\n}\n\nexport function evaluateGuard<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guard: GuardDefinition<TContext, TEvent>,\n context: TContext,\n _event: SCXML.Event<TEvent>,\n state: State<TContext, TEvent>\n): boolean {\n const { machine } = state;\n\n const predicate = machine?.options?.guards?.[guard.type] ?? guard.predicate;\n\n if (!predicate) {\n throw new Error(`Guard '${guard.type}' is not implemented.'.`);\n }\n\n return predicate({\n context,\n event: _event.data,\n state,\n guard,\n _event,\n evaluate: evaluateGuard\n });\n}\n\nexport function toGuardDefinition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guardConfig: GuardConfig<TContext, TEvent>,\n getPredicate?: (guardType: string) => GuardPredicate<TContext, TEvent>\n): GuardDefinition<TContext, TEvent> {\n if (isString(guardConfig)) {\n return {\n type: guardConfig,\n predicate: getPredicate?.(guardConfig) || undefined,\n params: { type: guardConfig }\n };\n }\n\n if (isFunction(guardConfig)) {\n return {\n type: guardConfig.name,\n predicate: guardConfig,\n params: {\n type: guardConfig.name,\n name: guardConfig.name\n }\n };\n }\n\n return {\n type: guardConfig.type,\n params: guardConfig.params || guardConfig,\n children: (\n guardConfig.children as Array<GuardConfig<TContext, TEvent>>\n )?.map((childGuard) => toGuardDefinition(childGuard, getPredicate)),\n predicate:\n getPredicate?.(guardConfig.type) || (guardConfig as any).predicate\n };\n}\n","export const STATE_DELIMITER = '.';\nexport const TARGETLESS_KEY = '';\nexport const NULL_EVENT = '';\nexport const STATE_IDENTIFIER = '#';\nexport const WILDCARD = '*';\n","import {\n toStatePath,\n toArray,\n warn,\n isArray,\n isFunction,\n isString,\n toTransitionConfigArray,\n normalizeTarget,\n toStateValue,\n mapContext,\n toSCXMLEvent\n} from './utils.ts';\nimport {\n BaseActionObject,\n EventObject,\n InvokeActionObject,\n StopActionObject,\n StateValue,\n TransitionConfig,\n TransitionDefinition,\n SingleOrArray,\n DelayExpr,\n SCXML,\n StateValueMap,\n RaiseActionObject,\n InitialTransitionConfig,\n MachineContext\n} from './types.ts';\nimport { cloneState, State } from './State.ts';\nimport {\n after,\n done,\n toActionObjects,\n actionTypes,\n resolveActionObject\n} from './actions.ts';\nimport { send } from './actions/send.ts';\nimport { cancel } from './actions/cancel.ts';\nimport { invoke } from './actions/invoke.ts';\nimport { stop } from './actions/stop.ts';\nimport { IS_PRODUCTION } from './environment.ts';\nimport { STATE_IDENTIFIER, NULL_EVENT, WILDCARD } from './constants.ts';\nimport { evaluateGuard, toGuardDefinition } from './guards.ts';\nimport type { StateNode } from './StateNode.ts';\nimport { isDynamicAction } from '../actions/dynamicAction.ts';\nimport {\n AnyActorContext,\n AnyEventObject,\n AnyHistoryValue,\n AnyState,\n AnyStateMachine,\n AnyStateNode,\n AnyTransitionDefinition,\n DelayedTransitionDefinition,\n HistoryValue,\n InitialTransitionDefinition,\n SendActionObject,\n StateFromMachine\n} from '.';\nimport { stopSignalType } from './actors/index.ts';\nimport { ActorStatus } from './interpreter.ts';\n\ntype Configuration<\n TContext extends MachineContext,\n TE extends EventObject\n> = Iterable<StateNode<TContext, TE>>;\ntype AnyConfiguration = Configuration<any, any>;\n\ntype AdjList = Map<AnyStateNode, Array<AnyStateNode>>;\n\nfunction getOutput<TContext extends MachineContext, TEvent extends EventObject>(\n configuration: StateNode<TContext, TEvent>[],\n context: TContext,\n _event: SCXML.Event<TEvent>\n) {\n const machine = configuration[0].machine;\n const finalChildStateNode = configuration.find(\n (stateNode) =>\n stateNode.type === 'final' && stateNode.parent === machine.root\n );\n\n const doneData =\n finalChildStateNode && finalChildStateNode.doneData\n ? mapContext(finalChildStateNode.doneData, context, _event)\n : undefined;\n\n return doneData;\n}\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 | null\n): Array<typeof stateNode> {\n const ancestors: Array<typeof stateNode> = [];\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 getConfiguration(\n stateNodes: Iterable<AnyStateNode>\n): Set<AnyStateNode> {\n const configuration = new Set(stateNodes);\n const configurationSet = new Set(stateNodes);\n\n const adjList = getAdjList(configurationSet);\n\n // add descendants\n for (const s of configuration) {\n // if previously active, add existing child nodes\n if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s)!.length)) {\n getInitialStateNodes(s).forEach((sn) => configurationSet.add(sn));\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 (!configurationSet.has(child)) {\n for (const initialStateNode of getInitialStateNodes(child)) {\n configurationSet.add(initialStateNode);\n }\n }\n }\n }\n }\n }\n\n // add all ancestors\n for (const s of configurationSet) {\n let m = s.parent;\n\n while (m) {\n configurationSet.add(m);\n m = m.parent;\n }\n }\n\n return configurationSet;\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 = {};\n for (const childStateNode of childStateNodes) {\n stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList);\n }\n\n return stateValue;\n}\n\nexport function getAdjList<\n TContext extends MachineContext,\n TE extends EventObject\n>(configuration: Configuration<TContext, TE>): AdjList {\n const adjList: AdjList = new Map();\n\n for (const s of configuration) {\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 configuration: AnyConfiguration\n): StateValue {\n const config = getConfiguration(configuration);\n return getValueFromAdj(rootNode, getAdjList(config));\n}\n\nexport function isInFinalState(\n configuration: Array<AnyStateNode>,\n stateNode: AnyStateNode = configuration[0].machine.root\n): boolean {\n if (stateNode.type === 'compound') {\n return getChildren(stateNode).some(\n (s) => s.type === 'final' && configuration.includes(s)\n );\n }\n if (stateNode.type === 'parallel') {\n return getChildren(stateNode).every((sn) =>\n isInFinalState(configuration, sn)\n );\n }\n\n return false;\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 /**\n * If `true`, will use SCXML event partial token matching semantics\n * without the need for the \".*\" suffix\n */\n partialMatch: boolean = false\n): Array<TransitionDefinition<any, TEvent>> {\n const candidates = stateNode.transitions.filter((transition) => {\n const { eventType } = transition;\n // First, check the trivial case: event names are exactly equal\n if (eventType === receivedEventType) {\n return true;\n }\n\n // Then, check if transition is a wildcard transition,\n // which matches any non-transient events\n if (eventType === WILDCARD) {\n return true;\n }\n\n if (!partialMatch && !eventType.endsWith('.*')) {\n return false;\n }\n\n if (!IS_PRODUCTION) {\n warn(\n !/.*\\*.+/.test(eventType),\n `Wildcards can only be the last token of an event descriptor (e.g., \"event.*\") or the entire event descriptor (\"*\"). Check the \"${eventType}\" event.`\n );\n }\n\n const partialEventTokens = eventType.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 (!IS_PRODUCTION) {\n warn(\n isLastToken,\n `Infix wildcards in transition events are not allowed. Check the \"${eventType}\" event.`\n );\n }\n\n return isLastToken;\n }\n\n if (partialEventToken !== eventToken) {\n return false;\n }\n }\n\n return true;\n });\n\n return candidates;\n}\n\n/**\n * All delayed transitions from the config.\n */\nexport function getDelayedTransitions<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode\n): Array<DelayedTransitionDefinition<TContext, TEvent>> {\n const afterConfig = stateNode.config.after;\n if (!afterConfig) {\n return [];\n }\n\n const mutateEntryExit = (\n delay: string | number | DelayExpr<TContext, TEvent>,\n i: number\n ) => {\n const delayRef = isFunction(delay) ? `${stateNode.id}:delay[${i}]` : delay;\n const eventType = after(delayRef, stateNode.id);\n stateNode.entry.push(send({ type: eventType }, { delay }));\n stateNode.exit.push(cancel(eventType));\n return eventType;\n };\n\n const delayedTransitions = isArray(afterConfig)\n ? afterConfig.map((transition, i) => {\n const eventType = mutateEntryExit(transition.delay, i);\n return { ...transition, event: eventType };\n })\n : Object.keys(afterConfig).flatMap((delay, i) => {\n const configTransition = afterConfig[delay];\n const resolvedTransition = isString(configTransition)\n ? { target: configTransition }\n : configTransition;\n const resolvedDelay = !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(stateNode, delayedTransition),\n delay\n };\n });\n}\n\nexport function formatTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n transitionConfig: TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | typeof NULL_EVENT | '*';\n }\n): AnyTransitionDefinition {\n const normalizedTarget = normalizeTarget(transitionConfig.target);\n const external = transitionConfig.external ?? false;\n const { guards } = stateNode.machine.options;\n const target = resolveTarget(stateNode, normalizedTarget);\n\n // TODO: should this be part of a lint rule instead?\n if (!IS_PRODUCTION && (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: toActionObjects(toArray(transitionConfig.actions)),\n guard: transitionConfig.guard\n ? toGuardDefinition(\n transitionConfig.guard,\n (guardType) => guards[guardType]\n )\n : undefined,\n target,\n source: stateNode,\n external,\n eventType: transitionConfig.event,\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>(stateNode: AnyStateNode): Array<AnyTransitionDefinition> {\n const transitionConfigs: Array<\n TransitionConfig<TContext, TEvent> & {\n event: string;\n }\n > = [];\n if (Array.isArray(stateNode.config.on)) {\n transitionConfigs.push(...stateNode.config.on);\n } else if (stateNode.config.on) {\n const { [WILDCARD]: wildcardConfigs = [], ...namedTransitionConfigs } =\n stateNode.config.on;\n for (const eventType of Object.keys(namedTransitionConfigs)) {\n if (eventType === NULL_EVENT) {\n throw new Error(\n 'Null events (\"\") cannot be specified as a transition key. Use `always: { ... }` instead.'\n );\n }\n const eventTransitionConfigs = toTransitionConfigArray<TContext, TEvent>(\n eventType,\n namedTransitionConfigs![eventType as string]\n );\n\n transitionConfigs.push(...eventTransitionConfigs);\n // TODO: add dev-mode validation for unreachable transitions\n }\n transitionConfigs.push(\n ...toTransitionConfigArray(\n WILDCARD,\n wildcardConfigs as SingleOrArray<\n TransitionConfig<TContext, TEvent> & {\n event: '*';\n }\n >\n )\n );\n }\n const doneConfig = stateNode.config.onDone\n ? toTransitionConfigArray(\n String(done(stateNode.id)),\n stateNode.config.onDone\n )\n : [];\n const invokeConfig = stateNode.invoke.flatMap((invokeDef) => {\n const settleTransitions: any[] = [];\n if (invokeDef.onDone) {\n settleTransitions.push(\n ...toTransitionConfigArray(\n `done.invoke.${invokeDef.id}`,\n invokeDef.onDone\n )\n );\n }\n if (invokeDef.onError) {\n settleTransitions.push(\n ...toTransitionConfigArray(\n `error.platform.${invokeDef.id}`,\n invokeDef.onError\n )\n );\n }\n if (invokeDef.onSnapshot) {\n settleTransitions.push(\n ...toTransitionConfigArray(\n `xstate.snapshot.${invokeDef.id}`,\n invokeDef.onSnapshot\n )\n );\n }\n return settleTransitions;\n });\n const delayedTransitions = stateNode.after;\n const formattedTransitions = [\n ...doneConfig,\n ...invokeConfig,\n ...transitionConfigs\n ].flatMap(\n (\n transitionConfig: TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | '*';\n }\n ) =>\n toArray(transitionConfig).map((transition) =>\n formatTransition(stateNode, transition)\n )\n );\n for (const delayedTransition of delayedTransitions) {\n formattedTransitions.push(delayedTransition as any);\n }\n return formattedTransitions;\n}\n\nexport function formatInitialTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n _target: SingleOrArray<string> | InitialTransitionConfig<TContext, TEvent>\n): InitialTransitionDefinition<TContext, TEvent> {\n if (isString(_target) || isArray(_target)) {\n const targets = toArray(_target).map((t) => {\n // Resolve state string keys (which represent children)\n // to their state node\n const descStateNode = isString(t)\n ? isStateId(t)\n ? stateNode.machine.getStateNodeById(t)\n : stateNode.states[t]\n : t;\n\n if (!descStateNode) {\n throw new Error(\n `Initial state node \"${t}\" not found on parent state node #${stateNode.id}`\n );\n }\n\n if (!isDescendant(descStateNode, stateNode)) {\n throw new Error(\n `Invalid initial target: state node #${descStateNode.id} is not a descendant of #${stateNode.id}`\n );\n }\n\n return descStateNode;\n });\n const resolvedTarget = resolveTarget(stateNode, targets);\n\n const transition = {\n source: stateNode,\n actions: [],\n eventType: null as any,\n external: false,\n target: resolvedTarget!,\n toJSON: () => ({\n ...transition,\n source: `#${stateNode.id}`,\n target: resolvedTarget\n ? resolvedTarget.map((t) => `#${t.id}`)\n : undefined\n })\n };\n\n return transition;\n }\n\n return formatTransition(stateNode, {\n target: toArray(_target.target).map((t) => {\n if (isString(t)) {\n return isStateId(t) ? t : `${stateNode.machine.delimiter}${t}`;\n }\n\n return t;\n }),\n actions: _target.actions,\n event: null as any\n }) as InitialTransitionDefinition<TContext, TEvent>;\n}\n\nexport function resolveTarget(\n stateNode: AnyStateNode,\n targets: Array<string | AnyStateNode> | undefined\n): Array<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 (!isString(target)) {\n return target;\n }\n const isInternalTarget = target[0] === stateNode.machine.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) {\n throw new Error(\n `Invalid transition definition for state node '${stateNode.id}':\\n${err.message}`\n );\n }\n } else {\n return getStateNodeByPath(stateNode, resolvedTarget);\n }\n });\n}\n\nfunction resolveHistoryTarget<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateNode: AnyStateNode & { type: 'history' }): Array<AnyStateNode> {\n const normalizedTarget = normalizeTarget<TContext, TEvent>(stateNode.target);\n if (!normalizedTarget) {\n return stateNode.parent!.initial.target;\n }\n return normalizedTarget.map((t) =>\n typeof t === 'string' ? getStateNodeByPath(stateNode.parent!, t) : t\n );\n}\n\nfunction isHistoryNode(\n stateNode: AnyStateNode\n): stateNode is AnyStateNode & { type: 'history' } {\n return stateNode.type === 'history';\n}\n\nexport function getInitialStateNodes(\n stateNode: AnyStateNode\n): Array<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 for (const targetStateNode of descStateNode.initial.target) {\n for (const a of getProperAncestors(targetStateNode, stateNode)) {\n set.add(a);\n }\n\n iter(targetStateNode);\n }\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/**\n * Returns the child state node from its relative `stateKey`, or throws.\n */\nexport function getStateNode(\n stateNode: AnyStateNode,\n stateKey: string\n): 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 */\nfunction 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(\n statePath,\n stateNode.machine.delimiter\n ).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 state The state value or State instance\n */\nexport function getStateNodes<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n state: StateValue | State<TContext, TEvent>\n): Array<AnyStateNode> {\n const stateValue =\n state instanceof State\n ? state.value\n : toStateValue(state, stateNode.machine.delimiter);\n\n if (isString(stateValue)) {\n return [stateNode, stateNode.states[stateValue]];\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\nexport function transitionAtomicNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: string,\n state: State<TContext, TEvent>,\n _event: SCXML.Event<TEvent>\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const childStateNode = getStateNode(stateNode, stateValue);\n const next = childStateNode.next(state, _event);\n\n if (!next || !next.length) {\n return stateNode.next(state, _event);\n }\n\n return next;\n}\n\nexport function transitionCompoundNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n state: State<TContext, TEvent>,\n _event: SCXML.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 state,\n _event\n );\n\n if (!next || !next.length) {\n return stateNode.next(state, _event);\n }\n\n return next;\n}\n\nexport function transitionParallelNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n state: State<TContext, TEvent>,\n _event: SCXML.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 state,\n _event\n );\n if (innerTransitions) {\n allInnerTransitions.push(...innerTransitions);\n }\n }\n if (!allInnerTransitions.length) {\n return stateNode.next(state, _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 state: State<TContext, TEvent, any>,\n _event: SCXML.Event<TEvent>\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n // leaf node\n if (isString(stateValue)) {\n return transitionAtomicNode(stateNode, stateValue, state, _event);\n }\n\n // compound node\n if (Object.keys(stateValue).length === 1) {\n return transitionCompoundNode(stateNode, stateValue, state, _event);\n }\n\n // parallel node\n return transitionParallelNode(stateNode, stateValue, state, _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\nexport function removeConflictingTransitions(\n enabledTransitions: Array<AnyTransitionDefinition>,\n configuration: 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], configuration, historyValue),\n computeExitSet([t2], configuration, 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 findLCCA(stateNodes: Array<AnyStateNode>): AnyStateNode {\n const [head] = stateNodes;\n\n let current = getPathFromRootToNode(head);\n let candidates: Array<AnyStateNode> = [];\n\n for (const stateNode of stateNodes) {\n const path = getPathFromRootToNode(stateNode);\n\n candidates = current.filter((sn) => path.includes(sn));\n current = candidates;\n candidates = [];\n }\n\n return current[current.length - 1];\n}\n\nfunction getEffectiveTargetStates(\n transition: AnyTransitionDefinition,\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 {\n target: resolveHistoryTarget(targetNode)\n } as AnyTransitionDefinition,\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 | null {\n const targetStates = getEffectiveTargetStates(transition, historyValue);\n\n if (!targetStates) {\n return null;\n }\n\n if (\n !transition.external &&\n transition.source.type === 'compound' &&\n targetStates.every((targetStateNode) =>\n isDescendant(targetStateNode, transition.source)\n )\n ) {\n return transition.source;\n }\n\n const lcca = findLCCA(targetStates.concat(transition.source));\n\n return lcca;\n}\n\nfunction computeExitSet(\n transitions: AnyTransitionDefinition[],\n configuration: 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 for (const stateNode of configuration) {\n if (isDescendant(stateNode, domain!)) {\n statesToExit.add(stateNode);\n }\n }\n }\n }\n\n return [...statesToExit];\n}\n\n/**\n * https://www.w3.org/TR/scxml/#microstepProcedure\n *\n * @private\n * @param transitions\n * @param currentState\n * @param mutConfiguration\n */\n\nexport function microstep<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n transitions: Array<TransitionDefinition<TContext, TEvent>>,\n currentState: State<TContext, TEvent, any>,\n actorCtx: AnyActorContext | undefined,\n scxmlEvent: SCXML.Event<TEvent>\n): State<TContext, TEvent, any> {\n const { machine } = currentState;\n // Transition will \"apply\" if:\n // - the state node is the initial state (there is no current state)\n // - OR there are transitions\n const willTransition = currentState._initial || transitions.length > 0;\n\n const mutConfiguration = new Set(currentState.configuration);\n\n if (!currentState._initial && !willTransition) {\n const inertState = cloneState(currentState, {\n _event: scxmlEvent,\n actions: [],\n transitions: []\n });\n\n inertState.changed = false;\n return inertState;\n }\n\n const microstate = microstepProcedure(\n currentState._initial\n ? [\n {\n target: [...currentState.configuration].filter(isAtomicStateNode),\n source: machine.root,\n external: true,\n actions: [],\n eventType: null as any,\n toJSON: null as any // TODO: fix\n }\n ]\n : transitions,\n currentState,\n mutConfiguration,\n scxmlEvent,\n actorCtx\n );\n\n const { context, actions: nonRaisedActions } = microstate;\n\n const children = setChildren(currentState, nonRaisedActions);\n\n const nextState = cloneState(microstate, {\n value: {}, // TODO: make optional\n transitions,\n children\n });\n\n nextState.changed = currentState._initial\n ? undefined\n : !stateValuesEqual(nextState.value, currentState.value) ||\n nextState.actions.length > 0 ||\n context !== currentState.context;\n\n return nextState;\n}\n\nfunction setChildren(\n currentState: AnyState,\n nonRaisedActions: BaseActionObject[]\n) {\n const children = { ...currentState.children };\n for (const action of nonRaisedActions) {\n if (\n action.type === actionTypes.invoke &&\n (action as InvokeActionObject).params.ref\n ) {\n const ref = (action as InvokeActionObject).params.ref;\n if (ref) {\n children[ref.id] = ref;\n }\n } else if (action.type === actionTypes.stop) {\n const ref = (action as StopActionObject).params.actor;\n if (ref) {\n delete children[ref.id];\n }\n }\n }\n return children;\n}\n\nfunction microstepProcedure(\n transitions: Array<AnyTransitionDefinition>,\n currentState: AnyState,\n mutConfiguration: Set<AnyStateNode>,\n scxmlEvent: SCXML.Event<AnyEventObject>,\n actorCtx: AnyActorContext | undefined\n): typeof currentState {\n const { machine } = currentState;\n const actions: BaseActionObject[] = [];\n const historyValue = {\n ...currentState.historyValue\n };\n\n const filteredTransitions = removeConflictingTransitions(\n transitions,\n mutConfiguration,\n historyValue\n );\n\n const internalQueue = [...currentState._internalQueue];\n\n // Exit states\n if (!currentState._initial) {\n exitStates(filteredTransitions, mutConfiguration, historyValue, actions);\n }\n\n // Execute transition content\n actions.push(...filteredTransitions.flatMap((t) => t.actions));\n\n // Enter states\n enterStates(\n filteredTransitions,\n mutConfiguration,\n actions,\n internalQueue,\n currentState,\n historyValue\n );\n\n const nextConfiguration = [...mutConfiguration];\n\n const done = isInFinalState(nextConfiguration);\n\n if (done) {\n const finalActions = nextConfiguration\n .sort((a, b) => b.order - a.order)\n .flatMap((state) => state.exit);\n actions.push(...finalActions);\n }\n\n try {\n const { nextState } = resolveActionsAndContext(\n actions,\n scxmlEvent,\n currentState,\n actorCtx\n );\n\n const output = done\n ? getOutput(nextConfiguration, nextState.context, scxmlEvent)\n : undefined;\n\n internalQueue.push(...nextState._internalQueue);\n\n return cloneState(currentState, {\n actions: nextState.actions,\n configuration: nextConfiguration,\n historyValue,\n _internalQueue: internalQueue,\n context: nextState.context,\n _event: scxmlEvent,\n done,\n output,\n children: nextState.children\n });\n } catch (e) {\n // TODO: Refactor this once proper error handling is implemented.\n // See https://github.com/statelyai/rfcs/pull/4\n if (machine.config.scxml) {\n return cloneState(currentState, {\n actions: [],\n configuration: Array.from(mutConfiguration),\n historyValue,\n _internalQueue: [toSCXMLEvent({ type: 'error.execution' })],\n context: currentState.context\n });\n } else {\n throw e;\n }\n }\n}\n\nfunction enterStates(\n filteredTransitions: AnyTransitionDefinition[],\n mutConfiguration: Set<AnyStateNode>,\n actions: BaseActionObject[],\n internalQueue: SCXML.Event<AnyEventObject>[],\n currentState: AnyState,\n historyValue: HistoryValue<any, any>\n): void {\n const statesToEnter = new Set<AnyStateNode>();\n const statesForDefaultEntry = new Set<AnyStateNode>();\n\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 (currentState._initial) {\n statesForDefaultEntry.add(currentState.machine.root);\n }\n\n for (const stateNodeToEnter of [...statesToEnter].sort(\n (a, b) => a.order - b.order\n )) {\n mutConfiguration.add(stateNodeToEnter);\n\n for (const invokeDef of stateNodeToEnter.invoke) {\n actions.push(invoke(invokeDef));\n }\n\n // Add entry actions\n actions.push(...stateNodeToEnter.entry);\n\n if (statesForDefaultEntry.has(stateNodeToEnter)) {\n for (const stateNode of statesForDefaultEntry) {\n const initialActions = stateNode.initial!.actions;\n actions.push(...initialActions);\n }\n }\n if (stateNodeToEnter.type === 'final') {\n const parent = stateNodeToEnter.parent!;\n\n if (!parent.parent) {\n continue;\n }\n\n internalQueue.push(\n toSCXMLEvent(\n done(\n parent!.id,\n stateNodeToEnter.doneData\n ? mapContext(\n stateNodeToEnter.doneData,\n currentState.context,\n currentState._event\n )\n : undefined\n )\n )\n );\n\n if (parent.parent) {\n const grandparent = parent.parent;\n\n if (grandparent.type === 'parallel') {\n if (\n getChildren(grandparent).every((parentNode) =>\n isInFinalState([...mutConfiguration], parentNode)\n )\n ) {\n internalQueue.push(toSCXMLEvent(done(grandparent.id)));\n }\n }\n }\n }\n }\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 for (const s of t.target || []) {\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n const ancestor = getTransitionDomain(t, historyValue);\n const targetStates = getEffectiveTargetStates(t, historyValue);\n for (const s of targetStates) {\n addAncestorStatesToEnter(\n s,\n ancestor,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\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 addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n for (const s of historyStateNodes) {\n addAncestorStatesToEnter(\n s,\n stateNode.parent!,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n for (const stateForDefaultEntry of statesForDefaultEntry) {\n statesForDefaultEntry.add(stateForDefaultEntry);\n }\n }\n } else {\n const targets = resolveHistoryTarget<TContext, TEvent>(stateNode);\n for (const s of targets) {\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n for (const s of targets) {\n addAncestorStatesToEnter(\n s,\n stateNode,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n for (const stateForDefaultEntry of statesForDefaultEntry) {\n statesForDefaultEntry.add(stateForDefaultEntry);\n }\n }\n }\n } else {\n statesToEnter.add(stateNode);\n if (stateNode.type === 'compound') {\n statesForDefaultEntry.add(stateNode);\n const initialStates = stateNode.initial.target;\n\n for (const initialState of initialStates) {\n addDescendantStatesToEnter(\n initialState,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n\n for (const initialState of initialStates) {\n addAncestorStatesToEnter(\n initialState,\n stateNode,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\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 addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n }\n}\n\nfunction addAncestorStatesToEnter(\n stateNode: AnyStateNode,\n toStateNode: AnyStateNode | null,\n statesToEnter: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>\n) {\n const properAncestors = getProperAncestors(stateNode, toStateNode);\n for (const anc of properAncestors) {\n statesToEnter.add(anc);\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 addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n}\n\nfunction exitStates(\n transitions: AnyTransitionDefinition[],\n mutConfiguration: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n actions: BaseActionObject[]\n) {\n const statesToExit = computeExitSet(\n transitions,\n mutConfiguration,\n historyValue\n );\n\n statesToExit.sort((a, b) => b.order - a.order);\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 historyValue[historyNode.id] =\n Array.from(mutConfiguration).filter(predicate);\n }\n }\n\n for (const s of statesToExit) {\n actions.push(...s.exit.flat(), ...s.invoke.map((def) => stop(def.id)));\n mutConfiguration.delete(s);\n }\n}\n\nexport function resolveActionsAndContext<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n actions: BaseActionObject[],\n scxmlEvent: SCXML.Event<TEvent>,\n currentState: State<TContext, TEvent, any>,\n actorCtx: AnyActorContext | undefined\n): {\n nextState: AnyState;\n} {\n const { machine } = currentState;\n const resolvedActions: BaseActionObject[] = [];\n const raiseActions: Array<RaiseActionObject<TContext, TEvent>> = [];\n let intermediateState = currentState;\n\n function handleAction(action: BaseActionObject): void {\n resolvedActions.push(action);\n if (actorCtx?.self.status === ActorStatus.Running) {\n action.execute?.(actorCtx!);\n // TODO: this is hacky; re-evaluate\n delete action.execute;\n }\n }\n\n function resolveAction(actionObject: BaseActionObject) {\n const executableActionObject = resolveActionObject(\n actionObject,\n machine.options.actions\n );\n\n if (isDynamicAction(executableActionObject)) {\n const [nextState, resolvedAction] = executableActionObject.resolve(\n scxmlEvent,\n {\n state: intermediateState,\n action: actionObject,\n actorContext: actorCtx\n }\n );\n const matchedActions = resolvedAction.params?.actions;\n\n intermediateState = nextState;\n\n if (\n (resolvedAction.type === actionTypes.raise ||\n (resolvedAction.type === actionTypes.send &&\n (resolvedAction as SendActionObject).params.internal)) &&\n typeof (resolvedAction as any).params.delay !== 'number'\n ) {\n raiseActions.push(resolvedAction);\n }\n\n // TODO: remove the check; just handleAction\n if (resolvedAction.type !== actionTypes.pure) {\n handleAction(resolvedAction);\n }\n\n toActionObjects(matchedActions).forEach(resolveAction);\n\n return;\n }\n\n handleAction(executableActionObject);\n }\n\n for (const actionObject of actions) {\n resolveAction(actionObject);\n }\n\n return {\n nextState: cloneState(intermediateState, {\n actions: resolvedActions,\n _internalQueue: raiseActions.map((a) => a.params._event)\n })\n };\n}\n\nexport function macrostep<TMachine extends AnyStateMachine>(\n state: StateFromMachine<TMachine>,\n scxmlEvent: SCXML.Event<TMachine['__TEvent']>,\n actorCtx: AnyActorContext | undefined\n): {\n state: typeof state;\n microstates: Array<typeof state>;\n} {\n if (!IS_PRODUCTION && scxmlEvent.name === WILDCARD) {\n throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);\n }\n\n let nextState = state;\n const states: StateFromMachine<TMachine>[] = [];\n\n // Handle stop event\n if (scxmlEvent?.name === stopSignalType) {\n nextState = stopStep(scxmlEvent, nextState, actorCtx);\n states.push(nextState);\n\n return {\n state: nextState,\n microstates: states\n };\n }\n\n // Assume the state is at rest (no raised events)\n // Determine the next state based on the next microstep\n if (scxmlEvent.name !== actionTypes.init) {\n const transitions = selectTransitions(scxmlEvent, nextState);\n nextState = microstep(transitions, state, actorCtx, scxmlEvent);\n states.push(nextState);\n }\n\n while (!nextState.done) {\n let enabledTransitions = selectEventlessTransitions(nextState);\n\n if (enabledTransitions.length === 0) {\n // TODO: this is a bit of a hack, we need to review this\n // this matches the behavior from v4 for eventless transitions\n // where for `hasAlwaysTransitions` we were always trying to resolve with a NULL event\n // and if a transition was not selected the `state.transitions` stayed empty\n // without this we get into an infinite loop in the dieHard test in `@xstate/test` for the `simplePathsTo`\n if (nextState.configuration.some((state) => state.always)) {\n nextState.transitions = [];\n }\n\n if (!nextState._internalQueue.length) {\n break;\n } else {\n const currentActions = nextState.actions;\n const nextEvent = nextState._internalQueue[0];\n const transitions = selectTransitions(nextEvent, nextState);\n nextState = microstep(transitions, nextState, actorCtx, nextEvent);\n nextState._internalQueue.shift();\n nextState.actions.unshift(...currentActions);\n\n states.push(nextState);\n }\n }\n\n if (enabledTransitions.length) {\n const currentActions = nextState.actions;\n nextState = microstep(\n enabledTransitions,\n nextState,\n actorCtx,\n nextState._event\n );\n nextState.actions.unshift(...currentActions);\n\n states.push(nextState);\n }\n }\n\n if (nextState.done) {\n // Perform the stop step to ensure that child actors are stopped\n stopStep(nextState._event, nextState, actorCtx);\n }\n\n return {\n state: nextState,\n microstates: states\n };\n}\n\nfunction stopStep(\n scxmlEvent: SCXML.Event<any>,\n nextState: AnyState,\n actorCtx: AnyActorContext | undefined\n): AnyState {\n const actions: BaseActionObject[] = [];\n\n for (const stateNode of nextState.configuration.sort(\n (a, b) => b.order - a.order\n )) {\n actions.push(...stateNode.exit);\n }\n\n for (const child of Object.values(nextState.children)) {\n actions.push(stop(child));\n }\n\n const { nextState: stoppedState } = resolveActionsAndContext(\n actions,\n scxmlEvent,\n nextState,\n actorCtx\n );\n\n return stoppedState;\n}\n\nfunction selectTransitions(\n scxmlEvent: SCXML.Event<any>,\n nextState: AnyState\n): AnyTransitionDefinition[] {\n return nextState.machine.getTransitionData(nextState, scxmlEvent);\n}\n\nfunction selectEventlessTransitions(\n nextState: AnyState\n): AnyTransitionDefinition[] {\n const enabledTransitionSet: Set<AnyTransitionDefinition> = new Set();\n const atomicStates = nextState.configuration.filter(isAtomicStateNode);\n\n for (const stateNode of atomicStates) {\n loop: for (const s of [stateNode].concat(\n getProperAncestors(stateNode, null)\n )) {\n if (!s.always) {\n continue;\n }\n for (const transition of s.always) {\n if (\n transition.guard === undefined ||\n evaluateGuard(\n transition.guard,\n nextState.context,\n nextState._event,\n nextState\n )\n ) {\n enabledTransitionSet.add(transition);\n break loop;\n }\n }\n }\n }\n\n return removeConflictingTransitions(\n Array.from(enabledTransitionSet),\n new Set(nextState.configuration),\n nextState.historyValue\n );\n}\n\n/**\n * Resolves a partial state value with its full representation in the state 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 configuration = getConfiguration(getStateNodes(rootNode, stateValue));\n return getStateValue(rootNode, [...configuration]);\n}\n\nexport function 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 (isString(a) || isString(b)) {\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\nexport function getInitialConfiguration(\n rootNode: AnyStateNode\n): AnyStateNode[] {\n const configuration: AnyStateNode[] = [];\n const initialTransition = rootNode.initial;\n\n const statesToEnter = new Set<AnyStateNode>();\n const statesForDefaultEntry = new Set<AnyStateNode>([rootNode]);\n\n computeEntrySet(\n [initialTransition],\n {},\n statesForDefaultEntry,\n statesToEnter\n );\n\n for (const stateNodeToEnter of [...statesToEnter].sort(\n (a, b) => a.order - b.order\n )) {\n configuration.push(stateNodeToEnter);\n }\n\n return configuration;\n}\n"],"names":["isString","value","toGuardDefinition","guardConfig","getPredicate","type","predicate","undefined","params","name","children","_guardConfig$children","map","childGuard","guards","op","guard","evaluate","context","_event","state","every","evaluateGuard","machine","options","_machine$options","_machine$options$guar2","Error","event","data","some","stateValue","configuration","sn","id","slice","matches"],"mappings":"oPAiVO,SAASA,EAASC,GACvB,MAAwB,iBAAVA,ECvOT,SAASC,EAIdC,EACAC,GACmC,MACnC,OAAIJ,EAASG,GACJ,CACLE,KAAMF,EACNG,WAAWF,MAAAA,SAAAA,EAAeD,UAAgBI,EAC1CC,OAAQ,CAAEH,KAAMF,IDwNI,mBCpNTA,EACN,CACLE,KAAMF,EAAYM,KAClBH,UAAWH,EACXK,OAAQ,CACNH,KAAMF,EAAYM,KAClBA,KAAMN,EAAYM,OAKjB,CACLJ,KAAMF,EAAYE,KAClBG,OAAQL,EAAYK,QAAUL,EAC9BO,mBACEP,EAAYO,6BADJC,EAEPC,KAAI,SAACC,GAAU,OAAKX,EAAkBW,EAAYT,MACrDE,WACEF,MAAAA,SAAAA,EAAeD,EAAYE,QAAUF,EAAoBG,iBA7FxD,SAILQ,GAEA,MAAO,CACLT,KAAM,iBACNG,OAAQ,CAAEO,GAAI,OACdL,SAAUI,EAAOF,KAAI,SAACI,GAAK,OAAKd,EAAkBc,MAClDV,UAAW,YAAiD,IAA9CW,IAAAA,SAAUD,IAAAA,MAAOE,IAAAA,QAASC,IAAAA,OAAQC,IAAAA,MAC9C,OAAOJ,EAAMN,SAAUW,OAAM,SAACR,GAC5B,OAAOI,EAASJ,EAAYK,EAASC,EAAQC,yBAqB9C,SAASE,EAIdN,EACAE,EACAC,EACAC,GACS,UACDG,EAAYH,EAAZG,QAEFjB,YAAYiB,MAAAA,aAAAA,EAASC,gCAATC,EAAkBX,2BAAlBY,EAA2BV,EAAMX,qBAASW,EAAMV,UAElE,IAAKA,EACH,MAAM,IAAIqB,uBAAgBX,EAAMX,iCAGlC,OAAOC,EAAU,CACfY,QAAAA,EACAU,MAAOT,EAAOU,KACdT,MAAAA,EACAJ,MAAAA,EACAG,OAAAA,EACAF,SAAUK,WAxEP,SAILN,GAEA,MAAO,CACLX,KAAM,iBACNG,OAAQ,CAAEO,GAAI,OACdL,SAAU,CAACR,EAAkBc,IAC7BV,UAAW,YAAiD,IAA9CW,IAAAA,SAAUD,IAAAA,MAAOE,IAAAA,QAASC,IAAAA,OAAQC,IAAAA,MAC9C,OAAQH,EAASD,EAAMN,SAAU,GAAIQ,EAASC,EAAQC,WAuBrD,SACLN,GAEA,MAAO,CACLT,KAAM,iBACNG,OAAQ,CAAEO,GAAI,MACdL,SAAUI,EAAOF,KAAI,SAACI,GAAK,OAAKd,EAAkBc,MAClDV,UAAW,YAAiD,IAA9CW,IAAAA,SAAUD,IAAAA,MAAOE,IAAAA,QAASC,IAAAA,OAAQC,IAAAA,MAC9C,OAAOJ,EAAMN,SAAUoB,MAAK,SAACjB,GAC3B,OAAOI,EAASJ,EAAYK,EAASC,EAAQC,mBA5D9C,SAGLW,GACA,MAAO,CACL1B,KAAM,kBACNG,OAAQ,CAAEuB,WAAAA,GACVzB,UAAW,YAAe,IAAZc,IAAAA,MACZ,OAAIpB,EAAS+B,ICnBa,MDmBYA,EEmNE,GFlN/BX,EAAMY,cAAcF,MAAK,SAACG,GAAE,OAAKA,EAAGC,KAAOH,EAAWI,MAAM,MAG9Df,EAAMgB,QAAQL"}
|
|
1
|
+
{"version":3,"file":"xstate-guards.umd.min.js","sources":["../../src/utils.ts","../../src/guards.ts","../../src/constants.ts","../../src/stateUtils.ts"],"sourcesContent":["import { AnyActorBehavior, AnyState } from './index.ts';\nimport { errorExecution, errorPlatform } from './actionTypes.ts';\nimport { NULL_EVENT, STATE_DELIMITER, TARGETLESS_KEY } from './constants.ts';\nimport { IS_PRODUCTION } from './environment.ts';\nimport type { StateNode } from './StateNode.ts';\nimport type {\n ActorBehavior,\n EventObject,\n EventType,\n InvokeConfig,\n MachineContext,\n Mapper,\n Observer,\n PropertyMapper,\n SCXML,\n SCXMLErrorEvent,\n SingleOrArray,\n StateLike,\n StateValue,\n Subscribable,\n TransitionConfig,\n TransitionConfigTarget\n} from './types.ts';\n\nexport function keys<T extends object>(value: T): Array<keyof T & string> {\n return Object.keys(value) as Array<keyof T & string>;\n}\n\nexport function matchesState(\n parentStateId: StateValue,\n childStateId: StateValue,\n delimiter: string = STATE_DELIMITER\n): boolean {\n const parentStateValue = toStateValue(parentStateId, delimiter);\n const childStateValue = toStateValue(childStateId, delimiter);\n\n if (isString(childStateValue)) {\n if (isString(parentStateValue)) {\n return childStateValue === parentStateValue;\n }\n\n // Parent more specific than child\n return false;\n }\n\n if (isString(parentStateValue)) {\n return parentStateValue in childStateValue;\n }\n\n return Object.keys(parentStateValue).every((key) => {\n if (!(key in childStateValue)) {\n return false;\n }\n\n return matchesState(parentStateValue[key], childStateValue[key]);\n });\n}\n\nexport function toStatePath(\n stateId: string | string[],\n delimiter: string\n): string[] {\n try {\n if (isArray(stateId)) {\n return stateId;\n }\n\n return stateId.toString().split(delimiter);\n } catch (e) {\n throw new Error(`'${stateId}' is not a valid state path.`);\n }\n}\n\nexport function isStateLike(state: any): state is AnyState {\n return (\n typeof state === 'object' &&\n 'value' in state &&\n 'context' in state &&\n 'event' in state &&\n '_event' in state\n );\n}\n\nexport function toStateValue(\n stateValue: StateLike<any> | StateValue | string[],\n delimiter: string\n): StateValue {\n if (isStateLike(stateValue)) {\n return stateValue.value;\n }\n\n if (isArray(stateValue)) {\n return pathToStateValue(stateValue);\n }\n\n if (typeof stateValue !== 'string') {\n return stateValue as StateValue;\n }\n\n const statePath = toStatePath(stateValue as string, delimiter);\n\n return pathToStateValue(statePath);\n}\n\nexport function pathToStateValue(statePath: string[]): StateValue {\n if (statePath.length === 1) {\n return statePath[0];\n }\n\n const value = {};\n let marker = value;\n\n for (let i = 0; i < statePath.length - 1; i++) {\n if (i === statePath.length - 2) {\n marker[statePath[i]] = statePath[i + 1];\n } else {\n marker[statePath[i]] = {};\n marker = marker[statePath[i]];\n }\n }\n\n return value;\n}\n\nexport function mapValues<P, O extends Record<string, unknown>>(\n collection: O,\n iteratee: (item: O[keyof O], key: keyof O, collection: O, i: number) => P\n): { [key in keyof O]: P };\nexport function mapValues(\n collection: Record<string, unknown>,\n iteratee: (\n item: unknown,\n key: string,\n collection: Record<string, unknown>,\n i: number\n ) => unknown\n) {\n const result: Record<string, unknown> = {};\n\n const collectionKeys = Object.keys(collection);\n for (let i = 0; i < collectionKeys.length; i++) {\n const key = collectionKeys[i];\n result[key] = iteratee(collection[key], key, collection, i);\n }\n\n return result;\n}\n\nexport function mapFilterValues<T, P>(\n collection: { [key: string]: T },\n iteratee: (item: T, key: string, collection: { [key: string]: T }) => P,\n predicate: (item: T) => boolean\n): { [key: string]: P } {\n const result: { [key: string]: P } = {};\n\n for (const key of Object.keys(collection)) {\n const item = collection[key];\n\n if (!predicate(item)) {\n continue;\n }\n\n result[key] = iteratee(item, key, collection);\n }\n\n return result;\n}\n\n/**\n * Retrieves a value at the given path.\n * @param props The deep path to the prop of the desired value\n */\nexport function path<T extends Record<string, any>>(props: string[]): any {\n return (object: T): any => {\n let result: T = object;\n\n for (const prop of props) {\n result = result[prop as keyof typeof result];\n }\n\n return result;\n };\n}\n\nexport function toStatePaths(stateValue: StateValue | undefined): string[][] {\n if (!stateValue) {\n return [[]];\n }\n\n if (isString(stateValue)) {\n return [[stateValue]];\n }\n\n const result = flatten(\n Object.keys(stateValue).map((key) => {\n const subStateValue = stateValue[key];\n\n if (\n typeof subStateValue !== 'string' &&\n (!subStateValue || !Object.keys(subStateValue).length)\n ) {\n return [[key]];\n }\n\n return toStatePaths(stateValue[key]).map((subPath) => {\n return [key].concat(subPath);\n });\n })\n );\n\n return result;\n}\n\nexport function flatten<T>(array: Array<T | T[]>): T[] {\n return ([] as T[]).concat(...array);\n}\n\nexport function toArrayStrict<T>(value: T[] | T): T[] {\n if (isArray(value)) {\n return value;\n }\n return [value];\n}\n\nexport function toArray<T>(value: T[] | T | undefined): T[] {\n if (value === undefined) {\n return [];\n }\n return toArrayStrict(value);\n}\n\nexport function mapContext<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n mapper: Mapper<TContext, TEvent, any> | PropertyMapper<TContext, TEvent, any>,\n context: TContext,\n _event: SCXML.Event<TEvent>\n): any {\n if (isFunction(mapper)) {\n return mapper({ context, event: _event.data });\n }\n\n const result = {} as any;\n const args = { context, event: _event.data };\n\n for (const key of Object.keys(mapper)) {\n const subMapper = mapper[key];\n\n if (isFunction(subMapper)) {\n result[key] = subMapper(args);\n } else {\n result[key] = subMapper;\n }\n }\n\n return result;\n}\n\nexport function isBuiltInEvent(eventType: EventType): boolean {\n return /^(done|error)\\./.test(eventType);\n}\n\nexport function isPromiseLike(value: any): value is PromiseLike<any> {\n if (value instanceof Promise) {\n return true;\n }\n // Check if shape matches the Promise/A+ specification for a \"thenable\".\n if (\n value !== null &&\n (isFunction(value) || typeof value === 'object') &&\n isFunction(value.then)\n ) {\n return true;\n }\n return false;\n}\n\nexport function isBehavior(value: any): value is ActorBehavior<any, any> {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'transition' in value &&\n typeof value.transition === 'function'\n );\n}\n\nexport function partition<T, A extends T, B extends T>(\n items: T[],\n predicate: (item: T) => item is A\n): [A[], B[]] {\n const [truthy, falsy] = [[], []] as [A[], B[]];\n\n for (const item of items) {\n if (predicate(item)) {\n truthy.push(item);\n } else {\n falsy.push(item as B);\n }\n }\n\n return [truthy, falsy];\n}\n\n// tslint:disable-next-line:no-empty\nexport let warn: (\n condition: boolean | Error,\n message: string\n) => void = () => {};\n\nif (!IS_PRODUCTION) {\n warn = (condition: boolean | Error, message: string) => {\n const error = condition instanceof Error ? condition : undefined;\n if (!error && condition) {\n return;\n }\n\n if (console !== undefined) {\n const args: [string, ...any[]] = [`Warning: ${message}`];\n if (error) {\n args.push(error);\n }\n // tslint:disable-next-line:no-console\n console.warn.apply(console, args);\n }\n };\n}\n\nexport function isArray(value: any): value is any[] {\n return Array.isArray(value);\n}\n\n// tslint:disable-next-line:ban-types\nexport function isFunction(value: any): value is Function {\n return typeof value === 'function';\n}\n\nexport function isString(value: any): value is string {\n return typeof value === 'string';\n}\n\nexport function isObservable<T>(value: any): value is Subscribable<T> {\n try {\n return 'subscribe' in value && isFunction(value.subscribe);\n } catch (e) {\n return false;\n }\n}\n\nexport const uniqueId = (() => {\n let currentId = 0;\n\n return () => {\n currentId++;\n return currentId.toString(16);\n };\n})();\n\nexport function isSCXMLEvent<TEvent extends EventObject>(\n event: TEvent | SCXML.Event<TEvent>\n): event is SCXML.Event<TEvent> {\n return '$$type' in event && event.$$type === 'scxml';\n}\n\nexport function isSCXMLErrorEvent(\n event: SCXML.Event<any>\n): event is SCXMLErrorEvent {\n return (\n typeof event.name === 'string' &&\n (event.name === errorExecution || event.name.startsWith(errorPlatform))\n );\n}\n\nexport function toSCXMLEvent<TEvent extends EventObject>(\n event: TEvent | SCXML.Event<TEvent>,\n scxmlEvent?: Partial<SCXML.Event<TEvent>>\n): SCXML.Event<TEvent> {\n if (isSCXMLEvent(event)) {\n return event as SCXML.Event<TEvent>;\n }\n\n return {\n name: event.type,\n data: event,\n $$type: 'scxml',\n type: 'external',\n ...scxmlEvent\n };\n}\n\nexport function toTransitionConfigArray<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n event: TEvent['type'] | typeof NULL_EVENT | '*',\n configLike: SingleOrArray<\n TransitionConfig<TContext, TEvent> | TransitionConfigTarget\n >\n): Array<\n TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | typeof NULL_EVENT | '*';\n }\n> {\n const transitions = toArrayStrict(configLike).map((transitionLike) => {\n if (\n typeof transitionLike === 'undefined' ||\n typeof transitionLike === 'string'\n ) {\n return { target: transitionLike, event };\n }\n\n return { ...transitionLike, event };\n }) as Array<\n TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | typeof NULL_EVENT | '*';\n } // TODO: fix 'as' (remove)\n >;\n\n return transitions;\n}\n\nexport function normalizeTarget<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n target: SingleOrArray<string | StateNode<TContext, TEvent>> | undefined\n): Array<string | StateNode<TContext, TEvent>> | undefined {\n if (target === undefined || target === TARGETLESS_KEY) {\n return undefined;\n }\n return toArray(target);\n}\n\nexport function reportUnhandledExceptionOnInvocation(\n originalError: any,\n currentError: any,\n id: string\n) {\n if (!IS_PRODUCTION) {\n const originalStackTrace = originalError.stack\n ? ` Stacktrace was '${originalError.stack}'`\n : '';\n if (originalError === currentError) {\n // tslint:disable-next-line:no-console\n console.error(\n `Missing onError handler for invocation '${id}', error was '${originalError}'.${originalStackTrace}`\n );\n } else {\n const stackTrace = currentError.stack\n ? ` Stacktrace was '${currentError.stack}'`\n : '';\n // tslint:disable-next-line:no-console\n console.error(\n `Missing onError handler and/or unhandled exception/promise rejection for invocation '${id}'. ` +\n `Original error: '${originalError}'. ${originalStackTrace} Current error is '${currentError}'.${stackTrace}`\n );\n }\n }\n}\n\nexport function toInvokeConfig<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n invocable: InvokeConfig<TContext, TEvent> | string | ActorBehavior<any, any>,\n id: string\n): InvokeConfig<TContext, TEvent> {\n if (typeof invocable === 'object') {\n if ('src' in invocable) {\n return invocable;\n }\n\n if ('transition' in invocable) {\n return {\n id,\n src: invocable\n };\n }\n }\n\n return {\n id,\n src: invocable\n };\n}\n\nexport function toObserver<T>(\n nextHandler?: Observer<T> | ((value: T) => void),\n errorHandler?: (error: any) => void,\n completionHandler?: () => void\n): Observer<T> {\n const noop = () => {};\n const isObserver = typeof nextHandler === 'object';\n const self = isObserver ? nextHandler : null;\n\n return {\n next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),\n error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),\n complete: (\n (isObserver ? nextHandler.complete : completionHandler) || noop\n ).bind(self)\n };\n}\n\nexport function createInvokeId(stateNodeId: string, index: number): string {\n return `${stateNodeId}:invocation[${index}]`;\n}\n\nexport function resolveReferencedActor(\n referenced:\n | AnyActorBehavior\n | { src: AnyActorBehavior; input: Mapper<any, any, any> | any }\n | undefined\n) {\n return referenced\n ? 'transition' in referenced\n ? { src: referenced, input: undefined }\n : referenced\n : undefined;\n}\n","import type {\n EventObject,\n StateValue,\n BooleanGuardDefinition,\n GuardConfig,\n GuardDefinition,\n SCXML,\n GuardPredicate,\n MachineContext\n} from './types.ts';\nimport { isStateId } from './stateUtils.ts';\nimport { isFunction, isString } from './utils.ts';\nimport type { State } from './State.ts';\n\nexport function stateIn<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateValue: StateValue): GuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.guard:in',\n params: { stateValue },\n predicate: ({ state }) => {\n if (isString(stateValue) && isStateId(stateValue)) {\n return state.configuration.some((sn) => sn.id === stateValue.slice(1));\n }\n\n return state.matches(stateValue);\n }\n };\n}\n\nexport function not<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guard: GuardConfig<TContext, TEvent>\n): BooleanGuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.boolean',\n params: { op: 'not' },\n children: [toGuardDefinition(guard)],\n predicate: ({ evaluate, guard, context, _event, state }) => {\n return !evaluate(guard.children![0], context, _event, state);\n }\n };\n}\n\nexport function and<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guards: Array<GuardConfig<TContext, TEvent>>\n): BooleanGuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.boolean',\n params: { op: 'and' },\n children: guards.map((guard) => toGuardDefinition(guard)),\n predicate: ({ evaluate, guard, context, _event, state }) => {\n return guard.children!.every((childGuard) => {\n return evaluate(childGuard, context, _event, state);\n });\n }\n };\n}\n\nexport function or<TContext extends MachineContext, TEvent extends EventObject>(\n guards: Array<GuardConfig<TContext, TEvent>>\n): BooleanGuardDefinition<TContext, TEvent> {\n return {\n type: 'xstate.boolean',\n params: { op: 'or' },\n children: guards.map((guard) => toGuardDefinition(guard)),\n predicate: ({ evaluate, guard, context, _event, state }) => {\n return guard.children!.some((childGuard) => {\n return evaluate(childGuard, context, _event, state);\n });\n }\n };\n}\n\nexport function evaluateGuard<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guard: GuardDefinition<TContext, TEvent>,\n context: TContext,\n _event: SCXML.Event<TEvent>,\n state: State<TContext, TEvent>\n): boolean {\n const { machine } = state;\n\n const predicate = machine?.options?.guards?.[guard.type] ?? guard.predicate;\n\n if (!predicate) {\n throw new Error(`Guard '${guard.type}' is not implemented.'.`);\n }\n\n return predicate({\n context,\n event: _event.data,\n state,\n guard,\n _event,\n evaluate: evaluateGuard\n });\n}\n\nexport function toGuardDefinition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n guardConfig: GuardConfig<TContext, TEvent>,\n getPredicate?: (guardType: string) => GuardPredicate<TContext, TEvent>\n): GuardDefinition<TContext, TEvent> {\n if (isString(guardConfig)) {\n return {\n type: guardConfig,\n predicate: getPredicate?.(guardConfig) || undefined,\n params: { type: guardConfig }\n };\n }\n\n if (isFunction(guardConfig)) {\n return {\n type: guardConfig.name,\n predicate: guardConfig,\n params: {\n type: guardConfig.name,\n name: guardConfig.name\n }\n };\n }\n\n return {\n type: guardConfig.type,\n params: guardConfig.params || guardConfig,\n children: (\n guardConfig.children as Array<GuardConfig<TContext, TEvent>>\n )?.map((childGuard) => toGuardDefinition(childGuard, getPredicate)),\n predicate:\n getPredicate?.(guardConfig.type) || (guardConfig as any).predicate\n };\n}\n","export const STATE_DELIMITER = '.';\nexport const TARGETLESS_KEY = '';\nexport const NULL_EVENT = '';\nexport const STATE_IDENTIFIER = '#';\nexport const WILDCARD = '*';\n","import {\n toStatePath,\n toArray,\n warn,\n isArray,\n isFunction,\n isString,\n toTransitionConfigArray,\n normalizeTarget,\n toStateValue,\n mapContext,\n toSCXMLEvent\n} from './utils.ts';\nimport {\n BaseActionObject,\n EventObject,\n InvokeActionObject,\n StopActionObject,\n StateValue,\n TransitionConfig,\n TransitionDefinition,\n SingleOrArray,\n DelayExpr,\n SCXML,\n StateValueMap,\n RaiseActionObject,\n InitialTransitionConfig,\n MachineContext\n} from './types.ts';\nimport { cloneState, State } from './State.ts';\nimport {\n after,\n done,\n toActionObjects,\n actionTypes,\n resolveActionObject\n} from './actions.ts';\nimport { send } from './actions/send.ts';\nimport { cancel } from './actions/cancel.ts';\nimport { invoke } from './actions/invoke.ts';\nimport { stop } from './actions/stop.ts';\nimport { IS_PRODUCTION } from './environment.ts';\nimport { STATE_IDENTIFIER, NULL_EVENT, WILDCARD } from './constants.ts';\nimport { evaluateGuard, toGuardDefinition } from './guards.ts';\nimport type { StateNode } from './StateNode.ts';\nimport { isDynamicAction } from '../actions/dynamicAction.ts';\nimport {\n AnyActorContext,\n AnyEventObject,\n AnyHistoryValue,\n AnyState,\n AnyStateMachine,\n AnyStateNode,\n AnyTransitionDefinition,\n DelayedTransitionDefinition,\n HistoryValue,\n InitialTransitionDefinition,\n SendActionObject,\n StateFromMachine\n} from '.';\nimport { stopSignalType } from './actors/index.ts';\nimport { ActorStatus } from './interpreter.ts';\n\ntype Configuration<\n TContext extends MachineContext,\n TE extends EventObject\n> = Iterable<StateNode<TContext, TE>>;\ntype AnyConfiguration = Configuration<any, any>;\n\ntype AdjList = Map<AnyStateNode, Array<AnyStateNode>>;\n\nfunction getOutput<TContext extends MachineContext, TEvent extends EventObject>(\n configuration: StateNode<TContext, TEvent>[],\n context: TContext,\n _event: SCXML.Event<TEvent>\n) {\n const machine = configuration[0].machine;\n const finalChildStateNode = configuration.find(\n (stateNode) =>\n stateNode.type === 'final' && stateNode.parent === machine.root\n );\n\n return finalChildStateNode && finalChildStateNode.output\n ? mapContext(finalChildStateNode.output, context, _event)\n : undefined;\n}\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 | null\n): Array<typeof stateNode> {\n const ancestors: Array<typeof stateNode> = [];\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 getConfiguration(\n stateNodes: Iterable<AnyStateNode>\n): Set<AnyStateNode> {\n const configuration = new Set(stateNodes);\n const configurationSet = new Set(stateNodes);\n\n const adjList = getAdjList(configurationSet);\n\n // add descendants\n for (const s of configuration) {\n // if previously active, add existing child nodes\n if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s)!.length)) {\n getInitialStateNodes(s).forEach((sn) => configurationSet.add(sn));\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 (!configurationSet.has(child)) {\n for (const initialStateNode of getInitialStateNodes(child)) {\n configurationSet.add(initialStateNode);\n }\n }\n }\n }\n }\n }\n\n // add all ancestors\n for (const s of configurationSet) {\n let m = s.parent;\n\n while (m) {\n configurationSet.add(m);\n m = m.parent;\n }\n }\n\n return configurationSet;\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 = {};\n for (const childStateNode of childStateNodes) {\n stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList);\n }\n\n return stateValue;\n}\n\nexport function getAdjList<\n TContext extends MachineContext,\n TE extends EventObject\n>(configuration: Configuration<TContext, TE>): AdjList {\n const adjList: AdjList = new Map();\n\n for (const s of configuration) {\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 configuration: AnyConfiguration\n): StateValue {\n const config = getConfiguration(configuration);\n return getValueFromAdj(rootNode, getAdjList(config));\n}\n\nexport function isInFinalState(\n configuration: Array<AnyStateNode>,\n stateNode: AnyStateNode = configuration[0].machine.root\n): boolean {\n if (stateNode.type === 'compound') {\n return getChildren(stateNode).some(\n (s) => s.type === 'final' && configuration.includes(s)\n );\n }\n if (stateNode.type === 'parallel') {\n return getChildren(stateNode).every((sn) =>\n isInFinalState(configuration, sn)\n );\n }\n\n return false;\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 /**\n * If `true`, will use SCXML event partial token matching semantics\n * without the need for the \".*\" suffix\n */\n partialMatch: boolean = false\n): Array<TransitionDefinition<any, TEvent>> {\n const candidates = stateNode.transitions.filter((transition) => {\n const { eventType } = transition;\n // First, check the trivial case: event names are exactly equal\n if (eventType === receivedEventType) {\n return true;\n }\n\n // Then, check if transition is a wildcard transition,\n // which matches any non-transient events\n if (eventType === WILDCARD) {\n return true;\n }\n\n if (!partialMatch && !eventType.endsWith('.*')) {\n return false;\n }\n\n if (!IS_PRODUCTION) {\n warn(\n !/.*\\*.+/.test(eventType),\n `Wildcards can only be the last token of an event descriptor (e.g., \"event.*\") or the entire event descriptor (\"*\"). Check the \"${eventType}\" event.`\n );\n }\n\n const partialEventTokens = eventType.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 (!IS_PRODUCTION) {\n warn(\n isLastToken,\n `Infix wildcards in transition events are not allowed. Check the \"${eventType}\" event.`\n );\n }\n\n return isLastToken;\n }\n\n if (partialEventToken !== eventToken) {\n return false;\n }\n }\n\n return true;\n });\n\n return candidates;\n}\n\n/**\n * All delayed transitions from the config.\n */\nexport function getDelayedTransitions<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode\n): Array<DelayedTransitionDefinition<TContext, TEvent>> {\n const afterConfig = stateNode.config.after;\n if (!afterConfig) {\n return [];\n }\n\n const mutateEntryExit = (\n delay: string | number | DelayExpr<TContext, TEvent>,\n i: number\n ) => {\n const delayRef = isFunction(delay) ? `${stateNode.id}:delay[${i}]` : delay;\n const eventType = after(delayRef, stateNode.id);\n stateNode.entry.push(send({ type: eventType }, { delay }));\n stateNode.exit.push(cancel(eventType));\n return eventType;\n };\n\n const delayedTransitions = isArray(afterConfig)\n ? afterConfig.map((transition, i) => {\n const eventType = mutateEntryExit(transition.delay, i);\n return { ...transition, event: eventType };\n })\n : Object.keys(afterConfig).flatMap((delay, i) => {\n const configTransition = afterConfig[delay];\n const resolvedTransition = isString(configTransition)\n ? { target: configTransition }\n : configTransition;\n const resolvedDelay = !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(stateNode, delayedTransition),\n delay\n };\n });\n}\n\nexport function formatTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n transitionConfig: TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | typeof NULL_EVENT | '*';\n }\n): AnyTransitionDefinition {\n const normalizedTarget = normalizeTarget(transitionConfig.target);\n const reenter = transitionConfig.reenter ?? false;\n const { guards } = stateNode.machine.options;\n const target = resolveTarget(stateNode, normalizedTarget);\n\n // TODO: should this be part of a lint rule instead?\n if (!IS_PRODUCTION && (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: toActionObjects(toArray(transitionConfig.actions)),\n guard: transitionConfig.guard\n ? toGuardDefinition(\n transitionConfig.guard,\n (guardType) => guards[guardType]\n )\n : undefined,\n target,\n source: stateNode,\n reenter,\n eventType: transitionConfig.event,\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>(stateNode: AnyStateNode): Array<AnyTransitionDefinition> {\n const transitionConfigs: Array<\n TransitionConfig<TContext, TEvent> & {\n event: string;\n }\n > = [];\n if (Array.isArray(stateNode.config.on)) {\n transitionConfigs.push(...stateNode.config.on);\n } else if (stateNode.config.on) {\n const { [WILDCARD]: wildcardConfigs = [], ...namedTransitionConfigs } =\n stateNode.config.on;\n for (const eventType of Object.keys(namedTransitionConfigs)) {\n if (eventType === NULL_EVENT) {\n throw new Error(\n 'Null events (\"\") cannot be specified as a transition key. Use `always: { ... }` instead.'\n );\n }\n const eventTransitionConfigs = toTransitionConfigArray<TContext, TEvent>(\n eventType,\n namedTransitionConfigs![eventType as string]\n );\n\n transitionConfigs.push(...eventTransitionConfigs);\n // TODO: add dev-mode validation for unreachable transitions\n }\n transitionConfigs.push(\n ...toTransitionConfigArray(\n WILDCARD,\n wildcardConfigs as SingleOrArray<\n TransitionConfig<TContext, TEvent> & {\n event: '*';\n }\n >\n )\n );\n }\n const doneConfig = stateNode.config.onDone\n ? toTransitionConfigArray(\n String(done(stateNode.id)),\n stateNode.config.onDone\n )\n : [];\n const invokeConfig = stateNode.invoke.flatMap((invokeDef) => {\n const settleTransitions: any[] = [];\n if (invokeDef.onDone) {\n settleTransitions.push(\n ...toTransitionConfigArray(\n `done.invoke.${invokeDef.id}`,\n invokeDef.onDone\n )\n );\n }\n if (invokeDef.onError) {\n settleTransitions.push(\n ...toTransitionConfigArray(\n `error.platform.${invokeDef.id}`,\n invokeDef.onError\n )\n );\n }\n if (invokeDef.onSnapshot) {\n settleTransitions.push(\n ...toTransitionConfigArray(\n `xstate.snapshot.${invokeDef.id}`,\n invokeDef.onSnapshot\n )\n );\n }\n return settleTransitions;\n });\n const delayedTransitions = stateNode.after;\n const formattedTransitions = [\n ...doneConfig,\n ...invokeConfig,\n ...transitionConfigs\n ].flatMap(\n (\n transitionConfig: TransitionConfig<TContext, TEvent> & {\n event: TEvent['type'] | '*';\n }\n ) =>\n toArray(transitionConfig).map((transition) =>\n formatTransition(stateNode, transition)\n )\n );\n for (const delayedTransition of delayedTransitions) {\n formattedTransitions.push(delayedTransition as any);\n }\n return formattedTransitions;\n}\n\nexport function formatInitialTransition<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n _target: SingleOrArray<string> | InitialTransitionConfig<TContext, TEvent>\n): InitialTransitionDefinition<TContext, TEvent> {\n if (isString(_target) || isArray(_target)) {\n const targets = toArray(_target).map((t) => {\n // Resolve state string keys (which represent children)\n // to their state node\n const descStateNode = isString(t)\n ? isStateId(t)\n ? stateNode.machine.getStateNodeById(t)\n : stateNode.states[t]\n : t;\n\n if (!descStateNode) {\n throw new Error(\n `Initial state node \"${t}\" not found on parent state node #${stateNode.id}`\n );\n }\n\n if (!isDescendant(descStateNode, stateNode)) {\n throw new Error(\n `Invalid initial target: state node #${descStateNode.id} is not a descendant of #${stateNode.id}`\n );\n }\n\n return descStateNode;\n });\n const resolvedTarget = resolveTarget(stateNode, targets);\n\n const transition = {\n source: stateNode,\n actions: [],\n eventType: null as any,\n reenter: false,\n target: resolvedTarget!,\n toJSON: () => ({\n ...transition,\n source: `#${stateNode.id}`,\n target: resolvedTarget\n ? resolvedTarget.map((t) => `#${t.id}`)\n : undefined\n })\n };\n\n return transition;\n }\n\n return formatTransition(stateNode, {\n target: toArray(_target.target).map((t) => {\n if (isString(t)) {\n return isStateId(t) ? t : `${stateNode.machine.delimiter}${t}`;\n }\n\n return t;\n }),\n actions: _target.actions,\n event: null as any\n }) as InitialTransitionDefinition<TContext, TEvent>;\n}\n\nexport function resolveTarget(\n stateNode: AnyStateNode,\n targets: Array<string | AnyStateNode> | undefined\n): Array<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 (!isString(target)) {\n return target;\n }\n if (isStateId(target)) {\n return stateNode.machine.getStateNodeById(target);\n }\n\n const isInternalTarget = target[0] === stateNode.machine.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) {\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 resolveHistoryTarget<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(stateNode: AnyStateNode & { type: 'history' }): Array<AnyStateNode> {\n const normalizedTarget = normalizeTarget<TContext, TEvent>(stateNode.target);\n if (!normalizedTarget) {\n return stateNode.parent!.initial.target;\n }\n return normalizedTarget.map((t) =>\n typeof t === 'string' ? getStateNodeByPath(stateNode.parent!, t) : t\n );\n}\n\nfunction isHistoryNode(\n stateNode: AnyStateNode\n): stateNode is AnyStateNode & { type: 'history' } {\n return stateNode.type === 'history';\n}\n\nexport function getInitialStateNodes(\n stateNode: AnyStateNode\n): Array<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 for (const targetStateNode of descStateNode.initial.target) {\n for (const a of getProperAncestors(targetStateNode, stateNode)) {\n set.add(a);\n }\n\n iter(targetStateNode);\n }\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/**\n * Returns the child state node from its relative `stateKey`, or throws.\n */\nexport function getStateNode(\n stateNode: AnyStateNode,\n stateKey: string\n): 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(\n statePath,\n stateNode.machine.delimiter\n ).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 state The state value or State instance\n */\nexport function getStateNodes<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n state: StateValue | State<TContext, TEvent>\n): Array<AnyStateNode> {\n const stateValue =\n state instanceof State\n ? state.value\n : toStateValue(state, stateNode.machine.delimiter);\n\n if (isString(stateValue)) {\n return [stateNode, stateNode.states[stateValue]];\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\nexport function transitionAtomicNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: string,\n state: State<TContext, TEvent>,\n _event: SCXML.Event<TEvent>\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n const childStateNode = getStateNode(stateNode, stateValue);\n const next = childStateNode.next(state, _event);\n\n if (!next || !next.length) {\n return stateNode.next(state, _event);\n }\n\n return next;\n}\n\nexport function transitionCompoundNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n state: State<TContext, TEvent>,\n _event: SCXML.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 state,\n _event\n );\n\n if (!next || !next.length) {\n return stateNode.next(state, _event);\n }\n\n return next;\n}\n\nexport function transitionParallelNode<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n stateNode: AnyStateNode,\n stateValue: StateValueMap,\n state: State<TContext, TEvent>,\n _event: SCXML.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 state,\n _event\n );\n if (innerTransitions) {\n allInnerTransitions.push(...innerTransitions);\n }\n }\n if (!allInnerTransitions.length) {\n return stateNode.next(state, _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 state: State<TContext, TEvent, any>,\n _event: SCXML.Event<TEvent>\n): Array<TransitionDefinition<TContext, TEvent>> | undefined {\n // leaf node\n if (isString(stateValue)) {\n return transitionAtomicNode(stateNode, stateValue, state, _event);\n }\n\n // compound node\n if (Object.keys(stateValue).length === 1) {\n return transitionCompoundNode(stateNode, stateValue, state, _event);\n }\n\n // parallel node\n return transitionParallelNode(stateNode, stateValue, state, _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\nexport function removeConflictingTransitions(\n enabledTransitions: Array<AnyTransitionDefinition>,\n configuration: 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], configuration, historyValue),\n computeExitSet([t2], configuration, 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 findLCCA(stateNodes: Array<AnyStateNode>): AnyStateNode {\n const [head] = stateNodes;\n\n let current = getPathFromRootToNode(head);\n let candidates: Array<AnyStateNode> = [];\n\n for (const stateNode of stateNodes) {\n const path = getPathFromRootToNode(stateNode);\n\n candidates = current.filter((sn) => path.includes(sn));\n current = candidates;\n candidates = [];\n }\n\n return current[current.length - 1];\n}\n\nfunction getEffectiveTargetStates(\n transition: AnyTransitionDefinition,\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 {\n target: resolveHistoryTarget(targetNode)\n } as AnyTransitionDefinition,\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 | null {\n const targetStates = getEffectiveTargetStates(transition, historyValue);\n\n if (!targetStates) {\n return null;\n }\n\n if (\n !transition.reenter &&\n transition.source.type !== 'parallel' &&\n targetStates.every((targetStateNode) =>\n isDescendant(targetStateNode, transition.source)\n )\n ) {\n return transition.source;\n }\n\n const lcca = findLCCA(targetStates.concat(transition.source));\n\n return lcca;\n}\n\nfunction computeExitSet(\n transitions: AnyTransitionDefinition[],\n configuration: 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 for (const stateNode of configuration) {\n if (isDescendant(stateNode, domain!)) {\n statesToExit.add(stateNode);\n }\n }\n }\n }\n\n return [...statesToExit];\n}\n\n/**\n * https://www.w3.org/TR/scxml/#microstepProcedure\n *\n * @private\n * @param transitions\n * @param currentState\n * @param mutConfiguration\n */\n\nexport function microstep<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n transitions: Array<TransitionDefinition<TContext, TEvent>>,\n currentState: State<TContext, TEvent, any>,\n actorCtx: AnyActorContext | undefined,\n scxmlEvent: SCXML.Event<TEvent>\n): State<TContext, TEvent, any> {\n const { machine } = currentState;\n // Transition will \"apply\" if:\n // - the state node is the initial state (there is no current state)\n // - OR there are transitions\n const willTransition = currentState._initial || transitions.length > 0;\n\n const mutConfiguration = new Set(currentState.configuration);\n\n if (!currentState._initial && !willTransition) {\n const inertState = cloneState(currentState, {\n _event: scxmlEvent,\n actions: [],\n transitions: []\n });\n\n inertState.changed = false;\n return inertState;\n }\n\n const microstate = microstepProcedure(\n currentState._initial\n ? [\n {\n target: [...currentState.configuration].filter(isAtomicStateNode),\n source: machine.root,\n reenter: true,\n actions: [],\n eventType: null as any,\n toJSON: null as any // TODO: fix\n }\n ]\n : transitions,\n currentState,\n mutConfiguration,\n scxmlEvent,\n actorCtx\n );\n\n const { context, actions: nonRaisedActions } = microstate;\n\n const children = setChildren(currentState, nonRaisedActions);\n\n const nextState = cloneState(microstate, {\n value: {}, // TODO: make optional\n transitions,\n children\n });\n\n nextState.changed = currentState._initial\n ? undefined\n : !stateValuesEqual(nextState.value, currentState.value) ||\n nextState.actions.length > 0 ||\n context !== currentState.context;\n\n return nextState;\n}\n\nfunction setChildren(\n currentState: AnyState,\n nonRaisedActions: BaseActionObject[]\n) {\n const children = { ...currentState.children };\n for (const action of nonRaisedActions) {\n if (\n action.type === actionTypes.invoke &&\n (action as InvokeActionObject).params.ref\n ) {\n const ref = (action as InvokeActionObject).params.ref;\n if (ref) {\n children[ref.id] = ref;\n }\n } else if (action.type === actionTypes.stop) {\n const ref = (action as StopActionObject).params.actor;\n if (ref) {\n delete children[ref.id];\n }\n }\n }\n return children;\n}\n\nfunction microstepProcedure(\n transitions: Array<AnyTransitionDefinition>,\n currentState: AnyState,\n mutConfiguration: Set<AnyStateNode>,\n scxmlEvent: SCXML.Event<AnyEventObject>,\n actorCtx: AnyActorContext | undefined\n): typeof currentState {\n const { machine } = currentState;\n const actions: BaseActionObject[] = [];\n const historyValue = {\n ...currentState.historyValue\n };\n\n const filteredTransitions = removeConflictingTransitions(\n transitions,\n mutConfiguration,\n historyValue\n );\n\n const internalQueue = [...currentState._internalQueue];\n\n // Exit states\n if (!currentState._initial) {\n exitStates(filteredTransitions, mutConfiguration, historyValue, actions);\n }\n\n // Execute transition content\n actions.push(...filteredTransitions.flatMap((t) => t.actions));\n\n // Enter states\n enterStates(\n filteredTransitions,\n mutConfiguration,\n actions,\n internalQueue,\n currentState,\n historyValue\n );\n\n const nextConfiguration = [...mutConfiguration];\n\n const done = isInFinalState(nextConfiguration);\n\n if (done) {\n const finalActions = nextConfiguration\n .sort((a, b) => b.order - a.order)\n .flatMap((state) => state.exit);\n actions.push(...finalActions);\n }\n\n try {\n const { nextState } = resolveActionsAndContext(\n actions,\n scxmlEvent,\n currentState,\n actorCtx\n );\n\n const output = done\n ? getOutput(nextConfiguration, nextState.context, scxmlEvent)\n : undefined;\n\n internalQueue.push(...nextState._internalQueue);\n\n return cloneState(currentState, {\n actions: nextState.actions,\n configuration: nextConfiguration,\n historyValue,\n _internalQueue: internalQueue,\n context: nextState.context,\n _event: scxmlEvent,\n done,\n output,\n children: nextState.children\n });\n } catch (e) {\n // TODO: Refactor this once proper error handling is implemented.\n // See https://github.com/statelyai/rfcs/pull/4\n if (machine.config.scxml) {\n return cloneState(currentState, {\n actions: [],\n configuration: Array.from(mutConfiguration),\n historyValue,\n _internalQueue: [toSCXMLEvent({ type: 'error.execution' })],\n context: currentState.context\n });\n } else {\n throw e;\n }\n }\n}\n\nfunction enterStates(\n filteredTransitions: AnyTransitionDefinition[],\n mutConfiguration: Set<AnyStateNode>,\n actions: BaseActionObject[],\n internalQueue: SCXML.Event<AnyEventObject>[],\n currentState: AnyState,\n historyValue: HistoryValue<any, any>\n): void {\n const statesToEnter = new Set<AnyStateNode>();\n const statesForDefaultEntry = new Set<AnyStateNode>();\n\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 (currentState._initial) {\n statesForDefaultEntry.add(currentState.machine.root);\n }\n\n for (const stateNodeToEnter of [...statesToEnter].sort(\n (a, b) => a.order - b.order\n )) {\n mutConfiguration.add(stateNodeToEnter);\n\n for (const invokeDef of stateNodeToEnter.invoke) {\n actions.push(invoke(invokeDef));\n }\n\n // Add entry actions\n actions.push(...stateNodeToEnter.entry);\n\n if (statesForDefaultEntry.has(stateNodeToEnter)) {\n for (const stateNode of statesForDefaultEntry) {\n const initialActions = stateNode.initial!.actions;\n actions.push(...initialActions);\n }\n }\n if (stateNodeToEnter.type === 'final') {\n const parent = stateNodeToEnter.parent!;\n\n if (!parent.parent) {\n continue;\n }\n\n internalQueue.push(\n toSCXMLEvent(\n done(\n parent!.id,\n stateNodeToEnter.output\n ? mapContext(\n stateNodeToEnter.output,\n currentState.context,\n currentState._event\n )\n : undefined\n )\n )\n );\n\n if (parent.parent) {\n const grandparent = parent.parent;\n\n if (grandparent.type === 'parallel') {\n if (\n getChildren(grandparent).every((parentNode) =>\n isInFinalState([...mutConfiguration], parentNode)\n )\n ) {\n internalQueue.push(toSCXMLEvent(done(grandparent.id)));\n }\n }\n }\n }\n }\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 for (const s of t.target || []) {\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n const ancestor = getTransitionDomain(t, historyValue);\n const targetStates = getEffectiveTargetStates(t, historyValue);\n for (const s of targetStates) {\n addAncestorStatesToEnter(\n s,\n ancestor,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\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 addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n for (const s of historyStateNodes) {\n addAncestorStatesToEnter(\n s,\n stateNode.parent!,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n for (const stateForDefaultEntry of statesForDefaultEntry) {\n statesForDefaultEntry.add(stateForDefaultEntry);\n }\n }\n } else {\n const targets = resolveHistoryTarget<TContext, TEvent>(stateNode);\n for (const s of targets) {\n addDescendantStatesToEnter(\n s,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n for (const s of targets) {\n addAncestorStatesToEnter(\n s,\n stateNode,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\n for (const stateForDefaultEntry of statesForDefaultEntry) {\n statesForDefaultEntry.add(stateForDefaultEntry);\n }\n }\n }\n } else {\n statesToEnter.add(stateNode);\n if (stateNode.type === 'compound') {\n statesForDefaultEntry.add(stateNode);\n const initialStates = stateNode.initial.target;\n\n for (const initialState of initialStates) {\n addDescendantStatesToEnter(\n initialState,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n\n for (const initialState of initialStates) {\n addAncestorStatesToEnter(\n initialState,\n stateNode,\n statesToEnter,\n historyValue,\n statesForDefaultEntry\n );\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 addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n }\n}\n\nfunction addAncestorStatesToEnter(\n stateNode: AnyStateNode,\n toStateNode: AnyStateNode | null,\n statesToEnter: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n statesForDefaultEntry: Set<AnyStateNode>\n) {\n const properAncestors = getProperAncestors(stateNode, toStateNode);\n for (const anc of properAncestors) {\n statesToEnter.add(anc);\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 addDescendantStatesToEnter(\n child,\n historyValue,\n statesForDefaultEntry,\n statesToEnter\n );\n }\n }\n }\n }\n}\n\nfunction exitStates(\n transitions: AnyTransitionDefinition[],\n mutConfiguration: Set<AnyStateNode>,\n historyValue: HistoryValue<any, any>,\n actions: BaseActionObject[]\n) {\n const statesToExit = computeExitSet(\n transitions,\n mutConfiguration,\n historyValue\n );\n\n statesToExit.sort((a, b) => b.order - a.order);\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 historyValue[historyNode.id] =\n Array.from(mutConfiguration).filter(predicate);\n }\n }\n\n for (const s of statesToExit) {\n actions.push(...s.exit.flat(), ...s.invoke.map((def) => stop(def.id)));\n mutConfiguration.delete(s);\n }\n}\n\nexport function resolveActionsAndContext<\n TContext extends MachineContext,\n TEvent extends EventObject\n>(\n actions: BaseActionObject[],\n scxmlEvent: SCXML.Event<TEvent>,\n currentState: State<TContext, TEvent, any>,\n actorCtx: AnyActorContext | undefined\n): {\n nextState: AnyState;\n} {\n const { machine } = currentState;\n const resolvedActions: BaseActionObject[] = [];\n const raiseActions: Array<RaiseActionObject<TContext, TEvent>> = [];\n let intermediateState = currentState;\n\n function handleAction(action: BaseActionObject): void {\n resolvedActions.push(action);\n if (actorCtx?.self.status === ActorStatus.Running) {\n action.execute?.(actorCtx!);\n // TODO: this is hacky; re-evaluate\n delete action.execute;\n }\n }\n\n function resolveAction(actionObject: BaseActionObject) {\n const executableActionObject = resolveActionObject(\n actionObject,\n machine.options.actions\n );\n\n if (isDynamicAction(executableActionObject)) {\n const [nextState, resolvedAction] = executableActionObject.resolve(\n scxmlEvent,\n {\n state: intermediateState,\n action: actionObject,\n actorContext: actorCtx\n }\n );\n const matchedActions = resolvedAction.params?.actions;\n\n intermediateState = nextState;\n\n if (\n (resolvedAction.type === actionTypes.raise ||\n (resolvedAction.type === actionTypes.send &&\n (resolvedAction as SendActionObject).params.internal)) &&\n typeof (resolvedAction as any).params.delay !== 'number'\n ) {\n raiseActions.push(resolvedAction);\n }\n\n // TODO: remove the check; just handleAction\n if (resolvedAction.type !== actionTypes.pure) {\n handleAction(resolvedAction);\n }\n\n toActionObjects(matchedActions).forEach(resolveAction);\n\n return;\n }\n\n handleAction(executableActionObject);\n }\n\n for (const actionObject of actions) {\n resolveAction(actionObject);\n }\n\n return {\n nextState: cloneState(intermediateState, {\n actions: resolvedActions,\n _internalQueue: raiseActions.map((a) => a.params._event)\n })\n };\n}\n\nexport function macrostep<TMachine extends AnyStateMachine>(\n state: StateFromMachine<TMachine>,\n scxmlEvent: SCXML.Event<TMachine['__TEvent']>,\n actorCtx: AnyActorContext | undefined\n): {\n state: typeof state;\n microstates: Array<typeof state>;\n} {\n if (!IS_PRODUCTION && scxmlEvent.name === WILDCARD) {\n throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);\n }\n\n let nextState = state;\n const states: StateFromMachine<TMachine>[] = [];\n\n // Handle stop event\n if (scxmlEvent?.name === stopSignalType) {\n nextState = stopStep(scxmlEvent, nextState, actorCtx);\n states.push(nextState);\n\n return {\n state: nextState,\n microstates: states\n };\n }\n\n // Assume the state is at rest (no raised events)\n // Determine the next state based on the next microstep\n if (scxmlEvent.name !== actionTypes.init) {\n const transitions = selectTransitions(scxmlEvent, nextState);\n nextState = microstep(transitions, state, actorCtx, scxmlEvent);\n states.push(nextState);\n }\n\n while (!nextState.done) {\n let enabledTransitions = selectEventlessTransitions(nextState);\n\n if (enabledTransitions.length === 0) {\n // TODO: this is a bit of a hack, we need to review this\n // this matches the behavior from v4 for eventless transitions\n // where for `hasAlwaysTransitions` we were always trying to resolve with a NULL event\n // and if a transition was not selected the `state.transitions` stayed empty\n // without this we get into an infinite loop in the dieHard test in `@xstate/test` for the `simplePathsTo`\n if (nextState.configuration.some((state) => state.always)) {\n nextState.transitions = [];\n }\n\n if (!nextState._internalQueue.length) {\n break;\n } else {\n const currentActions = nextState.actions;\n const nextEvent = nextState._internalQueue[0];\n const transitions = selectTransitions(nextEvent, nextState);\n nextState = microstep(transitions, nextState, actorCtx, nextEvent);\n nextState._internalQueue.shift();\n nextState.actions.unshift(...currentActions);\n\n states.push(nextState);\n }\n }\n\n if (enabledTransitions.length) {\n const currentActions = nextState.actions;\n nextState = microstep(\n enabledTransitions,\n nextState,\n actorCtx,\n nextState._event\n );\n nextState.actions.unshift(...currentActions);\n\n states.push(nextState);\n }\n }\n\n if (nextState.done) {\n // Perform the stop step to ensure that child actors are stopped\n stopStep(nextState._event, nextState, actorCtx);\n }\n\n return {\n state: nextState,\n microstates: states\n };\n}\n\nfunction stopStep(\n scxmlEvent: SCXML.Event<any>,\n nextState: AnyState,\n actorCtx: AnyActorContext | undefined\n): AnyState {\n const actions: BaseActionObject[] = [];\n\n for (const stateNode of nextState.configuration.sort(\n (a, b) => b.order - a.order\n )) {\n actions.push(...stateNode.exit);\n }\n\n for (const child of Object.values(nextState.children)) {\n actions.push(stop(child));\n }\n\n const { nextState: stoppedState } = resolveActionsAndContext(\n actions,\n scxmlEvent,\n nextState,\n actorCtx\n );\n\n return stoppedState;\n}\n\nfunction selectTransitions(\n scxmlEvent: SCXML.Event<any>,\n nextState: AnyState\n): AnyTransitionDefinition[] {\n return nextState.machine.getTransitionData(nextState, scxmlEvent);\n}\n\nfunction selectEventlessTransitions(\n nextState: AnyState\n): AnyTransitionDefinition[] {\n const enabledTransitionSet: Set<AnyTransitionDefinition> = new Set();\n const atomicStates = nextState.configuration.filter(isAtomicStateNode);\n\n for (const stateNode of atomicStates) {\n loop: for (const s of [stateNode].concat(\n getProperAncestors(stateNode, null)\n )) {\n if (!s.always) {\n continue;\n }\n for (const transition of s.always) {\n if (\n transition.guard === undefined ||\n evaluateGuard(\n transition.guard,\n nextState.context,\n nextState._event,\n nextState\n )\n ) {\n enabledTransitionSet.add(transition);\n break loop;\n }\n }\n }\n }\n\n return removeConflictingTransitions(\n Array.from(enabledTransitionSet),\n new Set(nextState.configuration),\n nextState.historyValue\n );\n}\n\n/**\n * Resolves a partial state value with its full representation in the state 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 configuration = getConfiguration(getStateNodes(rootNode, stateValue));\n return getStateValue(rootNode, [...configuration]);\n}\n\nexport function 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 (isString(a) || isString(b)) {\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\nexport function getInitialConfiguration(\n rootNode: AnyStateNode\n): AnyStateNode[] {\n const configuration: AnyStateNode[] = [];\n const initialTransition = rootNode.initial;\n\n const statesToEnter = new Set<AnyStateNode>();\n const statesForDefaultEntry = new Set<AnyStateNode>([rootNode]);\n\n computeEntrySet(\n [initialTransition],\n {},\n statesForDefaultEntry,\n statesToEnter\n );\n\n for (const stateNodeToEnter of [...statesToEnter].sort(\n (a, b) => a.order - b.order\n )) {\n configuration.push(stateNodeToEnter);\n }\n\n return configuration;\n}\n"],"names":["isString","value","toGuardDefinition","guardConfig","getPredicate","type","predicate","undefined","params","name","children","_guardConfig$children","map","childGuard","guards","op","guard","evaluate","context","_event","state","every","evaluateGuard","machine","options","_machine$options","_machine$options$guar2","Error","event","data","some","stateValue","configuration","sn","id","slice","matches"],"mappings":"oPAiVO,SAASA,EAASC,GACvB,MAAwB,iBAAVA,ECvOT,SAASC,EAIdC,EACAC,GACmC,MACnC,OAAIJ,EAASG,GACJ,CACLE,KAAMF,EACNG,WAAWF,MAAAA,SAAAA,EAAeD,UAAgBI,EAC1CC,OAAQ,CAAEH,KAAMF,IDwNI,mBCpNTA,EACN,CACLE,KAAMF,EAAYM,KAClBH,UAAWH,EACXK,OAAQ,CACNH,KAAMF,EAAYM,KAClBA,KAAMN,EAAYM,OAKjB,CACLJ,KAAMF,EAAYE,KAClBG,OAAQL,EAAYK,QAAUL,EAC9BO,mBACEP,EAAYO,6BADJC,EAEPC,KAAI,SAACC,GAAU,OAAKX,EAAkBW,EAAYT,MACrDE,WACEF,MAAAA,SAAAA,EAAeD,EAAYE,QAAUF,EAAoBG,iBA7FxD,SAILQ,GAEA,MAAO,CACLT,KAAM,iBACNG,OAAQ,CAAEO,GAAI,OACdL,SAAUI,EAAOF,KAAI,SAACI,GAAK,OAAKd,EAAkBc,MAClDV,UAAW,YAAiD,IAA9CW,IAAAA,SAAUD,IAAAA,MAAOE,IAAAA,QAASC,IAAAA,OAAQC,IAAAA,MAC9C,OAAOJ,EAAMN,SAAUW,OAAM,SAACR,GAC5B,OAAOI,EAASJ,EAAYK,EAASC,EAAQC,yBAqB9C,SAASE,EAIdN,EACAE,EACAC,EACAC,GACS,UACDG,EAAYH,EAAZG,QAEFjB,YAAYiB,MAAAA,aAAAA,EAASC,gCAATC,EAAkBX,2BAAlBY,EAA2BV,EAAMX,qBAASW,EAAMV,UAElE,IAAKA,EACH,MAAM,IAAIqB,uBAAgBX,EAAMX,iCAGlC,OAAOC,EAAU,CACfY,QAAAA,EACAU,MAAOT,EAAOU,KACdT,MAAAA,EACAJ,MAAAA,EACAG,OAAAA,EACAF,SAAUK,WAxEP,SAILN,GAEA,MAAO,CACLX,KAAM,iBACNG,OAAQ,CAAEO,GAAI,OACdL,SAAU,CAACR,EAAkBc,IAC7BV,UAAW,YAAiD,IAA9CW,IAAAA,SAAUD,IAAAA,MAAOE,IAAAA,QAASC,IAAAA,OAAQC,IAAAA,MAC9C,OAAQH,EAASD,EAAMN,SAAU,GAAIQ,EAASC,EAAQC,WAuBrD,SACLN,GAEA,MAAO,CACLT,KAAM,iBACNG,OAAQ,CAAEO,GAAI,MACdL,SAAUI,EAAOF,KAAI,SAACI,GAAK,OAAKd,EAAkBc,MAClDV,UAAW,YAAiD,IAA9CW,IAAAA,SAAUD,IAAAA,MAAOE,IAAAA,QAASC,IAAAA,OAAQC,IAAAA,MAC9C,OAAOJ,EAAMN,SAAUoB,MAAK,SAACjB,GAC3B,OAAOI,EAASJ,EAAYK,EAASC,EAAQC,mBA5D9C,SAGLW,GACA,MAAO,CACL1B,KAAM,kBACNG,OAAQ,CAAEuB,WAAAA,GACVzB,UAAW,YAAe,IAAZc,IAAAA,MACZ,OAAIpB,EAAS+B,ICnBa,MDmBYA,EEgNE,GF/M/BX,EAAMY,cAAcF,MAAK,SAACG,GAAE,OAAKA,EAAGC,KAAOH,EAAWI,MAAM,MAG9Df,EAAMgB,QAAQL"}
|