fix: fix int enum bugs

This commit is contained in:
Dmitriy Pleshevskiy 2019-10-17 13:54:15 +03:00
parent 60f5763b8b
commit a85702fd7b
4 changed files with 72 additions and 17 deletions

View file

@ -1,3 +1,35 @@
# IT FSM # IT FSM
Simple finite state machine Simple finite state machine
### Installation
`npm install --save it-fsm`
### Usage
```javascript
import { StateMachine } from 'it-fsm';
const fsm = new StateMachine('TODO', {
TODO: {
complete: 'COMPLETE'
}
})
if (fsm.can('complete')) {
fsm.complete().then(() => {
})
}
// or
if (fsm.canToState('COMPLETE')) {
fsm.complete().then(() => {
});
}
```

2
package-lock.json generated
View file

@ -1,5 +1,5 @@
{ {
"name": "rusn", "name": "it-fsm",
"version": "1.0.3", "version": "1.0.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,

View file

@ -1,6 +1,6 @@
{ {
"name": "it-fsm", "name": "it-fsm",
"version": "1.0.2", "version": "1.0.3",
"description": "Simple finite state machine for nodejs", "description": "Simple finite state machine for nodejs",
"main": "./src/index.js", "main": "./src/index.js",
"types": "./src/index.d.ts", "types": "./src/index.d.ts",

View file

@ -1,56 +1,77 @@
export type Payload = Record<string, any> export type Payload = Record<string, any>
export type SystemEvent = (event: string, fromState: string, toState: string, export type StateType = string | number
export type ActionConfigMap = Record<string, StateType | IActionConfig>
export type ActionEvent = (event: string, fromState: string, toState: string,
payload: Payload) => Promise<any> payload: Payload) => Promise<any>
export interface StateEvents { export interface IConfig {
[key: string]: string [key: string]: ActionEvent | ActionConfigMap
onEnter: ActionEvent
onLeave: ActionEvent
} }
export interface IActionConfig {
state: StateType
onBeforeChange?: ActionEvent
onChange?: ActionEvent
}
export class StateMachine { export class StateMachine {
[key: string]: any; [key: string]: any;
private _currentState: string; private _currentState: string;
private _onEnter: SystemEvent; private _onEnter: ActionEvent;
private _onLeave: ActionEvent;
private _eventsByState: Record<string, Record<string, (payload: Payload) => any>> = {}; private _eventsByState: Record<string, Record<string, (payload: Payload) => any>> = {};
private _statesByState: Record<string, string[]> = {}; private _statesByState: Record<string, string[]> = {};
constructor(initial: string, config: Record<string, StateEvents | SystemEvent>) { constructor(initial: StateType, config: IConfig) {
this._currentState = initial; this._currentState = initial.toString();
for (let fromState in config) { for (let fromState in config) {
if (fromState === 'onEnter') { if (['onEnter', 'onLeave'].includes(fromState)) {
this._onEnter = config.onEnter as SystemEvent; this._onEnter = config.onEnter;
continue continue
} }
this._statesByState[fromState] = []; this._statesByState[fromState] = [];
let events = config[fromState] as StateEvents; let actions = config[fromState] as ActionConfigMap;
for (let eventName in events) { for (let actionName in actions) {
let toState: string = events[eventName]; let action = actions[actionName];
this._statesByState[fromState].push(toState); let actionConfig: IActionConfig = action.constructor === Object ?
this._initChangeState(eventName, fromState, toState) action as IActionConfig
: { state: action as StateType };
this._statesByState[fromState].push(actionConfig.state.toString());
this._initChangeState(actionName, fromState, actionConfig.state.toString(), actionConfig);
} }
} }
} }
private _initChangeState(eventName: string, fromState: string, toState: string): void { private _initChangeState(eventName: string, fromState: string, toState: string, actionConfig: IActionConfig): void {
if (!this._eventsByState[fromState]) { if (!this._eventsByState[fromState]) {
this._eventsByState[fromState] = {}; this._eventsByState[fromState] = {};
} }
const { onBeforeChange, onChange } = actionConfig;
this._eventsByState[fromState][eventName] = async (payload: Payload = {}) => { this._eventsByState[fromState][eventName] = async (payload: Payload = {}) => {
console.log(this._currentState, typeof this._currentState, fromState, typeof fromState);
if (this._currentState !== fromState) { if (this._currentState !== fromState) {
return; return;
} }
await this._onEnter(eventName, fromState, toState, payload); this._onEnter && await this._onEnter(eventName, fromState, toState, payload);
onBeforeChange && await onBeforeChange(eventName, fromState, toState, payload);
this._currentState = toState; this._currentState = toState;
onChange && await onChange(eventName, fromState, toState, payload);
this._onLeave && await this._onLeave(eventName, fromState, toState, payload)
return this; return this;
}; };
@ -60,6 +81,8 @@ export class StateMachine {
&& this._eventsByState[this._currentState][eventName]) { && this._eventsByState[this._currentState][eventName]) {
return this._eventsByState[this._currentState][eventName](payload); return this._eventsByState[this._currentState][eventName](payload);
} }
console.log(this._eventsByState, this._currentState, eventName)
} }
} }
} }