UNPKG

33.8 kBMarkdownView Raw
1# jssm
2
3Wouldn't it be nice if your Javascript state machines were simple and readable?
4
5```javascript
6import { sm } from 'jssm';
7
8const Machine = sm`
9 Green => Yellow => Red => Green;
10 [Red Yellow Green] ~> Off -> Red;
11`;
12
13console.log( Machine.state() ); // 'Green'
14
15Machine.transition('Yellow'); // true
16console.log( Machine.state() ); // 'Yellow'
17
18Machine.transition('Blue'); // false
19console.log( Machine.state() ); // 'Yellow'
20```
21
22What if that were easy to render visually, with styling?
23
24![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/doc%20light%20styled.png)
25
26
27
28<br/><br/>
29
30## Introducing JSSM
31
32JSSM is a Javascript state machine implementing [Finite State Language](https://fsl.tools/), with a terse DSL and a simple API.
33100% test coverage; typed with Flowtype. MIT licensed.
34
35The NPM package includes pure `es6`, a `cjs es5` bundle, and `.d.ts` typings. The repository includes the original typescript, the bundle, the es6, documentation, tests, tutorials, and so on.
36
37[Try it live!](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html)
38
39Visualize with [jssm-viz](https://github.com/StoneCypher/jssm-viz), or at the command line with [jssm-viz-cli](https://github.com/StoneCypher/jssm-viz-cli).
40
41Language test cases for Belorussian, English, German, Hebrew, Italian, Russian, Spanish, Ukrainian, and Emoji. Please help to make sure that your language is well handled!
42
43<div id="badge_style_hook">
44
45[![Actions Status](https://github.com/StoneCypher/jssm/workflows/Node%20CI/badge.svg)](https://github.com/StoneCypher/jssm/actions)
46
47[![GitHub forks](https://img.shields.io/github/forks/StoneCypher/jssm.svg?style=social&label=Fork%20JSSM)]()
48[![GitHub watchers](https://img.shields.io/github/watchers/StoneCypher/jssm.svg?style=social&label=Watch%20JSSM)]()
49[![GitHub stars](https://img.shields.io/github/stars/StoneCypher/jssm.svg?style=social&label=JSSM%20Stars)]()
50
51[![GitHub followers](https://img.shields.io/github/followers/StoneCypher.svg?style=social&label=Follow%20StoneCypher)]()
52
53[![License](https://img.shields.io/npm/l/jssm.svg)](https://github.com/StoneCypher/jssm/blob/master/LICENSE.md)
54[![Open issues](https://img.shields.io/github/issues/StoneCypher/jssm.svg)](https://github.com/StoneCypher/jssm/issues)
55[![Closed issues](https://img.shields.io/github/issues-closed/StoneCypher/jssm.svg)](https://github.com/StoneCypher/jssm/issues?q=is%3Aissue+is%3Aclosed)
56
57[![Dependency status](https://david-dm.org/StoneCypher/jssm/status.svg)](https://david-dm.org/StoneCypher/jssm)
58[![Travis status](https://img.shields.io/travis/StoneCypher/jssm.svg)](https://travis-ci.org/StoneCypher/jssm)
59[![Coveralls status](https://img.shields.io/coveralls/StoneCypher/jssm.svg)](https://coveralls.io/github/StoneCypher/jssm)
60
61[![NPM version](https://img.shields.io/npm/v/jssm.svg)](https://www.npmjs.com/package/jssm)
62[![CDNjs version](https://img.shields.io/cdnjs/v/jquery.svg)](https://img.shields.io/cdnjs/v/jquery.svg)
63[![NPM downloads](https://img.shields.io/npm/dt/jssm.svg)](https://www.npmjs.com/package/jssm)
64
65</div>
66
67
68
69<br/><br/>
70
71## TL;DR
72Specify finite state machines with a brief syntax. Run them; they're fast. Make mistakes; they're strict. Derive
73charts. Save and load states, and histories. Make machine factories to churn out dozens or thousands of instances.
74Impress friends and loved ones. Cure corns and callouses.
75
76```fsl
77Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;
78```
79
80This will produce the following FSM (graphed with [jssm-viz](https://github.com/StoneCypher/jssm-viz)):
81
82![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
83
84You'll build an executable state machine.
85
86![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20traffic%20light%20console%20screenshot.png)
87
88
89
90<br/><br/>
91
92## Why
93
94As usual, a valid question.
95
96
97
98<br/>
99
100### Why state machines
101
102State machines are a method of making your software better able to prevent illegal states. Similar to type systems, SQL
103constraints, and linters, state machines are a way to teach the software to catch mistakes in ways you define, to help
104lead to better software.
105
106The major mechanism of a state machine is to define `states`, the `transitions` between them, and sometimes associated
107`data` and other niceties. The minor mechanism of state machines is to attach `actions` to the transitions, such that
108the state machine can partially run itself.
109
110![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
111
112So, to look at the same traffic light as above, you'll notice some things.
113
1141. A sufficiently smart implementation will know that it's okay for `Green` to switch to `Yellow`, but not to `Red`
1151. A sufficiently smart implementation knows there's no such thing as `Blue`
1161. A sufficiently smart implementation knows that when in `Green`, to be told to `Proceed` means to go to `Yellow`, but
117 when in `Yellow`, it means to go to `Red` instead
118
119Along with other common sense things, a good state machine implementation can help eliminate large classes of error in
120software. State machines are often applied when the stakes on having things correct are high.
121
122
123
124<br/>
125
126### Why this implementation
127
128Brevity.
129
130High quality testing. JSSM has 100% coverage, and has partial stochastic test coverage.
131
132Feature parity, especially around the DSL and data control.
133
134Data integrity. JSSM allows a much stricter form of state machine than is common, with a relatively low performance
135and storage overhead. It also offers an extremely terse domain specific language (though it does not require said DSL)
136to produce state machines in otherwise comparatively tiny and easily read code.
137
138
139
140<br/><br/>
141
142## Quick Start
143
144> A state machine in `JSSM` is defined in one of two ways: through the DSL, or through a datastructure.
145
146So yeah, let's start by getting some terminology out of the way, and then we can go right back to that impenetrable
147sentence, so that it'll make sense.
148
149
150
151<br/>
152
153### Quick Terminology
154
155Finite state machines have been around forever, are used by everyone, and are hugely important. As a result, the
156terminology is a mess, is in conflict, and is very poorly chosen, in accordince with everything-is-horrible law.
157
158This section describes the terminology *as used by this library*. The author has done his best to choose a terminology
159that matches common use and will be familiar to most. Conflicts are explained in the following section, to keep this
160simple.
161
162For this quick overview, we'll define six basic concepts:
163
1641. `Finite state machine`s
1651. `Machine`s
1661. `State`s
1671. `Current state`
1681. `Transition`s
1691. `Action`s
170
171There's other stuff, of course, but these five are enough to wrap your head around `finite state machine`s.
172
173
174
175<br/>
176
177#### Basic concepts
178
179This is a trivial traffic light `FSM`, with three states, three transitions, and one action:
180
181```fsl
182Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;
183```
184
185![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
186
187Let's review its pieces.
188
189* `finite state machine`s
190 * A `finite state machine` (or `FSM`) is a collection of `state`s, and rules about how you can `transition` between
191 the `state`s.
192 * We tend to refer to a design for a machine as "an `FSM`."
193 * In this example, the traffic light's structure is "a traffic light `FSM`."
194
195* `state`s
196 * `FSM`s always have at least one `state`, and nearly always many `state`s
197 * In this example,
198 * the `state`s are **Red**, **Yellow**, and **Green**
199 * Something made from this `FSM` will only ever be one of those colors - not, say, **Blue**
200
201* `machine`s
202 * Single instances of an `FSM` are referred to as a `machine`
203 * We might have a thousand instances of the traffic light designed above
204 * We would say "My intersection has four `machines` of the standard three color light `FSM`."
205
206* `current state`
207 * A `machine` has a `current state`, though an `FSM` does not
208 * "This specific traffic light is currently **Red**"
209 * Traffic lights in general do not have a current color, only specific lights
210 * `FSM`s do not have a current state, only specific `machine`s
211 * A given `machine` will always have exactly one `state` - never multiple, never none
212
213* `transitions`
214 * `FSM`s nearly always have `transition`s
215 * Transitions govern whether a `state` may be reached from another `state`
216 * This restriction is much of the value of `FSM`s
217 * In this example,
218 * the `transition`s are
219 * **Green** &rarr; **Yellow**
220 * **Yellow** &rarr; **Red**
221 * **Red** &rarr; **Green**
222 * a `machine` whose `current state` is **Green** may switch to **Yellow**, because there is an appropriate transition
223 * a `machine` whose `current state` is **Green** may not switch to **Red**, or to **Green** anew, because there is no
224 such transition
225 * A `machine` in **Yellow** which is told to `transition` to **Green** (which isn't legal) will know to refuse
226 * This makes `FSM`s an effective tool for error prevention
227
228* `actions`
229 * Many `FSM`s have `action`s, which represent events from the outside world.
230 * In this example, there is only one action - **Proceed**
231 * The `action` **Proceed** is available from all three colors
232 * At any time we may indicate to this light to go to its next color, without
233 taking the time to know what it is.
234 * This allows `FSM`s like the light to self-manage.
235 * A `machine` in **Yellow** which is told to take the `action` **Proceed** will
236 know on its own to switch its `current state` to **Red**.
237 * This makes `FSM`s an effective tool for complexity reduction
238
239Those six ideas in hand - `FSM`s, `state`s, `machine`s, `current state`, `transition`s, and `action`s - and you're ready
240to move forwards.
241
242One other quick definition - a `DSL`, or `domain specific language`, is when someone makes a language and embeds it into
243a different language, for the purpose of attacking a specific job. When `React` uses a precompiler to embed stuff that
244looks like HTML in Javascript, that's a DSL.
245
246This library implements a simple language for `defining finite state machine`s inside of strings. For example, this
247`DSL` defines that `'a -> b;'` actually means "create two states, create a transition between them, assign the first as
248the initial state", et cetera. That micro-language is the `DSL` that we'll be referring to a lot, coming up. This
249`DSL`'s formal name is `jssm-dot`, because it's a descendant-in-spirit of an older flowcharting language
250[DOT](http://www.graphviz.org/content/dot-language), from [graphviz](graphviz.org), which is also used to make the
251visualizations in [jssm-viz](https://github.com/StoneCypher/jssm-viz) by way of [viz-js](viz-js.com).
252
253Enough history lesson. On with the tooling.
254
255
256
257<br/>
258
259### And now, that Quick Start we were talking about
260
261So let's put together a trivial four-state traffic light: the three colors, plus **Off**. This will give us an
262opportunity to go over the basic facilities in the language.
263
264At any time, you can take the code and put it into the
265[graph explorer](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) for an opportunity to mess with the
266code as you see fit.
267
268
269
270<br/>
271
272#### 0: Lights always have an off state
273
274Our light will start in the **Off** `state`, with the ability to switch to the **Red** `state`.
275
276Since that's a normal, not-notable thing, we'll just make it a regular `-> legal transition`.
277
278```fsl
279Off -> Red;
280```
281
282We will give that `transition` an `action`, and call it **TurnOn**.
283
284```fsl
285Off 'TurnOn' -> Red;
286```
287
288So far, our machine is simple:
289
290![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20Red.png)
291
292
293
294<br/>
295
296#### 1: Traffic lights have a three-color cycle
297
298The main path of a traffic light is cycling from **Green** to **Yellow**, then to **Red**, then back again. Because
299this is the main path, we'll mark these steps `=> main transition`s.
300
301```fsl
302Off 'TurnOn' -> Red => Green => Yellow => Red;
303```
304
305We will give those all the same action name, **Proceed**, indicating "next color" without needing to know what we're
306currently on.
307
308```fsl
309Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
310```
311
312Machine's still pretty simple:
313
314![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20RGY.png)
315
316
317
318<br/>
319
320#### 2: Traffic lights can be shut down
321
322We'd also like to be able to turn this light back off. Because that's expected to be a rarity, we'll require that it
323be a `~> forced transition`.
324
325We could write
326
327```fsl
328Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
329Red ~> Off;
330Yellow ~> Off;
331Green ~> Off;
332```
333
334But that takes a lot of space even with this short list, so, instead we'll use the array notation
335
336```fsl
337Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
338[Red Yellow Green] ~> Off;
339```
340
341And we'd like those all to have the action **TurnOff**, so
342
343```fsl
344Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
345[Red Yellow Green] 'TurnOff' ~> Off;
346```
347
348Machine's still not too bad:
349
350![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20From%20RGY.png)
351
352
353
354<br/>
355
356### Let's actually use the traffic light
357
358That's actually the bulk of the language. There are other little add-ons here and there, but, primarily you now know
359how to write a state machine.
360
361Let's load it and use it! 😀
362
363#### loading into node
364#### loading into html
365#### jssm-viz
366#### redistribution on npm
367
368
369
370<br/>
371
372### An introduction to machine design
373
374Let's make a `state machine` for ATMs. In the process, we will use a lot of core concepts of `finite state machine`s
375and of `jssm-dot`, this library's `DSL`.
376
377We're going to improve on this [NCSU ATM diagram](https://people.engr.ncsu.edu/efg/210/s99/Notes/fsm/atm.gif) that I
378found:
379
380![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/ncsu%20atm%20diagram.gif)
381
382Remember, at any time, you can take the code and put it into the
383[graph explorer](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) for an opportunity to mess with the
384code as you see fit.
385
386
387
388<br/>
389
390#### 0: Empty machine
391
392We'll start with an [empty machine](https://github.com/StoneCypher/jssm/blob/master/src/machines/atm%20quick%20start%20tutorial/1_EmptyWaiting.jssm).
393
394```fsl
395EmptyWaiting 'Wait' -> EmptyWaiting;
396```
397
398![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/0_EmptyWaiting.png)
399
400
401
402<br/>
403
404#### 1: Should be able to eject cards
405
406We'll add the ability to physically eject the user's card and reset to the empty and waiting state. Right now it'll
407dangle around un-used at the top, but later it'll become useful.
408
409This is expressed as the path `EjectCardAndReset -> EmptyWaiting;`
410
411```fsl
412EmptyWaiting 'Wait' -> EmptyWaiting;
413EjectCardAndReset -> EmptyWaiting;
414```
415
416![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/1_EjectCard.png)
417
418
419
420<br/>
421
422#### 2: Should be able to insert cards
423
424We'll add the ability to physically insert a card, next. You know, the, uh, thing ATMs are pretty much for.
425
426To get this, add the path leg `EmptyWaiting 'InsertCard' -> HasCardNoAuth;`
427
428```fsl
429EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
430EjectCardAndReset -> EmptyWaiting;
431```
432
433Notice that the new `state`, **HasCardNoAuth**, has been rendered red. This is because it is `terminal` - there is
434no exit from this node currently. (**EmptyAndWaiting** did not render that way because it had a transition to itself.)
435That will change as we go back to adding more nodes. `terminal node`s are usually either mistakes or the last single
436`state` of a given `FSM`.
437
438![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/2_InsertCard.png)
439
440
441
442<br/>
443
444#### 3: Should be able to cancel and recover the card
445
446Next, we should have a cancel, because the ATM's <key>7</key> key is broken, and we need our card back. Cancel will
447exit to the main menu, and return our card credential.
448
449To that end, we add the path `HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;`
450
451```fsl
452EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
453
454HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
455
456EjectCardAndReset -> EmptyWaiting;
457```
458
459![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/3_ReturnCard.png)
460
461
462
463<br/>
464
465#### 4: Can give the wrong PIN
466
467Next, let's give the ability to get the password ... wrong. 😂 Because we all know that one ATM that only has the
468wrong-PIN path, so, apparently that's a product to someone.
469
470When they get the PIN wrong, they're prompted to try again (or to cancel.)
471
472We'll add the path `HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;`
473
474```fsl
475EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
476
477HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
478HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
479
480EjectCardAndReset -> EmptyWaiting;
481```
482
483![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/4_WrongPin.png)
484
485
486
487
488
489<br/>
490
491#### 5: Can give the correct PIN
492
493Next, let's give the ability to get the password right.
494
495We'll add two paths. The first gets the password right: `HasCardNoAuth 'RightPIN' -> MainMenu;`
496
497The second, from our new `state` **MainMenu**, gives people the ability to leave: `MainMenu 'ExitReturnCard' -> EjectCardAndReset;`
498
499
500```fsl
501EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
502
503HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
504HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
505HasCardNoAuth 'RightPIN' -> MainMenu;
506
507MainMenu 'ExitReturnCard' -> EjectCardAndReset;
508
509EjectCardAndReset -> EmptyWaiting;
510```
511
512![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/5_RightPin.png)
513
514
515
516<br/>
517
518#### 6: Can check balance from main menu
519
520Hooray, now we're getting somewhere.
521
522Let's add the ability to check your balance. First pick that from the main menu, then pick which account to see the
523balance of, then you're shown a screen with the information you requested; then go back to the main menu.
524
525That's `MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;`.
526
527```fsl
528EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
529
530HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
531HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
532HasCardNoAuth 'RightPIN' -> MainMenu;
533
534MainMenu 'ExitReturnCard' -> EjectCardAndReset;
535MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;
536
537EjectCardAndReset -> EmptyWaiting;
538```
539
540![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/6_CanCheckBalance.png)
541
542
543
544<br/>
545
546#### 7: Can deposit money from main menu
547
548Let's add something difficult. Their state machine just proceeds assuming everything is okay.
549
550To desposit money:
551
5521. Accept physical money
5532. If accept failed (eg door jammed,) reject physical object, go to main menu
5543. If accept succeeded, ask human expected value
5554. Pick an account this should go into
5565. Contact bank. Request to credit for theoretical physical money.
5576. Three results: yes, no, offer-after-audit.
5587. If no, reject physical object, go to main menu.
5598. If yes, consume physical object, tell user consumed, go to main menu
5609. If offer-after-audit, ask human what to do
56110. if human-yes, consume physical object, tell user consumed, go to main menu
56211. if human-no, reject physical object, go to main menu
563
564Writing this out in code is not only generally longer than the text form, but also error prone and hard to maintain.
565
566... or there's the `FSM` `DSL`, which is usually as-brief-as the text, and frequently both briefer and more explicit.
567
568* Rules 1-2: `MainMenu 'AcceptDeposit' -> TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;`
569* Rules 3-6: `TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;`
570* Rule 7: `BankResponse 'BankNo' -> RejectPhysicalMoney;`
571* Rule 8: `BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;`
572* Rules 9-10: `BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;`
573* Rule 11: `BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;`
574
575Or, as a block,
576
577```fsl
578MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
579
580TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
581TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
582
583BankResponse 'BankNo' -> RejectPhysicalMoney;
584BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
585BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
586
587BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
588```
589
590Which leaves us with the total code
591
592
593```fsl
594EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
595
596HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
597HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
598HasCardNoAuth 'RightPIN' -> MainMenu;
599
600MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
601MainMenu 'ExitReturnCard' -> EjectCardAndReset;
602MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;
603
604TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
605TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
606
607BankResponse 'BankNo' -> RejectPhysicalMoney;
608BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
609BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
610
611BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
612
613EjectCardAndReset -> EmptyWaiting;
614```
615
616![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/7_CanDepositMoney.png)
617
618
619
620<br/>
621
622#### 8: Can withdraw money from main menu
623
624Let's also be able to take money from the machine. After this, we'll move on, since our example is pretty squarely made
625by now.
626
6271. Pick a withdrawl account, or cancel to the main menu
6282. Shown a balance, pick a withdrawl amount, or cancel to acct picker
6293. Is the withdrawl account too high? If so go to 2
6304. Does the machine actually have the money? If not go to 2
6315. Otherwise confirm intent w/ human
6326. Attempt to post the transaction.
6337. If fail, display reason and go to 1
6348. If succeed, dispense money and go to main menu
635
636* Rules 1-3: `MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;`
637* Rule 4: `AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;`
638* Rule 5: `MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;`
639* Rule 6: `ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;`
640* Rule 7: `BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;`
641* Rule 8: `BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;`
642
643Rule 1 canceller: `PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;`
644Rule 2 canceller: `PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;`
645
646Or as a whole, we're adding
647
648```fsl
649MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;
650AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;
651MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;
652ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;
653BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;
654BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
655
656PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;
657PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
658```
659
660Which leaves us with
661
662```fsl
663EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
664
665HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
666HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
667HasCardNoAuth 'RightPIN' -> MainMenu;
668
669MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
670MainMenu 'ExitReturnCard' -> EjectCardAndReset;
671MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;
672
673TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
674TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
675
676BankResponse 'BankNo' -> RejectPhysicalMoney;
677BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
678BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
679
680BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
681
682MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;
683AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;
684MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;
685ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;
686BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;
687BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
688
689PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;
690PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
691
692EjectCardAndReset -> EmptyWaiting;
693```
694
695![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/8_CanWithdrawMoney.png)
696
697As you can see, building up even very complex state machines is actually relatively straightforward, in a short
698amount of time.
699
700
701
702<br/><br/>
703
704## Features
705### DSL
706### States
707### Transitions
708### Cycles
709### Stripes
710### Named Ordered Lists
711### Atoms
712### Strings
713### Arrow types
714### Unicode representations
715### Node declarations
716### All the styling bullshit
717### Named edges
718### URL callouts
719### The 9 or whatever directives
720### How to publish a machine
721#### Legal, main, and forced
722### Validators
723### State history
724### Automatic visualization
725
726
727
728<br/><br/>
729
730## How to think in state machines
731
732
733
734<br/><br/>
735
736## Example Machines
737### Door lock
738### Traffic lights
739#### Basic three-state
740#### RYG, Off, Flash-red, Flash-yellow
741#### RYG, Off, Flash-red, Flash-yellow, Green-left, Yellow-left
742#### Heirarchal intersection
743### [ATM](https://people.engr.ncsu.edu/efg/210/s99/Notes/fsm/atm.gif)
744### [HTTP](https://www.w3.org/Library/User/Architecture/HTTP.gif)
745#### Better HTTP
746### [TCP](http://www.texample.net/media/tikz/examples/PNG/tcp-state-machine.png)
747### Coin-op vending machine (data)
748### Video games
749#### Pac-man Ghost (sensors)
750#### Weather (probabilistics)
751#### Roguelike monster (interface satisfaction)
752### Candy crush clone game flow (practical large use)
753### Vegas locked 21 dealer behavior
754### React SPA website (practical large use)
755### [BGP](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/BGP_FSM.svg/549px-BGP_FSM.svg.png)
756### [LibGCrypt FIPS mode FSM](https://www.gnupg.org/documentation/manuals/gcrypt/fips-fsm.png)
757
758
759
760<br/><br/>
761
762## How to debug
763
764
765
766<br/><br/>
767
768## How to publish
769It's really quite simple.
770
7711. Make a github repository.
7721. Put your code in a file inside, with the extension `.fsl`
7731. Make sure your code contains a `machine_name`
774
775Once done, your work should show up [here](https://github.com/search?utf8=%E2%9C%93&q=extension%3Afsl+machine_name&type=Code).
776
777
778
779<br/><br/>
780
781## Notation Comparison
782### Their notations, one by one
783### Apples to Apples - Traffic Light
784
785
786
787<br/><br/>
788
789## Other state machines
790There are a lot of state machine impls for JS, many quite a bit more mature than this one. Here are some options:
791
7921. [Finity](https://github.com/nickuraltsev/finity) 😮
7931. [Stately.js](https://github.com/fschaefer/Stately.js)
7941. [machina.js](https://github.com/ifandelse/machina.js)
7951. [Pastafarian](https://github.com/orbitbot/pastafarian)
7961. [Henderson](https://github.com/orbitbot/henderson)
7971. [fsm-as-promised](https://github.com/vstirbu/fsm-as-promised)
7981. [state-machine](https://github.com/DEADB17/state-machine)
7991. [mood](https://github.com/bredele/mood)
8001. [FSM Workbench](https://github.com/MatthewHepburn/FSM-Workbench)
8011. [SimpleStateMachine](https://github.com/ccnokes/SimpleStateMachine)
8021. shime/[micro-machine](https://github.com/shime/micro-machine)
803 1. soveran/[micromachine](https://github.com/soveran/micromachine) (ruby)
8041. fabiospampinato/[FSM](https://github.com/fabiospampinato/FSM)
8051. HQarroum/[FSM](https://github.com/HQarroum/Fsm)
8061. [Finite-State-Automata](https://github.com/RolandR/Finite-State-Automata)
8071. [finite-state-machine](https://github.com/MarkH817/finite-state-machine)
8081. [nfm](https://github.com/ajauhri/nfm)
809
810
811And some similar stuff:
8121. [redux-machine](https://github.com/mheiber/redux-machine)
8131. [ember-fsm](https://github.com/heycarsten/ember-fsm)
8141. [State machine cat](https://github.com/sverweij/state-machine-cat)
8151. [Workty](https://github.com/AlexLevshin/workty) 😮
8161. [sam-simpler](https://github.com/sladiri/sam-simpler)
8171. [event_chain](https://github.com/quilin/event_chain)
8181. [DRAKON](https://en.wikipedia.org/wiki/DRAKON)
8191. [Yakindu Statechart Tools](https://github.com/Yakindu/statecharts)
8201. [GraphViz](http://www.graphviz.org/)
821 1. [Viz.js](https://github.com/mdaines/viz.js/), which we use
822
823
824
825<br/><br/><br/>
826
827# Thanks
828
829JSSM and FSL have had a lot of help.
830
831
832
833<br/><br/>
834
835## Internationalization
836
837* [Mykhaylo Les](https://github.com/miles91) provided three translation test cases ([Ukrainian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/ukrainian.json), [Belarussian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/belarussian.json), and [Russian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/russian.json),) and the corresponding Traffic Light translations (also [Ukrainian](https://github.com/StoneCypher/fsl_traffic_light_ukrainian/blob/master/traffic%20light.fsl), [Belarussian](https://github.com/StoneCypher/fsl_traffic_light_belarussian/blob/master/traffic_light.fsl), and [Russian](https://github.com/StoneCypher/fsl_traffic_light_russian/blob/master/traffic%20light.fsl).)
838* [Tanvir Islam](https://github.com/tanvirrb) provided the [Bengali test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/bengali.json), translated the [Traffic Light](https://github.com/tanvirrb/fsl-traffic-light-bengali/blob/master/traffic_light.fsl) to Bengali, and published the first non-English `FSL` machine, in Bengali.
839* [Francisco Junior](https://github.com/fcojr) provided the [Portuguese test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/portuguese.json) and translated the [Traffic Light](https://github.com/StoneCypher/fsl_traffic_light_portuguese/blob/master/traffic_light.fsl) to Portuguese
840* [Jeff Katz](https://github.com/cohendvir) provided the [German test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/german.json).
841* [Alex Cresswell](https://github.com/technophile77) provdied the [Spanish test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/spanish.json)
842* [Dvir Cohen](https://github.com/cohendvir) provided the [Hebrew test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/hebrew.json).
843* [David de la Peña](https://github.com/daviddelapena) provided the [French test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/french.json)
844
845If I've overlooked you, please let me know.
846
847If you'd like to help, it's straightforward.
848
8491. Easy mode: open a PR with [this file](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/english.json) translated into your language
8501. Extra mile: create a new repo containing [this file](https://github.com/StoneCypher/fsl_traffic_light/blob/master/traffic_light.fsl) translated
851
852
853
854<br/><br/>
855
856## Code and Language
857
858[Forest Belton](https://github.com/forestbelton) has provided guidance, bugfixes, parser and language commentary.
859
860[Jordan Harbrand](https://github.com/ljharb) suggested two interesting features and provided strong feedback on the initial tutorial draft.
861
862The biggest thanks must go to [Michael Morgan](https://github.com/msmorgan/), who has debated significant sections of
863the notation, invented several concepts and operators, helped with the parser, with system nomenclature, for having published
864the first not-by-me `FSL` machine, for encouragement, and generally just for having been as interested as he has been.