Home

Awesome

Introduction

A stateflow is a collection of steps which has to be executed in a controlled order. A step is defined as a state, a state has an action which is executed asynchronously. The next state to go is defined as an "on" mapping either by mapping a state action completion event triggered by an execution callback or by an event emitted from one of the registered objects.

A step/state is also a resting point, waiting for the next event/decision before going to the next state.

A flow can also be used as an action in an other flow, in this case it's a subflow where the flow end event is mapped to state completion event.

Intention

The intention of stateflow is provide a means to implement high level processes, using a flow/state machine as a programming language often tends more complex graph than the original implementation.

See example shopping cart flow and checkout subflow from stateflow-example

Use cases

Example

Javascript

function loader(resource, cb) {
	fs.readFile(resource,'utf8', function(err, contents) {
		cb(err, contents);
	});
}
var stateflow = require('stateflow');
stateflow.load('myflow.flow', loader, function(error, flow) {
	if(!error) {
		flow.set('myService', service);
		flow.start();
	}
});

Example flow a -> b -> c

a.type = begin
a.action(service) {
	service.emit('event');
}
a.'service.event' -> b

b.action {
	this.installTimeout(100, 'mytimeout');
}
b.mytimeout -> c

c.type = end
c -> finish 

Install

npm install stateflow --save

Module

var stateflow = require('stateflow');

JavaScript object notation

{
   <stateName>: {
	   initialize: <function>,
	   destroy: <function>, 
	   action: <function> | <namedAction> | <js subflow object>	
       on: {
			<event|service.event>:'<nextState>', ...
	   }
	   ... other properties
   }
}

Simple stateflow language notation

A stateflow consists of zero or more statement a statement is terminated either by a newline or semicolon (;) .

Transitions are statements defined in the format state.eventName -> targetStateName.

state.event -> target

Every of 3 different names may also be enclosed in single or double quotes, this is for example needed if you need to create a transition on a service which is delimited by a dot and which is not allowed in a literal string.

state.'myService.event' -> next

State properties is a statement defined in the format stateName.propertyName = value

	state.number = 9.9
	state.action = namedAction
	state.specialString = '!!! extra !!!'
	state.flag = true

The action property is the action to be executed when the state becomes active.

The type property is to specify whether a state is a begin, end or regular state is, and must be set for begin and end states.

The state maybe be a quoted or a literal string, the property may be a quoted, literal string or number, the value may be a quoted, literal string, number or boolean.

State function property is a statement defined in the format state.property { }, general used to define actions

The state and property have the same restrictions as a regular State property then curly brackets enclose a JavaScript function body and are generally used to implement state actions.

	state.action {
		this.emit('event');
	}

Actions function can be injected with one or more services (equivalent of flow.get('<SERVICE>') as named arguments.

	state.action(myService) { // service was set via flow.set('myService', service)
		myService.someMethod();
		this.emit('event');
	}

A literal string is string without quotes out following characters of 0-9, a-Z, @, -, _

A literal number a number can have any digit, minus sign and a dot (.)

A literal boolean a boolean can be either true or false

Quoted strings can have any characters except the the quotes which it was enclosed in.

Create a flow

Use var flow = new stateflow.StateFlow(obj); to create a flow with js object nation.

Use var flow = stateflow.create(flowLanguage) to create a flow with the flow language

Use stateflow.load(name, loader, loadedCallback) to load a flow from a resource and subflows (named action which start with the @ sign).

Error handling

When an error has been thrown in action, timeout handler, onStateActive handler or onFlowActive handler.

  1. There is state error event listener ( state.on('error', listener) ) the error is emitted to the state
  2. If there was no error event listener and there is an error event transition mapping (aka state.error-> other OR state: { on:{ error:'other'} } ), the flow continues to that state.
  3. There was no error event listener and no error mapping then the flow ends with 'error' and the error object.

State

State extends EventEmitter.

Methods

get(name)

Get a service from the current state or parent(s), bottom up.

set(name, service)

Set a service

onStateActive(service, event, listener)

Listen for events on the service (name or object) while the state is active (aka automatically removed when the state exits)

onFlowActive(service, event, listener)

Listen for events on the service (name or object) while the flow is running

installTimeout(timeout, listener)

Install a state timeout

cancelTimeout()

Cancel a previously installed timeout, always executed on state exit

stateComplete(event)

Try to complete the current state with the specified event.

Properties

Events

StateFlow

StateFlow extends State

Methods

start(callback)

Execute the flow and call the callback when finished. the event is passed as first argument.

getStateObject(statName)

Get the state instance object

registerAction(name, action, initializer, destructor)

Register an action which can be referenced by state action defined as string

addStateDecorator(callback)

Add state decorator which is called just after a state or subflow is created, used to add methods and properties to states, a subflow inherent all decorators from it's parent flow.

Properties

Events

Browser

There is also a browserify version available.