fix: fix int enum bugs
This commit is contained in:
parent
60f5763b8b
commit
a85702fd7b
4 changed files with 72 additions and 17 deletions
32
README.md
32
README.md
|
@ -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
2
package-lock.json
generated
|
@ -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,
|
||||||
|
|
|
@ -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",
|
||||||
|
|
53
src/index.ts
53
src/index.ts
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue