diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..0c75fcf --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,65 @@ +on: + push: + branches: + - main + + pull_request: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: package.json + cache: npm + + # Working around https://github.com/npm/cli/issues/4828 + # - run: npm ci + - run: npm install --no-package-lock + + - name: Check formatting + run: npm run format:check + + - name: Check syntax + run: npm run lint + + - name: Check types + run: npm run typecheck + + - name: Run tests + run: npm test + + - run: npm run build + + publish: + runs-on: ubuntu-latest + if: github.event_name == 'release' + needs: build + + permissions: + contents: read + id-token: write + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: package.json + cache: npm + registry-url: "https://registry.npmjs.org" + + # Working around https://github.com/npm/cli/issues/4828 + # - run: npm ci + - run: npm install --no-package-lock + + - run: npm run build + + - run: npm run npm:publish:dry-run + + - run: npm run npm:publish diff --git a/.gitignore b/.gitignore index 0831864..f7bcf6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .idea -.goose -.goosehints +.bin coverage node_modules diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 6988e2b..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -registry = "https://registry.npmjs.org/" \ No newline at end of file diff --git a/VERSION b/VERSION index 13ca50c..a6a256f 100644 --- a/VERSION +++ b/VERSION @@ -1,13 +1,14 @@ PureMVC Typescript Utility - State Machine -------------------------------------------------------------------------- -Release Date: 4/22/25 +Release Date: 11/25/25 Platform: Typescript Version: 1 Revision: 0 - Minor: 2 + Minor: 3 Authors: Cliff Hall -------------------------------------------------------------------------- 1.0.0 Initial port from the AS3 source. 1.0.1 NPM Package link 1.0.2 Fix entry point in package.json +1.0.3 Add github workflow file for build/publish diff --git a/bin/cjs/fsm/FSMInjector.js b/bin/cjs/fsm/FSMInjector.js deleted file mode 100644 index e63a0df..0000000 --- a/bin/cjs/fsm/FSMInjector.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.FSMInjector = void 0; -const puremvc_typescript_multicore_framework_1 = require("@puremvc/puremvc-typescript-multicore-framework"); -const State_1 = require("./State"); -const StateMachine_1 = require("./StateMachine"); -class FSMInjector extends puremvc_typescript_multicore_framework_1.Notifier { - constructor(multitonKey, fsmConfig) { - super(); - this.stateList = null; - this.initializeNotifier(multitonKey); - this.fsmConfig = fsmConfig; - } - inject() { - const stateMachine = new StateMachine_1.StateMachine(); - stateMachine.initializeNotifier(this.multitonKey); - for (const state of this.states) { - stateMachine.registerState(state, this.isInitial(state.name)); - } - // Register the StateMachine with the facade - this.facade.registerMediator(stateMachine); - return stateMachine; - } - get states() { - if (this.stateList === null) { - this.stateList = []; - for (const stateDef of this.fsmConfig.states) { - const state = this.createState(stateDef); - this.stateList.push(state); - } - } - return this.stateList; - } - createState(stateDef) { - const name = stateDef.name; - const exiting = stateDef.exiting || null; - const entering = stateDef.entering || null; - const changed = stateDef.changed || null; - const state = new State_1.State(name, entering, exiting, changed); - const transitions = stateDef.transitions || []; - for (const transDef of transitions) { - state.defineTransition(transDef.action, transDef.target); - } - return state; - } - isInitial(stateName) { - return stateName === this.fsmConfig.initial; - } -} -exports.FSMInjector = FSMInjector; diff --git a/bin/cjs/fsm/State.js b/bin/cjs/fsm/State.js deleted file mode 100644 index 606ff53..0000000 --- a/bin/cjs/fsm/State.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.State = void 0; -class State { - constructor(name, entering = null, exiting = null, changed = null) { - this.transitions = {}; - this.name = name; - this.entering = entering || null; - this.exiting = exiting || null; - this.changed = changed || null; - } - defineTransition(action, target) { - if (this.getTarget(action) !== undefined) - return; - this.transitions[action] = target; - } - getTarget(action) { - return action ? this.transitions[action] : undefined; - } -} -exports.State = State; diff --git a/bin/cjs/fsm/StateMachine.js b/bin/cjs/fsm/StateMachine.js deleted file mode 100644 index 2b27ee3..0000000 --- a/bin/cjs/fsm/StateMachine.js +++ /dev/null @@ -1,85 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.StateMachine = void 0; -const puremvc_typescript_multicore_framework_1 = require("@puremvc/puremvc-typescript-multicore-framework"); -class StateMachine extends puremvc_typescript_multicore_framework_1.Mediator { - constructor() { - super(StateMachine.NAME); - this.states = {}; - this.initial = null; - this.canceled = false; - this.currentState = null; - } - onRegister() { - if (this.initial) - this.transitionTo(this.initial, null); - } - registerState(state, initial = false) { - if (state === null || this.states[state.name] != null) - return; - this.states[state.name] = state; - if (initial) - this.initial = state; - } - getState(name) { - return this.states[name]; - } - removeState(stateName) { - const state = this.states[stateName]; - if (state === null) - return; - delete this.states[stateName]; - } - transitionTo(nextState, data = null) { - if (nextState === null) - return; - this.canceled = false; - if (this.currentState && this.currentState.exiting) { - this.sendNotification(this.currentState.exiting, data, nextState.name); - } - if (this.canceled) { - this.canceled = false; - return; - } - if (nextState.entering) { - this.sendNotification(nextState.entering, data); - } - if (this.canceled) { - this.canceled = false; - return; - } - this.currentState = nextState; - if (nextState.changed) { - if (this.currentState.changed !== null) { - this.sendNotification(this.currentState.changed, data); - } - } - this.sendNotification(StateMachine.CHANGED, this.currentState, this.currentState.name); - } - listNotificationInterests() { - return [StateMachine.ACTION, StateMachine.CANCEL]; - } - handleNotification(note) { - var _a; - switch (note.name) { - case StateMachine.ACTION: - const action = note.type; - const target = (_a = this.currentState) === null || _a === void 0 ? void 0 : _a.getTarget(action); - const newState = this.states[target]; - if (newState) - this.transitionTo(newState, note.body); - break; - case StateMachine.CANCEL: - this.canceled = true; - break; - } - } - get viewComponent() { - return this.currentState; - } -} -exports.StateMachine = StateMachine; -StateMachine.NAME = "StateMachine"; -StateMachine.ACTION = StateMachine.NAME + "/notes/action"; -StateMachine.CHANGED = StateMachine.NAME + "/notes/changed"; -StateMachine.CANCEL = StateMachine.NAME + "/notes/cancel"; diff --git a/bin/cjs/index.js b/bin/cjs/index.js deleted file mode 100644 index 01b1a8a..0000000 --- a/bin/cjs/index.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.State = exports.FSMInjector = exports.StateMachine = void 0; -var StateMachine_1 = require("./fsm/StateMachine"); -Object.defineProperty(exports, "StateMachine", { enumerable: true, get: function () { return StateMachine_1.StateMachine; } }); -var FSMInjector_1 = require("./fsm/FSMInjector"); -Object.defineProperty(exports, "FSMInjector", { enumerable: true, get: function () { return FSMInjector_1.FSMInjector; } }); -var State_1 = require("./fsm/State"); -Object.defineProperty(exports, "State", { enumerable: true, get: function () { return State_1.State; } }); diff --git a/bin/cjs/package.json b/bin/cjs/package.json deleted file mode 100644 index b731bd6..0000000 --- a/bin/cjs/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "commonjs"} diff --git a/bin/cjs/types.js b/bin/cjs/types.js deleted file mode 100644 index c8ad2e5..0000000 --- a/bin/cjs/types.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/bin/esm/fsm/FSMInjector.js b/bin/esm/fsm/FSMInjector.js deleted file mode 100644 index 9849cf7..0000000 --- a/bin/esm/fsm/FSMInjector.js +++ /dev/null @@ -1,46 +0,0 @@ -import { Notifier, } from "@puremvc/puremvc-typescript-multicore-framework"; -import { State } from "./State"; -import { StateMachine } from "./StateMachine"; -export class FSMInjector extends Notifier { - constructor(multitonKey, fsmConfig) { - super(); - this.stateList = null; - this.initializeNotifier(multitonKey); - this.fsmConfig = fsmConfig; - } - inject() { - const stateMachine = new StateMachine(); - stateMachine.initializeNotifier(this.multitonKey); - for (const state of this.states) { - stateMachine.registerState(state, this.isInitial(state.name)); - } - // Register the StateMachine with the facade - this.facade.registerMediator(stateMachine); - return stateMachine; - } - get states() { - if (this.stateList === null) { - this.stateList = []; - for (const stateDef of this.fsmConfig.states) { - const state = this.createState(stateDef); - this.stateList.push(state); - } - } - return this.stateList; - } - createState(stateDef) { - const name = stateDef.name; - const exiting = stateDef.exiting || null; - const entering = stateDef.entering || null; - const changed = stateDef.changed || null; - const state = new State(name, entering, exiting, changed); - const transitions = stateDef.transitions || []; - for (const transDef of transitions) { - state.defineTransition(transDef.action, transDef.target); - } - return state; - } - isInitial(stateName) { - return stateName === this.fsmConfig.initial; - } -} diff --git a/bin/esm/fsm/State.js b/bin/esm/fsm/State.js deleted file mode 100644 index 7b44f25..0000000 --- a/bin/esm/fsm/State.js +++ /dev/null @@ -1,17 +0,0 @@ -export class State { - constructor(name, entering = null, exiting = null, changed = null) { - this.transitions = {}; - this.name = name; - this.entering = entering || null; - this.exiting = exiting || null; - this.changed = changed || null; - } - defineTransition(action, target) { - if (this.getTarget(action) !== undefined) - return; - this.transitions[action] = target; - } - getTarget(action) { - return action ? this.transitions[action] : undefined; - } -} diff --git a/bin/esm/fsm/StateMachine.js b/bin/esm/fsm/StateMachine.js deleted file mode 100644 index b83f5a9..0000000 --- a/bin/esm/fsm/StateMachine.js +++ /dev/null @@ -1,81 +0,0 @@ -import { Mediator, } from "@puremvc/puremvc-typescript-multicore-framework"; -export class StateMachine extends Mediator { - constructor() { - super(StateMachine.NAME); - this.states = {}; - this.initial = null; - this.canceled = false; - this.currentState = null; - } - onRegister() { - if (this.initial) - this.transitionTo(this.initial, null); - } - registerState(state, initial = false) { - if (state === null || this.states[state.name] != null) - return; - this.states[state.name] = state; - if (initial) - this.initial = state; - } - getState(name) { - return this.states[name]; - } - removeState(stateName) { - const state = this.states[stateName]; - if (state === null) - return; - delete this.states[stateName]; - } - transitionTo(nextState, data = null) { - if (nextState === null) - return; - this.canceled = false; - if (this.currentState && this.currentState.exiting) { - this.sendNotification(this.currentState.exiting, data, nextState.name); - } - if (this.canceled) { - this.canceled = false; - return; - } - if (nextState.entering) { - this.sendNotification(nextState.entering, data); - } - if (this.canceled) { - this.canceled = false; - return; - } - this.currentState = nextState; - if (nextState.changed) { - if (this.currentState.changed !== null) { - this.sendNotification(this.currentState.changed, data); - } - } - this.sendNotification(StateMachine.CHANGED, this.currentState, this.currentState.name); - } - listNotificationInterests() { - return [StateMachine.ACTION, StateMachine.CANCEL]; - } - handleNotification(note) { - var _a; - switch (note.name) { - case StateMachine.ACTION: - const action = note.type; - const target = (_a = this.currentState) === null || _a === void 0 ? void 0 : _a.getTarget(action); - const newState = this.states[target]; - if (newState) - this.transitionTo(newState, note.body); - break; - case StateMachine.CANCEL: - this.canceled = true; - break; - } - } - get viewComponent() { - return this.currentState; - } -} -StateMachine.NAME = "StateMachine"; -StateMachine.ACTION = StateMachine.NAME + "/notes/action"; -StateMachine.CHANGED = StateMachine.NAME + "/notes/changed"; -StateMachine.CANCEL = StateMachine.NAME + "/notes/cancel"; diff --git a/bin/esm/index.js b/bin/esm/index.js deleted file mode 100644 index c7ec70a..0000000 --- a/bin/esm/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { StateMachine } from "./fsm/StateMachine"; -export { FSMInjector } from "./fsm/FSMInjector"; -export { State } from "./fsm/State"; diff --git a/bin/esm/package.json b/bin/esm/package.json deleted file mode 100644 index 6990891..0000000 --- a/bin/esm/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "module"} diff --git a/bin/esm/types.js b/bin/esm/types.js deleted file mode 100644 index cb0ff5c..0000000 --- a/bin/esm/types.js +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/bin/types/fsm/FSMInjector.d.ts b/bin/types/fsm/FSMInjector.d.ts deleted file mode 100644 index b3b38bb..0000000 --- a/bin/types/fsm/FSMInjector.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Notifier } from "@puremvc/puremvc-typescript-multicore-framework"; -import { State } from "./State"; -import { StateMachine } from "./StateMachine"; -import { FSM, StateDef } from "../types"; -export declare class FSMInjector extends Notifier { - private fsmConfig; - private stateList; - constructor(multitonKey: string, fsmConfig: FSM); - inject(): StateMachine; - protected get states(): State[]; - protected createState(stateDef: StateDef): State; - protected isInitial(stateName: string): boolean; -} diff --git a/bin/types/fsm/State.d.ts b/bin/types/fsm/State.d.ts deleted file mode 100644 index ecca11e..0000000 --- a/bin/types/fsm/State.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -export declare class State { - name: string; - entering: string | null; - exiting: string | null; - changed: string | null; - protected transitions: { - [action: string]: string | undefined; - }; - constructor(name: string, entering?: string | null, exiting?: string | null, changed?: string | null); - defineTransition(action: string, target: string): void; - getTarget(action: string | undefined): string | undefined; -} diff --git a/bin/types/fsm/StateMachine.d.ts b/bin/types/fsm/StateMachine.d.ts deleted file mode 100644 index 0b90a02..0000000 --- a/bin/types/fsm/StateMachine.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Mediator, INotification } from "@puremvc/puremvc-typescript-multicore-framework"; -import { State } from "./State"; -export declare class StateMachine extends Mediator { - static NAME: string; - static ACTION: string; - static CHANGED: string; - static CANCEL: string; - protected states: { - [name: string]: State; - }; - protected initial: State | null; - protected canceled: boolean; - protected currentState: State | null; - constructor(); - onRegister(): void; - registerState(state: State, initial?: boolean): void; - getState(name: string): State | undefined; - removeState(stateName: string): void; - protected transitionTo(nextState: State, data?: unknown): void; - listNotificationInterests(): string[]; - handleNotification(note: INotification): void; - get viewComponent(): State | null; -} diff --git a/bin/types/index.d.ts b/bin/types/index.d.ts deleted file mode 100644 index c80048f..0000000 --- a/bin/types/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { FSM, StateDef, Transition } from "./types"; -export { StateMachine } from "./fsm/StateMachine"; -export { FSMInjector } from "./fsm/FSMInjector"; -export { State } from "./fsm/State"; diff --git a/bin/types/types.d.ts b/bin/types/types.d.ts deleted file mode 100644 index 573ab19..0000000 --- a/bin/types/types.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type Transition = { - action: string; - target: string; -}; -export type StateDef = { - name: string; - entering?: string; - exiting?: string; - changed?: string; - transitions?: Transition[]; -}; -export type FSM = { - initial: string; - states: StateDef[]; -}; diff --git a/docs/classes/FSMInjector.html b/docs/classes/FSMInjector.html index 092f6c1..fe39a7e 100644 --- a/docs/classes/FSMInjector.html +++ b/docs/classes/FSMInjector.html @@ -1,4 +1,4 @@ -FSMInjector | @puremvc/puremvc-typescript-util-state-machine

