@vsirotin/ts-stop 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +173 -0
  2. package/lib/DefaultState.d.ts +9 -0
  3. package/lib/DefaultState.d.ts.map +1 -0
  4. package/lib/DefaultState.js +15 -0
  5. package/lib/DefaultState.js.map +1 -0
  6. package/lib/FiniteStateMachine.d.ts +222 -0
  7. package/lib/FiniteStateMachine.d.ts.map +1 -0
  8. package/lib/FiniteStateMachine.js +302 -0
  9. package/lib/FiniteStateMachine.js.map +1 -0
  10. package/lib/IStateWithActions.d.ts +18 -0
  11. package/lib/IStateWithActions.d.ts.map +1 -0
  12. package/lib/IStateWithActions.js +3 -0
  13. package/lib/IStateWithActions.js.map +1 -0
  14. package/lib/IStateWithOutputSignal.d.ts +4 -0
  15. package/lib/IStateWithOutputSignal.d.ts.map +1 -0
  16. package/lib/IStateWithOutputSignal.js +3 -0
  17. package/lib/IStateWithOutputSignal.js.map +1 -0
  18. package/lib/MatrixBasedStateMachine.d.ts +108 -0
  19. package/lib/MatrixBasedStateMachine.d.ts.map +1 -0
  20. package/lib/MatrixBasedStateMachine.js +132 -0
  21. package/lib/MatrixBasedStateMachine.js.map +1 -0
  22. package/lib/TransitionMatrix.d.ts +61 -0
  23. package/lib/TransitionMatrix.d.ts.map +1 -0
  24. package/lib/TransitionMatrix.js +104 -0
  25. package/lib/TransitionMatrix.js.map +1 -0
  26. package/lib/esm/DefaultState.js +10 -0
  27. package/lib/esm/FiniteStateMachine.js +297 -0
  28. package/lib/esm/IStateWithActions.js +1 -0
  29. package/lib/esm/IStateWithOutputSignal.js +1 -0
  30. package/lib/esm/MatrixBasedStateMachine.js +127 -0
  31. package/lib/esm/TransitionMatrix.js +98 -0
  32. package/lib/esm/index.js +9 -0
  33. package/lib/index.d.ts +10 -0
  34. package/lib/index.d.ts.map +1 -0
  35. package/lib/index.js +26 -0
  36. package/lib/index.js.map +1 -0
  37. package/package.json +45 -0
