Code Monkey home page Code Monkey logo

state's Introduction

state

Executable finite state machine for TypeScript and JavaScript.

If you like @steelbreeze/state, please star it...

NPM Version NPM Downloads Build Status Maintainability Test Coverage

Note: v8 is now live and contains breaking changes but offers a further simplified code base performance improvements. See the release notes for more information.

Warning: v8 does not yet contain any support for serialization due to the challanges brought by the introduction of deferred events which are cached within the state machine instance alongside the active state configuration.

Install

npm i @steelbreeze/state

Usage

The API is broken up into two distinct parts:

  1. A set of classes that represent a state machine model (State, PseudoState, Region, etc.);
  2. An class managing the active state configuration of a state machine instance at runtime (Instance).

Together, they enable multiple instances of the same state machine model.

The full API reference can be found here.

TypeScript

import * as state from "@steelbreeze/state";

// create event class that a transition will respond to
class MyEvent {
	public constructor(public fieldA: string, public fieldB: number) { }

	public toString(): string {
		return JSON.stringify(this);
	}
}

// log state entry, exit and trigger event evaluation
state.log.add(message => console.info(message), state.log.Entry | state.log.Exit | state.log.Evaluate);

// create the state machine model elements
const model = new state.State("model");
const initial = new state.PseudoState("initial", model, state.PseudoStateKind.Initial);
const stateA = new state.State("stateA", model);
const stateB = new state.State("stateB", model);

// create the transition from initial pseudo state to stateA
initial.to(stateA);

// create a transtion from stateA to stateB a for events of type MyEvent with a guard condition
stateA.on(MyEvent).when(myEvent => myEvent.fieldB > 2).to(stateB);

// create an instance of the state machine model
let instance = new state.Instance("instance", model);

// send the machine events for evaluation
instance.evaluate(new MyEvent("test", 1));
instance.evaluate(new MyEvent("test", 3));

JavaScript (ECMAScript 2015)

var state = require("@steelbreeze/state");

// create event class that a transition will respond to
class MyEvent {
	constructor(fieldA, fieldB) { this.fieldA = fieldA; this.fieldB = fieldB; }

	toString() { return JSON.stringify(this); }
}

// log state entry, exit and trigger event evaluation
state.log.add(message => console.info(message), state.log.Entry | state.log.Exit | state.log.Evaluate);

// create the state machine model elements
const model = new state.State("model");
const initial = new state.PseudoState("initial", model, state.PseudoStateKind.Initial);
const stateA = new state.State("stateA", model);
const stateB = new state.State("stateB", model);

// create the transition from initial pseudo state to stateA
initial.to(stateA);

// create a transtion from stateA to stateB a for events of type MyEvent with a guard condition
stateA.on(MyEvent).when(myEvent => myEvent.fieldB > 2).to(stateB);

// create an instance of the state machine model
let instance = new state.Instance("instance", model);

// send the machine events for evaluation
instance.evaluate(new MyEvent("test", 1));
instance.evaluate(new MyEvent("test", 3));

Output

The output of the above code will be:

instance enter model
instance enter model.default
instance enter model.default.initial
instance leave model.default.initial
instance enter model.default.stateA
instance evaluate {"fieldA":"test","fieldB":1}
instance evaluate {"fieldA":"test","fieldB":3}
instance leave model.default.stateA
instance enter model.default.stateB

Note that in the example above, a default region is inserted as a child of model and parent of initial, stateA and stateB; the name of default regions copy their parent state hence seeing model.model in the output above.

License

MIT License

Copyright (c) 2022 David Morris

state's People

Contributors

mesmo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

state's Issues

Could not install @steelbreeze/state with npm

$ npm i @steelbreeze/state
npm ERR! Darwin 16.4.0
npm ERR! argv "/Users/user/.nvm/versions/node/v6.11.1/bin/node" "/Users/dmtrs/.nvm/versions/node/v6.11.1/bin/npm" "i" "@steelbreeze/state"
npm ERR! node v6.11.1
npm ERR! npm  v3.10.10
npm ERR! code E404

npm ERR! 404 Not found : @steelbreeze/state
npm ERR! 404
npm ERR! 404  '@steelbreeze/state' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/user/code/tmp/npm-debug.log

$ node --version
v6.11.1

$ npm --version
3.10.10