Hierarchy

  • Notifier
    • FSMInjector

Constructors

constructor +FSMInjector | @puremvc/puremvc-typescript-util-state-machine

Hierarchy

  • Notifier
    • FSMInjector

Constructors

Properties

Accessors

Constructors

Properties

multitonKey: string

The Multiton Key for this app

+

Constructors

Properties

multitonKey: string

The Multiton Key for this app

MULTITON_MSG: string

Message Constants

Accessors

  • get facade(): IFacade

    Return the Multiton Facade instance

    Returns IFacade

    The facade instance.

    If the multiton key is not initialized.

    -

Methods

  • Initialize this Notifier instance.

    +

Methods

  • Initialize this Notifier instance.

    This is how a Notifier gets its multitonKey. Calls to sendNotification or to access the facade will fail until after this method @@ -25,7 +25,7 @@ in their constructors, since this method will not yet have been called.

    Parameters

    • key: string

      the multitonKey for this Notifier to use

      -

    Returns void

  • Create and send an Notification.

    +

Returns void

+

Returns void

diff --git a/docs/types/FSM.html b/docs/types/FSM.html index 7c265b4..2ab585c 100644 --- a/docs/types/FSM.html +++ b/docs/types/FSM.html @@ -1 +1 @@ -FSM | @puremvc/puremvc-typescript-util-state-machine
FSM: { initial: string; states: StateDef[] }

