Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

typescript-state-machine

Package Overview
Dependencies
Maintainers
8
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

typescript-state-machine - npm Package Compare versions

Comparing version 0.9.5 to 0.9.6

.eslintrc

338

dist/index.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
var log4javascript_1 = require("log4javascript");
var fsm;
(function (fsm) {
var StateMachineImpl = /** @class */ (function () {
function StateMachineImpl(states, validTransitions, initialState) {
this.log = log4javascript_1.getLogger(this.constructor.name);
this.states = states;
this.validTransitions = validTransitions;
this._state = initialState;
this._transitionListeners = {};
}
Object.defineProperty(StateMachineImpl.prototype, "state", {
get: function () {
return this._state;
},
enumerable: true,
configurable: true
});
StateMachineImpl.prototype.onEnterState = function (state, callBack) {
return this.addTransitionListener(callBack, undefined, state);
};
StateMachineImpl.prototype.onLeaveState = function (state, callBack) {
return this.addTransitionListener(callBack, state, undefined);
};
StateMachineImpl.prototype.onTransition = function (fromState, toState, callBack) {
return this.addTransitionListener(callBack, fromState, toState);
};
StateMachineImpl.prototype.onAnyTransition = function (callBack) {
return this.addTransitionListener(callBack, undefined, undefined);
};
StateMachineImpl.prototype.addTransitionListener = function (callBack, fromState, toState) {
var transition = this.transitionLabel(fromState, toState);
if (!this._transitionListeners[transition]) {
this._transitionListeners[transition] = [];
}
var listenersForTransition = this._transitionListeners[transition];
var transitionListener = new TransitionListener(callBack, fromState, toState);
listenersForTransition.push(transitionListener);
return {
cancel: function () {
transitionListener.active = false;
}
};
};
StateMachineImpl.prototype.checkInState = function (state, message) {
if (!this.inState(state)) {
throw new Error(message || 'Expected to be in ' + state + ' but was in ' + this.state);
}
};
StateMachineImpl.prototype.checkInOneOfStates = function (states, message) {
if (!this.inOneOfStates(states)) {
throw new Error(message || 'Expected to be in one of ' + states + ' but was in ' + this.state);
}
};
StateMachineImpl.prototype.inOneOfStates = function (states) {
return (states.indexOf(this._state) !== -1);
};
StateMachineImpl.prototype.inState = function (state) {
return this._state === state;
};
StateMachineImpl.prototype.invokeAllTransitionListeners = function (fromState, toState) {
var allLeaveTransitions = this.transitionLabel(fromState, undefined);
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[allLeaveTransitions]);
var transition = this.transitionLabel(fromState, toState);
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[transition]);
var allEnterTransitions = this.transitionLabel(undefined, toState);
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[allEnterTransitions]);
var allTransitions = this.transitionLabel(undefined, undefined);
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[allTransitions]);
};
StateMachineImpl.prototype.invokeTransitionListeners = function (fromState, toState, listeners) {
if (listeners) {
for (var index = 0; index < listeners.length; index++) {
var listener = listeners[index];
if (listener.active) {
try {
listener.callBack(fromState, toState);
}
catch (e) {
this.log.error('Uncaught error in listener', e);
}
}
else {
// Remove inactive listener
listeners.splice(index, 1);
index--;
}
}
}
};
StateMachineImpl.prototype.transitionLabel = function (fromState, toState) {
return ((fromState && fromState.label) || '*') + ' --> ' + ((toState && toState.label) || '*');
};
StateMachineImpl.prototype.waitUntilLeft = function (state) {
var _this = this;
return new Promise(function (resolve) {
if (_this._state !== state) {
resolve(_this._state);
}
else {
var registration_1 = _this.onLeaveState(state, function (from, to) {
registration_1.cancel();
resolve(to);
});
}
});
};
StateMachineImpl.prototype.waitUntilEntered = function (state) {
return this.waitUntilEnteredOneOf([state]);
};
StateMachineImpl.prototype.waitUntilEnteredOneOf = function (states) {
var _this = this;
return new Promise(function (resolve) {
if (states.indexOf(_this._state) !== -1) {
resolve(_this._state);
}
else {
var registrations_1 = [];
var finished_1 = false;
var _loop_1 = function (state) {
var registration = _this.onEnterState(state, function (from, to) {
registration.cancel();
registrations_1.forEach(function (reg) {
if (registration !== reg) {
reg.cancel();
}
});
finished_1 = true;
resolve(to);
});
if (finished_1) {
return "break";
}
registrations_1.push(registration);
};
for (var _i = 0, states_1 = states; _i < states_1.length; _i++) {
var state = states_1[_i];
var state_1 = _loop_1(state);
if (state_1 === "break")
break;
}
}
});
};
StateMachineImpl.prototype.setState = function (newState) {
this.checkTransition(newState);
this.log.debug("State : " + this._state + " --> " + newState);
var oldState = this._state;
this._state = newState;
this.invokeAllTransitionListeners(oldState, newState);
};
StateMachineImpl.prototype.canGoToState = function (newState) {
return this.validTransitions[this._state.label].indexOf(newState) !== -1;
};
StateMachineImpl.prototype.checkTransition = function (newState) {
if (!this.canGoToState(newState)) {
throw new Error('Invalid transition from ' + this._state + ' to ' + newState);
}
};
return StateMachineImpl;
}());
fsm.StateMachineImpl = StateMachineImpl;
var State = /** @class */ (function () {
function State(label, parent) {
var _this = this;
this.label = label;
this.parent = parent;
this.toString = function () {
if (_this.parent) {
return _this.parent.toString() + '/' + _this.label;
}
else {
return _this.label;
}
};
}
// noinspection JSUnusedGlobalSymbols
State.prototype.userFriendlyDescription = function () {
return this.label;
};
return State;
}());
fsm.State = State;
var TransitionListener = /** @class */ (function () {
function TransitionListener(callBack, fromState, toState) {
this.callBack = callBack;
this.fromState = fromState;
this.toState = toState;
this.active = true;
}
return TransitionListener;
}());
// Decorators
var log = log4javascript_1.getLogger('fsm.decorators');
/*
Method annotator. Throw an error if the state when the method is called
is different from the given state
*/
function CheckStateIs(state, message) {
return function (target, propertyKey, descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function () {
var context = this;
if (context.state === state) {
originalMethod.apply(context, arguments);
}
else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should be ' + state + ' but state = ' + context.state);
}
};
return descriptor;
};
}
fsm.CheckStateIs = CheckStateIs;
/*
Method annotator. Throw an error if the state when the method is called
is not one of the given states
*/
function CheckStateIn(states, message) {
return function (target, propertyKey, descriptor) {
var originalMethod;
if (descriptor.value) {
originalMethod = descriptor.value;
descriptor.value = function () {
var context = this;
if (states.indexOf(context.state) !== -1) {
return originalMethod.apply(context, arguments);
}
else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should be one of ' + states + ' but state = ' + context.state);
}
};
}
else if (descriptor.get) {
var originalGetter_1 = descriptor.get;
descriptor.get = function () {
var context = this;
if (states.indexOf(context.state) !== -1) {
return originalGetter_1.apply(context, arguments);
}
else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should be one of ' + states + ' but state = ' + context.state);
}
};
}
return descriptor;
};
}
fsm.CheckStateIn = CheckStateIn;
/*
Method annotator. Throw an error if the state when the method is called
is one of the given states
*/
function CheckStateNotIn(states, message) {
return function (target, propertyKey, descriptor) {
var originalMethod;
if (descriptor.value) {
originalMethod = descriptor.value;
descriptor.value = function () {
var context = this;
if (states.indexOf(context.state) === -1) {
return originalMethod.apply(context, arguments);
}
else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should not be one of ' + states);
}
};
}
else if (descriptor.get) {
var originalGetter_2 = descriptor.get;
descriptor.get = function () {
var context = this;
if (states.indexOf(context.state) === -1) {
return originalGetter_2.apply(context, arguments);
}
else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should not be one of these states: ' + states);
}
};
}
return descriptor;
};
}
fsm.CheckStateNotIn = CheckStateNotIn;
/*
Method annotator. Skip the method execution if the state when the method is called
is different from the given state
*/
function AssumeStateIs(state) {
return function (target, propertyKey, descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function () {
var context = this;
if (context.state === state) {
originalMethod.apply(context, arguments);
}
else {
log.warn('Skipping execution of ' + propertyKey + ' : State should be ' + state + ' but state = ' + context.state);
}
};
return descriptor;
};
}
fsm.AssumeStateIs = AssumeStateIs;
/*
Method annotator. Skip the method execution if the state when the method is called
is the same as the given state
*/
function AssumeStateIsNot(state) {
return function (target, propertyKey, descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function () {
var context = this;
if (context.state !== state) {
originalMethod.apply(context, arguments);
}
else {
log.warn('Skipping execution of ' + propertyKey + ' : State should be different from ' + state);
}
};
return descriptor;
};
}
fsm.AssumeStateIsNot = AssumeStateIsNot;
})(fsm = exports.fsm || (exports.fsm = {}));
__exportStar(require("./decorators"), exports);
__exportStar(require("./stateMachine"), exports);
__exportStar(require("./typings"), exports);
//# sourceMappingURL=index.js.map
{
"name": "typescript-state-machine",
"version": "0.9.5",
"version": "0.9.6",
"description": "",

@@ -18,16 +18,25 @@ "main": "dist/index.js",

"scripts": {
"prepublish": "npm run build",
"build": "npm run tslint && tsc",
"tslint": "tslint src/*"
"prepublishOnly": "npm run build && jest",
"build": "npm run eslint && tsc --project tsconfig.build.json",
"eslint": "eslint src/*"
},
"homepage": "https://github.com/taktik/typescript-state-machine#readme",
"dependencies": {
"log4javascript": "^1.4.15"
"devDependencies": {
"@types/jest": "27.0.3",
"@typescript-eslint/eslint-plugin": "5.7.0",
"@typescript-eslint/parser": "5.7.0",
"eslint": "8.4.1",
"eslint-config-prettier": "8.3.0",
"husky": "7.0.4",
"jest": "27.4.5",
"lint-staged": "12.1.3",
"prettier": "2.5.1",
"ts-jest": "27.1.2",
"typescript": "4.5.4"
},
"devDependencies": {
"tslint": "^5.11.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.1.6",
"typescript-eslint-parser": "^20.1.1"
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}

@@ -1,369 +0,3 @@

import { getLogger } from 'log4javascript'
export namespace fsm {
export interface StateMachine<T extends State> {
/* Get the current state of the fsm */
readonly state: T
/*
Listen for state changes. The callback will be called once when the fsm enters the given state.
@param callBack The callBack that will be called
*/
onEnterState(state: T, callBack: (from: T, to: T) => void): ListenerRegistration
/*
Listen for state changes. The callback will be called once when the fsm leaves the given state.
@param callBack The callBack that will be called
*/
onLeaveState(state: T, callBack: (from: T, to: T) => void): ListenerRegistration
/*
Listen for state changes. The callback will be called once when the fsm leaves the given fromState and enters the given toState.
@param callBack The callBack that will be called
*/
onTransition(fromState: T, toState: T, callBack: (from: T, to: T) => void): ListenerRegistration
onAnyTransition(callBack: (from: T, to: T) => void): ListenerRegistration
/*
Wait for state changes.
*/
waitUntilLeft(state: T): Promise<T>
waitUntilEntered(state: T): Promise<T>
waitUntilEnteredOneOf(states: [T]): Promise<T>
}
export class StateMachineImpl<T extends State> implements StateMachine<T> {
readonly states: T[]
readonly validTransitions: Transitions<T>
protected _state: T
private readonly _transitionListeners: TransitionListeners<T>
protected log = getLogger(this.constructor.name)
constructor(states: T[], validTransitions: Transitions<T>, initialState: T) {
this.states = states
this.validTransitions = validTransitions
this._state = initialState
this._transitionListeners = {}
}
get state(): T {
return this._state
}
onEnterState(state: T, callBack: (from: T, to: T) => void): ListenerRegistration {
return this.addTransitionListener(callBack, undefined, state)
}
onLeaveState(state: T, callBack: (from: T, to: T) => void): ListenerRegistration {
return this.addTransitionListener(callBack, state, undefined)
}
onTransition(fromState: T, toState: T, callBack: (from: T, to: T) => void): ListenerRegistration {
return this.addTransitionListener(callBack, fromState, toState)
}
onAnyTransition(callBack: (from: T, to: T) => void): ListenerRegistration {
return this.addTransitionListener(callBack, undefined, undefined)
}
protected addTransitionListener(callBack: (from: T, to: T) => void, fromState?: T, toState?: T) {
const transition = this.transitionLabel(fromState, toState)
if (!this._transitionListeners[transition]) {
this._transitionListeners[transition] = []
}
const listenersForTransition = this._transitionListeners[transition]
const transitionListener = new TransitionListener(callBack, fromState, toState)
listenersForTransition.push(transitionListener)
return {
cancel(): void {
transitionListener.active = false
}
}
}
checkInState(state: T, message?: string): void {
if (!this.inState(state)) {
throw new Error(message || 'Expected to be in ' + state + ' but was in ' + this.state)
}
}
checkInOneOfStates(states: T[], message?: string): void {
if (!this.inOneOfStates(states)) {
throw new Error(message || 'Expected to be in one of ' + states + ' but was in ' + this.state)
}
}
inOneOfStates(states: T[]): boolean {
return (states.indexOf(this._state) !== -1)
}
inState(state: T): boolean {
return this._state === state
}
private invokeAllTransitionListeners(fromState: T, toState: T) {
const allLeaveTransitions = this.transitionLabel(fromState, undefined)
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[allLeaveTransitions])
const transition = this.transitionLabel(fromState, toState)
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[transition])
const allEnterTransitions = this.transitionLabel(undefined, toState)
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[allEnterTransitions])
const allTransitions = this.transitionLabel(undefined, undefined)
this.invokeTransitionListeners(fromState, toState, this._transitionListeners[allTransitions])
}
private invokeTransitionListeners(fromState: T, toState: T, listeners?: TransitionListener<T>[]) {
if (listeners) {
for (let index = 0; index < listeners.length; index++) {
const listener = listeners[index]
if (listener.active) {
try {
listener.callBack(fromState, toState)
} catch (e) {
this.log.error('Uncaught error in listener', e)
}
} else {
// Remove inactive listener
listeners.splice(index, 1)
index--
}
}
}
}
private transitionLabel(fromState?: T, toState?: T) {
return ((fromState && fromState.label) || '*') + ' --> ' + ((toState && toState.label) || '*')
}
waitUntilLeft(state: T): Promise<T> {
return new Promise<T>((resolve) => {
if (this._state !== state) {
resolve(this._state)
} else {
const registration = this.onLeaveState(state, (from, to) => {
registration.cancel()
resolve(to)
})
}
})
}
waitUntilEntered(state: T): Promise<T> {
return this.waitUntilEnteredOneOf([state])
}
waitUntilEnteredOneOf(states: T[]): Promise<T> {
return new Promise<T>((resolve) => {
if (states.indexOf(this._state) !== -1) {
resolve(this._state)
} else {
const registrations: ListenerRegistration[] = []
let finished = false
for (let state of states) {
let registration = this.onEnterState(state, (from, to) => {
registration.cancel()
registrations.forEach(reg => {
if (registration !== reg) {
reg.cancel()
}
})
finished = true
resolve(to)
})
if (finished) {
break
}
registrations.push(registration)
}
}
})
}
setState(newState: T) {
this.checkTransition(newState)
this.log.debug(`State : ${this._state} --> ${newState}`)
const oldState = this._state
this._state = newState
this.invokeAllTransitionListeners(oldState, newState)
}
canGoToState(newState: T): boolean {
return this.validTransitions[this._state.label].indexOf(newState) !== -1
}
private checkTransition(newState: T) {
if (!this.canGoToState(newState)) {
throw new Error('Invalid transition from ' + this._state + ' to ' + newState)
}
}
}
export interface Transitions<T> {
[stateLabel: string]: T[]
}
export class State {
constructor(readonly label: string, readonly parent?: State) {}
toString = (): string => {
if (this.parent) {
return this.parent.toString() + '/' + this.label
} else {
return this.label
}
}
// noinspection JSUnusedGlobalSymbols
userFriendlyDescription() {
return this.label
}
}
class TransitionListener<T> {
active: boolean = true
constructor(
readonly callBack: (from: T, to: T) => void,
readonly fromState?: T,
readonly toState?: T
) {
}
}
interface TransitionListeners<T> {
[transition: string]: TransitionListener<T>[]
}
export interface ListenerRegistration {
// Cancels listener registration
cancel(): void
}
// Decorators
const log = getLogger('fsm.decorators')
/*
Method annotator. Throw an error if the state when the method is called
is different from the given state
*/
export function CheckStateIs(state: State, message?: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
descriptor.value = function() {
const context = this as StateMachine<any>
if (context.state === state) {
originalMethod.apply(context, arguments)
} else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should be ' + state + ' but state = ' + context.state)
}
}
return descriptor
}
}
/*
Method annotator. Throw an error if the state when the method is called
is not one of the given states
*/
export function CheckStateIn(states: State[], message?: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let originalMethod: any
if (descriptor.value) {
originalMethod = descriptor.value
descriptor.value = function() {
const context = this as StateMachine<any>
if (states.indexOf(context.state) !== -1) {
return originalMethod.apply(context, arguments)
} else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should be one of ' + states + ' but state = ' + context.state)
}
}
} else if (descriptor.get) {
const originalGetter = descriptor.get
descriptor.get = function() {
const context = this as StateMachine<any>
if (states.indexOf(context.state) !== -1) {
return originalGetter.apply(context, arguments)
} else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should be one of ' + states + ' but state = ' + context.state)
}
}
}
return descriptor
}
}
/*
Method annotator. Throw an error if the state when the method is called
is one of the given states
*/
export function CheckStateNotIn(states: State[], message?: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let originalMethod: any
if (descriptor.value) {
originalMethod = descriptor.value
descriptor.value = function() {
const context = this as StateMachine<any>
if (states.indexOf(context.state) === -1) {
return originalMethod.apply(context, arguments)
} else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should not be one of ' + states)
}
}
} else if (descriptor.get) {
const originalGetter = descriptor.get
descriptor.get = function() {
const context = this as StateMachine<any>
if (states.indexOf(context.state) === -1) {
return originalGetter.apply(context, arguments)
} else {
throw new Error(message || 'Illegal execution of ' + propertyKey + ' : State should not be one of these states: ' + states)
}
}
}
return descriptor
}
}
/*
Method annotator. Skip the method execution if the state when the method is called
is different from the given state
*/
export function AssumeStateIs(state: State) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
descriptor.value = function() {
const context = this as StateMachine<any>
if (context.state === state) {
originalMethod.apply(context, arguments)
} else {
log.warn('Skipping execution of ' + propertyKey + ' : State should be ' + state + ' but state = ' + context.state)
}
}
return descriptor
}
}
/*
Method annotator. Skip the method execution if the state when the method is called
is the same as the given state
*/
export function AssumeStateIsNot(state: State) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
descriptor.value = function() {
const context = this as StateMachine<any>
if (context.state !== state) {
originalMethod.apply(context, arguments)
} else {
log.warn('Skipping execution of ' + propertyKey + ' : State should be different from ' + state)
}
}
return descriptor
}
}
}
export * from './decorators'
export * from './stateMachine'
export * from './typings'

@@ -17,8 +17,3 @@ {

"allowSyntheticDefaultImports": true,
"lib": [
"es2017",
"es6",
"es5",
"dom"
],
"lib": ["es2017", "es6", "es5", "dom"],
"sourceMap": true,

@@ -30,5 +25,3 @@ "declaration": true,

},
"files": [
"./src/index.ts"
]
"include": ["./src"]
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc