UNPKG

@hexworks/cobalt-state

Version:

State machine utility for Cobalt.

54 lines 2.6 kB
/* eslint-disable @typescript-eslint/ban-types */ import { safeParseAsync } from "@hexworks/cobalt-core"; import * as RTE from "fp-ts/ReaderTaskEither"; import { pipe } from "fp-ts/lib/function"; import { Map } from "immutable"; import { ThisIsABugError, UnknownEventError, UnknownStateError, } from "."; import { StateTransitionError } from "./errors/StateTransitionError"; export const newStateMachine = (possibleStates) => { const supportedStates = possibleStates.reduce((map, state) => map.set(state.name, state), Map()); const supportedEventTypes = possibleStates .flatMap((state) => Object.keys(state.transitions)) .toSet(); const enter = (stateInstance) => { const { state, data } = stateInstance; const stateName = state.name; const expectedState = supportedStates.get(stateName); if (!expectedState || expectedState !== state) { return RTE.left(new UnknownStateError(stateName)); } return pipe(RTE.fromTaskEither(safeParseAsync(state.schema)(data)), RTE.chain(() => state.onEntry(data)), RTE.map((data) => ({ ...stateInstance, data, }))); }; const dispatch = (stateInstance, event) => { const { state, data } = stateInstance; const stateName = state.name; const expectedState = supportedStates.get(stateName); const eventType = event.type; if (expectedState && expectedState === state) { const transitions = state.transitions[eventType]; if (transitions) { const transition = transitions.find((t) => t.condition(data, event)); if (transition) { return pipe(RTE.fromTaskEither(safeParseAsync(state.schema)(data)), RTE.chain(() => state.onExit(data)), RTE.chain((d) => transition.transitionTo(d, event)), RTE.chain((stateInstance) => pipe(stateInstance.state.onEntry(stateInstance.data), RTE.map((data) => ({ ...stateInstance, data, })))), RTE.mapLeft((e) => new StateTransitionError(state.name, e))); } else { return RTE.left(new ThisIsABugError(event, data)); } } else { return RTE.left(new UnknownEventError(state.name, event.type)); } } else { return RTE.left(new UnknownStateError(stateName)); } }; return { supportedStates, supportedEventTypes, enter, dispatch }; }; //# sourceMappingURL=StateMachine.js.map