- Notifications
You must be signed in to change notification settings - Fork24
Fast, easy Javascript finite state machines with visualizations; enjoy a one liner FSM instead of pages. MIT; Typescripted; 100% test coverage. Implements the FSL language.
License
StoneCypher/jssm
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Easy. Small. Fast. TS, es6, es5. Node, Browser. 100% coverage. Propertytests. Fuzz tests. Language tests for a dozen languages and emoji. Easy toshare online. Easy to embed.
Readable, useful state machines as one-liner strings.
5,072 tests, run 5,963 times.
- 5,063 specs with 100.0% coverage.
- 9 fuzz tests with 12.4% coverage.
With 3,007 lines, that's about 1.7 tests per line, or 2.0 generated tests per line.
Meet your new state machine library.
Discord community -Documentation -Issue tracker -CI build history
Wouldn't it be nice if your TypeScript and Javascript state machines were simple and readable one-liners?
import{sm}from'jssm';constTrafficLight=sm`Red -> Green -> Yellow -> Red;`;
Wouldn't it be great if they were easy to work with?
constlog=s=>console.log(s);log(TrafficLight.state());// 'Red'Machine.transition('Green');// truelog(TrafficLight.state());// 'Green'
What if the notation supported action names easily?
constTLWA=sm`Red 'next' -> Green 'next' -> Yellow 'next' -> Red;`;// TLWA = Traffic Light With Actionslog(TLWA.state());// 'Red'TLWA.action('next');// truelog(TLWA.state());// 'Green'TLWA.action('next');// truelog(TLWA.state());// 'Yellow'TLWA.action('next');// truelog(TLWA.state());// 'Red'
What if integration with the outside was straightforward?
constMTL=sm`Red 'next' -> Green 'next' -> Yellow 'next' -> Red;`// MTL = More Traffic Lights.hook('Red','Green',()=>log('GO GO GO'))// node will jump the gun when you hit return, though.hook_entry('Red',()=>log('STOP'));// so put it on one line in nodelog(MTL.state());// 'Red'MTL.action('next');// true, console logs 'GO GO GO'log(MTL.state());// 'Green'MTL.action('next');// truelog(MTL.state());// 'Yellow'MTL.action('next');// true, console logs 'STOP'log(MTL.state());// 'Red'
What if the machine followed JS standards, and distinguished refusals asfalse from mistakes asthrown?
constATL=sm`Red -> Green -> Yellow -> Red;`;// ATL = Another Traffic Lightlog(ATL.state());// 'Red' - uses 1st state unless told otherwiseATL.transition('Yellow');// false (Yellow isn't allowed from Red)ATL.transition('Blue');// throws (Blue isn't a state at all)
What if there were easy convenience notations for lists, and for designating main-path=> vs available path-> vsonly-when-forced~> ?
constTrafficLightWithOff=sm` Red => Green => Yellow => Red; [Red Yellow Green] ~> Off -> Red;`;
What if that were easy to render visually?
constTrafficLightWithOff=sm` Red => Green => Yellow => Red; [Red Yellow Green] ~> Off -> Red;`;
What if that were easy to render visually, with styling, in PNG, JPEG, or SVG?
constTrafficLightWithOff=sm` Red => Green => Yellow => Red; [Red Yellow Green] ~> Off -> Red; flow: left; state Red : { background-color: pink; corners: rounded; }; state Yellow : { background-color: lightyellow; corners: rounded; }; state Green : { background-color: lightgreen; corners: rounded; }; state Off : { background-color : steelblue; text-color : white; shape : octagon; linestyle : dashed; };`;
What if the machine was lighting fast, able to do tens of millions of transitions per second?
- What if the machine and language hadextensive 100% test coveragewiththousands of cases?
- What if the machine gave extensive Typescript introspection support?
- What if the machine had been around and active since May 2017?
- What if the machine was MIT licensed, end to end?
But, above all else:
What if it was easy?
Meet JSSM: theJavascriptStateMachine.
State machines can make your code cleaner, safer, and more trustworthy.
And, with the right language, state machines can be easy and fun.
JSSM is a Javascript state machine implementingFinite State Language, with a terse DSL and a simple API.100% test coverage; typed with Flowtype. MIT licensed.
The NPM package includes purees6, acjs es5 bundle, and.d.ts typings. The repository includes the original typescript, the bundle, the es6, documentation, tests, tutorials, and so on.
Visualize withjssm-viz, or at the command line withjssm-viz-cli.
Language test cases for Belorussian, English, German, Hebrew, Italian, Russian, Spanish, Ukrainian, and Emoji. Please help to make sure that your language is well handled!
Specify finite state machines with a brief syntax. Run them; they're fast. Make mistakes; they're strict. Derivecharts. Save and load states, and histories. Make machine factories to churn out dozens or thousands of instances.Impress friends and loved ones. Cure corns and callouses.
Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;This will produce the following FSM (graphed withjssm-viz):
You'll build an executable state machine.
As usual, a valid question.
State machines are a method of making your software better able to prevent illegal states. Similar to type systems, SQLconstraints, and linters, state machines are a way to teach the software to catch mistakes in ways you define, to helplead to better software.
The major mechanism of a state machine is to definestates, thetransitions between them, and sometimes associateddata and other niceties. The minor mechanism of state machines is to attachactions to the transitions, such thatthe state machine can partially run itself.
So, to look at the same traffic light as above, you'll notice some things.
- A sufficiently smart implementation will know that it's okay for
Greento switch toYellow, but not toRed - A sufficiently smart implementation knows there's no such thing as
Blue - A sufficiently smart implementation knows that when in
Green, to be told toProceedmeans to go toYellow, butwhen inYellow, it means to go toRedinstead
Along with other common sense things, a good state machine implementation can help eliminate large classes of error insoftware. State machines are often applied when the stakes on having things correct are high.
Brevity.
High quality testing. JSSM has 100% coverage, and has partial stochastic test coverage.
Feature parity, especially around the DSL and data control.
Data integrity. JSSM allows a much stricter form of state machine than is common, with a relatively low performanceand storage overhead. It also offers an extremely terse domain specific language (though it does not require said DSL)to produce state machines in otherwise comparatively tiny and easily read code.
A state machine in
JSSMis defined in one of two ways: through the DSL, or through a datastructure.
So yeah, let's start by getting some terminology out of the way, and then we can go right back to that impenetrablesentence, so that it'll make sense.
Finite state machines have been around forever, are used by everyone, and are hugely important. As a result, theterminology is a mess, is in conflict, and is very poorly chosen, in accordince with everything-is-horrible law.
This section describes the terminologyas used by this library. The author has done his best to choose a terminologythat matches common use and will be familiar to most. Conflicts are explained in the following section, to keep thissimple.
For this quick overview, we'll define six basic concepts:
Finite state machinesMachinesStatesCurrent stateTransitionsActions
There's other stuff, of course, but these five are enough to wrap your head aroundfinite state machines.
This is a trivial traffic lightFSM, with three states, three transitions, and one action:
Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;Let's review its pieces.
finite state machines- A
finite state machine(orFSM) is a collection ofstates, and rules about how you cantransitionbetweenthestates. - We tend to refer to a design for a machine as "an
FSM." - In this example, the traffic light's structure is "a traffic light
FSM."
- A
statesFSMs always have at least onestate, and nearly always manystates- In this example,
- the
states areRed,Yellow, andGreen - Something made from this
FSMwill only ever be one of those colors - not, say,Blue
- the
machines- Single instances of an
FSMare referred to as amachine - We might have a thousand instances of the traffic light designed above
- We would say "My intersection has four
machinesof the standard three color lightFSM."
- Single instances of an
current state- A
machinehas acurrent state, though anFSMdoes not- "This specific traffic light is currentlyRed"
- Traffic lights in general do not have a current color, only specific lights
FSMs do not have a current state, only specificmachines- A given
machinewill always have exactly onestate- never multiple, never none
- A
transitionsFSMs nearly always havetransitions- Transitions govern whether a
statemay be reached from anotherstate- This restriction is much of the value of
FSMs
- This restriction is much of the value of
- In this example,
- the
transitions are- Green →Yellow
- Yellow →Red
- Red →Green
- a
machinewhosecurrent stateisGreen may switch toYellow, because there is an appropriate transition - a
machinewhosecurrent stateisGreen may not switch toRed, or toGreen anew, because there is nosuch transition- A
machineinYellow which is told totransitiontoGreen (which isn't legal) will know to refuse - This makes
FSMs an effective tool for error prevention
- A
- the
actions- Many
FSMs haveactions, which represent events from the outside world. - In this example, there is only one action -Proceed
- The
actionProceed is available from all three colors
- The
- At any time we may indicate to this light to go to its next color, withouttaking the time to know what it is.
- This allows
FSMs like the light to self-manage. - A
machineinYellow which is told to take theactionProceed willknow on its own to switch itscurrent statetoRed. - This makes
FSMs an effective tool for complexity reduction
- This allows
- Many
Those six ideas in hand -FSMs,states,machines,current state,transitions, andactions - and you're readyto move forwards.
One other quick definition - aDSL, ordomain specific language, is when someone makes a language and embeds it intoa different language, for the purpose of attacking a specific job. WhenReact uses a precompiler to embed stuff thatlooks like HTML in Javascript, that's a DSL.
This library implements a simple language fordefining finite state machines inside of strings. For example, thisDSL defines that'a -> b;' actually means "create two states, create a transition between them, assign the first asthe initial state", et cetera. That micro-language is theDSL that we'll be referring to a lot, coming up. ThisDSL's parser's original name wasjssm-dot, because it's a descendant-in-spirit of an older flowcharting languageDOT, fromgraphviz, which is also used to make thevisualizations injssm-viz by way ofviz-js.
Enough history lesson. On with the tooling.
So let's put together a trivial four-state traffic light: the three colors, plusOff. This will give us anopportunity to go over the basic facilities in the language.
At any time, you can take the code and put it into thegraph explorer for an opportunity to mess with thecode as you see fit.
Our light will start in theOffstate, with the ability to switch to theRedstate.
Since that's a normal, not-notable thing, we'll just make it a regular-> legal transition.
Off -> Red;We will give thattransition anaction, and call itTurnOn.
Off 'TurnOn' -> Red;So far, our machine is simple:
The main path of a traffic light is cycling fromGreen toYellow, then toRed, then back again. Becausethis is the main path, we'll mark these steps=> main transitions.
Off 'TurnOn' -> Red => Green => Yellow => Red;We will give those all the same action name,Proceed, indicating "next color" without needing to know what we'recurrently on.
Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;Machine's still pretty simple:
We'd also like to be able to turn this light back off. Because that's expected to be a rarity, we'll require that itbe a~> forced transition.
We could write
Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;Red ~> Off;Yellow ~> Off;Green ~> Off;But that takes a lot of space even with this short list, so, instead we'll use the array notation
Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;[Red Yellow Green] ~> Off;And we'd like those all to have the actionTurnOff, so
Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;[Red Yellow Green] 'TurnOff' ~> Off;Machine's still not too bad:
That's actually the bulk of the language. There are other little add-ons here and there, but, primarily you now knowhow to write a state machine.
Let's load it and use it! 😀
Let's make astate machine for ATMs. In the process, we will use a lot of core concepts offinite state machinesand offsl, this library'sDSL.
We're going to improve on thisNCSU ATM diagram that Ifound:
Remember, at any time, you can take the code and put it into thegraph explorer for an opportunity to mess with thecode as you see fit.
We'll start with anempty machine.
EmptyWaiting 'Wait' -> EmptyWaiting;We'll add the ability to physically eject the user's card and reset to the empty and waiting state. Right now it'lldangle around un-used at the top, but later it'll become useful.
This is expressed as the pathEjectCardAndReset -> EmptyWaiting;
EmptyWaiting 'Wait' -> EmptyWaiting;EjectCardAndReset -> EmptyWaiting;We'll add the ability to physically insert a card, next. You know, the, uh, thing ATMs are pretty much for.
To get this, add the path legEmptyWaiting 'InsertCard' -> HasCardNoAuth;
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;EjectCardAndReset -> EmptyWaiting;Notice that the newstate,HasCardNoAuth, has been rendered red. This is because it isterminal - there isno exit from this node currently. (EmptyAndWaiting did not render that way because it had a transition to itself.)That will change as we go back to adding more nodes.terminal nodes are usually either mistakes or the last singlestate of a givenFSM.
Next, we should have a cancel, because the ATM's 7 key is broken, and we need our card back. Cancel willexit to the main menu, and return our card credential.
To that end, we add the pathHasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;EjectCardAndReset -> EmptyWaiting;Next, let's give the ability to get the password ... wrong. 😂 Because we all know that one ATM that only has thewrong-PIN path, so, apparently that's a product to someone.
When they get the PIN wrong, they're prompted to try again (or to cancel.)
We'll add the pathHasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;EjectCardAndReset -> EmptyWaiting;Next, let's give the ability to get the password right.
We'll add two paths. The first gets the password right:HasCardNoAuth 'RightPIN' -> MainMenu;
The second, from our newstateMainMenu, gives people the ability to leave:MainMenu 'ExitReturnCard' -> EjectCardAndReset;
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;HasCardNoAuth 'RightPIN' -> MainMenu;MainMenu 'ExitReturnCard' -> EjectCardAndReset;EjectCardAndReset -> EmptyWaiting;Hooray, now we're getting somewhere.
Let's add the ability to check your balance. First pick that from the main menu, then pick which account to see thebalance of, then you're shown a screen with the information you requested; then go back to the main menu.
That'sMainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;.
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;HasCardNoAuth 'RightPIN' -> MainMenu;MainMenu 'ExitReturnCard' -> EjectCardAndReset;MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;EjectCardAndReset -> EmptyWaiting;Let's add something difficult. Their state machine just proceeds assuming everything is okay.
To desposit money:
- Accept physical money
- If accept failed (eg door jammed,) reject physical object, go to main menu
- If accept succeeded, ask human expected value
- Pick an account this should go into
- Contact bank. Request to credit for theoretical physical money.
- Three results: yes, no, offer-after-audit.
- If no, reject physical object, go to main menu.
- If yes, consume physical object, tell user consumed, go to main menu
- If offer-after-audit, ask human what to do
- if human-yes, consume physical object, tell user consumed, go to main menu
- if human-no, reject physical object, go to main menu
Writing this out in code is not only generally longer than the text form, but also error prone and hard to maintain.
... or there's theFSMDSL, which is usually as-brief-as the text, and frequently both briefer and more explicit.
- Rules 1-2:
MainMenu 'AcceptDeposit' -> TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu; - Rules 3-6:
TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse; - Rule 7:
BankResponse 'BankNo' -> RejectPhysicalMoney; - Rule 8:
BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu; - Rules 9-10:
BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney; - Rule 11:
BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
Or, as a block,
MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;BankResponse 'BankNo' -> RejectPhysicalMoney;BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;Which leaves us with the total code
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;HasCardNoAuth 'RightPIN' -> MainMenu;MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;MainMenu 'ExitReturnCard' -> EjectCardAndReset;MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;BankResponse 'BankNo' -> RejectPhysicalMoney;BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;EjectCardAndReset -> EmptyWaiting;Let's also be able to take money from the machine. After this, we'll move on, since our example is pretty squarely madeby now.
- Pick a withdrawl account, or cancel to the main menu
- Shown a balance, pick a withdrawl amount, or cancel to acct picker
- Is the withdrawl account too high? If so go to 2
- Does the machine actually have the money? If not go to 2
- Otherwise confirm intent w/ human
- Attempt to post the transaction.
- If fail, display reason and go to 1
- If succeed, dispense money and go to main menu
- Rules 1-3:
MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount; - Rule 4:
AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount; - Rule 5:
MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount; - Rule 6:
ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse; - Rule 7:
BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount; - Rule 8:
BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
Rule 1 canceller:PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;Rule 2 canceller:PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
Or as a whole, we're adding
MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;Which leaves us with
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;HasCardNoAuth 'RightPIN' -> MainMenu;MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;MainMenu 'ExitReturnCard' -> EjectCardAndReset;MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;BankResponse 'BankNo' -> RejectPhysicalMoney;BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;EjectCardAndReset -> EmptyWaiting;As you can see, building up even very complex state machines is actually relatively straightforward, in a shortamount of time.
It's really quite simple.
- Make a github repository.
- Put your code in a file inside, with the extension
.fsl - Make sure your code contains a
machine_name
Once done, your work should show uphere.
There are a lot of state machine impls for JS, many quite a bit more mature than this one. Here are some options:
- Finity 😮
- Stately.js
- machina.js
- Pastafarian
- Henderson
- fsm-as-promised
- state-machine
- mood
- FSM Workbench
- SimpleStateMachine
- shime/micro-machine
- soveran/micromachine (ruby)
- fabiospampinato/FSM
- HQarroum/FSM
- Finite-State-Automata
- finite-state-machine
- nfm
And some similar stuff:
- redux-machine
- ember-fsm
- State machine cat
- Workty 😮
- sam-simpler
- event_chain
- DRAKON
- Yakindu Statechart Tools
- GraphViz
- Viz.js, which we use
JSSM and FSL have had a lot of help.
- Mykhaylo Les provided three translation test cases (Ukrainian,Belarussian, andRussian,) and the corresponding Traffic Light translations (alsoUkrainian,Belarussian, andRussian.)
- Tanvir Islam provided theBengali test case, translated theTraffic Light to Bengali, and published the first non-English
FSLmachine, in Bengali. - Francisco Junior provided thePortuguese test case and translated theTraffic Light to Portuguese
- Jeff Katz provided theGerman test case.
- Alex Cresswell provdied theSpanish test case
- Dvir Cohen provided theHebrew test case.
- David de la Peña provided theFrench test case
If I've overlooked you, please let me know.
If you'd like to help, it's straightforward.
- Easy mode: open a PR withthis file translated into your language
- Extra mile: create a new repo containingthis file translated
Vat Raghavan has participated extensively in language discussion and implemented several features.
Forest Belton has provided guidance, bugfixes, parser and language commentary.
Jordan Harbrand suggested two interesting features and provided strong feedback on the initial tutorial draft.
The biggest thanks must go toMichael Morgan, who has debated significant sections ofthe notation, invented several concepts and operators, helped with the parser, with system nomenclature, for having publishedthe first not-by-meFSL machine, for encouragement, and generally just for having been as interested as he has been.
About
Fast, easy Javascript finite state machines with visualizations; enjoy a one liner FSM instead of pages. MIT; Typescripted; 100% test coverage. Implements the FSL language.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors10
Uh oh!
There was an error while loading.Please reload this page.


















