Powerful finite state machine module that is very easy to use. From basic finite state machines to acceptance, locks and middleware. Install the module with npm.
$ npm install --save node-state-machine
Basics
; // We will start with a basic example. Lets create a machine// with three states: 'A', 'B' and 'C'. The first state will// always be the initial state. The machine will take care of// duplicate states itself. So new Machine('A', 'B', 'C', 'B')// only has three states.let machine = 'A''B''C'; // Now lets make some simple transitions. For example, this first// one says "if we process 'b' and are in state 'A', go to state// 'B'". The last one uses the '*' wildcard. It is called when// there is no other transition found.machine;machine;machine;machine; // Finalize the machine. From now on we can't add transitions// anymore and we can start using the machine!machine; machinecurrent; // 'A'machine; // machine.current() == 'B';machine; // machine.current() == 'C';machine; // machine.current() == 'A';machinecurrent; // 'A'
Transitions
; // We will create the exact same machine as the example before.let machine = 'A' 'B' 'C'; // With the same transitions...machine;machine; // However, we can define more complex triggers for certain// transitions if needed. Note that we define the same trigger// here as the .on('a') like in the example above! However, we can// write whatever we want in this lambda function.machine; // We can use .default() instead of .on('*'). Use whichever you like!machine; // Finalize the machine. From now on we can't add transitions// and can start using the machine!machine; machinecurrent; // 'A'machine; // machine.current() == 'B';machine; // machine.current() == 'C';machine; // machine.current() == 'A';machinecurrent; // 'A'
Callbacks
// Again, we will use the same machine.;let machine = 'A' 'B' 'C';machine;machine;machine;machine;machine; // But now, we use the callback function of the machine!// Note that we can define (or change) it after the machine// is finalized! This is because it doesn't change anything// about the internal state of the machine.machine; // We can also chain the process functions.machine; // The logs are now as follows:// Went from A to B via b!// Went from B to C via c!// Went from C to A via d!
Acceptance
// Again, we will use the same machine.;let machine = 'A' 'B' 'C';machine;machine;machine;machine; // But now we define accepting states! These are states// that define whether or not the input is accepted.machine; machine;machine; // Now accept is true because the current state belongs// to one of the accepting states!let accept = machine;
Locks & Async
// Same code as above...machine; // When the machine is locked, it won't change its internal// state! This can be used when waiting for async functions.// After these transitions, the current state is 'A'.machine;machine;machine;machine;machine;machine
Middlewares
// Again, we will use the same machine.;let machine = 'A' 'B' 'C'; // The use of middlewares is very useful in some cases. A middleware// is a function that handles the trigger of a transition. For// example, every time we go from 'B' to 'C', we would like to add// the trigger value to a global value.let output = '';let { output += v; } // We create the same machine as above, and append the middleware to// the transition from 'B' to 'C'.machine;machine;machine;machine; machine;machine;machine;machine;machine;machine; // Now output == 'cc' !// Note: You can also use multiple middlewares: .middlewares(m1, m2, m3).on('a');
Extra
// A little script that shows some extra functions that you can use. // Process all the values at once. Returns true or false on whether or not the// machine accepts the input. This function does the same as this code snippet:// machine.process('a').process('b').process('c');// let accept = machine.accepted();let accept = machine; // Sets all default transitions to the same state. ex A > A.machine; // Check if the created machine is deterministic for the given alphabet.machine; // Checking the finalized state.machine; // false;machine;machine; // true; // Checking the locked state.machine;machine; // true;machine;machine; // false; // Returns the current state of the machine.machinecurrent;// Returns the initial state of the machine.machine;// Returns the number of states of the machine.machine; // Resets the machine to its initial state.machine;
Development
Feel free to contribute some cool features. The following ideas will also be implemented in the future, but feel free to do it yourself if you want to. I will also add eslint and add all the development processes to gulp. To contribute, clone the repo and run npm install. Make sure gulp is installed globally.
$ npm install # Install dependencies
$ npm install -g gulp # Make sure you have gulp
$ gulp # This will run flow & babel
$ npm test # To run the tests
// Future Code Features // Return a new machine which is the minimal DFA of this machine. This// depends on isDeterministic(alphabet: Array<string>).machine; // Build a machine based on a regex.machine;
License
MIT - Jensen Bernard