statebot
    Preparing search index...

    Interface TStatebotFsm

    interface TStatebotFsm {
        canTransitionTo(
            stateOrStates: string | string[],
            options?: { afterEmitting: string },
        ): boolean;
        currentState(): string;
        emit(eventName: string, ...args?: any[]): boolean;
        Emit(
            eventName: string,
            ...curriedArgs?: any[],
        ): (...args: any[]) => boolean;
        enter(state: string, ...args?: any[]): boolean;
        Enter(state: string, ...curriedArgs?: any[]): (...args: any[]) => boolean;
        history(): string[];
        info(): void;
        inspect(): { events: any[]; states: any[]; transitions: any[] };
        inState(state: string): boolean;
        inState(state: string, outputWhenTrue?: any, ...fnArgs: any[]): any;
        inState(state: object): any;
        InState(state: string): (...fnArgs: any[]) => boolean;
        InState(state: string, outputWhenTrue?: any): (...fnArgs: any[]) => any;
        InState(state: object): () => any;
        name(): string;
        onEntered(
            state: string,
            cb: (fromState?: string, ...args: any[]) => void,
        ): Function;
        onEntering(
            state: string,
            cb: (fromState?: string, ...args: any[]) => void,
        ): Function;
        onEvent(eventName: string, cb: (...args: any[]) => void): Function;
        onExited(
            state: string,
            cb: (toState?: string, ...args: any[]) => void,
        ): Function;
        onExiting(
            state: string,
            cb: (toState?: string, ...args: any[]) => void,
        ): Function;
        onSwitched(
            cb: (toState?: string, fromState?: string, ...args: any[]) => void,
        ): Function;
        onSwitching(
            cb: (toState?: string, fromState?: string, ...args: any[]) => void,
        ): Function;
        onTransitions(transitions: object | Function): Function;
        pause(): void;
        paused(): boolean;
        peek(eventName: string, stateObject?: any): any;
        performTransitions(transitions: object | Function): Function;
        previousState(): string | undefined;
        reset(): void;
        resume(): void;
        statesAvailableFromHere(state?: string): string[];
    }
    Index
    • Tests to see if we can transition to the specified state from the TStatebotFsm.currentState.

      If more than one state is specified, true is returned only if ALL states are available.

      See also: TStatebotFsm.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 TStatebotFsm.performTransitions.

      Parameters

      • stateOrStates: string | string[]
      • Optionaloptions: { afterEmitting: string }

      Returns boolean

      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
    • Returns the current state.

      Returns string

      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 TStatebotFsm.performTransitions or TStatebotFsm.onEvent.

      Parameters

      • eventName: string
      • Optional...args: any[]

        Optional arguments to pass to listeners.

      Returns boolean

      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"
    • Creates a function that emits the specified event.

      (This is essentially a convenience wrapper around TStatebotFsm.emit.)

      Parameters

      • eventName: string

        The desired event to TStatebotFsm.emit.

      • Optional...curriedArgs: any[]

        Arguments that will curry into the returned emit() function whenever it is called.

      Returns (...args: any[]) => boolean

      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"
    • Immediately changes to the specified state, so long as it is accessible from the TStatebotFsm.currentState.

      Parameters

      • state: string

        The desired state to switch-to.

      • Optional...args: any[]

        Optional arguments to pass to transition callbacks.

      Returns boolean

      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
    • Creates a function that changes to the specified state, so long as it is accessible from the TStatebotFsm.currentState.

      (This is essentially a convenience wrapper around TStatebotFsm.enter.)

      Parameters

      • state: string

        The desired state to switch-to.

      • Optional...curriedArgs: any[]

        Arguments that will curry into the returned enter() function whenever it is called.

      Returns (...args: any[]) => boolean

      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"
    • Returns all states the machine has been in so far, up to a limit set by historyLimit in TStatebotOptions.

      Returns string[]

      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"]
    • Print information about the current machine to the console.

      Returns void

      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 TStatebotFsm.info in object-form.

      Returns { events: any[]; states: any[]; transitions: any[] }

      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.
    • Checks if the TStatebotFsm.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.

      Parameters

      • state: string

        The state to test against. This can be a string if you have a single condition, or an object for multiple. (See example.)

      Returns boolean

      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.
    • Parameters

      • state: string
      • OptionaloutputWhenTrue: any
      • ...fnArgs: any[]

      Returns any

    • Parameters

      • state: object

      Returns any

    • Returns a function which, when run, tests that TStatebotFsm.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 TStatebotFsm.inState.)

      Parameters

      • state: string

        The state to test against.

      Returns (...fnArgs: any[]) => boolean

      A function that calls TStatebotFsm.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.
    • Parameters

      • state: string
      • OptionaloutputWhenTrue: any

      Returns (...fnArgs: any[]) => any

    • Parameters

      • state: object

      Returns () => any

    • Returns the name of the state-machine.

      Used for logging and also by assert.assertRoute for the same.

      Returns string

      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.

      Parameters

      • state: string

        The state.

      • cb: (fromState?: string, ...args: any[]) => void

        A callback function with the signature:

        (fromState, ...args?)

      Returns Function

      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
    • Function

      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.

      Parameters

      • state: string

        The state.

      • cb: (fromState?: string, ...args: any[]) => void

        A callback function with the signature:

        (fromState, ...args?)

      Returns Function

      A function that removes the listener.

      TStatebotFsm

      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!
    • Adds a listener that runs a callback immediately after the specified event is called.

      A function is returned that will remove the listener.

      Parameters

      • eventName: string
      • cb: (...args: any[]) => void

        The callback.

      Returns Function

      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)
    • 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.

      Parameters

      • state: string

        The state.

      • cb: (toState?: string, ...args: any[]) => void

        A callback function with the signature:

        (toState, ...args?)

      Returns Function

      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
    • 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.

      Parameters

      • state: string

        The state.

      • cb: (toState?: string, ...args: any[]) => void

        A callback function with the signature:

        (toState, ...args?)

      Returns Function

      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!
    • Adds a listener that runs a callback immediately after ANY state-change.

      A function is returned that will remove the listener.

      Parameters

      • cb: (toState?: string, fromState?: string, ...args: any[]) => void

        A callback function with the signature:

        (toState, fromState, ...args?)

      Returns Function

      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"
    • Adds a listener that runs a callback immediately before ANY state-change.

      A function is returned that will remove the listener.

      Parameters

      • cb: (toState?: string, fromState?: string, ...args: any[]) => void

        A callback function with the signature:

        (toState, fromState, ...args?)

      Returns Function

      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"
    • 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 TStatebotFsm.onExiting handler was created using it.

      Parameters

      Returns Function

      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 TStatebotFsm.pause'd

      Returns boolean

    • Return the state the machine will be in after TStatebotFsm.emit'ing the specified event.

      Works only after using TStatebotFsm.performTransitions.

      See also: TStatebotFsm.canTransitionTo.

      Parameters

      • eventName: string
      • OptionalstateObject: any

        If stateObject is undefined, .peek() defaults to returning TStatebotFsm.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.

      Returns any


      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"
    • 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 TStatebotFsm.onExiting handler was created using it.

      Parameters

      Returns Function

      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.

      Returns string | undefined

      The previous state, or undefined if there isn't one (ie; you have just called TStatebotFsm.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.

      Returns void

      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 TStatebotFsm.pause'd machine.

      Returns void

    • Return an array of states accessible from the state specified. If no state is passed-in, the TStatebotFsm.currentState is used.

      Parameters

      Returns string[]

      import { Statebot } from 'statebot'

      let machine = Statebot('half-duplex', {
      chart: `
      idle -> sending | receiving -> done
      `
      })

      machine.statesAvailableFromHere()
      // ["sending", "receiving"]

      machine.statesAvailableFromHere('receiving')
      // ["done"]