UNPKG

xstate

Version:

Finite State Machines and Statecharts for the Modern Web.

160 lines (159 loc) 6.49 kB
import { EventObject, StateNode, TransitionDefinition, Snapshot, MachineContext, ActorLogic, MachineSnapshot } from "../index.js"; export type AnyStateNode = StateNode<any, any>; type JSONSerializable<T extends object, U> = T & { toJSON: () => U; }; type DirectedGraphLabel = JSONSerializable<{ text: string; }, { text: string; }>; export type DirectedGraphEdge = JSONSerializable<{ id: string; source: AnyStateNode; target: AnyStateNode; label: DirectedGraphLabel; transition: TransitionDefinition<any, any>; }, { source: string; target: string; label: ReturnType<DirectedGraphLabel['toJSON']>; }>; export type DirectedGraphNode = JSONSerializable<{ id: string; stateNode: StateNode; children: DirectedGraphNode[]; /** The edges representing all transitions from this `stateNode`. */ edges: DirectedGraphEdge[]; }, { id: string; children: DirectedGraphNode[]; }>; interface StatePlan<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> { /** The target state. */ state: TSnapshot; /** The paths that reach the target state. */ paths: Array<StatePath<TSnapshot, TEvent>>; } export interface StatePath<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> { /** The ending state of the path. */ state: TSnapshot; /** * The ordered array of state-event pairs (steps) which reach the ending * `state`. */ steps: Steps<TSnapshot, TEvent>; /** The combined weight of all steps in the path. */ weight: number; } export interface StatePlanMap<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> { [key: string]: StatePlan<TSnapshot, TEvent>; } export interface Step<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> { /** The event that resulted in the current state */ event: TEvent; /** The current state after taking the event. */ state: TSnapshot; } export type Steps<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> = Array<Step<TSnapshot, TEvent>>; type ExtractEvent<TEvent extends EventObject, TType extends TEvent['type']> = TEvent extends { type: TType; } ? TEvent : never; export interface VisitedContext<TState, TEvent> { vertices: Set<SerializedSnapshot>; edges: Set<SerializedEvent>; a?: TState | TEvent; } export interface SerializationConfig<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> { serializeState: (state: TSnapshot, event: TEvent | undefined, prevState?: TSnapshot) => string; serializeEvent: (event: TEvent) => string; } type SerializationOptions<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> = Partial<Pick<SerializationConfig<TSnapshot, TEvent>, 'serializeState' | 'serializeEvent'>>; export type TraversalOptions<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject, TInput> = { input?: TInput; } & SerializationOptions<TSnapshot, TEvent> & Partial<Pick<TraversalConfig<TSnapshot, TEvent>, 'events' | 'limit' | 'fromState' | 'stopWhen' | 'toState'>>; export interface TraversalConfig<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> extends SerializationConfig<TSnapshot, TEvent> { events: readonly TEvent[] | ((state: TSnapshot) => readonly TEvent[]); /** * The maximum number of traversals to perform when calculating the state * transition adjacency map. * * @default `Infinity` */ limit: number; fromState: TSnapshot | undefined; /** When true, traversal of the adjacency map will stop for that current state. */ stopWhen: ((state: TSnapshot) => boolean) | undefined; toState: ((state: TSnapshot) => boolean) | undefined; } type Brand<T, Tag extends string> = T & { __tag: Tag; }; export type SerializedSnapshot = Brand<string, 'state'>; export type SerializedEvent = Brand<string, 'event'>; export interface TestMeta<T, TContext extends MachineContext> { test?: (testContext: T, state: MachineSnapshot<TContext, any, any, any, any, any, any, // TMeta any>) => Promise<void> | void; description?: string | ((state: MachineSnapshot<TContext, any, any, any, any, any, any, // TMeta any>) => string); skip?: boolean; } interface TestStateResult { error: null | Error; } export interface TestStepResult { step: Step<any, any>; state: TestStateResult; event: { error: null | Error; }; } export interface TestParam<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> { states?: { [key: string]: (state: TSnapshot) => void | Promise<void>; }; events?: { [TEventType in TEvent['type']]?: EventExecutor<TSnapshot, { type: ExtractEvent<TEvent, TEventType>['type']; }>; }; } export interface TestPath<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> extends StatePath<TSnapshot, TEvent> { description: string; /** * Tests and executes each step in `steps` sequentially, and then tests the * postcondition that the `state` is reached. */ test: (params: TestParam<TSnapshot, TEvent>) => Promise<TestPathResult>; } export interface TestPathResult { steps: TestStepResult[]; state: TestStateResult; } /** * Executes an effect using the `testContext` and `event` that triggers the * represented `event`. */ export type EventExecutor<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject> = (step: Step<TSnapshot, TEvent>) => Promise<any> | void; export interface TestModelOptions<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject, TInput> extends TraversalOptions<TSnapshot, TEvent, TInput> { stateMatcher: (state: TSnapshot, stateKey: string) => boolean; logger: { log: (msg: string) => void; error: (msg: string) => void; }; serializeTransition: (state: TSnapshot, event: TEvent | undefined, prevState?: TSnapshot) => string; } export type PathGenerator<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject, TInput> = (behavior: ActorLogic<TSnapshot, TEvent, TInput>, options: TraversalOptions<TSnapshot, TEvent, TInput>) => Array<StatePath<TSnapshot, TEvent>>; export interface AdjacencyValue<TState, TEvent> { state: TState; transitions: { [key: SerializedEvent]: { event: TEvent; state: TState; }; }; } export interface AdjacencyMap<TState, TEvent> { [key: SerializedSnapshot]: AdjacencyValue<TState, TEvent>; } export {};