overmind
Version:
Frictionless state management
1 lines • 10.7 kB
Source Map (JSON)
{"version":3,"file":"statemachine.js","sourceRoot":"","sources":["../src/statemachine.ts"],"names":[],"mappings":"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","sourcesContent":["import isPlainObject from 'is-plain-obj'\nimport { PATH, PROXY_TREE, VALUE } from 'proxy-state-tree'\n\nimport { IState } from '.'\n\ntype TState = {\n current: string\n} & TBaseState\n\ntype TBaseState = {\n [key: string]: IState | Statemachine<any, any, any>\n}\n\ntype TEvents = {\n type: string\n data?: any\n}\n\nexport type StatemachineTransitions<\n States extends TState,\n Events extends TEvents,\n BaseState extends TBaseState\n> =\n | ([BaseState] extends [never]\n ? (event: Events, state: States) => States | void\n : (event: Events, state: States & BaseState) => States | void)\n | {\n [State in States['current']]: {\n [Type in Events['type']]?: [BaseState] extends [never]\n ? ((\n event: Events extends { type: Type } ? Events['data'] : never,\n state: States extends { current: State } ? States : never\n ) => States | void)\n : ((\n event: Events extends { type: Type } ? Events['data'] : never,\n state: States extends { current: State }\n ? States & BaseState\n : never\n ) => States | void)\n }\n }\n\nexport interface MachineMethods<\n States extends TState,\n Events extends TEvents,\n BaseState extends TBaseState\n> {\n matches<T extends States['current']>(\n current: T\n ):\n | Statemachine<\n States extends { current: T } ? States : never,\n Events,\n BaseState\n >\n | undefined\n send<T extends Events['type']>(\n ...args: Events extends { type: T; data: any } ? [T, Events['data']] : [T]\n ): Statemachine<States, Events, BaseState>\n onTransition(listener: (state: States) => void): void\n}\n\nexport type Statemachine<\n States extends TState,\n Events extends TEvents,\n BaseState extends TBaseState = never\n> = [BaseState] extends [never]\n ? States & MachineMethods<States, Events, BaseState>\n : States & BaseState & MachineMethods<States, Events, BaseState>\n\nconst INITIAL_STATE = Symbol('INITIAL_STATE')\nconst TRANSITIONS = Symbol('TRANSITIONS')\nconst STATE = Symbol('STATE')\nconst IS_DISPOSED = Symbol('IS_DISPOSED')\nconst CURRENT_KEYS = Symbol('CURRENT_KEYS')\nconst BASE_STATE = Symbol('BASE_STATE')\nconst TRANSITION_LISTENERS = Symbol('TRANSITION_LISTENERS')\n\n// We have to export here to avoid a circular dependency issue with \"utils\"\nexport function deepCopy(obj) {\n if (obj instanceof StateMachine) {\n return (obj as any).clone()\n } else if (isPlainObject(obj)) {\n return Object.keys(obj).reduce((aggr: any, key) => {\n if (key === '__esModule') {\n return aggr\n }\n\n const originalDescriptor = Object.getOwnPropertyDescriptor(obj, key)\n const isAGetter = originalDescriptor && 'get' in originalDescriptor\n const value = obj[key]\n\n if (isAGetter) {\n Object.defineProperty(aggr, key, originalDescriptor as any)\n } else {\n aggr[key] = deepCopy(value)\n }\n\n return aggr\n }, {})\n } else if (Array.isArray(obj)) {\n return obj.map((item) => deepCopy(item))\n }\n\n return obj\n}\n\nexport class StateMachine<\n State extends TState,\n Events extends TEvents,\n BaseState extends TBaseState\n> {\n current: State['current']\n private [INITIAL_STATE]: State['current']\n private [TRANSITIONS]: StatemachineTransitions<State, Events, BaseState>\n private [STATE]: any\n private [BASE_STATE]: BaseState\n private [TRANSITION_LISTENERS]: Array<(state: State) => void> = []\n private [IS_DISPOSED] = false\n private clone() {\n return new StateMachine(\n this[TRANSITIONS],\n deepCopy(this[STATE]),\n deepCopy(this[BASE_STATE])\n )\n }\n\n private dispose() {\n this[VALUE][TRANSITION_LISTENERS] = []\n Object.keys(this[VALUE]).forEach((key) => {\n if (this[VALUE][key] instanceof StateMachine) {\n this[key].dispose()\n }\n })\n this[VALUE][IS_DISPOSED] = true\n }\n\n constructor(\n transitions: StatemachineTransitions<State, Events, BaseState>,\n state: State,\n baseState: BaseState\n ) {\n this[STATE] = state\n this[BASE_STATE] = baseState\n this[INITIAL_STATE] = state.current\n this[BASE_STATE] = baseState\n this[TRANSITIONS] = transitions\n this[CURRENT_KEYS] = Object.keys(state)\n Object.assign(this, state, baseState)\n }\n\n send(type, data) {\n if (this[VALUE][IS_DISPOSED]) {\n if (process.env.NODE_ENV === 'development') {\n console.warn(\n `Overmind - The statemachine at \"${\n this[PATH]\n }\" has been disposed, but you tried to transition on it`\n )\n }\n return this\n }\n\n const tree = this[PROXY_TREE].master.mutationTree || this[PROXY_TREE]\n\n tree.enableMutations()\n\n let result\n\n if (typeof this[VALUE][TRANSITIONS] === 'function') {\n const transition = this[VALUE][TRANSITIONS]\n\n result = transition({ type, data }, this)\n } else if (this[VALUE][TRANSITIONS][this[VALUE].current][type]) {\n const transition = this[VALUE][TRANSITIONS][this[VALUE].current][type]\n\n result = transition(data, this)\n }\n\n if (result) {\n this[VALUE][CURRENT_KEYS].forEach((key) => {\n if (key !== 'current') {\n delete this[key]\n }\n })\n this[VALUE][CURRENT_KEYS] = Object.keys(result)\n Object.assign(this, result)\n this[VALUE][TRANSITION_LISTENERS].forEach((listener) => listener(this))\n }\n\n tree.blockMutations()\n\n return this\n }\n\n matches(state: any) {\n if (this.current === state) {\n return this\n }\n }\n\n onTransition(listener: (state: State) => void) {\n this[VALUE][TRANSITION_LISTENERS].push(listener)\n }\n}\n\nexport type StatemachineFactory<\n States extends TState,\n Events extends TEvents,\n BaseState extends TBaseState\n> = [BaseState] extends [never]\n ? {\n create(state: States): Statemachine<States, Events, {}>\n }\n : {\n create(\n state: States,\n baseState: BaseState\n ): Statemachine<States, Events, BaseState>\n }\n\nexport function statemachine<\n States extends TState,\n Events extends TEvents,\n BaseState extends TBaseState = never\n>(\n transitions: StatemachineTransitions<States, Events, BaseState>\n): StatemachineFactory<States, Events, BaseState> {\n return {\n create(state, baseState) {\n return new StateMachine(transitions, state as any, baseState as any)\n },\n } as any\n}\n"]}