UNPKG

ixfx

Version:

Bundle of ixfx libraries

390 lines (389 loc) 13.5 kB
import { n as SimpleEventEmitter } from "./index-DzASKzet.js"; import { i as LogOption } from "./index-Qd9XxFg7.js"; //#region ../packages/flow/src/state-machine/types.d.ts type DriverOptions<V extends Transitions> = { readonly handlers: readonly DriverStatesHandler<V>[]; readonly debug?: LogOption; /** * If _true_ execution of handlers is shuffled each time */ readonly shuffleHandlers?: boolean; }; type DriverExpressionOrResult<T extends Transitions> = DriverResult<T> | ((machine?: MachineState<T>) => DriverResult<T> | undefined | void); type DriverStatesHandler<V extends Transitions> = { readonly if: readonly StateNames<V>[] | StateNames<V>[] | StateNames<V>; readonly then: readonly DriverExpressionOrResult<V>[] | DriverExpressionOrResult<V>; /** * Logic for choosing which result, if there are multiple expressions. * By default 'highest' (for highest ranked result) */ readonly resultChoice?: `first` | `highest` | `lowest` | `random`; }; type DriverRunner<V extends Transitions> = { readonly run: () => Promise<MachineState<V> | undefined>; readonly getValue: () => StateNames<V>; readonly reset: () => void; readonly to: (state: StateNames<V>) => MachineState<V>; }; type DriverResult<V extends Transitions> = { /** * Score of this result. This is used when a state * has multiple handlers returning results separately. * If not defined, 0 is used. */ readonly score?: number; /** * If specified,the state to transition to. Use * _true_ to attempt to automatically advance machine. * This field is 2nd priority. */ readonly next?: StateNames<V> | boolean; /** * If true, resets the machine. * This flag is 1st priority, taking precedence over the `next` field. */ readonly reset?: boolean; }; /** * Transition result * * 'Ok': transition valid * * 'FromNotFound': the from state is missing from machine definition * * 'ToNotFound': the 'to' state is missing from machine definition * * 'Invalid': not allowed to transition to target state from the current state * * 'Terminal': not allowed to transition because from state is the final state */ type TransitionResult = `Ok` | `FromNotFound` | `ToNotFound` | `Invalid` | `Terminal`; type TransitionCondition<V extends Transitions> = { readonly hasPriorState: readonly StateNames<V>[]; readonly isInState: StateNames<V>; }; type StateTargetStrict<V extends Transitions> = { readonly state: StateNames<V> | null; readonly preconditions?: readonly TransitionCondition<V>[]; }; /** * Possible state transitions, or _null_ if final state. */ type StateTarget<V extends Transitions> = string | string[] | readonly string[] | null | StateTargetStrict<V>; /** * Maps state to allowable next states */ type Transitions = { readonly [key: string]: StateTarget<Transitions>; }; type TransitionsStrict = Readonly<Record<string, readonly StateTargetStrict<Transitions>[]>>; /** * List of possible states */ type StateNames<V extends Transitions> = keyof V & string; type Machine<V extends Transitions> = { /** * Allowable state transitions */ readonly states: V; }; /** * Encapsulation of a 'running' machine description and state. * * See: * - {@link cloneState} */ type MachineState<V extends Transitions> = { /** * Current state */ readonly value: StateNames<V>; /** * List of unique states visited. Won't contain the current * state unless it has already been visited. */ readonly visited: readonly StateNames<V>[]; /** * Definition of state machine */ readonly machine: Readonly<Record<StateNames<V>, readonly StateTargetStrict<V>[]>>; }; type StateEvent = (args: unknown, sender: any) => void; type StateHandler = string | StateEvent | null; type State = Readonly<Record<string, StateHandler>>; //#endregion //#region ../packages/flow/src/state-machine/driver.d.ts /** * Drives a state machine. * * [Read more on the ixfx Guide](https://ixfx.fun/flow/state-machine/driver/) * * Uses a 'handlers' structure to determine when to change * state and actions to take. * * The structure is a set of logical conditions: if we're in * this state, then move to this other state etc. * * ```js * const handlers = [ * { * // If we're in the 'sleeping' state, move to next state * if: 'sleeping', * then: { next: true } * }, * { * // If we're in the 'waking' state, randomly either go to 'resting' or 'sleeping' state * if: 'waking', * then: [ * () => { * if (Math.random() > 0.5) { * return { next: 'resting' } * } else { * return { next: 'sleeping' } * } * } * ] * } * ]; * ``` * * Set up the driver, and call `run()` when you want to get * the machine to change state or take action: * * ```js * const driver = await StateMachine.driver(states, handlers); * setInterval(async () => { * await driver.run(); // Note use of 'await' again * }, 1000); * ``` * * Essentially, the 'handlers' structure gets run through each time `run()` * is called. * * Defaults to selecting the highest-ranked result to determine * what to do next. * @param machine * @param handlersOrOpts * @returns */ declare function driver<V extends Transitions>(machine: Machine<V> | Transitions, handlersOrOpts: readonly DriverStatesHandler<V>[] | DriverOptions<V>): Promise<DriverRunner<V>>; //#endregion //#region ../packages/flow/src/state-machine/state-machine-fns.d.ts /** * Clones machine state * @param toClone * @returns Cloned of `toClone` */ declare const cloneState: <V extends Transitions>(toClone: MachineState<V>) => MachineState<V>; /** * Initialises a state machine. [Read more in the ixfx Guide](https://ixfx.fun/flow/state-machine/overview/) * * ```js * const desc = { * pants: ['shoes','socks'], * socks: ['shoes', 'pants'], * shoes: 'shirt', * shirt: null * } * * // Defaults to first key, 'pants' * let sm = StateMachine.init(descr); * * // Move to 'shoes' state * sm = StateMachine.to(sm, 'shoes'); * sm.state; // 'shoes' * sm.visited; // [ 'pants' ] * * StateMachine.isDone(sm); // false * StateMachine.possible(sm); // [ 'shirt' ] * ``` * @param stateMachine Settings for state machine * @param initialState Initial state name * @returns */ declare const init: <V extends Transitions>(stateMachine: Machine<V> | Transitions | TransitionsStrict, initialState?: StateNames<V>) => MachineState<V>; declare const reset: <V extends Transitions>(sm: MachineState<V>) => MachineState<V>; declare const validateMachine: <V extends Transitions>(smOrTransitions: Machine<V> | Transitions | TransitionsStrict) => [machine: Machine<V> | undefined, msg: string]; /** * Returns _true_ if MachineState `sm` is in its final state. * @param sm * @returns */ declare const isDone: <V extends Transitions>(sm: MachineState<V>) => boolean; /** * Returns a list of possible state targets for `sm`, or * an empty list if no transitions are possible. * @param sm * @returns */ declare const possibleTargets: <V extends Transitions>(sm: MachineState<V>) => readonly StateTargetStrict<V>[]; /** * Returns a list of possible state names for `sm`, or * an empty list if no transitions are possible. * * @param sm * @returns */ declare const possible: <V extends Transitions>(sm: MachineState<V>) => (StateNames<V> | null)[]; declare const normaliseTargets: <V extends Transitions>(targets: StateTarget<V> | readonly StateTargetStrict<V>[] | StateTargetStrict<V>) => StateTargetStrict<V>[] | null | undefined; /** * Attempts to transition to a new state. Either a new * `MachineState` is returned reflecting the change, or * an exception is thrown. * * @example Attempts to transition to 'name-of-state' * ```js * const newState = StateMachine.to(currentState, `name-of-state`); * ``` * * Note that 'currentState' is not changed. * @param sm * @param toState * @returns */ declare const to: <V extends Transitions>(sm: MachineState<V>, toState: StateNames<V>) => MachineState<V>; declare const next: <V extends Transitions>(sm: MachineState<V>) => MachineState<V>; /** * Returns _true_ if `toState` is a valid transition from current state of `sm` * @param sm * @param toState * @returns */ declare const isValidTransition: <V extends Transitions>(sm: MachineState<V>, toState: StateNames<V>) => boolean; declare const validateTransition: <V extends Transitions>(sm: MachineState<V>, toState: StateNames<V>) => void; /** * Returns state transitions based on a list of strings. * The last string is the terminal state. * A -> B -> C -> D * * See also: {@link fromListBidirectional} * * ```js * const transitions = fromList([`a`, `b`, `c`, `d`]); * // Object state machine with events * const sm = new StateMachine.WithEvents(transitions); * // OR, immutable state machine * const sm = StateMachine.init(transitions); * ``` * @param states List of states * @return MachineDescription */ declare const fromList: (...states: readonly string[]) => Transitions; /** * Returns a machine description based on a list of strings. Machine * can go back and forth between states: * A <-> B <-> C <-> D * * See also {@link fromList}. * * ```js * const transitions = fromListBidirectional([`a`, `b`, `c`, `d`]); * // Object state machine with events * const sm = new StateMachine.WithEvents(transitions); * // OR, immutable state machine * const sm = StateMachine.init(transitions); * ``` * @param states * @returns */ declare const fromListBidirectional: (...states: readonly string[]) => Transitions; //#endregion //#region ../packages/flow/src/state-machine/with-events.d.ts type StateChangeEvent<V extends Transitions> = { readonly newState: StateNames<V>; readonly priorState: StateNames<V>; }; type StopEvent<V extends Transitions> = { readonly state: StateNames<V>; }; type StateMachineEventMap<V extends Transitions> = { readonly change: StateChangeEvent<V>; readonly stop: StopEvent<V>; }; type StateMachineWithEventsOptions<V extends Transitions> = { readonly debug?: boolean; readonly initial?: StateNames<V>; }; /** * A state machine that fires events when state changes. * * ```js * const transitions = StateMachine.fromList(`a`, `b`, `c`); * const m = new StateMachineWithEvents(transitions); * m.addEventListener(`change`, event => { * console.log(`${event.priorState} -> ${event.newState}`); * }); * m.addEventListener(`stop`, event => { * console.log(`State machine has reached final state`); * }); * ``` */ declare class StateMachineWithEvents<V extends Transitions> extends SimpleEventEmitter<StateMachineEventMap<V>> { #private; /** * Create a state machine with initial state, description and options * @param m Machine description * @param opts Options for machine (defaults to `{debug:false}`) */ constructor(m: V, opts?: StateMachineWithEventsOptions<V>); /** * Return a list of possible states from current state. * * If list is empty, no states are possible. Otherwise lists * possible states, including 'null' for terminal */ get statesPossible(): readonly (StateNames<V> | null)[]; /** * Return a list of all defined states */ get statesDefined(): readonly StateNames<V>[]; /** * Moves to the next state if possible. If multiple states are possible, it will use the first. * If machine is finalised, no error is thrown and null is returned. * * @returns {(string|null)} Returns new state, or null if machine is finalised */ next(): string | null; /** * Returns _true_ if state machine is in its final state * * @returns */ get isDone(): boolean; /** * Resets machine to initial state */ reset(): void; /** * Throws if it's not valid to transition to `newState` * @param newState * @returns */ validateTransition(newState: StateNames<V>): void; /** * Returns _true_ if `newState` is valid transition from current state. * Use {@link validateTransition} if you want an explanation for the _false_ results. * @param newState * @returns */ isValid(newState: StateNames<V>): boolean; /** * Gets or sets state. Throws an error if an invalid transition is attempted. * Use `isValid()` to check validity without changing. * * If `newState` is the same as current state, the request is ignored silently. */ set state(newState: StateNames<V>); get state(): string; /** * Returns timestamp when state was last changed. * See also `elapsed` */ get changedAt(): number; /** * Returns milliseconds elapsed since last state change. * See also `changedAt` */ get elapsed(): number; } declare namespace state_machine_d_exports { export { DriverExpressionOrResult, DriverOptions, DriverResult, DriverRunner, DriverStatesHandler, Machine, MachineState, State, StateChangeEvent, StateEvent, StateHandler, StateMachineEventMap, StateMachineWithEvents, StateMachineWithEventsOptions, StateNames, StateTarget, StateTargetStrict, StopEvent, TransitionCondition, TransitionResult, Transitions, TransitionsStrict, cloneState, driver, fromList, fromListBidirectional, init, isDone, isValidTransition, next, normaliseTargets, possible, possibleTargets, reset, to, validateMachine, validateTransition }; } //#endregion export { Transitions as i, StateChangeEvent as n, StateMachineWithEvents as r, state_machine_d_exports as t }; //# sourceMappingURL=state-machine-CTmK75_L.d.ts.map