Global

Methods

private _allValuesAreObjects(obj) → {boolean}

Checks a given object to make sure that all its values are also objects

Parameters:
Name Type Description
obj Object.<string, Object.<string, string>>

An Object of (only) Objects. Inside each of those Objects all values are Strings which correspond to keys on the outer Object.

Returns:
boolean -

Whether or not the object contains values which are all also objects

private _allValuesFromTransitionsAreStates(obj) → {boolean}

Checks that each value the transitions lead to on a state machine are also states on the state machine

Parameters:
Name Type Description
obj Object.<string, Object.<string, string>>

An Object of (only) Objects. Inside each of those Objects all values are Strings which correspond to keys on the outer Object.

Returns:
boolean -

Whether or not all values that the transitions lead to are also states on the state machine

private _isObject(val) → {boolean}

Checks if a given value is an Object {}

Parameters:
Name Type Description
val *

A value which may possibly be an object

Returns:
boolean -

Whether or not the given values is an object

createMachine(stateMachine, initialState) → {function}

Creates a state machine - which is managed inside a closure - that will only transition if name of the transition you pass into it is among those registered for the current state. You pass in a state machine Object and you'll have a function returned to you that can repeatedly receive a transition name and always return to you the next state (if it even changes at all).

The current state will always match one of the keys in the state machine object. Associated with those keys are each Objects that hold the possible transitions that can move that state to another one.

So each sub-object in the state machine holds transition names as keys and states-to-transition-to as values. The curent state can only change if a given transition's name is among those registered for the current state. Only registered transition names can produce changes to the current state.

If you use this with Redux then you'll probably want to make the transition names match the names of Redux Action Types. That way your state machine can be used in a reducer (or a piece of Redux middleware) to alter a single prop on your Redux store (representing that machine's current state).

Parameters:
Name Type Description
stateMachine Object.<string, Object.<string, string>>

An Object of (only) Objects. Inside each of those Objects all values are Strings which correspond to keys on the outer Object.

initialState string

The state at which the machine should be initialized (will default to the first key name in the state machine)

Throws:
  • If the state machine is missing or not an object

    Type
    TypeError
  • If the state machine has any values which are not objects

    Type
    TypeError
  • If the state machine's "sub-objects" has values that are not keys on the root of the object

    Type
    TypeError
  • If the initialState is not one of the state values on the state machine

    Type
    Error
Returns:
function -

A getNextState() function that is ready to receive your transition name and return the next state (which may or not be different).

Example
const authMachine = {
  initial: {
    ATTEMPT_LOGIN: 'inProgress'
  },
  inProgress: {
    LOGIN_ERROR: 'error',
    LOGOUT_ERROR: 'error',
    LOGIN_SUCCESSFUL: 'loggedIn',
    LOGOUT_SUCCESSFUL: 'loggedOut'
  },
  loggedIn: {
    ATTEMPT_LOGOUT: 'inProgress'
  },
  loggedOut: {
    ATTEMPT_LOGIN: 'inProgress'
  },
  error: {
    ATTEMPT_LOGIN: 'inProgress',
    CLEAR_ERROR: 'loggedOut'
  }
}

const getNextAuthState = createMachine(authMachine, 'initial')

getNextAuthState('LOGIN_SUCCESSFUL')
// initial - Can't transition there yet
getNextAuthState('CLEAR_ERROR')
// initial - Also doesn't affect state
getNextAuthState('ATTEMPT_LOGIN')
// inProgress - Now we have a login attempt, which changes state
getNextAuthState('LOGIN_SUCCESSFUL')
// loggedIn - Advances from that pending state to logged-in
getNextAuthState('ATTEMPT_LOGOUT')
// inProgress - Attempting to log out
getNextAuthState('LOGOUT_ERROR')
// error - Now we're in an error state
getNextAuthState('CLEAR_ERROR')
// loggedOut - Finishes logout process

createTransitionHandler(handler, machine) → {function}

