Flux machine
Spec compliant finite state machines using JSX and chainable methods.
Installation:
npm install flux-machine
Example:
import fsm, { State, Transition } from "flux-machine";
// Define state chart using JSX (finite state)
const humanStateChart = (
<>
<State initial id="sleeping">
<Transition event="walk" target="walking" />
</State>
<State id="walking">
<Transition event="sleep" target="sleeping" />
<Transition event="run" target="running" />
</State>
<State id="running">
<Transition event="walk" target="walking" />
</State>
</>
);
// Define data (infinite state)
const data = {
energy: 10,
speed: 0,
};
// Create a machine
const humanMachine = fsm(humanStateChart, data);
// Add conditions, assignments or invoke side effects with chained syntax
humanMachine
.when({
state: "sleeping",
event: "walk",
})
.assign(() => ({
speed: 1,
}));
humanMachine
.when({
state: "walking",
event: "run",
})
.cond((data) => {
return data.energy > 5;
})
.assign((context) => ({
energy: data.energy--,
speed: 10,
}));
humanMachine
.when({
state: "sleeping",
})
.assign((data) => ({
energy: data.energy++,
speed: 0,
}));
// Start machine
export const service = humanMachine.start();
// Interact with machine
service.send("walk");
console.log(service.state.value); // walking
console.log(service.state.context); // { speed: 1 }
Features
SCXML specification | flux-machine | Supported via |
---|---|---|
scxml | <SCXML> |
|
state | <State> |
|
parallel | ||
transition | <Transition> |
|
initial | <State initial> |
|
final | <Final> |
|
onentry | .onEntry() |
|
onexit | .onExit() |
|
history | ||
raise | ||
if | ||
elseif | ||
else | ||
foreach | ||
log | ||
datamodel | fsm(..., data) |
|
data | fsm(..., data) |
|
assign | .assign() |
|
donedata | ||
content | ||
param | ||
script | .action() |
|
send | .send() |
|
cancel | ||
invoke | ||
finalize |
Additional features
Feature | flux-machine |
---|---|
JSX | |
SCXML | |
JSON |
Additional examples
Set an initial state that is not the first state
By default the first state is the initial state
const sc = (
<>
<State id="sleeping"></State>
<State initial id="awake"></State>
</>
);
const service = fsm(sc).start();
console.log(machine.state.value); // awake
Re-use transitions
const goToStart = <Transition event="start" target="1" />;
const goToEnd = <Transition event="end" target="3" />;
const sc = (
<>
<State id="1">{goToEnd}</State>
<State id="2">{goToEnd}</State>
<State id="3">{goToStart}</State>
</>
);
Listen to transitions from any state
machine
.when({
event: "end",
})
.action(() => {
console.log("transitioning to end"); // 'end' event was fired from any state
});
Project goals
- Match the SCXML specification as closely as possible
- Allows developers to reference the spec directly
- Allows developers learning efforts to be transferable
- Avoids us having to write extensive documentation
- Improved developer experience
- Separate finite and extended state
- Fluent API should provide intellisense to avoid guessing method or property names
- Small bundle size (
< 5kb
)- Allows developers to import it into existing projects to address specific problems
- High code coverage (
>= 95%
)- Allows developers to be confident the library works as expected
Bundle size
Code coverage
FAQ
Can I use this in production?
- I do not recommend it until it reaches V1.0.0
Why the name flux?
Credit
This library uses @xstate/fsm for its finite state machine.