Type declaration

+FSM | @puremvc/puremvc-typescript-util-state-machine
FSM: { initial: string; states: StateDef[] }

Type declaration

diff --git a/docs/types/StateDef.html b/docs/types/StateDef.html index 4a421b7..c29a291 100644 --- a/docs/types/StateDef.html +++ b/docs/types/StateDef.html @@ -1 +1 @@ -StateDef | @puremvc/puremvc-typescript-util-state-machine
StateDef: {
    changed?: string;
    entering?: string;
    exiting?: string;
    name: string;
    transitions?: Transition[];
}

Type declaration

  • Optionalchanged?: string
  • Optionalentering?: string
  • Optionalexiting?: string
  • name: string
  • Optionaltransitions?: Transition[]
+StateDef | @puremvc/puremvc-typescript-util-state-machine
StateDef: {
    changed?: string;
    entering?: string;
    exiting?: string;
    name: string;
    transitions?: Transition[];
}

Type declaration

  • Optionalchanged?: string
  • Optionalentering?: string
  • Optionalexiting?: string
  • name: string
  • Optionaltransitions?: Transition[]
diff --git a/docs/types/Transition.html b/docs/types/Transition.html index 4c2e83f..d74c251 100644 --- a/docs/types/Transition.html +++ b/docs/types/Transition.html @@ -1 +1 @@ -Transition | @puremvc/puremvc-typescript-util-state-machine
Transition: { action: string; target: string }

