https://github.com/blackglory/extra-fsm
🌲
https://github.com/blackglory/extra-fsm
browser esm library nodejs npm-package typescript
Last synced: 2 months ago
JSON representation
🌲
- Host: GitHub
- URL: https://github.com/blackglory/extra-fsm
- Owner: BlackGlory
- License: mit
- Created: 2022-09-23T16:23:39.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2023-09-14T13:13:26.000Z (almost 3 years ago)
- Last Synced: 2025-08-09T05:57:22.088Z (11 months ago)
- Topics: browser, esm, library, nodejs, npm-package, typescript
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/extra-fsm
- Size: 472 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# extra-fsm
## Install
```sh
npm install --save extra-fsm
# or
yarn add extra-fsm
```
## Usage
The finite state machine provided in the library is the most common table-driven state machine,
where the transition rules are defined in a table,
which is easy to understand.
Example, a machine that can be started and stopped:
```ts
import { FiniteStateMachine, transition } from 'extra-fsm'
const schema = {
stopped: { start: 'running' }
, running: { stop: 'stopped' }
}
// OOP
const machine = new FiniteStateMachine(schema, 'stopped')
machine.send('start')
console.log(machine.state) // running
// FP
const newState = transition(schema, 'stopped', 'start')
console.log(newState) // running
```
The library intentionally does not add any kind of advanced transition rules,
such as defining state transition events as functions.
Advanced features are not supported because my experience has shown that
they are not as good as customized specialized wrappers,
especially when considering extensibility.
Example, a machine that is not reliable,
has a 50% chance of failing to start,
but your luck attribute affects the success rate:
```ts
import { FiniteStateMachine, transition } from 'extra-fsm'
interface IGameState {
attributes: IAttributes
}
interface IAttributes {
luck: number
}
class UnreliableMachine {
static schema = {
stopped: { start: 'running' }
, running: { stop: 'stopped' }
}
private fsm = new FiniteStateMachine(UnreliableMachine.schema, 'stopped')
get state() {
return this.fsm.state
}
constructor(private game: IGameState) {}
start(): void {
assert(this.fsm.can('start'))
if (Math.random() < 0.5 * (this.game.attributes.luck + 1)) {
this.fsm.send('start')
}
}
stop(): void {
this.fsm.send('stop')
}
}
const game: IGameState = {
attributes: {
luck: 1
}
}
const machine = new UnreliableMachine(game)
machine.start()
console.log(machine.state) // running
```
## API
```ts
type IFiniteStateMachineSchema<
State extends string | number | symbol
, Event extends string | number | symbol
> = Record>>
```
### FiniteStateMachine
```ts
class FiniteStateMachine<
State extends string | number | symbol
, Event extends string | number | symbol
> {
get [Symbol.toStringTag](): string
get state(): State
constructor(
schema: IFiniteStateMachineSchema
, initialState: State
)
matches(state: State): boolean
can(event: Event): boolean
/**
* @throws {BadEventError}
*/
send(event: Event): void
}
```
### ObservableFiniteStateMachine
```ts
interface IFiniteStateMachineStateChange<
State extends string | number | symbol
, Event extends string | number | symbol
> {
event: Event
oldState: State
newState: State
}
class ObservableFiniteStateMachine<
State extends string | number | symbol
, Event extends string | number | symbol
> extends FiniteStateMachine {
get [Symbol.toStringTag](): string
observeStateChanges(): Observable>
}
```
### transition
```ts
export function transition<
State extends string | number | symbol
, Event extends string | number | symbol
, TransitionEvent extends Event
>(
schema: IFiniteStateMachineSchema
, state: State
, event: TransitionEvent
): State
```
### canTransition
```ts
function canTransition<
State extends string | number | symbol
, Event extends string | number | symbol
>(
schema: IFiniteStateMachineSchema
, state: State
, event: Event
) => boolean
```