Takes a given state machine and handler and returns a function which is ready to receive the starting "state" value and any starting data, following through the entire sequence of async function until the state stops advancing. Note, a handler will receive the initial data, the starting "state" value and any (optional) dependencies to place into the context for the async functions contained in the handler. A handler doesn't have to be a function but can also be an object whose keys are possible "state" values and whose values are functions that receive the initial data, state machine, and context.

Parameters:
Name Type Description
handler function | Object.<string, function()>

A handler function or an object of individual handler function (the keys on the object must match possible "states" otherwise they'll never be called)

machine Object.<string, Object.<string, string>>

An object whose keys are possible states and whose values are also objects (but whose keys are transition names and whose values are states they will advance to)

Throws:
  • If a state machine is not provided

    Type
    TypeError
  • If a handler function/object is not provided

    Type
    TypeError
  • If the handler is not a function or an object whose keys do not correspond to keys in the state machine

    Type
    TypeError
  • If the state machine has any values which are not objects

    Type
    TypeError
  • If the state machine's "sub-objects" has values that are not keys on the root of the object

    Type
    TypeError
Returns:
function -

A wrapped handler function that is ready to receive the (1) initial data, (2) starting "state" value on the machine, and (3) an object containing any dependencies the handler may have

getFirstState(stateMachine, initialState) → {string}

Gets the first state in a given state machine

Parameters:
Name Type Description
stateMachine Object.<string, Object.<string, string>>

An Object of (only) Objects. Inside each of those Objects all values are Strings which correspond to keys on the outer Object.

initialState string

The state at which the machine should be initialized (will default to the first key name in the state machine)

Returns:
string -

The state value at which the machine should start

getNextState(currentState, transitionName, stateMachine) → {string}

Compares a current state value to a transition name, using a state machine (Object) where all the possible states also have transition names registered to each one (which link to new states). Invoking this function will make that calculation and always return to you what the next state should be (which may be un-changed). This function is used by createMachine().

Parameters:
Name Type Description
currentState string

The current state - which matches one of the keys in the 'stateMachine'

transitionName string

A string value that will cause a state change _if_ it matches the key name of one (or more) of the sub-objects in the 'stateMachine'

stateMachine Object.<string, Object.<string, function()>>

An Object of (only) Objects. Inside each of those Objects all values are Strings which correspond to keys on the outer Object.

Returns:
string -

The next state (which might not have changed from the current state)

nextState(transitionopt) → {string}

A simple function that retrieves the current state or optionally advances to the next state determined by a given transition value

Parameters:
Name Type Attributes Description
transition string <optional>

One of the transition names registered for the current state

Returns:
string -

The current state (one of the root-level keys from the state machine

validateStateMachine(stateMachine)

Checks a given state machine to make sure it is valid, and throws an error if not

Parameters:
Name Type Description
stateMachine Object.<string, Object.<string, string>>

An Object of (only) Objects. Inside each of those Objects all values are Strings which correspond to keys on the outer Object.

Throws:
  • If the state machine is missing or not an object

    Type
    TypeError
  • If the state machine has any values which are not objects

    Type
    TypeError
  • If the state machine's "sub-objects" has values that are not keys on the root of the object

    Type
    TypeError

wrappedTransitionHandler(initialData, initialState, contextopt) → {*}

A handler function that will advance from state to state - executing each piece of logic and/or async function the user defined, until the state can no longer advance and the current value or error is returned at that point.

Parameters:
Name Type Attributes Description
initialData Object.<string, any>

Any starting data for the handler

initialState string

A starting "state" value which should be one of the possible values on the state machine

context Object.<string, any> <optional>

An optional object containing any dependencies of the handler (API clients, caches, etc.)

Throws:

If the handler encounters an unexpected exception

Type
TransitionError
Returns:
* -

When the handler can no longer advance to another possible state, the value of the last function it executed is returned

Type Definitions

TransitionError

Exends the base JavaScript base Error

Properties:
Name Type Description
name string

The name of the error (in this case "TransitionError")

data.currentState string

The current state of the state machine at the time the error was encountered