Gathering detailed insights and metrics for fsm-iterator
Gathering detailed insights and metrics for fsm-iterator
Gathering detailed insights and metrics for fsm-iterator
Gathering detailed insights and metrics for fsm-iterator
es-iterator-helpers
An ESnext spec-compliant iterator helpers shim/polyfill/replacement that works as far down as ES3.
es-get-iterator
Get an iterator for any JS language value. Works robustly across all environments, all versions.
stop-iteration-iterator
Firefox 17-26 iterators throw a StopIteration object to indicate "done". This normalizes it.
es6-iterator
Iterator abstraction based on ES6 specification
npm install fsm-iterator
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
16 Stars
11 Commits
3 Watching
1 Branches
1 Contributors
Updated on 27 Sept 2021
JavaScript (100%)
Cumulative downloads
Total Downloads
Last day
-14.3%
27,231
Compared to previous day
Last week
-0.2%
155,146
Compared to previous week
Last month
5.4%
663,365
Compared to previous month
Last year
3.6%
7,763,455
Compared to previous year
A finite state machine iterator for JavaScript.
Use fsm-iterator to implement a finite state machine generator function without
the need for generator function*
syntax. This is a perfect for library authors
that need to use generators but don't want to burden their ES5 users with a
transpiled generator runtime.
npm install --save fsm-iterator
The default export is the fsmIterator
function. It takes an initial state as
the first argument and the state machine as an object literal as the second
argument. Each key-value pair of your definition is a state and a function to
handle that state. States can be strings or symbols.
The state function takes any value that was passed into the next
method of the
iterator as the first argument and the finite state machine definition itself as
the second argument. This allows you to act on values passed back into the
"generator" and delegate to other states. The finite state machine argument also
includes a previousState
property if you need to use it.
To yield a value from your state function return an object literal with the
value
property set to the yielded value. To specify the next state to
transition to, set the next
property to the next state. You can end the
iterator by including the done
property set to true
. If you don't supply the
next
property, then the iterator will stay in the same state. This is fine if
you want to loop on one thing, but if you have multiple states, then remember to
use the next
property.
You may include a throw
function to handle the throw
method of the iterator.
It takes the thrown error as the first argument and the finite state machine
definition as the second argument. If you don't supply a throw
function, then
your iterator will stop, rethrowing the error.
You may intercept the iterator's return
method by supplying a return
function that receives the passed-in return value as the first argument and the
finite state machine definition as the second argument. You can return your own
return value or keep your iterator returning. This is similar to handling the
finally
block in a try..finally
statement in a ES2015 generator function.
1// ES2015 modules 2import fsmIterator from 'fsm-iterator'; 3 4// ES5 and CJS 5var fsmIterator = require('fsm-iterator').default; 6 7const FOO = 'FOO'; 8const BAR = 'BAR'; 9const BAZ = 'BAZ'; 10 11const definition = { 12 [FOO]: () => ({ 13 value: 'foo', 14 next: BAR, 15 }), 16 17 [BAR](x) { 18 if (x < 0) { 19 return { 20 value: x / 2, 21 done: true, 22 }; 23 } 24 25 return { 26 value: x * 2, 27 next: BAZ, 28 }; 29 }, 30 31 [BAZ]: (_, fsm) => ({ 32 value: `baz : ${fsm.previousState}`, 33 next: FOO, 34 }), 35 36 return(value, fsm) { 37 return { 38 value: 'my own return', 39 done: true, 40 } 41 }, 42 43 throw: (e, fsm) => ({ 44 value: `${e.message} : ${fsm.previousState}`, 45 next: FOO, 46 }), 47}; 48 49// Normal path 50let iterator = fsmIterator(FOO, definition); 51 52iterator.next(); // { value: 'foo', done: false } 53iterator.next(21); // { value: 42, done: false } 54iterator.next(); // { value: 'baz : BAR', done: false } 55iterator.next(); // { value: 'foo', done: false } 56iterator.next(-42); // { value: -21, done: true } 57 58// Throwing 59const error = new Error('error'); 60iterator = fsmIterator(FOO, definition); 61 62iterator.next(); // { value: 'foo', done: false } 63iterator.next(21); // { value: 42, done: false } 64iterator.throw(error); // { value: 'error : BAR', done: false } 65iterator.next(); // { value: 'foo', done: false } 66 67// Returning 68iterator = fsmIterator(FOO, definition); 69 70iterator.next(); // { value: 'foo', done: false } 71iterator.next(21); // { value: 42, done: false } 72iterator.return('the end'); // { value: 'my own return', done: true }
Here is the comparable ES2015 generator for the previous example.
1const FOO = 'FOO'; 2const BAR = 'BAR'; 3const BAZ = 'BAZ'; 4 5function* myGenerator() { 6 let currentState = FOO; 7 let previousState = null; 8 9 function setState(newState) { 10 previousState = currentState; 11 currentState = newState; 12 } 13 14 while (true) { 15 try { 16 const x = yield 'foo'; 17 18 setState(BAR); 19 20 if (x < 0) { 21 return x / 2; 22 } 23 24 yield x * 2; 25 26 setState(BAZ); 27 28 yield `baz : ${previousState}`; 29 30 setState(FOO); 31 } catch (e) { 32 setState(FOO); 33 34 yield `${e.message} : ${previousState}`; 35 } finally { 36 return 'my own return'; 37 } 38 } 39}
Here is the implementation of the router
saga from
redux-saga-router using
fsmIterator
.
1import { call, take } from 'redux-saga/effects'; 2import fsmIterator from 'fsm-iterator'; 3import buildRouteMatcher from './buildRouteMatcher'; 4import createHistoryChannel from './createHistoryChannel'; 5 6const INIT = 'INIT'; 7const LISTEN = 'LISTEN'; 8const HANDLE_LOCATION = 'HANDLE_LOCATION'; 9 10export default function router(history, routes) { 11 const routeMatcher = buildRouteMatcher(routes); 12 let historyChannel = null; 13 let lastMatch = null; 14 15 function errorMessageValue(error, message) { 16 let finalMessage = `Redux Saga Router: ${message}:\n${error.message}`; 17 18 if ('stack' in error) { 19 finalMessage += `\n${error.stack}`; 20 } 21 22 return { 23 value: call([console, console.error], finalMessage), 24 next: LISTEN, 25 }; 26 } 27 28 return fsmIterator(INIT, { 29 [INIT]: () => ({ 30 value: call(createHistoryChannel, history), 31 next: LISTEN, 32 }), 33 34 [LISTEN](channel) { 35 if (channel) { 36 historyChannel = channel; 37 } 38 39 return { 40 value: take(historyChannel), 41 next: HANDLE_LOCATION, 42 }; 43 }, 44 45 [HANDLE_LOCATION](location, fsm) { 46 const path = location.pathname; 47 const match = routeMatcher.match(path); 48 49 if (match) { 50 lastMatch = match; 51 52 return { 53 value: call(match.action, match.params), 54 next: LISTEN, 55 }; 56 } 57 58 return fsm[LISTEN](); 59 }, 60 61 throw(e, fsm) { 62 switch (fsm.previousState) { 63 case HANDLE_LOCATION: 64 return errorMessageValue(e, `Unhandled ${e.name} in route "${lastMatch.route}"`); 65 66 case LISTEN: 67 return errorMessageValue(e, `Unexpected ${e.name} while listening for route`); 68 69 default: 70 return { done: true }; 71 } 72 }, 73 }); 74}
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
Found 0/11 approved changesets -- score normalized to 0
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
74 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More