UNPKG

finitestate

Version:

1. All actions are functions which have a $$displayName property. 2. All states are strings 3. Json representation for SSR

94 lines (87 loc) 2.97 kB
import has from "lodash/has"; const _state = Symbol(); const _value = Symbol(); const _actions = Symbol(); export default class FSM { __control__ = { [_state]: undefined, [_value]: undefined, [_actions]: {} }; constructor({ startState, startValue, transitions, states, transitionMap }) { // grab options this.states = states; this.startState = startState; this.startValue = Object.freeze(startValue); this.transitions = transitions; this.transitionMap = transitionMap; // set private fields this.__control__[_state] = this.startState; this.__control__[_value] = Object.freeze(this.startValue); // create corresponding actions for transitions const actions = {}; this.transitions.forEach(transition => { actions[transition] = (...args) => { //if the current state has a valid transition in the transitionMap if (this.isTransitionValid(transition)) { const newState = this.transitionMap[this.__control__[_state]][ transition ]; let newValue = this.__control__[_value]; const original = this[transition]; if (typeof original === "function") { const transformationFn = original(...args); if (typeof transformationFn === "function") { newValue = transformationFn(this.__control__[_value]); } } else { throw Error( `Found transition of type ${typeof transition}. Transition ${transition} should be a function which returns a transformation function.` ); } const oldProps = { state: this.__control__[_state], value: this.__control__[_value] }; const newProps = { state: newState, value: newValue }; if (this.shouldTransitionOccur(oldProps, newProps, transition)) { this.transitionWillOccur(oldProps, newProps, transition); this.__control__[_value] = Object.freeze(newValue); this.__control__[_state] = newState; this.transitionDidOccur(oldProps, newProps, transition); } else { console.debug(`transition was not performed`); } return this.__control__[_value]; } else { console.warn( `Transition ${transition} cannot be performed right now` ); return this.__control__[_value]; } }; }); // freeze actions this.__control__[_actions] = Object.freeze(actions); } isTransitionValid(transition) { return has(this.transitionMap[this.__control__[_state]], transition); } shouldTransitionOccur() { return true; } transitionWillOccur() {} transitionDidOccur() {} get value() { return this.__control__[_value]; } get state() { return this.__control__[_state]; } get actions() { return this.__control__[_actions]; } }