Storing application state

Use case: A multi-step form (potentially 100+ steps) which gathers information from a user (a type of Decision Support System, DSS). At each point in the multi-step form (state), I want to store the answers for use by a subsequent step (sibling state in the same region, or child state in a composite state region), or for the purpose of reloading previously-entered information into a form in the event that the user moves back in the decision-making process.

Can you recommend an approach for storing application state (not a snapshot of the FSM, but a snapshot of the application context) within a state machine instance? Does the following seem reasonable?

export interface IInstance {
  ...
  setCurrentAppContext(vertex: Vertex, context: any): void;
  getCurrentAppContext(vertex: Vertex): any;
  ...
}

Thank you.

visitElement return types and return values

Can you help me reconcile the following:

  • Visitor::visitElement returns any and has no implementation
  • Runtime::visitElement returns void
  • Visitor::{visitRegion, visitVertex, visitStateMachine} return this.visitElement(...)

Second pass through state machine yields different results

Given this state machine, and the corresponding execution log at the end of this post:

  • On the first pass, when "Continue" then "No" is processed, the instance moves into A_1.
  • On the second pass, when "Continue" then "No" is processed, the instance moves into A_pass, when I expected it to move to A_1.

initialise model
initialise instance
instance enter model.default
instance enter model.default.initial
instance leave model.default.initial
instance enter model.default.identify

instance evaluate message: Continue
instance leave model.default.identify
instance enter model.default.exception_1

instance evaluate message: No
instance leave model.default.exception_1
instance enter model.default.A
instance enter model.default.A.default
instance enter model.default.A.default.A_initial
instance leave model.default.A.default.A_initial
instance enter model.default.A.default.A_1

instance evaluate message: Yes
instance leave model.default.A.default.A_1
instance enter model.default.A.default.A_2

instance evaluate message: Yes
instance leave model.default.A.default.A_2
instance enter model.default.A.default.A_pass
instance leave model.default.A.default.A_pass
instance leave model.default.A.default
instance leave model.default.A
instance enter model.default.model_pass
instance leave model.default.model_pass
instance enter model.default.identify

instance evaluate message: Continue
instance leave model.default.identify
instance enter model.default.exception_1

instance evaluate message: No
instance leave model.default.exception_1
instance enter model.default.A
instance enter model.default.A.default
instance enter model.default.A.default.A_initial
instance leave model.default.A.default.A_initial
instance enter model.default.A.default.A_pass`

How to use instance.evaluate in entry of State.

Although I wrote instance.evaluate() in entry of State(see the below code), the instance can't move to a next state.
Could you give me a way to evaluate in entry?

var state = require("@steelbreeze/state");

// create event class that a transition will respond to
class MyEvent {
	constructor(fieldA, fieldB) { this.fieldA = fieldA; this.fieldB = fieldB; }

	toString() { return JSON.stringify(this); }
}

// log state entry, exit and trigger event evaluation
state.log.add(message => console.info(message), state.log.Entry | state.log.Exit | state.log.Evaluate);

// create the state machine model elements
const model = new state.State("model");
const initial = new state.PseudoState("initial", model, state.PseudoStateKind.Initial);
const stateA = new state.State("stateA", model);
const stateB = new state.State("stateB", model).entry(() => {console.log("hellkow B")}).exit(() => {console.log("bye B")});
let instance = new state.Instance("instance", model);

// HERE
stateA.entry(() => {
	instance.evaluate(new MyEvent(1, 2));
});

stateA.on(MyEvent).when((e) => { return e.fieldA === 1; }).to(stateB);
stateB.on(MyEvent).when((e) => { return e.fieldA === 1; }).to(stateA);
// create the transition from initial pseudo state to stateA
initial.to(stateA);

Breaking change in 7.2.0

Hei, since the release 7.2.0 code similar to the following example don't work anymore. msg is undefined.

DefaultStatusState.to(null).when((msg) => {
  return msg.type === 'abc';
}).effect((stalled) => {
  console.log('abc');
});

The FinalState removal could be added to the breaking changes list

Hei,
I am updating from state.js 5 to @steelbreeze/state 7, following the breaking changes indications in the RELEASES.md file. Looking at the exception I have and the new examples, FinalState doesn't exist anymore.

This could be added to the breaking changes list.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.