1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-19 18:34:45 +00:00

refactor(core/stdlib): update state machine classes to use consistent property names and improve type safety

This commit is contained in:
2026-02-15 03:26:42 +07:00
parent bb644579ca
commit 3380d90cee
3 changed files with 40 additions and 41 deletions

View File

@@ -1,3 +1,4 @@
import { isString } from '../../../types';
import { BaseStateMachine } from './base';
import type { AsyncStateNodeConfig, ExtractStates, ExtractEvents } from './types';
@@ -24,33 +25,33 @@ export class AsyncStateMachine<
* @returns The current state after processing the event
*/
async send(event: Events): Promise<States> {
const stateNode = this._states[this._current];
const stateNode = this.states[this.currentState];
if (!stateNode?.on)
return this._current;
return this.currentState;
const transition = stateNode.on[event];
if (transition === undefined)
return this._current;
return this.currentState;
let target: string;
if (typeof transition === 'string') {
if (isString(transition)) {
target = transition;
} else {
if (transition.guard && !(await transition.guard(this._context)))
return this._current;
if (transition.guard && !(await transition.guard(this.context)))
return this.currentState;
await transition.action?.(this._context);
await transition.action?.(this.context);
target = transition.target;
}
await stateNode.exit?.(this._context);
this._current = target as States;
await this._states[this._current]?.entry?.(this._context);
await stateNode.exit?.(this.context);
this.currentState = target as States;
await this.states[this.currentState]?.entry?.(this.context);
return this._current;
return this.currentState;
}
/**
@@ -59,7 +60,7 @@ export class AsyncStateMachine<
* @param event - Event to check
*/
async can(event: Events): Promise<boolean> {
const stateNode = this._states[this._current];
const stateNode = this.states[this.currentState];
if (!stateNode?.on)
return false;
@@ -69,8 +70,8 @@ export class AsyncStateMachine<
if (transition === undefined)
return false;
if (typeof transition !== 'string' && transition.guard)
return await transition.guard(this._context);
if (!isString(transition) && transition.guard)
return await transition.guard(this.context);
return true;
}

View File

@@ -12,28 +12,25 @@ export class BaseStateMachine<
Context,
NodeConfig,
> {
protected _current: States;
protected _context: Context;
protected _states: Record<string, NodeConfig>;
protected currentState: States;
protected readonly states: Record<string, NodeConfig>;
/** Machine context */
readonly context: Context;
constructor(
initial: States,
states: Record<string, NodeConfig>,
context: Context,
) {
this._current = initial;
this._context = context;
this._states = states;
this.currentState = initial;
this.context = context;
this.states = states;
}
/** Current state of the machine */
get current(): States {
return this._current;
}
/** Machine context */
get context(): Context {
return this._context;
return this.currentState;
}
/**
@@ -42,6 +39,6 @@ export class BaseStateMachine<
* @param state - State to check
*/
matches(state: States): boolean {
return this._current === state;
return this.currentState === state;
}
}

View File

@@ -1,3 +1,4 @@
import { isString } from '../../../types';
import { BaseStateMachine } from './base';
import type { SyncStateNodeConfig, ExtractStates, ExtractEvents } from './types';
@@ -24,33 +25,33 @@ export class StateMachine<
* @returns The current state after processing the event
*/
send(event: Events): States {
const stateNode = this._states[this._current];
const stateNode = this.states[this.currentState];
if (!stateNode?.on)
return this._current;
return this.currentState;
const transition = stateNode.on[event];
if (transition === undefined)
return this._current;
return this.currentState;
let target: string;
if (typeof transition === 'string') {
if (isString(transition)) {
target = transition;
} else {
if (transition.guard && !transition.guard(this._context))
return this._current;
if (transition.guard && !transition.guard(this.context))
return this.currentState;
transition.action?.(this._context);
transition.action?.(this.context);
target = transition.target;
}
stateNode.exit?.(this._context);
this._current = target as States;
this._states[this._current]?.entry?.(this._context);
stateNode.exit?.(this.context);
this.currentState = target as States;
this.states[this.currentState]?.entry?.(this.context);
return this._current;
return this.currentState;
}
/**
@@ -59,7 +60,7 @@ export class StateMachine<
* @param event - Event to check
*/
can(event: Events): boolean {
const stateNode = this._states[this._current];
const stateNode = this.states[this.currentState];
if (!stateNode?.on)
return false;
@@ -69,8 +70,8 @@ export class StateMachine<
if (transition === undefined)
return false;
if (typeof transition !== 'string' && transition.guard)
return transition.guard(this._context);
if (!isString(transition) && transition.guard)
return transition.guard(this.context);
return true;
}