package/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # @vsirotin/ts-stop
2
+
3
+ State Oriented Programming library for TypeScript.
4
+
5
+ DEvelopment in progress.
6
+
7
+ ## Installation
8
+
9
+ ### From NPM (when published)
10
+ ```bash
11
+ npm install @vsirotin/ts-stop
12
+ ```
13
+
14
+ ### Local Installation for Another Project
15
+
16
+ If you want to use this package in another project without publishing to NPM:
17
+
18
+ #### Step 1: Build and Pack the Library
19
+ ```bash
20
+ # In the ts-stop directory
21
+ cd /path/to/StOP/ts/ts-stop
22
+ npm run build
23
+ npm pack
24
+ ```
25
+
26
+ This creates a file `vsirotin-ts-stop-<version>.tgz` in the ts-stop directory.
27
+
28
+ #### Step 2: Install in Your Project
29
+
30
+ Choose one of these methods:
31
+
32
+ **Method 1: Install from Tarball (Recommended)**
33
+ ```bash
34
+ # In your project directory
35
+ npm install /Users/viktorsirotin/VSCodeProjects/StOP/ts/ts-stop/vsirotin-ts-stop-0.0.1.tgz
36
+ ```
37
+
38
+ **Method 2: Install from Directory**
39
+ ```bash
40
+ # In your project directory
41
+ npm install /path/to/StOP/ts/ts-stop
42
+ ```
43
+
44
+ **Method 3: Add to package.json**
45
+ ```json
46
+ {
47
+ "dependencies": {
48
+ "@vsirotin/ts-stop": "file:/path/to/StOP/ts/ts-stop"
49
+ }
50
+ }
51
+ ```
52
+ Then run `npm install`.
53
+
54
+ #### Step 3: Update After Changes
55
+
56
+ When you make changes to the ts-stop library:
57
+
58
+ ```bash
59
+ # In the ts-stop directory
60
+ npm run build
61
+ npm pack
62
+
63
+ # In your project directory
64
+ npm install /path/to/StOP/ts/ts-stop/vsirotin-ts-stop-0.0.1.tgz --force
65
+ ```
66
+
67
+ Or if using Method 2 or 3:
68
+ ```bash
69
+ # In your project directory
70
+ npm install --force
71
+ ```
72
+
73
+ ## Usage
74
+
75
+ ```typescript
76
+ import { FiniteStateMachine, DefaultState } from '@vsirotin/ts-stop';
77
+
78
+ // Example: Simple State Machine
79
+ const states = [/* your states */];
80
+ const signals = [/* your signals */];
81
+ const transitions = [/* your transitions */];
82
+ const startState = states[0];
83
+
84
+ const machine = new FiniteStateMachine(
85
+ states,
86
+ signals,
87
+ transitions,
88
+ startState
89
+ );
90
+
91
+ // Process signals
92
+ machine.processSignal(someSignal);
93
+ ```
94
+
95
+ ## Development
96
+
97
+ ### Build
98
+ ```bash
99
+ npm run build # Build both CommonJS and ESM versions
100
+ npm run build:cjs # Build CommonJS version only
101
+ npm run build:esm # Build ESM version only
102
+ ```
103
+
104
+ ### Test
105
+ ```bash
106
+ npm test # Run tests
107
+ npm run test:coverage # Run tests with coverage
108
+ ```
109
+
110
+ ### Clean
111
+ ```bash
112
+ npm run clean # Remove build artifacts
113
+ ```
114
+
115
+ ### Package
116
+ ```bash
117
+ npm run pack # Build and create tarball for distribution
118
+ ```
119
+
120
+ ## Package Structure
121
+
122
+ After building, the package contains:
123
+
124
+ ```
125
+ lib/
126
+ ├── index.js # CommonJS entry point
127
+ ├── index.d.ts # TypeScript declarations
128
+ ├── index.d.ts.map # TypeScript declaration source map
129
+ ├── index.js.map # JavaScript source map
130
+ ├── esm/ # ES Modules
131
+ │ └── index.js # ESM entry point
132
+ └── [other modules with .js, .d.ts, and .map files]
133
+ ```
134
+
135
+ The package includes:
136
+ - **CommonJS** modules in `lib/` for Node.js compatibility
137
+ - **ESM** (ES Modules) in `lib/esm/` for modern JavaScript
138
+ - **TypeScript declarations** (`.d.ts`) for type checking
139
+ - **Source maps** for debugging
140
+
141
+ ## Using the Package Locally
142
+
143
+ To use this package in another project without publishing to NPM:
144
+
145
+ ### Method 1: Direct Installation
146
+ ```bash
147
+ # From your target project directory
148
+ npm install /path/to/StOP/ts/ts-stop
149
+ ```
150
+
151
+ ### Method 2: Using the Packed Tarball
152
+ ```bash
153
+ # In ts-stop directory
154
+ npm run pack
155
+
156
+ # In your target project directory
157
+ npm install /path/to/StOP/ts/ts-stop/vsirotin-ts-stop-0.0.1.tgz
158
+ ```
159
+
160
+ ### Method 3: Using package.json
161
+ In your target project's `package.json`:
162
+ ```json
163
+ {
164
+ "dependencies": {
165
+ "@vsirotin/ts-stop": "file:../StOP/ts/ts-stop"
166
+ }
167
+ }
168
+ ```
169
+ Then run `npm install`.
170
+
171
+ ## License
172
+
173
+ MIT
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Marker base class for states that should be used processed by invalid signals and
3
+ * in situation, then no transitions set for pair (current signal, current state).
4
+ * Only one state in a state machine can have this role.
5
+ */
6
+ export declare abstract class DefaultState {
7
+ isDefaultState(): boolean;
8
+ }
9
+ //# sourceMappingURL=DefaultState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultState.d.ts","sourceRoot":"","sources":["../src/DefaultState.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,8BAAsB,YAAY;IAC9B,cAAc,IAAI,OAAO;CAG5B"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultState = void 0;
4
+ /**
5
+ * Marker base class for states that should be used processed by invalid signals and
6
+ * in situation, then no transitions set for pair (current signal, current state).
7
+ * Only one state in a state machine can have this role.
8
+ */
9
+ class DefaultState {
10
+ isDefaultState() {
11
+ return true;
12
+ }
13
+ }
14
+ exports.DefaultState = DefaultState;
15
+ //# sourceMappingURL=DefaultState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultState.js","sourceRoot":"","sources":["../src/DefaultState.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,MAAsB,YAAY;IAC9B,cAAc;QACV,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AAJD,oCAIC"}
@@ -0,0 +1,222 @@
1
+ import { DefaultState } from './DefaultState';
2
+ import { IStateWithAfterEntryAction, IStateWithBeforeExitAction } from './IStateWithActions';
3
+ /**
4
+ * Represents a transition in a finite state machine.
5
+ *
6
+ * @template STATE - The type representing possible states
7
+ * @template SIGNAL - The type representing signals/events
8
+ */
9
+ export interface ITransition<STATE, SIGNAL> {
10
+ from: STATE;
11
+ signal: SIGNAL;
12
+ to: STATE;
13
+ }
14
+ /**
15
+ * Interface defining the contract for a finite state machine.
16
+ *
17
+ * @template STATE - The type representing possible states in the state machine
18
+ * @template SIGNAL - The type representing signals/events that trigger state transitions
19
+ */
20
+ export interface IFiniteStateMachine<STATE> {
21
+ /**
22
+ * Gets the current state of the state machine.
23
+ *
24
+ * @returns The current state
25
+ */
26
+ getCurrentState(): STATE;
27
+ }
28
+ /**
29
+ * Concrete implementation of a finite state machine with optional state actions.
30
+ *
31
+ * This class supports states that can optionally implement action interfaces:
32
+ * - IStateWithAfterEntryAction: Execute action when entering the state
33
+ * - IStateWithBeforeExitAction: Execute action when exiting the state
34
+ * - Both interfaces: Execute both entry and exit actions
35
+ * - Neither interface: Traditional state machine behavior (no actions)
36
+ *
37
+ * @template STATE - The type representing possible states
38
+ * @template SIGNAL - The type representing signals/events
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // Basic string-based turnstile (traditional approach)
43
+ * class Turnstile extends FiniteStateMachine<string, string> {
44
+ * constructor() {
45
+ * super(
46
+ * ['locked', 'unlocked'],
47
+ * ['coin', 'push'],
48
+ * [
49
+ * { from: 'locked', signal: 'coin', to: 'unlocked' },
50
+ * { from: 'unlocked', signal: 'push', to: 'locked' }
51
+ * ],
52
+ * 'locked'
53
+ * );
54
+ * }
55
+ *
56
+ * ...
57
+ * }
58
+ *
59
+
60
+ *
61
+ * class TurnstileWithActions extends FiniteStateMachine<ActionState, string> {
62
+ * private locked = new ActionState('locked', 'Payment required');
63
+ * private unlocked = new ActionState('unlocked', 'Please proceed');
64
+ *
65
+ * constructor() {
66
+ * super(
67
+ * [this.locked, this.unlocked],
68
+ * ['coin', 'push'],
69
+ * [
70
+ * { from: this.locked, signal: 'coin', to: this.unlocked },
71
+ * { from: this.unlocked, signal: 'push', to: this.locked }
72
+ * ],
73
+ * this.locked
74
+ * );
75
+ * }
76
+ *
77
+ * insertCoin(): ActionState { return this.sendSignal('coin'); }
78
+ * pushThrough(): ActionState { return this.sendSignal('push'); }
79
+ * }
80
+ *
81
+ * ```
82
+ */
83
+ export declare abstract class FiniteStateMachine<STATE, SIGNAL> implements IFiniteStateMachine<STATE> {
84
+ protected states: STATE[];
85
+ protected signals: SIGNAL[];
86
+ protected transitions: ITransition<STATE, SIGNAL>[];
87
+ protected startState: STATE;
88
+ /**
89
+ * The current state of the state machine.
90
+ * Protected to allow subclass access while maintaining encapsulation.
91
+ */
92
+ protected currentState: STATE;
93
+ /**
94
+ * The default state that handles invalid signals.
95
+ * Set to null if no state implements IDefaultState.
96
+ */
97
+ private defaultState;
98
+ /**
99
+ * Creates a new finite state machine.
100
+ *
101
+ * @param states - Array of all possible states
102
+ * @param signals - Array of all possible signals/events
103
+ * @param transitions - Array of transition rules defining how signals move between states
104
+ * @param startState - The initial state of the machine
105
+ */
106
+ constructor(states: STATE[], signals: SIGNAL[], transitions: ITransition<STATE, SIGNAL>[], startState: STATE);
107
+ /**
108
+ * Gets the current state of the state machine.
109
+ *
110
+ * @returns The current state
111
+ */
112
+ getCurrentState(): STATE;
113
+ /**
114
+ * Processes a signal and potentially transitions to a new state with action execution.
115
+ *
116
+ * This method:
117
+ * 1. Finds a matching transition for the current state and signal
118
+ * 2. If found and the target state is different:
119
+ * a. Executes beforeExitAction on current state (if implemented)
120
+ * b. Changes to the new state
121
+ * c. Executes afterEntryAction on new state (if implemented)
122
+ * 3. Returns the resulting state
123
+ *
124
+ * @param signal - The signal/event to process
125
+ * @returns The resulting state after processing the signal
126
+ */
127
+ protected sendSignal(signal: SIGNAL): STATE;
128
+ private tryProcessStateWithOutputSignal;
129
+ private isStateWithOutputSignal;
130
+ private executeStateTransition;
131
+ private executeStateActions;
132
+ /**
133
+ * Type guard to check if a state is an instance of DefaultState class.
134
+ *
135
+ * @param state - The state to check
136
+ * @returns true if the state is an instance of DefaultState
137
+ */
138
+ protected isDefaultState(state: STATE): boolean;
139
+ /**
140
+ * Type guard to check if a state implements IStateWithAfterEntryAction.
141
+ *
142
+ * @param state - The state to check
143
+ * @returns true if the state implements afterEntryAction method
144
+ */
145
+ protected hasAfterEntryAction(state: STATE): state is STATE & IStateWithAfterEntryAction;
146
+ /**
147
+ * Type guard to check if a state implements IStateWithBeforeExitAction.
148
+ *
149
+ * @param state - The state to check
150
+ * @returns true if the state implements beforeExitAction method
151
+ */
152
+ protected hasBeforeExitAction(state: STATE): state is STATE & IStateWithBeforeExitAction;
153
+ /**
154
+ * Executes the afterEntryAction on a state if it implements IStateWithAfterEntryAction.
155
+ *
156
+ * @param state - The state to execute the entry action on
157
+ */
158
+ private executeEntryAction;
159
+ /**
160
+ * Executes the beforeExitAction on a state if it implements IStateWithBeforeExitAction.
161
+ *
162
+ * @param state - The state to execute the exit action on
163
+ */
164
+ private executeExitAction;
165
+ /**
166
+ * Gets all possible states.
167
+ *
168
+ * @returns Array of all states
169
+ */
170
+ getAllStates(): STATE[];
171
+ /**
172
+ * Gets all possible signals.
173
+ *
174
+ * @returns Array of all signals
175
+ */
176
+ getAllSignals(): SIGNAL[];
177
+ /**
178
+ * Checks if a given signal is valid from the current state.
179
+ *
180
+ * @param signal - The signal to check
181
+ * @returns true if the signal can trigger a transition from the current state
182
+ */
183
+ isValidSignalFromCurrentState(signal: SIGNAL): boolean;
184
+ /**
185
+ * Gets all valid signals from the current state.
186
+ *
187
+ * @returns Array of signals that can trigger transitions from the current state
188
+ */
189
+ getValidSignalsFromCurrentState(): SIGNAL[];
190
+ /**
191
+ * Gets all transitions.
192
+ *
193
+ * @returns Array of all transitions
194
+ */
195
+ getTransitions(): ITransition<STATE, SIGNAL>[];
196
+ /**
197
+ * Checks if a signal is valid in the state machine.
198
+ * @param signal - The signal to check
199
+ * @returns True if the signal is valid, false otherwise.
200
+ */
201
+ hasSignal(signal: SIGNAL): boolean;
202
+ /**
203
+ * Checks if a given state exists in the state machine.
204
+ *
205
+ * @param state - The state to check
206
+ * @returns true if the state exists, false otherwise
207
+ */
208
+ hasState(state: STATE): boolean;
209
+ /**
210
+ * Gets the default state that handles invalid signals.
211
+ *
212
+ * @returns The default state or null if none exists
213
+ */
214
+ getDefaultState(): DefaultState | null;
215
+ /**
216
+ * Checks if the state machine has a default state.
217
+ *
218
+ * @returns true if a default state exists
219
+ */
220
+ hasDefaultState(): boolean;
221
+ }
222
+ //# sourceMappingURL=FiniteStateMachine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FiniteStateMachine.d.ts","sourceRoot":"","sources":["../src/FiniteStateMachine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAG7F;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,EAAE,MAAM;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB,CAAC,KAAK;IACtC;;;;OAIG;IACH,eAAe,IAAI,KAAK,CAAC;CAE5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,8BAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAE,YAAW,mBAAmB,CAAC,KAAK,CAAC;IAsBrF,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE;IACzB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IAC3B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;IACnD,SAAS,CAAC,UAAU,EAAE,KAAK;IAxB/B;;;OAGG;IACH,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC;IAE1B;;;GAGD;IACH,OAAO,CAAC,YAAY,CAA6B;IAEjD;;;;;;;OAOG;gBAEW,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EACzC,UAAU,EAAE,KAAK;IA6B/B;;;;OAIG;IACH,eAAe,IAAI,KAAK;IAIxB;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAqB3C,OAAO,CAAC,+BAA+B;IAcvC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,mBAAmB;IAK3B;;;;;OAKG;IACH,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI/C;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,0BAA0B;IAOxF;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,0BAA0B;IAOxF;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;OAIG;IACH,YAAY,IAAI,KAAK,EAAE;IAIvB;;;;OAIG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;;;;OAKG;IACH,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAMtD;;;;OAIG;IACH,+BAA+B,IAAI,MAAM,EAAE;IAM3C;;;;OAIG;IACH,cAAc,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;IAI9C;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIlC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI3B;;;;GAID;IACH,eAAe,IAAI,YAAY,GAAG,IAAI;IAItC;;;;OAIG;IACH,eAAe,IAAI,OAAO;CAG7B"}