The desired event to emit.
Optional
Rest
...curriedArgs: any[]Arguments that will curry into the returned emit()
function whenever it is called.
Creates a function that emits the specified event.
(This is essentially a convenience wrapper around emit.)
A function that emits that event.
import { Statebot } from 'statebot'
let machine = Statebot('traffic-lights', {
chart: `
go ->
prepare-to-stop ->
stop
// ...gotta keep that traffic flowing
stop ->
prepare-to-go ->
go
`,
startIn: 'stop'
})
machine.performTransitions({
'stop -> prepare-to-go': { on: 'timer' },
'prepare-to-go -> go': { on: 'timer' },
'go -> prepare-to-stop': { on: 'timer' },
'prepare-to-stop -> stop': { on: 'timer' }
})
let nextTrafficLight = machine.Emit('timer')
machine.currentState()
// "stop"
nextTrafficLight()
nextTrafficLight()
nextTrafficLight()
machine.currentState()
// "prepare-to-stop"
Rest
...args: any[]Creates a function that changes to the specified state, so long as it is accessible from the currentState.
(This is essentially a convenience wrapper around enter.)
A function that can change the state when called.
import { Statebot } from 'statebot'
let machine = Statebot('popup-menu', {
chart: `
idle -> menu-opened ->
(item-clicked | idle)
item-clicked -> idle
`,
startIn: 'menu-opened'
})
button.onclick = machine.Enter('item-clicked')
machine.currentState()
// "menu-opened"
button.onclick()
machine.currentState()
// "item-clicked"
The desired state to switch-to.
Optional
Rest
...curriedArgs: any[]Arguments that will curry into the returned
enter()
function whenever it is called.
Creates a function that changes to the specified state, so long as it is accessible from the currentState.
(This is essentially a convenience wrapper around enter.)
A function that can change the state when called.
import { Statebot } from 'statebot'
let machine = Statebot('popup-menu', {
chart: `
idle -> menu-opened ->
(item-clicked | idle)
item-clicked -> idle
`,
startIn: 'menu-opened'
})
button.onclick = machine.Enter('item-clicked')
machine.currentState()
// "menu-opened"
button.onclick()
machine.currentState()
// "item-clicked"
Rest
...args: any[]Returns a function which, when run, tests that
currentState matches the
specified state, returning either true
or false
.
If outputWhenTrue
is specified, then it will be returned
instead of true
, and null
will be returned instead of
false
.
(This is essentially a convenience wrapper around inState.)
A function that calls inState.
import { Statebot } from 'statebot'
let machine = Statebot('little-revver', {
chart: `
idle ->
(gear-1 | gear-2 | reverse) ->
idle
`
})
let idling = machine.InState('idle')
let purring = machine.InState('idle', () => {
console.log('Idling!')
return 'Purrrr...'
})
idling()
// true
purring()
// Idling!
// "Purrrr..."
machine.enter('gear-1')
purring()
// null
// ^ the function is not called at all in the `false` case,
// so no console.log either.
The state to test against.
Returns a function which, when run, tests that
currentState matches the
specified state, returning either true
or false
.
If outputWhenTrue
is specified, then it will be returned
instead of true
, and null
will be returned instead of
false
.
(This is essentially a convenience wrapper around inState.)
A function that calls inState.
import { Statebot } from 'statebot'
let machine = Statebot('little-revver', {
chart: `
idle ->
(gear-1 | gear-2 | reverse) ->
idle
`
})
let idling = machine.InState('idle')
let purring = machine.InState('idle', () => {
console.log('Idling!')
return 'Purrrr...'
})
idling()
// true
purring()
// Idling!
// "Purrrr..."
machine.enter('gear-1')
purring()
// null
// ^ the function is not called at all in the `false` case,
// so no console.log either.
Rest
...fnArgs: any[]Optional
outputWhenTrue: anyRest
...fnArgs: any[]Tests to see if we can transition to the specified state from the currentState.
If more than one state is specified, true
is returned only if
ALL states are available.
See also: peek.
Can test if a certain state will be entered after
emitting an event. Use { afterEmitting: 'eventName' }
as the
second argument. Works only after using performTransitions.
Whether the transition is possible.
import { Statebot } from 'statebot'
let machine = Statebot('game-menus', {
chart: `
loading ->
menu ->
play |
options |
sound |
quit
// Go back to menu
play | options | sound -> menu
// Can quit from main game, too
play -> quit
`
})
machine.canTransitionTo('play')
// false
machine.enter('menu')
machine.canTransitionTo(['play', 'options'])
// true
machine.canTransitionTo('play', {
afterEmitting: 'startGame'
})
// false
Optional
options: { afterEmitting: string }Test if a certain state will be entered after emitting an event. Works only after using performTransitions.
Returns the current state.
The current state.
import { Statebot } from 'statebot'
let machine = Statebot('coroutine', {
chart: `
suspended -> running -> (suspended | dead)
`
})
machine.currentState()
// "suspended"
Immediately emits an event, firing any listeners added using performTransitions or onEvent.
Whether or not the event had listeners.
import { Statebot } from 'statebot'
let machine = Statebot('basic-form', {
chart: `
idle -> sending -> redirect
`
})
machine.performTransitions({
'idle -> sending': {
on: 'post-data',
then: (...args) => {
console.log('Event args: ', args)
// setTimeout(machine.Enter('redirect'), 5000)
}
}
})
machine.emit('post-data', 'Hello, world!')
// Event args: ["Hello, world!"]
machine.currentState()
// "sending"
Optional
Rest
...args: any[]Optional arguments to pass to listeners.
Immediately changes to the specified state, so long as it is accessible from the currentState.
Whether or not the state changed.
import { Statebot } from 'statebot'
let machine = Statebot('dialog', {
chart: `
idle -> showing-modal -> (saving | idle)
saving -> idle
`
})
machine.currentState()
// "idle"
machine.enter('saving')
// false
// Statebot[dialog]: Invalid transition "idle->saving", not switching
// > Previous transition: "[undefined]->idle"
// > From "idle", valid states are: ["showing-modal"]
machine.enter('showing-modal')
// true
The desired state to switch-to.
Optional
Rest
...args: any[]Optional arguments to pass to transition callbacks.
Returns all states the machine has been in so far, up to a limit set
by historyLimit
in TStatebotOptions.
A copy of the state-history.
import { Statebot } from 'statebot'
let machine = Statebot('downloader', {
chart: `
loading -> (failure | success)
failure -> loading
success -> done
`,
historyLimit: 4
})
machine.enter('failure')
machine.enter('loading')
machine.enter('success')
machine.enter('done')
machine.history()
// ["failure", "loading", "success", "done"]
Checks if the currentState
matches the specified state
, immediately returning either
true
or false
.
An object can be used instead of a string, with the keys
being the states, and the values corresponding to their
outputWhenTrue
value. See the example.
If outputWhenTrue
is specified, then it will be returned
instead of true
, and null
will be returned instead of
false
. If a function is specified, then its return-value
will be used as the true
-value.
import { Statebot } from 'statebot'
let machine = Statebot('little-revver', {
chart: `
idle ->
(gear-1 | gear-2 | reverse) ->
idle
`
})
machine.inState('idle')
// true
machine.inState('idle', 'Purrrr...')
// "Purrrr..."
machine.enter('gear-1')
machine.inState({
'idle': 'Purrrr...',
'gear-1': () => 'Chugga-chugga-chugga...',
'gear-2': () => 'Brumma-brumma-brum-brum...',
'reverse': false,
})
// "Chugga-chugga-chugga..."
machine.inState('idle', () => {
console.log('Idling!')
return 'Purrrr...'
})
// null
// ^ the function is not called at all in the `false` case,
// so no console.log either.
The state to test against. This can be a string if you have a single condition, or an object for multiple. (See example.)
Optional
outputWhenTrue: anyRest
...fnArgs: any[]Print information about the current machine to the console.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.info()
// [half-duplex]: Information about this state-machine.
// [half-duplex]: Listening for the following state-changes:
// ┌---------┬-------------┬--------┐
// │ (index) │ states │ # │
// ├---------┼-------------┼--------┤
// │ 0 │ 'done' │ 'None' │
// │ 1 │ 'idle' │ 'None' │
// │ 2 │ 'receiving' │ 'None' │
// │ 3 │ 'sending' │ 'None' │
// └---------┴-------------┴--------┘
// [half-duplex] Listening for the following transitions:
// ┌---------┬-------------------┬--------┐
// │ (index) │ transitions │ # │
// ├---------┼-------------------┼--------┤
// │ 0 │ 'idle->receiving' │ 'None' │
// │ 1 │ 'idle->sending' │ 'None' │
// │ 2 │ 'receiving->done' │ 'None' │
// │ 3 │ 'sending->done' │ 'None' │
// └---------┴-------------------┴--------┘
// [half-duplex]: Listening for the following events:
// (No information)
Get information about the current machine.
Same details as info in object-form.
An object containing information about the current machine.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.inspect()
// Will return an object with the following signature:
// { states, transitions, events }
// These will each have key-values, the key being the name
// and the value being the number of listeners attached.
Returns the name of the state-machine.
Used for logging and also by assertRoute for the same.
The name of the state-machine.
import { Statebot } from 'statebot'
let machine = Statebot('Ay, there’s the rub.', {
chart: `
the-question -> (to-be | not-to-be)
not-to-be -> perchance-to-dream
`
})
machine.name()
// "Ay, there’s the rub."
Adds a listener that runs a callback immediately AFTER the specified-state becomes the current one.
A function is returned that will remove the listener.
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onEntered('done', fromState => {
console.log('Entered from:', fromState)
})
machine.enter('receiving')
machine.enter('done')
// Entered from: receiving
The state.
A callback function with the signature:
(fromState, ...args?)
Optional
fromState: stringRest
...args: any[]Adds a listener that runs a callback immediately BEFORE the specified-state becomes the current one.
A function is returned that will remove the listener.
TStatebotFsm
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onEntered('done', () => {
console.log('We made it!')
})
machine.onEntering('done', fromState => {
console.log('Entering from:', fromState)
})
machine.enter('sending')
machine.enter('done')
// Entering from: sending
// We made it!
The state.
A callback function with the signature:
(fromState, ...args?)
Optional
fromState: stringRest
...args: any[]Adds a listener that runs a callback immediately after the specified event is called.
A function is returned that will remove the listener.
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('traffic-lights', {
chart: `
go ->
prepare-to-stop ->
stop
// ...gotta keep that traffic flowing
stop ->
prepare-to-go ->
go
`
})
machine.performTransitions({
'stop -> prepare-to-go -> go': { on: 'timer' },
'go -> prepare-to-stop -> stop': { on: 'timer' },
})
machine.onEvent('timer', () => {
redrawTrafficLights()
})
setInterval(machine.Emit('timer'), 2000)
The callback.
Rest
...args: any[]Adds a listener that runs a callback immediately AFTER the specified-state is no longer the current one.
A function is returned that will remove the listener.
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onExited('idle', toState => {
console.log('We are heading to:', toState)
})
machine.enter('sending')
// We are heading to: sending
The state.
A callback function with the signature:
(toState, ...args?)
Optional
toState: stringRest
...args: any[]Adds a listener that runs a callback immediately BEFORE the specified-state is no longer the current one.
A function is returned that will remove the listener.
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onExited('idle', () => {
console.log('Peace out!')
})
machine.onExiting('idle', toState => {
console.log('Heading to:', toState)
})
machine.enter('receiving')
machine.enter('done')
// Heading to: receiving
// Peace out!
The state.
A callback function with the signature:
(toState, ...args?)
Optional
toState: stringRest
...args: any[]Adds a listener that runs a callback immediately after ANY state-change.
A function is returned that will remove the listener.
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onSwitched((toState, fromState) => {
console.log(`We went from "${fromState}" to "${toState}"`)
})
machine.enter('receiving')
// We went from "idle" to "receiving"
A callback function with the signature:
(toState, fromState, ...args?)
Optional
toState: stringOptional
fromState: stringRest
...args: any[]Adds a listener that runs a callback immediately before ANY state-change.
A function is returned that will remove the listener.
A function that removes the listener.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onSwitching((toState, fromState) => {
console.log(`Going from "${fromState}" to "${toState}"`)
})
machine.enter('receiving')
// Going from "idle" to "receiving"
A callback function with the signature:
(toState, fromState, ...args?)
Optional
toState: stringOptional
fromState: stringRest
...args: any[]Run callbacks when transitions happen.
If a callback returns a function, it will be invoked when the state is exited in the same manner as if an onExiting handler was created using it.
A function that removes all listeners added by this method.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.onTransitions({
'idle -> sending': () => {
sendData()
.then(machine.Enter('done', 'sent'))
.catch(machine.Enter('done', 'failed'))
},
'idle -> receiving': () => {
receiveData()
.then(machine.Enter('done', 'received'))
.catch(machine.Enter('done', 'failed'))
},
'sending | receiving -> done': whatHappened => {
console.log('All finished: ', whatHappened)
}
})
machine.enter('sending')
function sendData() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
setTimeout(reject, 750 + Math.round(Math.random() * 750))
})
}
function receiveData() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
setTimeout(reject, 750 + Math.round(Math.random() * 750))
})
}
// The above example using a function for config
machine.onTransitions(({ Enter }) => ({
'idle -> sending': () => {
sendData()
.then(Enter('done', 'sent'))
.catch(Enter('done', 'failed'))
},
'idle -> receiving': () => {
receiveData()
.then(Enter('done', 'received'))
.catch(Enter('done', 'failed'))
},
'sending | receiving -> done': whatHappened => {
console.log('All finished: ', whatHappened)
}
}))
// etc...
Returns true
if the machine is pause'd
Return the state the machine will be in after emit'ing the specified event.
Works only after using performTransitions.
See also: canTransitionTo.
import { Statebot } from 'statebot'
let machine = Statebot('peek-a-boo', {
chart: `
idle -> running
`
})
machine.performTransitions({
'idle -> running': {
on: 'start'
}
})
machine.peek('start')
// "running"
machine.peek('start', {
'running': () => 'will be in the running state'
})
// "will be in the running state"
machine.peek('unknown')
// "idle"
// Logs: Statebot[peek-a-boo]: Event not handled: "unknown"
machine.peek('unknown', {
'running': () => 'will be in the running state'
})
// null
// Logs: Statebot[peek-a-boo]: Event not handled: "unknown"
machine.emit('start')
machine.peek('start')
// "running"
// Logs: Statebot[peek-a-boo]: Will not transition after emitting: "start"
Optional
stateObject: anyIf stateObject
is undefined, .peek()
defaults to returning
currentState
if the event will NOT trigger a transition. Otherwise,
stateObject
will be used as a key/value lookup, with key
being the predicted state, and value
being the corresponding
literal or function to be run and its value returned.
Perform transitions when events happen.
Use then
to optionally add callbacks to those transitions.
If a then
method returns a function, it will be invoked when
the state is exited in the same manner as if an onExiting
handler was created using it.
A function that removes all listeners added by this method.
import { Statebot } from 'statebot'
let machine = Statebot('complex-form', {
chart: `
idle ->
update
// Maybe things take a long time...
update ->
waiting -> waiting-a-while
// Which path will we take?
waiting | waiting-a-while ->
success | failed | timeout
// All done!
success | failed | timeout ->
done
`
})
machine.performTransitions(({ Enter, emit }) => ({
'idle -> update': {
on: 'user-saved',
then: (data) => {
console.log('Sending data: ', data)
sendData(data)
.then(Enter('success'))
.catch(Enter('failed'))
emit('data-sent')
}
},
'update -> waiting': {
on: 'data-sent',
then: () => {
setTimeout(Enter('waiting-a-while'), 750)
setTimeout(Enter('timeout'), 5000)
}
}
}))
// Just to illustrate that you can mix n' match with onTransitions:
machine.onTransitions({
'waiting | waiting-a-while -> success': () => {
console.log('Lovely!')
},
'waiting | waiting-a-while -> timeout': () => {
console.log('Well, at least you have your shoes')
}
})
machine.emit('user-saved', ['some', 'data'])
// Sending data: ["some", "data"]
function sendData() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
setTimeout(reject, 750 + Math.round(Math.random() * 750))
})
}
Returns the previous state.
The previous state, or undefined
if there isn't one (ie; you
have just called reset, or the
machine has just started.)
import { Statebot } from 'statebot'
let machine = Statebot('simple-sender', {
chart: `
idle -> sending -> done
`
})
machine.enter('sending')
machine.previousState()
// "idle"
Returns the state-machine to its starting-state and clears the state-history.
All listeners will still be attached, but no events or transitions will be fired. The pause-state will be maintained.
import { Statebot } from 'statebot'
let machine = Statebot('carousel', {
chart: `
page-1 ->
page-2 ->
page-3 ->
page-4 -> page-1
`
})
machine.enter('page-2')
machine.reset()
machine.currentState()
// "page-1"
Resume a pause'd machine.
Return an array
of states accessible from the state specified.
If no state is passed-in, the currentState is used.
import { Statebot } from 'statebot'
let machine = Statebot('half-duplex', {
chart: `
idle -> sending | receiving -> done
`
})
machine.statesAvailableFromHere()
// ["sending", "receiving"]
machine.statesAvailableFromHere('receiving')
// ["done"]
Optional
state: stringThe state to check. currentState if unspecified.
Generated using TypeDoc
Creates a function that emits the specified event.
(This is essentially a convenience wrapper around emit.)
Returns
A function that emits that event.
Example