Immutable state machine
A simple yet flexible immutable finite-state machine for Javascript. Great for when building with frameworks like React.
Features:
- Works in Node.js and the browser.
- Immutability - use simple object equality to check if state changed.
- Restrict state transitions using from/to rules.
- Store additional data alongside each state.
- Very small (<2 KB).
Installation
CommonJS
Install using npm:
$ npm install immutable-state-machine
Browser
Include the build/immutableStateMachine.js
script.
In the browser the library is exposed via the ImmutableStateMachine
class function.
How to use
The basics - states and data
Let's create a machine with two states - start
and stop
:
var Machine = ; /*We'll have two states - "start" and "stop"*/var m = 'start' 'stop'; console; // "start"console; // null
By default the first state passed-in (start
) is the initially active state.
The data associated with a state is initially always null
.
If needed we can explicitly set the initial state:
var m = 'start' id: 'stop' initial: true ; console; // "stop"
Now let's goto a new state and see what happens:
var m = 'start' 'start'; var m2 = m; console; // falseconsole; // "stop"console; // "start"
As expected according to immutability, it returned a new instance of the machine, leaving the original unchanged.
Instead, what if we went to the same state?
var m = 'start' 'start'; var m2 = m; console; // true console; // "start"console; // null
The same instance gets returned back as expected. But if we goto the same state with different data a new instance will be returned:
var m = 'start' 'start'; var m2 = m; console; // false console; // "start"console; // { some: 'data' } console; // "start"console; // null
Restricting transitions
By default we can transition from any state to any other state.
But sometimes we want to restrict state-to-state transitions according to
pre-configured rules. We can specify such rules using from
and to
arrays:
var Machine = ; var m = id: 'step1' from: to: 'step2' id: 'step2' from: 'step1' to: 'step3' id: 'step3' from: 'step2' to: 'step4' id: 'step4' from: 'step3' to: 'step1' console; // "step1" // m.goto('step3'); -> Error// m.goto('step4'); -> Error m; // m.goto('step1'); -> Error// m.goto('step4'); -> Error m; // m.goto('step1'); -> Error// m.goto('step2'); -> Error m; // m.goto('step1'); -> Error, because step1 "from" is empty array// m.goto('step2'); -> Error// m.goto('step3'); -> Error
The above machine allows us transition from step1
through to step4
and
then nothing else. Note that although we have specified that step4
may
transition to step1
, we specified an empty from array for step1
thus
specifying that it is not possible to transition to step1
from another step.
Seamless sub-classing
If you inherit from Machine
then all methods will return new instances of
your subclass rather than the base class.
{} var m = 'start' 'stop'; var m2 = m; console; /* true */
Building
To build the code and run the tests:
$ npm install -g gulp
$ npm install
$ npm run build
Contributing
Contributions are welcome! Please see CONTRIBUTING.md.
License
MIT - see LICENSE.md