Type declaration

  • action: string
  • target: string
+Transition | @puremvc/puremvc-typescript-util-state-machine
Transition: { action: string; target: string }

Type declaration

  • action: string
  • target: string
diff --git a/package.json b/package.json index 43803ea..3328ead 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@puremvc/puremvc-typescript-util-state-machine", - "version": "1.0.2", + "version": "1.0.3", "description": "PureMVC State Machine Utility for TypeScript", "main": "./bin/cjs/index.js", "module": "./bin/esm/index.js", @@ -27,18 +27,18 @@ "scripts": { "build": "npm run clean && npm run build:lib && npm run build:doc", "test": "jest --coverage", - "lint": "eslint ./src", - "lint:fix": "eslint ./src --fix", - "format": "prettier --write ./src", + "lint": "eslint ./src ./test", + "lint:fix": "eslint ./src ./test --fix", + "typecheck": "tsc --noEmit -p tsconfig.json --composite false", + "format:check": "prettier --check ./src ./test", + "format:fix": "prettier --write ./src ./test", "npm:publish:dry-run": "npm publish --dry-run", "npm:publish": "npm publish --access public", - "typecheck": "tsc --noEmit -p tsconfig.json --composite false", "build:lib": "npm run build:cjs && npm run build:esm", "build:esm": "tsc --module esnext --outDir bin/esm && echo '{\"type\": \"module\"}' > bin/esm/package.json && rm -rf bin/esm/interfaces", "build:cjs": "tsc --module commonjs --outDir bin/cjs && echo '{\"type\": \"commonjs\"}' > bin/cjs/package.json && rm -rf bin/cjs/interfaces", "build:doc": "typedoc", "clean": "rm -rf bin" - }, "nyc": { "extension": [ diff --git a/test/FSMInjector.test.ts b/test/FSMInjector.test.ts index d6dc22b..8627c70 100644 --- a/test/FSMInjector.test.ts +++ b/test/FSMInjector.test.ts @@ -1,59 +1,58 @@ -import { FSMInjector, FSM, StateMachine} from '../src'; +import { FSMInjector, FSM, StateMachine } from "../src"; -const fsmConfig:FSM = { - initial: "Closed", - states: [ +const fsmConfig: FSM = { + initial: "Closed", + states: [ + { + name: "Closed", + transitions: [ { - name: "Closed", - transitions: [ - { - action: "Open", - target: "Opened", - }, - { - action: "Lock", - target: "Locked", - } - ] + action: "Open", + target: "Opened", }, { - name: "Opened", - transitions: [ - { - action: "Close", - target: "Closed", - } - ] + action: "Lock", + target: "Locked", }, + ], + }, + { + name: "Opened", + transitions: [ { - name: "Locked", - transitions: [ - { - action: "Unlock", - target: "Closed", - }, - { - action: "KickIn", - target: "KickedIn", - }, - ] + action: "Close", + target: "Closed", }, + ], + }, + { + name: "Locked", + transitions: [ { - name: "KickedIn" + action: "Unlock", + target: "Closed", }, - ] + { + action: "KickIn", + target: "KickedIn", + }, + ], + }, + { + name: "KickedIn", + }, + ], }; -describe('FSMInjector', () => { - test('should create an FSMInjector instance', () => { - const fsmInjector = new FSMInjector("Test", fsmConfig); - expect(fsmInjector).toBeInstanceOf(FSMInjector); - }); - - test('should inject a state machine from configuration', () => { - const fsmInjector = new FSMInjector("FSM_Unit_Tests", fsmConfig); - const stateMachine = fsmInjector.inject(); - expect(stateMachine.name).toBe(StateMachine.NAME); - }); +describe("FSMInjector", () => { + test("should create an FSMInjector instance", () => { + const fsmInjector = new FSMInjector("Test", fsmConfig); + expect(fsmInjector).toBeInstanceOf(FSMInjector); + }); + test("should inject a state machine from configuration", () => { + const fsmInjector = new FSMInjector("FSM_Unit_Tests", fsmConfig); + const stateMachine = fsmInjector.inject(); + expect(stateMachine.name).toBe(StateMachine.NAME); + }); }); diff --git a/test/State.test.ts b/test/State.test.ts index 01539f7..c715c7a 100644 --- a/test/State.test.ts +++ b/test/State.test.ts @@ -1,28 +1,48 @@ -import { State } from '../src'; +import { State } from "../src"; -describe('State', () => { - test('should create a State instance with minimal constructor args', () => { - const state = new State("Waiting"); - expect(state).toBeInstanceOf(State); - }); - test('should create a State instance with all constructor args', () => { - const state = new State("Waiting", "enteringWaiting", "exitingWaiting", "changedToWaiting"); - expect(state).toBeInstanceOf(State); - }); - test('should define a transition' , () => { - const state = new State("Waiting", "enteringWaiting", "exitingWaiting", "changedToWaiting"); - state.defineTransition('exit', 'Doing'); - expect(state.getTarget('exit')).toEqual('Doing'); - }); - test('should not replace a transition that is already defined' , () => { - const state = new State("Waiting", "enteringWaiting", "exitingWaiting", "changedToWaiting"); - state.defineTransition('exit', 'Doing'); - state.defineTransition('exit', 'Loitering'); - expect(state.getTarget('exit')).toEqual('Doing'); - }); - test('should not replace a transition that is already defined' , () => { - const state = new State("Waiting", "enteringWaiting", "exitingWaiting", "changedToWaiting"); +describe("State", () => { + test("should create a State instance with minimal constructor args", () => { + const state = new State("Waiting"); + expect(state).toBeInstanceOf(State); + }); + test("should create a State instance with all constructor args", () => { + const state = new State( + "Waiting", + "enteringWaiting", + "exitingWaiting", + "changedToWaiting", + ); + expect(state).toBeInstanceOf(State); + }); + test("should define a transition", () => { + const state = new State( + "Waiting", + "enteringWaiting", + "exitingWaiting", + "changedToWaiting", + ); + state.defineTransition("exit", "Doing"); + expect(state.getTarget("exit")).toEqual("Doing"); + }); + test("should not replace a transition that is already defined", () => { + const state = new State( + "Waiting", + "enteringWaiting", + "exitingWaiting", + "changedToWaiting", + ); + state.defineTransition("exit", "Doing"); + state.defineTransition("exit", "Loitering"); + expect(state.getTarget("exit")).toEqual("Doing"); + }); + test("should not replace a transition that is already defined", () => { + const state = new State( + "Waiting", + "enteringWaiting", + "exitingWaiting", + "changedToWaiting", + ); - expect(state.getTarget('')).toEqual(undefined); - }); + expect(state.getTarget("")).toEqual(undefined); + }); }); diff --git a/test/StateMachine.test.ts b/test/StateMachine.test.ts index d936c14..e499c6f 100644 --- a/test/StateMachine.test.ts +++ b/test/StateMachine.test.ts @@ -1,111 +1,108 @@ -import {FSM, FSMInjector, State, StateMachine} from '../src'; -import {Notification} from "@puremvc/puremvc-typescript-multicore-framework"; +import { FSM, FSMInjector, State, StateMachine } from "../src"; +import { Notification } from "@puremvc/puremvc-typescript-multicore-framework"; const fsmConfig: FSM = { - initial: "Closed", - states: [ + initial: "Closed", + states: [ + { + name: "Closed", + transitions: [ { - name: "Closed", - transitions: [ - { - action: "Open", - target: "Opened", - }, - { - action: "Lock", - target: "Locked", - } - ], - exiting: "leaveClosed" + action: "Open", + target: "Opened", }, { - name: "Opened", - transitions: [ - { - action: "Close", - target: "Closed", - } - ], - entering: "enteringClosed", - changed: "doorIsClosed" + action: "Lock", + target: "Locked", }, + ], + exiting: "leaveClosed", + }, + { + name: "Opened", + transitions: [ { - name: "Locked", - transitions: [ - { - action: "Unlock", - target: "Closed", - }, - { - action: "KickIn", - target: "KickedIn", - }, - ] + action: "Close", + target: "Closed", }, + ], + entering: "enteringClosed", + changed: "doorIsClosed", + }, + { + name: "Locked", + transitions: [ { - name: "KickedIn" + action: "Unlock", + target: "Closed", }, - ] + { + action: "KickIn", + target: "KickedIn", + }, + ], + }, + { + name: "KickedIn", + }, + ], }; const multitonKey: string = "FSM_Unit_Tests"; -const testState: () => State = () => new State("Waiting", "enteringWaiting", "exitingWaiting", "changedToWaiting"); - -describe('StateMachine', () => { - test('should create a StateMachine instance', () => { - const stateMachine = new StateMachine(); - expect(stateMachine).toBeInstanceOf(StateMachine); - }); - - test('should register a state', () => { - const stateMachine = new StateMachine(); - const state = testState(); - stateMachine.registerState(state); - expect(stateMachine.getState("Waiting")).toBeInstanceOf(State); - expect(stateMachine.getState("Waiting")).toBe(state); - }); - - test('should remove a state', () => { - const stateMachine = new StateMachine(); - const state = testState(); - stateMachine.registerState(state); - stateMachine.removeState("Waiting"); - expect(stateMachine.getState("Waiting")).toBe(undefined); - }); - - test('should transition to initial state on registration', () => { - const fsmInjector = new FSMInjector(multitonKey, fsmConfig); - const stateMachine = fsmInjector.inject(); - stateMachine.onRegister(); - expect(stateMachine.viewComponent).toBeInstanceOf(State); - expect(stateMachine.viewComponent?.name).toBe("Closed"); - }); +const testState: () => State = () => + new State("Waiting", "enteringWaiting", "exitingWaiting", "changedToWaiting"); - test('should transition state on valid ACTION note', () => { - const fsmInjector = new FSMInjector(multitonKey, fsmConfig); - const stateMachine = fsmInjector.inject(); - stateMachine.onRegister(); +describe("StateMachine", () => { + test("should create a StateMachine instance", () => { + const stateMachine = new StateMachine(); + expect(stateMachine).toBeInstanceOf(StateMachine); + }); - // Try a valid action - const action = new Notification(StateMachine.ACTION, "", "Open"); - stateMachine.handleNotification(action); + test("should register a state", () => { + const stateMachine = new StateMachine(); + const state = testState(); + stateMachine.registerState(state); + expect(stateMachine.getState("Waiting")).toBeInstanceOf(State); + expect(stateMachine.getState("Waiting")).toBe(state); + }); - expect(stateMachine.viewComponent).toBeInstanceOf(State); - expect(stateMachine.viewComponent?.name).toBe("Opened"); - }); + test("should remove a state", () => { + const stateMachine = new StateMachine(); + const state = testState(); + stateMachine.registerState(state); + stateMachine.removeState("Waiting"); + expect(stateMachine.getState("Waiting")).toBe(undefined); + }); - test('should not transition state on invalid ACTION note', () => { - const fsmInjector = new FSMInjector(multitonKey, fsmConfig); - const stateMachine = fsmInjector.inject(); - stateMachine.onRegister(); + test("should transition to initial state on registration", () => { + const fsmInjector = new FSMInjector(multitonKey, fsmConfig); + const stateMachine = fsmInjector.inject(); + stateMachine.onRegister(); + expect(stateMachine.viewComponent).toBeInstanceOf(State); + expect(stateMachine.viewComponent?.name).toBe("Closed"); + }); - // Try an invalid action - const action = new Notification(StateMachine.ACTION, "", "Zork"); - stateMachine.handleNotification(action); + test("should transition state on valid ACTION note", () => { + const fsmInjector = new FSMInjector(multitonKey, fsmConfig); + const stateMachine = fsmInjector.inject(); + stateMachine.onRegister(); - expect(stateMachine.viewComponent?.name).toBe("Closed"); - }); + // Try a valid action + const action = new Notification(StateMachine.ACTION, "", "Open"); + stateMachine.handleNotification(action); + expect(stateMachine.viewComponent).toBeInstanceOf(State); + expect(stateMachine.viewComponent?.name).toBe("Opened"); + }); + test("should not transition state on invalid ACTION note", () => { + const fsmInjector = new FSMInjector(multitonKey, fsmConfig); + const stateMachine = fsmInjector.inject(); + stateMachine.onRegister(); + // Try an invalid action + const action = new Notification(StateMachine.ACTION, "", "Zork"); + stateMachine.handleNotification(action); + expect(stateMachine.viewComponent?.name).toBe("Closed"); + }); }); diff --git a/test/index.test.ts b/test/index.test.ts index fbb8ced..75dccdb 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,10 +1,10 @@ -import * as index from '../src'; +import * as index from "../src"; -describe('Index Module', () => { - test('should export expected components', () => { - expect(index).toBeDefined(); - expect(index.StateMachine).toBeDefined(); - expect(index.FSMInjector).toBeDefined(); - expect(index.State).toBeDefined(); - }); +describe("Index Module", () => { + test("should export expected components", () => { + expect(index).toBeDefined(); + expect(index.StateMachine).toBeDefined(); + expect(index.FSMInjector).toBeDefined(); + expect(index.State).toBeDefined(); + }); });