@axi-engine/states 0.3.1 → 0.3.3
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.
- package/README.md +6 -6
- package/dist/index.d.mts +30 -3
- package/dist/index.d.ts +30 -3
- package/dist/index.js +4 -4
- package/dist/index.mjs +4 -4
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -149,9 +149,9 @@ await gameState.call(GameState.Paused); // Error: Transition from MainMenu to Pa
|
|
|
149
149
|
The public `onChange` property is an `Emitter`. You can use its `subscribe` method to be notified of any state change. The method returns a function to unsubscribe.
|
|
150
150
|
|
|
151
151
|
```typescript
|
|
152
|
-
const unsubscribe = gameState.onChange.subscribe(
|
|
153
|
-
const fromState = from !== undefined ? GameState[from] : 'Start';
|
|
154
|
-
console.log(`State changed from ${fromState} to ${GameState[to]}`, { payload });
|
|
152
|
+
const unsubscribe = gameState.onChange.subscribe(event => {
|
|
153
|
+
const fromState = event.from !== undefined ? GameState[event.from] : 'Start';
|
|
154
|
+
console.log(`State changed from ${fromState} to ${GameState[event.to]}`, { payload: event.payload });
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
await gameState.call(GameState.MainMenu);
|
|
@@ -176,9 +176,9 @@ enum GameState {
|
|
|
176
176
|
// --- Setup ---
|
|
177
177
|
const game = new StateMachine<GameState>();
|
|
178
178
|
|
|
179
|
-
game.onChange.subscribe(
|
|
180
|
-
const fromState = from !== undefined ? GameState[from] : 'Start';
|
|
181
|
-
console.log(`[SYSTEM] Transition: ${fromState} -> ${GameState[to]}`);
|
|
179
|
+
game.onChange.subscribe(e => {
|
|
180
|
+
const fromState = e.from !== undefined ? GameState[e.from] : 'Start';
|
|
181
|
+
console.log(`[SYSTEM] Transition: ${fromState} -> ${GameState[e.to]}`);
|
|
182
182
|
});
|
|
183
183
|
|
|
184
184
|
game.register(GameState.MainMenu, {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
import { Emitter } from '@axijs/emitter';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Represents a lifecycle handler function for a state.
|
|
5
|
+
* If a payload type `P` is provided and is not `void`, the handler receives the payload.
|
|
6
|
+
* Supports both synchronous and asynchronous execution.
|
|
7
|
+
*
|
|
8
|
+
* @template P The type of the payload passed to the handler.
|
|
9
|
+
*/
|
|
3
10
|
type StateHandler<P = void> = P extends void ? () => void | Promise<void> : (payload: P) => void | Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Configuration object for defining a state's behavior and transition rules.
|
|
13
|
+
*
|
|
14
|
+
* @template T The type used for state identifiers.
|
|
15
|
+
* @template P The type of the payload passed to the `onEnter` handler.
|
|
16
|
+
*/
|
|
4
17
|
interface StateHandlerConfig<T, P = void> {
|
|
18
|
+
/**
|
|
19
|
+
* Hook executed when transitioning into this state.
|
|
20
|
+
*/
|
|
5
21
|
onEnter?: StateHandler<P>;
|
|
22
|
+
/**
|
|
23
|
+
* Hook executed when transitioning out of this state.
|
|
24
|
+
*/
|
|
6
25
|
onExit?: () => void | Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Optional list of states from which a transition to this state is permitted.
|
|
28
|
+
* If undefined, the state can be entered from any state.
|
|
29
|
+
*/
|
|
7
30
|
allowedFrom?: T[];
|
|
8
31
|
}
|
|
9
32
|
type StateHandlerRegistration<T, P = void> = StateHandler<P> | StateHandlerConfig<T, P>;
|
|
@@ -43,11 +66,15 @@ declare class StateMachine<T, P = void> {
|
|
|
43
66
|
* The event provides the old state, the new state, and the payload.
|
|
44
67
|
* @see Emitter
|
|
45
68
|
* @example
|
|
46
|
-
* fsm.onChange.subscribe(
|
|
47
|
-
* console.log(`State transitioned from ${from} to ${to}`);
|
|
69
|
+
* fsm.onChange.subscribe(e => {
|
|
70
|
+
* console.log(`State transitioned from ${e.from} to ${e.to}`);
|
|
48
71
|
* });
|
|
49
72
|
*/
|
|
50
|
-
readonly onChange: Emitter<
|
|
73
|
+
readonly onChange: Emitter<{
|
|
74
|
+
from?: T;
|
|
75
|
+
to?: T;
|
|
76
|
+
payload?: P;
|
|
77
|
+
}>;
|
|
51
78
|
/**
|
|
52
79
|
* Gets the current state of the machine.
|
|
53
80
|
* @returns The current state identifier, or `undefined` if the machine has not been started.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
import { Emitter } from '@axijs/emitter';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Represents a lifecycle handler function for a state.
|
|
5
|
+
* If a payload type `P` is provided and is not `void`, the handler receives the payload.
|
|
6
|
+
* Supports both synchronous and asynchronous execution.
|
|
7
|
+
*
|
|
8
|
+
* @template P The type of the payload passed to the handler.
|
|
9
|
+
*/
|
|
3
10
|
type StateHandler<P = void> = P extends void ? () => void | Promise<void> : (payload: P) => void | Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Configuration object for defining a state's behavior and transition rules.
|
|
13
|
+
*
|
|
14
|
+
* @template T The type used for state identifiers.
|
|
15
|
+
* @template P The type of the payload passed to the `onEnter` handler.
|
|
16
|
+
*/
|
|
4
17
|
interface StateHandlerConfig<T, P = void> {
|
|
18
|
+
/**
|
|
19
|
+
* Hook executed when transitioning into this state.
|
|
20
|
+
*/
|
|
5
21
|
onEnter?: StateHandler<P>;
|
|
22
|
+
/**
|
|
23
|
+
* Hook executed when transitioning out of this state.
|
|
24
|
+
*/
|
|
6
25
|
onExit?: () => void | Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Optional list of states from which a transition to this state is permitted.
|
|
28
|
+
* If undefined, the state can be entered from any state.
|
|
29
|
+
*/
|
|
7
30
|
allowedFrom?: T[];
|
|
8
31
|
}
|
|
9
32
|
type StateHandlerRegistration<T, P = void> = StateHandler<P> | StateHandlerConfig<T, P>;
|
|
@@ -43,11 +66,15 @@ declare class StateMachine<T, P = void> {
|
|
|
43
66
|
* The event provides the old state, the new state, and the payload.
|
|
44
67
|
* @see Emitter
|
|
45
68
|
* @example
|
|
46
|
-
* fsm.onChange.subscribe(
|
|
47
|
-
* console.log(`State transitioned from ${from} to ${to}`);
|
|
69
|
+
* fsm.onChange.subscribe(e => {
|
|
70
|
+
* console.log(`State transitioned from ${e.from} to ${e.to}`);
|
|
48
71
|
* });
|
|
49
72
|
*/
|
|
50
|
-
readonly onChange: Emitter<
|
|
73
|
+
readonly onChange: Emitter<{
|
|
74
|
+
from?: T;
|
|
75
|
+
to?: T;
|
|
76
|
+
payload?: P;
|
|
77
|
+
}>;
|
|
51
78
|
/**
|
|
52
79
|
* Gets the current state of the machine.
|
|
53
80
|
* @returns The current state identifier, or `undefined` if the machine has not been started.
|
package/dist/index.js
CHANGED
|
@@ -43,8 +43,8 @@ var StateMachine = class {
|
|
|
43
43
|
* The event provides the old state, the new state, and the payload.
|
|
44
44
|
* @see Emitter
|
|
45
45
|
* @example
|
|
46
|
-
* fsm.onChange.subscribe(
|
|
47
|
-
* console.log(`State transitioned from ${from} to ${to}`);
|
|
46
|
+
* fsm.onChange.subscribe(e => {
|
|
47
|
+
* console.log(`State transitioned from ${e.from} to ${e.to}`);
|
|
48
48
|
* });
|
|
49
49
|
*/
|
|
50
50
|
onChange = new import_emitter.Emitter();
|
|
@@ -98,7 +98,7 @@ var StateMachine = class {
|
|
|
98
98
|
*/
|
|
99
99
|
async call(newState, payload) {
|
|
100
100
|
const oldState = this._state;
|
|
101
|
-
const oldStateConfig = this._state ? this.states.get(this._state)
|
|
101
|
+
const oldStateConfig = (0, import_ensure.isUndefined)(this._state) ? void 0 : this.states.get(this._state);
|
|
102
102
|
const newStateConfig = this.states.get(newState);
|
|
103
103
|
(0, import_ensure.throwIfEmpty)(newStateConfig, `State ${String(newState)} is not registered.`);
|
|
104
104
|
(0, import_ensure.throwIf)(
|
|
@@ -108,7 +108,7 @@ var StateMachine = class {
|
|
|
108
108
|
await oldStateConfig?.onExit?.();
|
|
109
109
|
this._state = newState;
|
|
110
110
|
await newStateConfig.onEnter?.(payload);
|
|
111
|
-
this.onChange.emit(oldState, newState, payload);
|
|
111
|
+
this.onChange.emit({ from: oldState, to: newState, payload });
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
114
|
* Removes a single state configuration from the machine.
|
package/dist/index.mjs
CHANGED
|
@@ -17,8 +17,8 @@ var StateMachine = class {
|
|
|
17
17
|
* The event provides the old state, the new state, and the payload.
|
|
18
18
|
* @see Emitter
|
|
19
19
|
* @example
|
|
20
|
-
* fsm.onChange.subscribe(
|
|
21
|
-
* console.log(`State transitioned from ${from} to ${to}`);
|
|
20
|
+
* fsm.onChange.subscribe(e => {
|
|
21
|
+
* console.log(`State transitioned from ${e.from} to ${e.to}`);
|
|
22
22
|
* });
|
|
23
23
|
*/
|
|
24
24
|
onChange = new Emitter();
|
|
@@ -72,7 +72,7 @@ var StateMachine = class {
|
|
|
72
72
|
*/
|
|
73
73
|
async call(newState, payload) {
|
|
74
74
|
const oldState = this._state;
|
|
75
|
-
const oldStateConfig = this._state ? this.states.get(this._state)
|
|
75
|
+
const oldStateConfig = isUndefined(this._state) ? void 0 : this.states.get(this._state);
|
|
76
76
|
const newStateConfig = this.states.get(newState);
|
|
77
77
|
throwIfEmpty(newStateConfig, `State ${String(newState)} is not registered.`);
|
|
78
78
|
throwIf(
|
|
@@ -82,7 +82,7 @@ var StateMachine = class {
|
|
|
82
82
|
await oldStateConfig?.onExit?.();
|
|
83
83
|
this._state = newState;
|
|
84
84
|
await newStateConfig.onEnter?.(payload);
|
|
85
|
-
this.onChange.emit(oldState, newState, payload);
|
|
85
|
+
this.onChange.emit({ from: oldState, to: newState, payload });
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
88
|
* Removes a single state configuration from the machine.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axi-engine/states",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "A minimal, type-safe state machine for the Axi Engine, designed for managing game logic and component states with a simple API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -32,15 +32,16 @@
|
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsup",
|
|
35
|
-
"
|
|
36
|
-
"test": "
|
|
35
|
+
"prebuild": "npm test",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"docs": "typedoc src/index.ts --out docs/api --options ../../typedoc.json"
|
|
37
38
|
},
|
|
38
39
|
"files": [
|
|
39
40
|
"dist"
|
|
40
41
|
],
|
|
41
42
|
"peerDependencies": {
|
|
42
|
-
"@axijs/emitter": "^1.
|
|
43
|
-
"@axijs/ensure": "^1.0.
|
|
43
|
+
"@axijs/emitter": "^1.1.1",
|
|
44
|
+
"@axijs/ensure": "^1.0.2",
|
|
44
45
|
"@axi-engine/utils": "^0.3.0"
|
|
45
46
|
}
|
|
46
47
|
}
|