This implementation of a state machine made to overcome some limitations of famous XState. This is currently in Alpha stage, so documentation will be added, bugs fixed, and API may drastically change.
- Simple state management with entry, exit and onTransition actions.
- Nested states.
- Parallel regions.
- Guarded transitions with possibility to have multiple guards for a single transition.
- Supports and encourages message bus integration to externalize event handling logic.
- Supports "onAction" messages (pushed to the message bus).
- Configurable error handling and error behavior
- Extensible logger interface
- Extensible message bus interface
- Can be "visited" by an arbitrary visitor that conforms to the visitor interface (useful for translation or code generation)
The simplest example, machine with 2 states:
import { StateMachine } from 'adv-state'
// Assuming you have a message bus
import { MessageBus } from 'my-message-bus'
const sm = new StateMachine({
name: 'My first state machine',
messageBus: new MessageBus(),
stateMap: {
state1: {
initial: true,
events: {
go2: {
toState: 'state2'
}
}
},
state2: {
final: true
}
}
})
sm.run()
We interact with the state machine by sending it events. The state machine will react on received events depending on state it is in.
Event descriptor can have following properties:
- toState - defines a state transition for the event
- actions - a single callback or an array of callbacks that will be invoked when event occurs
- guards - a single funciton or an array of functions that return true or false. Only if all guards evaluate to true the event will be executed (meaning actions invoked and transition performed)
- message - specified message will be pushed to the message bus
Example:
const stateMap = {
state1: {
initial: true,
events: { // <= event descriptors container
bar: [
{ // event descriptor
toState: 'state2',
actions: [/*some callbacks*/],
guards: [/*some guards*/],
message: "DOING_BAR"
},
{
actions: (eventName, payload)=>{/*do work*/},
guards: (eventName, payload)=>/*evaluate*/,
}
],
foo: {
toState: 'state3',
actions: [/*some other actions*/],
message: "DOING_FOO"
}
}
},
state2: {/* State description*/},
state3: {/* State description*/}
}
})
There are 3 ways to send events to the machine:
-
Direct way
sm.handle.event(payload)
-
Through message bus. The message bus must call on the machine like this
subscriber.update('message', payload)
// subscriber is a state machine -
Update is a public method and can be used directly to send events:
sm.update('message', payload)