fix: fix bug with types

This commit is contained in:
Dmitriy Pleshevskiy 2019-10-19 20:06:18 +03:00
parent a85702fd7b
commit 9a499d3e9b
4 changed files with 56 additions and 31 deletions

18
package-lock.json generated
View file

@ -465,6 +465,19 @@
"integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==",
"dev": true "dev": true
}, },
"@types/lodash": {
"version": "4.14.144",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz",
"integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg=="
},
"@types/lodash.clonedeep": {
"version": "4.5.6",
"resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz",
"integrity": "sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA==",
"requires": {
"@types/lodash": "*"
}
},
"@types/stack-utils": { "@types/stack-utils": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
@ -3279,6 +3292,11 @@
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true "dev": true
}, },
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
},
"lodash.memoize": { "lodash.memoize": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",

View file

@ -1,6 +1,6 @@
{ {
"name": "it-fsm", "name": "it-fsm",
"version": "1.0.3", "version": "1.0.4",
"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",
@ -36,9 +36,13 @@
"homepage": "https://github.com/icetemple/npm-it-fsm#readme", "homepage": "https://github.com/icetemple/npm-it-fsm#readme",
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.15", "@types/jest": "^24.0.15",
"@types/lodash.clonedeep": "^4.5.6",
"coveralls": "^3.0.5", "coveralls": "^3.0.5",
"jest": "^24.8.0", "jest": "^24.8.0",
"ts-jest": "^24.0.2", "ts-jest": "^24.0.2",
"typescript": "^3.5.3" "typescript": "^3.5.3"
},
"dependencies": {
"lodash.clonedeep": "^4.5.0"
} }
} }

View file

@ -1,16 +1,16 @@
import cloneDeep from 'lodash.clonedeep';
export type Payload = Record<string, any> export type Payload = Record<string, any>
export type StateType = string | number export type StateType = string | number
export type ActionConfigMap = Record<string, StateType | IActionConfig> export type ActionConfigMap = Record<string, StateType | IActionConfig>
export type ActionEvent = (event: string, fromState: string, toState: string, export type ActionEvent = (event: string, fromState: StateType, toState: StateType,
payload: Payload) => Promise<any> payload: Payload) => Promise<any>
export interface IConfig { export interface IConfig {
[key: string]: ActionEvent | ActionConfigMap [key: string]: undefined | ActionEvent | ActionConfigMap
onEnter: ActionEvent onEnter?: ActionEvent
onLeave: ActionEvent onLeave?: ActionEvent
} }
export interface IActionConfig { export interface IActionConfig {
@ -23,54 +23,58 @@ export interface IActionConfig {
export class StateMachine { export class StateMachine {
[key: string]: any; [key: string]: any;
private _currentState: string; private _currentState: StateType;
private _onEnter: ActionEvent; private _onEnter?: ActionEvent;
private _onLeave: 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, StateType[]> = {};
constructor(initial: StateType, config: IConfig) { constructor(initial: StateType, config: IConfig) {
this._currentState = initial.toString(); this._currentState = initial;
for (let fromState in config) { for (let fromStateKey in config) {
if (['onEnter', 'onLeave'].includes(fromState)) { if (['onEnter', 'onLeave'].includes(fromStateKey)) {
this._onEnter = config.onEnter; this._onEnter = config.onEnter;
continue continue
} }
this._statesByState[fromState] = []; this._statesByState[fromStateKey] = [];
let actions = config[fromState] as ActionConfigMap; let actions = config[fromStateKey] as ActionConfigMap;
for (let actionName in actions) { for (let actionName in actions) {
let action = actions[actionName]; let action = actions[actionName];
let actionConfig: IActionConfig = action.constructor === Object ? let actionConfig: IActionConfig = action.constructor === Object ?
action as IActionConfig action as IActionConfig
: { state: action as StateType }; : { state: action as StateType };
this._statesByState[fromState].push(actionConfig.state.toString()); this._statesByState[fromStateKey].push(actionConfig.state);
this._initChangeState(actionName, fromState, actionConfig.state.toString(), actionConfig);
let fromState: StateType = /^\d+$/.test(fromStateKey) ? parseInt(fromStateKey, 10) : fromStateKey;
this._initChangeState(actionName, fromState, actionConfig.state, actionConfig);
} }
} }
} }
private _initChangeState(eventName: string, fromState: string, toState: string, actionConfig: IActionConfig): void {
private _initChangeState(eventName: string, fromState: StateType, toState: StateType, actionConfig: IActionConfig): void {
if (!this._eventsByState[fromState]) { if (!this._eventsByState[fromState]) {
this._eventsByState[fromState] = {}; this._eventsByState[fromState] = {};
} }
const { onBeforeChange, onChange } = actionConfig; const { onBeforeChange, onChange } = actionConfig;
const _runEvent = async (method?: ActionEvent, payload: Payload = {}): Promise<void> => {
this._eventsByState[fromState][eventName] = async (payload: Payload = {}) => { if (method) {
console.log(this._currentState, typeof this._currentState, fromState, typeof fromState); await method(eventName, fromState, toState, payload);
if (this._currentState !== fromState) {
return;
} }
};
this._onEnter && await this._onEnter(eventName, fromState, toState, payload); this._eventsByState[fromState][eventName] = async (sourcePayload: Payload = {}) => {
onBeforeChange && await onBeforeChange(eventName, fromState, toState, payload); const payload = cloneDeep(sourcePayload);
await _runEvent(this._onEnter, payload);
await _runEvent(onBeforeChange, payload);
this._currentState = toState; this._currentState = toState;
onChange && await onChange(eventName, fromState, toState, payload); await _runEvent(onChange, payload);
this._onLeave && await this._onLeave(eventName, fromState, toState, payload) await _runEvent(this._onLeave, payload);
return this; return this;
}; };
@ -81,13 +85,11 @@ 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)
} }
} }
} }
public getCurrentState(): string { public getCurrentState(): StateType {
return this._currentState; return this._currentState;
} }
@ -100,7 +102,7 @@ export class StateMachine {
return Object.keys(events).includes(eventName); return Object.keys(events).includes(eventName);
} }
public canToState(stateName: string) { public canToState(stateName: StateType) {
const states = this._statesByState[this._currentState]; const states = this._statesByState[this._currentState];
if (!states) { if (!states) {
return false; return false;

View file

@ -16,6 +16,7 @@
"noImplicitThis": true, "noImplicitThis": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"strictNullChecks": true, "strictNullChecks": true,
"esModuleInterop": true,
"outDir": "./src" "outDir": "./src"
}, },
"exclude": [ "exclude": [