diff --git a/benchmark/results/general.chart.html b/benchmark/results/general.chart.html index 49cecda9..5113b50c 100644 --- a/benchmark/results/general.chart.html +++ b/benchmark/results/general.chart.html @@ -28,7 +28,7 @@
- +
Options
All
  • Public
  • Public/Protected
  • All
Menu

Class Machine<mDT>

Type parameters

  • mDT

Hierarchy

  • Machine

Index

Constructors

Properties

Methods

Constructors

  • new Machine<mDT>(__namedParameters: JssmGenericConfig<mDT>): Machine<mDT>
  • Type parameters

    • mDT

    Parameters

    • __namedParameters: JssmGenericConfig<mDT>

    Returns Machine<mDT>

Properties

_actions: Map<string, Map<string, number>>
_any_action_hook: Function
_any_transition_hook: Function
_arrange_declaration: string[][]
_arrange_end_declaration: string[][]
_arrange_start_declaration: string[][]
_dot_preamble: string
_edge_map: Map<string, Map<string, number>>
_edges: JssmTransition<mDT>[]
_entry_hooks: Map<string, Function>
_exit_hooks: Map<string, Function>
_flow: FslDirection
_forced_transition_hook: Function
_fsl_version?: string
_global_action_hooks: Map<string, Function>
_graph_layout: JssmLayout
_has_basic_hooks: boolean
_has_entry_hooks: boolean
_has_exit_hooks: boolean
_has_global_action_hooks: boolean
_has_hooks: boolean
_has_named_hooks: boolean
_has_transition_hooks: boolean
_hooks: Map<string, Function>
_instance_name: string
_machine_author?: string[]
_machine_comment?: string
_machine_contributor?: string[]
_machine_definition?: string
_machine_language?: string
_machine_license?: string
_machine_name?: string
_machine_version?: string
_main_transition_hook: Function
_named_hooks: Map<string, Function>
_named_transitions: Map<string, number>
_raw_state_declaration?: Object[]
_reverse_action_targets: Map<string, Map<string, number>>
_reverse_actions: Map<string, Map<string, number>>
_standard_transition_hook: Function
_state: string
_state_declarations: Map<string, JssmStateDeclaration>
_states: Map<string, JssmGenericState>
_theme: FslTheme

Methods

  • _new_state(state_config: JssmGenericState): string
  • Parameters

    • state_config: JssmGenericState

    Returns string

  • action(actionName: string, newData?: mDT): boolean
  • Parameters

    • actionName: string
    • Optional newData: mDT

    Returns boolean

  • actions(whichState?: string): string[]
  • Parameters

    • whichState: string = ...

    Returns string[]

  • current_action_edge_for(action: string): JssmTransition<mDT>
  • Parameters

    • action: string

    Returns JssmTransition<mDT>

  • current_action_for(action: string): number
  • Parameters

    • action: string

    Returns number

  • dot_preamble(): string
  • edges_between(from: string, to: string): JssmTransition<mDT>[]
  • Parameters

    • from: string
    • to: string

    Returns JssmTransition<mDT>[]

  • flow(): FslDirection
  • force_transition(newState: string, newData?: mDT): boolean
  • Parameters

    • newState: string
    • Optional newData: mDT

    Returns boolean

  • fsl_version(): string
  • get_transition_by_state_names(from: string, to: string): number
  • Parameters

    • from: string
    • to: string

    Returns number

  • graph_layout(): string
  • has_completes(): boolean
  • has_state(whichState: string): boolean
  • Parameters

    • whichState: string

    Returns boolean

  • has_terminals(): boolean
  • has_unenterables(): boolean
  • hook(from: string, to: string, handler: Function): Machine<mDT>
  • hook_action(from: string, to: string, action: string, handler: Function): Machine<mDT>
  • Parameters

    • from: string
    • to: string
    • action: string
    • handler: Function

    Returns Machine<mDT>

  • hook_any_action(handler: Function): Machine<mDT>
  • hook_any_transition(handler: Function): Machine<mDT>
  • hook_entry(to: string, handler: Function): Machine<mDT>
  • hook_exit(from: string, handler: Function): Machine<mDT>
  • hook_forced_transition(handler: Function): Machine<mDT>
  • hook_global_action(action: string, handler: Function): Machine<mDT>
  • hook_main_transition(handler: Function): Machine<mDT>
  • hook_standard_transition(handler: Function): Machine<mDT>
  • instance_name(): string
  • is_complete(): boolean
  • is_final(): boolean
  • is_terminal(): boolean
  • is_unenterable(whichState: string): boolean
  • Parameters

    • whichState: string

    Returns boolean

  • list_actions(): string[]
  • list_edges(): JssmTransition<mDT>[]
  • list_entrances(whichState?: string): string[]
  • Parameters

    • whichState: string = ...

    Returns string[]

  • list_exit_actions(whichState?: string): string[]
  • Parameters

    • whichState: string = ...

    Returns string[]

  • list_exits(whichState?: string): string[]
  • Parameters

    • whichState: string = ...

    Returns string[]

  • list_named_transitions(): Map<string, number>
  • list_states_having_action(whichState: string): string[]
  • Parameters

    • whichState: string

    Returns string[]

  • list_transitions(whichState?: string): JssmTransitionList
  • Parameters

    • whichState: string = ...

    Returns JssmTransitionList

  • lookup_transition_for(from: string, to: string): JssmTransition<mDT>
  • Parameters

    • from: string
    • to: string

    Returns JssmTransition<mDT>

  • machine_author(): string[]
  • machine_comment(): string
  • machine_contributor(): string[]
  • machine_definition(): string
  • machine_language(): string
  • machine_license(): string
  • machine_name(): string
  • machine_state(): JssmMachineInternalState<mDT>
  • Returns JssmMachineInternalState<mDT>

  • machine_version(): string
  • probabilistic_histo_walk(n: number): Map<string, number>
  • Parameters

    • n: number

    Returns Map<string, number>

  • probabilistic_transition(): boolean
  • probabilistic_walk(n: number): string[]
  • Parameters

    • n: number

    Returns string[]

  • probable_action_exits(whichState?: string): any[]
  • Parameters

    • whichState: string = ...

    Returns any[]

  • probable_exits_for(whichState: string): JssmTransition<mDT>[]
  • Parameters

    • whichState: string

    Returns JssmTransition<mDT>[]

  • raw_state_declarations(): Object[]
  • set_hook(HookDesc: HookDescription): void
  • Parameters

    • HookDesc: HookDescription

    Returns void

  • sm(template_strings: TemplateStringsArray, ...remainder: any[]): Machine<mDT>
  • Parameters

    • template_strings: TemplateStringsArray
    • Rest ...remainder: any[]

    Returns Machine<mDT>

  • state(): string
  • state_declaration(which: string): JssmStateDeclaration
  • Parameters

    • which: string

    Returns JssmStateDeclaration

  • state_declarations(): Map<string, JssmStateDeclaration>
  • Returns Map<string, JssmStateDeclaration>

  • state_for(whichState: string): JssmGenericState
  • Parameters

    • whichState: string

    Returns JssmGenericState

  • state_is_complete(whichState: string): boolean
  • Parameters

    • whichState: string

    Returns boolean

  • state_is_final(whichState: string): boolean
  • Parameters

    • whichState: string

    Returns boolean

  • state_is_terminal(whichState: string): boolean
  • Parameters

    • whichState: string

    Returns boolean

  • states(): string[]
  • theme(): FslTheme
  • transition(newState: string, newData?: mDT): boolean
  • Parameters

    • newState: string
    • Optional newData: mDT

    Returns boolean

  • transition_impl(newStateOrAction: string, newData: mDT, wasForced: boolean, wasAction: boolean): boolean
  • Parameters

    • newStateOrAction: string
    • newData: mDT
    • wasForced: boolean
    • wasAction: boolean

    Returns boolean

  • valid_action(action: string, _newData?: mDT): boolean
  • Parameters

    • action: string
    • Optional _newData: mDT

    Returns boolean

  • valid_force_transition(newState: string, _newData?: mDT): boolean
  • Parameters

    • newState: string
    • Optional _newData: mDT

    Returns boolean

  • valid_transition(newState: string, _newData?: mDT): boolean
  • Parameters

    • newState: string
    • Optional _newData: mDT

    Returns boolean

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/docs/index.html b/docs/docs/index.html deleted file mode 100644 index c3aab832..00000000 --- a/docs/docs/index.html +++ /dev/null @@ -1,855 +0,0 @@ -jssm
Options
All
  • Public
  • Public/Protected
  • All
Menu

jssm

- -

jssm

-
-

Easy. Small. Fast. TS, es6, es5. Node, Browser. 100% coverage. Property -tests. Fuzz tests. Language tests for a dozen languages and emoji. Easy to -share online. Easy to embed.

-

Readable, useful state machines as one-liner strings.

-

Meet your new state machine library.

- - -

TRY THE LIVE EDITOR

- -

Discord community - Documentation - Issue tracker - CI build history

-

Discord community

-



-

Wouldn't it be nice if your TypeScript and Javascript state machines were simple and readable one-liners?

-
import { sm } from 'jssm';

const TrafficLight = sm`Red -> Green -> Yellow -> Red;`; -
-
- -

Wouldn't it be great if they were easy to work with?

-
const log = s => console.log(s);

log( TrafficLight.state() ); // 'Red'

Machine.transition('Green'); // true
log( TrafficLight.state() ); // 'Green' -
-
- -

What if the notation supported action names easily?

-
const TLWA = sm`Red 'next' -> Green 'next' -> Yellow 'next' -> Red;`;  // TLWA = Traffic Light With Actions

log( TLWA.state() ); // 'Red'

TLWA.action('next'); // true
log( TLWA.state() ); // 'Green'

TLWA.action('next'); // true
log( TLWA.state() ); // 'Yellow'

TLWA.action('next'); // true
log( TLWA.state() ); // 'Red' -
-
- -

What if integration with the outside was straightforward?

-
const MTL = 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 node

log( MTL.state() ); // 'Red'

TLWA.action('next'); // true, console logs 'GO GO GO'
log( TLWA.state() ); // 'Green'

TLWA.action('next'); // true
log( TLWA.state() ); // 'Yellow'

TLWA.action('next'); // true, console logs 'STOP'
log( TLWA.state() ); // 'Red' -
-
- -

What if the machine followed JS standards, and distinguished refusals as false from mistakes as thrown?

-
const ATL = sm`Red -> Green -> Yellow -> Red;`;  // ATL = Another Traffic Light

log( ATL.state() ); // 'Red' - uses 1st state unless told otherwise
ATL.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 -> vs -only-when-forced ~> ?

-
const TrafficLightWithOff = sm`
Red => Green => Yellow => Red;
[Red Yellow Green] ~> Off -> Red;
`; -
-
- -

What if that were easy to render visually?

-
const TrafficLightWithOff = 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?

-
const TrafficLightWithOff = 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 had extensive 100% test coverage -with thousands 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?

-



- - -

Introducing JSSM

-
-

Meet JSSM: the Javascript State Machine.

-

State machines can make your code cleaner, safer, and more trustworthy.

-

And, with the right language, state machines can be easy and fun.

-

TRY THE LIVE EDITOR

-
- - - -

What is JSSM?

-
-

JSSM is a Javascript state machine implementing Finite State Language, with a terse DSL and a simple API. -100% test coverage; typed with Flowtype. MIT licensed.

-

The 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.

-

Try it live!

-

Visualize with jssm-viz, or at the command line with jssm-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!

-
- -

Actions Status

-

GitHub forks -GitHub watchers -GitHub stars -GitHub followers

-

License -Open issues -Closed issues -Travis status -Coveralls status

-

NPM version -CDNjs version -NPM downloads

- - -
- - - -



- - -

TL;DR

-
-

Specify finite state machines with a brief syntax. Run them; they're fast. Make mistakes; they're strict. Derive -charts. 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 with jssm-viz):

-

-

You'll build an executable state machine.

-

-



- - -

Why

-
-

As usual, a valid question.

-
- - - -

Why state machines

-
-

State machines are a method of making your software better able to prevent illegal states. Similar to type systems, SQL -constraints, and linters, state machines are a way to teach the software to catch mistakes in ways you define, to help -lead to better software.

-

The major mechanism of a state machine is to define states, the transitions between them, and sometimes associated -data and other niceties. The minor mechanism of state machines is to attach actions to the transitions, such that -the state machine can partially run itself.

-

-

So, to look at the same traffic light as above, you'll notice some things.

-
    -
  1. A sufficiently smart implementation will know that it's okay for Green to switch to Yellow, but not to Red
  2. -
  3. A sufficiently smart implementation knows there's no such thing as Blue
  4. -
  5. A sufficiently smart implementation knows that when in Green, to be told to Proceed means to go to Yellow, but -when in Yellow, it means to go to Red instead
  6. -
-

Along with other common sense things, a good state machine implementation can help eliminate large classes of error in -software. State machines are often applied when the stakes on having things correct are high.

-
- - - -

Why this implementation

-
-

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 performance -and 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.

-



- - -

Quick Start

-
-
-

A state machine in JSSM is 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 impenetrable -sentence, so that it'll make sense.

-
- - - -

Quick Terminology

-
-

Finite state machines have been around forever, are used by everyone, and are hugely important. As a result, the -terminology is a mess, is in conflict, and is very poorly chosen, in accordince with everything-is-horrible law.

-

This section describes the terminology as used by this library. The author has done his best to choose a terminology -that matches common use and will be familiar to most. Conflicts are explained in the following section, to keep this -simple.

-

For this quick overview, we'll define six basic concepts:

-
    -
  1. Finite state machines
  2. -
  3. Machines
  4. -
  5. States
  6. -
  7. Current state
  8. -
  9. Transitions
  10. -
  11. Actions
  12. -
-

There's other stuff, of course, but these five are enough to wrap your head around finite state machines.

-
- - - -

Basic concepts

-
-

This is a trivial traffic light FSM, 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 (or FSM) is a collection of states, and rules about how you can transition between -the states.
    • -
    • 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."
    • -
    -
  • -
  • states

    -
      -
    • FSMs always have at least one state, and nearly always many states
    • -
    • In this example,
        -
      • the states are Red, Yellow, and Green
      • -
      • Something made from this FSM will only ever be one of those colors - not, say, Blue
      • -
      -
    • -
    -
  • -
  • machines

    -
      -
    • Single instances of an FSM are referred to as a machine
    • -
    • We might have a thousand instances of the traffic light designed above
    • -
    • We would say "My intersection has four machines of the standard three color light FSM."
    • -
    -
  • -
  • current state

    -
      -
    • A machine has a current state, though an FSM does not
        -
      • "This specific traffic light is currently Red"
      • -
      -
    • -
    • Traffic lights in general do not have a current color, only specific lights
    • -
    • FSMs do not have a current state, only specific machines
    • -
    • A given machine will always have exactly one state - never multiple, never none
    • -
    -
  • -
  • transitions

    -
      -
    • FSMs nearly always have transitions
    • -
    • Transitions govern whether a state may be reached from another state
        -
      • This restriction is much of the value of FSMs
      • -
      -
    • -
    • In this example,
        -
      • the transitions are
          -
        • GreenYellow
        • -
        • YellowRed
        • -
        • RedGreen
        • -
        -
      • -
      • a machine whose current state is Green may switch to Yellow, because there is an appropriate transition
      • -
      • a machine whose current state is Green may not switch to Red, or to Green anew, because there is no -such transition
          -
        • A machine in Yellow which is told to transition to Green (which isn't legal) will know to refuse
        • -
        • This makes FSMs an effective tool for error prevention
        • -
        -
      • -
      -
    • -
    -
  • -
  • actions

    -
      -
    • Many FSMs have actions, which represent events from the outside world.
    • -
    • In this example, there is only one action - Proceed
        -
      • The action Proceed is available from all three colors
      • -
      -
    • -
    • At any time we may indicate to this light to go to its next color, without -taking the time to know what it is.
        -
      • This allows FSMs like the light to self-manage.
      • -
      • A machine in Yellow which is told to take the action Proceed will -know on its own to switch its current state to Red.
      • -
      • This makes FSMs an effective tool for complexity reduction
      • -
      -
    • -
    -
  • -
-

Those six ideas in hand - FSMs, states, machines, current state, transitions, and actions - and you're ready -to move forwards.

-

One other quick definition - a DSL, or domain specific language, is when someone makes a language and embeds it into -a different language, for the purpose of attacking a specific job. When React uses a precompiler to embed stuff that -looks like HTML in Javascript, that's a DSL.

-

This library implements a simple language for defining finite state machines inside of strings. For example, this -DSL defines that 'a -> b;' actually means "create two states, create a transition between them, assign the first as -the initial state", et cetera. That micro-language is the DSL that we'll be referring to a lot, coming up. This -DSL's formal name is jssm-dot, because it's a descendant-in-spirit of an older flowcharting language -DOT, from graphviz, which is also used to make the -visualizations in jssm-viz by way of viz-js.

-

Enough history lesson. On with the tooling.

-
- - - -

And now, that Quick Start we were talking about

-
-

So let's put together a trivial four-state traffic light: the three colors, plus Off. This will give us an -opportunity to go over the basic facilities in the language.

-

At any time, you can take the code and put it into the -graph explorer for an opportunity to mess with the -code as you see fit.

-
- - - -

0: Lights always have an off state

-
-

Our light will start in the Off state, with the ability to switch to the Red state.

-

Since that's a normal, not-notable thing, we'll just make it a regular -> legal transition.

-
Off -> Red;
-
-

We will give that transition an action, and call it TurnOn.

-
Off 'TurnOn' -> Red;
-
-

So far, our machine is simple:

-

-
- - - -

1: Traffic lights have a three-color cycle

-
-

The main path of a traffic light is cycling from Green to Yellow, then to Red, then back again. Because -this 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're -currently on.

-
Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
-
-

Machine's still pretty simple:

-

-
- - - -

2: Traffic lights can be shut down

-
-

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 it -be 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 action TurnOff, so

-
Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
[Red Yellow Green] 'TurnOff' ~> Off; -
-

Machine's still not too bad:

-

-
- - - -

Let's actually use the traffic light

-
-

That's actually the bulk of the language. There are other little add-ons here and there, but, primarily you now know -how to write a state machine.

-

Let's load it and use it! 😀

- - -

loading into node

-
- - -

loading into html

-
- - -

jssm-viz

-
- - -

redistribution on npm

-
-
- - - -

An introduction to machine design

-
-

Let's make a state machine for ATMs. In the process, we will use a lot of core concepts of finite state machines -and of jssm-dot, this library's DSL.

-

We're going to improve on this NCSU ATM diagram that I -found:

-

-

Remember, at any time, you can take the code and put it into the -graph explorer for an opportunity to mess with the -code as you see fit.

-
- - - -

0: Empty machine

-
-

We'll start with an empty machine.

-
EmptyWaiting 'Wait' -> EmptyWaiting;
-
-

-
- - - -

1: Should be able to eject cards

-
-

We'll add the ability to physically eject the user's card and reset to the empty and waiting state. Right now it'll -dangle around un-used at the top, but later it'll become useful.

-

This is expressed as the path EjectCardAndReset -> EmptyWaiting;

-
EmptyWaiting 'Wait' -> EmptyWaiting;
EjectCardAndReset -> EmptyWaiting; -
-

-
- - - -

2: Should be able to insert cards

-
-

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 leg EmptyWaiting 'InsertCard' -> HasCardNoAuth;

-
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
EjectCardAndReset -> EmptyWaiting; -
-

Notice that the new state, HasCardNoAuth, has been rendered red. This is because it is terminal - there is -no 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 single -state of a given FSM.

-

-
- - - -

3: Should be able to cancel and recover the card

-
-

Next, we should have a cancel, because the ATM's 7 key is broken, and we need our card back. Cancel will -exit to the main menu, and return our card credential.

-

To that end, we add the path HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;

-
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;

HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;

EjectCardAndReset -> EmptyWaiting; -
-

-
- - - -

4: Can give the wrong PIN

-
-

Next, let's give the ability to get the password ... wrong. 😂 Because we all know that one ATM that only has the -wrong-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 path HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;

-
EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;

HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;

EjectCardAndReset -> EmptyWaiting; -
-

-
- - - -

5: Can give the correct PIN

-
-

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 new state MainMenu, 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; -
-

-
- - - -

6: Can check balance from main menu

-
-

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 the -balance of, then you're shown a screen with the information you requested; then go back to the main menu.

-

That's MainMenu '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; -
-

-
- - - -

7: Can deposit money from main menu

-
-

Let's add something difficult. Their state machine just proceeds assuming everything is okay.

-

To desposit money:

-
    -
  1. Accept physical money
  2. -
  3. If accept failed (eg door jammed,) reject physical object, go to main menu
  4. -
  5. If accept succeeded, ask human expected value
  6. -
  7. Pick an account this should go into
  8. -
  9. Contact bank. Request to credit for theoretical physical money.
  10. -
  11. Three results: yes, no, offer-after-audit.
  12. -
  13. If no, reject physical object, go to main menu.
  14. -
  15. If yes, consume physical object, tell user consumed, go to main menu
  16. -
  17. If offer-after-audit, ask human what to do
  18. -
  19. if human-yes, consume physical object, tell user consumed, go to main menu
  20. -
  21. if human-no, reject physical object, go to main menu
  22. -
-

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 the FSM DSL, 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; -
-

-
- - - -

8: Can withdraw money from main menu

-
-

Let's also be able to take money from the machine. After this, we'll move on, since our example is pretty squarely made -by now.

-
    -
  1. Pick a withdrawl account, or cancel to the main menu
  2. -
  3. Shown a balance, pick a withdrawl amount, or cancel to acct picker
  4. -
  5. Is the withdrawl account too high? If so go to 2
  6. -
  7. Does the machine actually have the money? If not go to 2
  8. -
  9. Otherwise confirm intent w/ human
  10. -
  11. Attempt to post the transaction.
  12. -
  13. If fail, display reason and go to 1
  14. -
  15. If succeed, dispense money and go to main menu
  16. -
-
    -
  • 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 short -amount of time.

-



- - -

Features

-
- - -

DSL

-
- - -

States

-
- - -

Transitions

-
- - -

Cycles

-
- - -

Stripes

-
- - -

Named Ordered Lists

-
- - -

Atoms

-
- - -

Strings

-
- - -

Arrow types

-
- - -

Unicode representations

-
- - -

Node declarations

-
- - -

All the styling bullshit

-
- - -

Named edges

-
- - -

URL callouts

-
- - -

The 9 or whatever directives

-
- - -

How to publish a machine

-
- - -

Legal, main, and forced

-
- - -

Validators

-
- - -

State history

-
- - -

Automatic visualization

-
-



- - -

How to think in state machines

-
-



- - -

Example Machines

-
- - -

Door lock

-
- - -

Traffic lights

-
- - -

Basic three-state

-
- - -

RYG, Off, Flash-red, Flash-yellow

-
- - -

RYG, Off, Flash-red, Flash-yellow, Green-left, Yellow-left

-
- - -

Heirarchal intersection

-
- - -

ATM

- - - -

HTTP

- - - -

Better HTTP

-
- - -

TCP

- - - -

Coin-op vending machine (data)

-
- - -

Video games

-
- - -

Pac-man Ghost (sensors)

-
- - -

Weather (probabilistics)

-
- - -

Roguelike monster (interface satisfaction)

-
- - -

Candy crush clone game flow (practical large use)

-
- - -

Vegas locked 21 dealer behavior

-
- - -

React SPA website (practical large use)

-
- - -

BGP

- - - -

LibGCrypt FIPS mode FSM

- -



- - -

How to debug

-
-



- - -

How to publish

-
-

It's really quite simple.

-
    -
  1. Make a github repository.
  2. -
  3. Put your code in a file inside, with the extension .fsl
  4. -
  5. Make sure your code contains a machine_name
  6. -
-

Once done, your work should show up here.

-



- - -

Notation Comparison

-
- - -

Their notations, one by one

-
- - -

Apples to Apples - Traffic Light

-
-



- - -

Other state machines

-
-

There are a lot of state machine impls for JS, many quite a bit more mature than this one. Here are some options:

-
    -
  1. Finity 😮
  2. -
  3. Stately.js
  4. -
  5. machina.js
  6. -
  7. Pastafarian
  8. -
  9. Henderson
  10. -
  11. fsm-as-promised
  12. -
  13. state-machine
  14. -
  15. mood
  16. -
  17. FSM Workbench
  18. -
  19. SimpleStateMachine
  20. -
  21. shime/micro-machine
      -
    1. soveran/micromachine (ruby)
    2. -
    -
  22. -
  23. fabiospampinato/FSM
  24. -
  25. HQarroum/FSM
  26. -
  27. Finite-State-Automata
  28. -
  29. finite-state-machine
  30. -
  31. nfm
  32. -
-

And some similar stuff:

-
    -
  1. redux-machine
  2. -
  3. ember-fsm
  4. -
  5. State machine cat
  6. -
  7. Workty 😮
  8. -
  9. sam-simpler
  10. -
  11. event_chain
  12. -
  13. DRAKON
  14. -
  15. Yakindu Statechart Tools
  16. -
  17. GraphViz
      -
    1. Viz.js, which we use
    2. -
    -
  18. -
-




- - -

Thanks

-
-

JSSM and FSL have had a lot of help.

-



- - -

Internationalization

-
- -

If I've overlooked you, please let me know.

-

If you'd like to help, it's straightforward.

-
    -
  1. Easy mode: open a PR with this file translated into your language
  2. -
  3. Extra mile: create a new repo containing this file translated
  4. -
-



- - -

Code and Language

-
-

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 to Michael Morgan, who has debated significant sections of -the notation, invented several concepts and operators, helped with the parser, with system nomenclature, for having published -the first not-by-me FSL machine, for encouragement, and generally just for having been as interested as he has been.

-

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/docs/modules.html b/docs/docs/modules.html deleted file mode 100644 index 27f0e89c..00000000 --- a/docs/docs/modules.html +++ /dev/null @@ -1 +0,0 @@ -jssm
Options
All
  • Public
  • Public/Protected
  • All
Menu

jssm

Index

Variables

gviz_shapes: string[] = ...
histograph: Function = ...
seq: Function = ...
shapes: string[] = gviz_shapes
version: string = "5.64.0"
weighted_histo_key: Function = ...
weighted_rand_select: Function = ...
weighted_sample_select: Function = ...

Functions

  • arrow_direction(arrow: JssmArrow): JssmArrowDirection
  • Parameters

    • arrow: JssmArrow

    Returns JssmArrowDirection

  • arrow_left_kind(arrow: JssmArrow): JssmArrowKind
  • Parameters

    • arrow: JssmArrow

    Returns JssmArrowKind

  • arrow_right_kind(arrow: JssmArrow): JssmArrowKind
  • Parameters

    • arrow: JssmArrow

    Returns JssmArrowKind

  • compile<mDT>(tree: JssmParseTree): JssmGenericConfig<mDT>
  • Type parameters

    • mDT

    Parameters

    • tree: JssmParseTree

    Returns JssmGenericConfig<mDT>

  • from<mDT>(MachineAsString: string, ExtraConstructorFields?: Partial<JssmGenericConfig<mDT>>): Machine<mDT>
  • Type parameters

    • mDT

    Parameters

    • MachineAsString: string
    • Optional ExtraConstructorFields: Partial<JssmGenericConfig<mDT>>

    Returns Machine<mDT>

  • make<mDT>(plan: string): JssmGenericConfig<mDT>
  • Type parameters

    • mDT

    Parameters

    • plan: string

    Returns JssmGenericConfig<mDT>

  • parse(input: string, options?: Object): any
  • Parameters

    • input: string
    • Optional options: Object

    Returns any

  • sm<mDT>(template_strings: TemplateStringsArray, ...remainder: any[]): Machine<mDT>
  • Type parameters

    • mDT

    Parameters

    • template_strings: TemplateStringsArray
    • Rest ...remainder: any[]

    Returns Machine<mDT>

  • transfer_state_properties(state_decl: JssmStateDeclaration): JssmStateDeclaration
  • Parameters

    • state_decl: JssmStateDeclaration

    Returns JssmStateDeclaration

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 30b9fef5..00000000 --- a/docs/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - -

JSSM repo site

- -

There isn't actually anything here. You're probably looking for:

- - - -

- -

Less commonly, you might be looking for

- - - - - - \ No newline at end of file diff --git a/jssm.d.ts b/jssm.d.ts index e1cda26a..387c2900 100644 --- a/jssm.d.ts +++ b/jssm.d.ts @@ -2,7 +2,7 @@ declare type StateType = string; import { JssmGenericState, JssmGenericConfig, JssmTransition, JssmTransitionList, // JssmTransitionRule, JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout, FslDirection, FslTheme, HookDescription, HookHandler } from './jssm_types'; import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util'; -import { shapes, gviz_shapes } from './jssm_constants'; +import { shapes, gviz_shapes, named_colors } from './jssm_constants'; import { version } from './version'; declare function arrow_direction(arrow: JssmArrow): JssmArrowDirection; declare function arrow_left_kind(arrow: JssmArrow): JssmArrowKind; @@ -131,4 +131,4 @@ declare class Machine { } declare function sm(template_strings: TemplateStringsArray, ...remainder: any[]): Machine; declare function from(MachineAsString: string, ExtraConstructorFields?: Partial> | undefined): Machine; -export { version, transfer_state_properties, Machine, make, wrap_parse as parse, compile, sm, from, arrow_direction, arrow_left_kind, arrow_right_kind, seq, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key, shapes, gviz_shapes }; +export { version, transfer_state_properties, Machine, make, wrap_parse as parse, compile, sm, from, arrow_direction, arrow_left_kind, arrow_right_kind, seq, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key, shapes, gviz_shapes, named_colors }; diff --git a/jssm_constants.d.ts b/jssm_constants.d.ts index e424d4ce..004efca5 100644 --- a/jssm_constants.d.ts +++ b/jssm_constants.d.ts @@ -1,3 +1,4 @@ declare const gviz_shapes: string[]; declare const shapes: string[]; -export { gviz_shapes, shapes }; +declare const named_colors: string[]; +export { gviz_shapes, shapes, named_colors }; diff --git a/package.json b/package.json index e3fb917a..51f7f6b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jssm", - "version": "5.64.0", + "version": "5.64.1", "engines": { "node": ">=10.0.0" }, diff --git a/src/ts/jssm.ts b/src/ts/jssm.ts index 670aa65c..2c0e82d5 100644 --- a/src/ts/jssm.ts +++ b/src/ts/jssm.ts @@ -37,7 +37,7 @@ import { -import { shapes, gviz_shapes } from './jssm_constants'; +import { shapes, gviz_shapes, named_colors } from './jssm_constants'; @@ -1534,6 +1534,7 @@ export { weighted_histo_key, shapes, - gviz_shapes + gviz_shapes, + named_colors }; diff --git a/src/ts/jssm_constants.ts b/src/ts/jssm_constants.ts index 2685cf84..c55c3a41 100644 --- a/src/ts/jssm_constants.ts +++ b/src/ts/jssm_constants.ts @@ -68,4 +68,38 @@ const shapes = gviz_shapes; -export { gviz_shapes, shapes }; +const named_colors = [ + "AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", + "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", + "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", + "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", + "DarkGoldenRod", "DarkGray", "DarkGrey", "DarkGreen", "DarkKhaki", + "DarkMagenta", "DarkOliveGreen", "Darkorange", "DarkOrchid", "DarkRed", + "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", + "DarkSlateGrey", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", + "DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", + "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Grey", + "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", + "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", + "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray", + "LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", + "LightSkyBlue", "LightSlateGray", "LightSlateGrey", "LightSteelBlue", + "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", + "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", + "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", + "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", + "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", + "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", + "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", + "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", + "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", + "SlateGray", "SlateGrey", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", + "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", + "Yellow", "YellowGreen" +]; + + + + + +export { gviz_shapes, shapes, named_colors }; diff --git a/src/ts/tests/constants.spec.ts b/src/ts/tests/constants.spec.ts index 04385ed6..9ff013ba 100644 --- a/src/ts/tests/constants.spec.ts +++ b/src/ts/tests/constants.spec.ts @@ -15,25 +15,8 @@ import { arr_uniq_p } from '../jssm_util'; test.todo('These constants should be derived from the source and compared'); -const Shapes = jssm.shapes; - -const NamedColors = ["AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", - "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", - "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGrey", - "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "Darkorange", "DarkOrchid", "DarkRed", "DarkSalmon", - "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkSlateGrey", "DarkTurquoise", "DarkViolet", "DeepPink", - "DeepSkyBlue", "DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", - "GhostWhite", "Gold", "GoldenRod", "Gray", "Grey", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", - "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", - "LightCyan", "LightGoldenRodYellow", "LightGray", "LightGrey", "LightGreen", "LightPink", "LightSalmon", - "LightSeaGreen", "LightSkyBlue", "LightSlateGray", "LightSlateGrey", "LightSteelBlue", "LightYellow", "Lime", - "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", - "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", - "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", - "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", - "Plum", "PowderBlue", "Purple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", - "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "SlateGrey", "Snow", "SpringGreen", "SteelBlue", - "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen"]; +const Shapes = jssm.shapes, + NamedColors = jssm.named_colors; diff --git a/src/ts/tests/shapes.spec.ts b/src/ts/tests/shapes.spec.ts index a4fc5714..a912509f 100644 --- a/src/ts/tests/shapes.spec.ts +++ b/src/ts/tests/shapes.spec.ts @@ -1,7 +1,17 @@ -import { Shapes } from './constants.spec'; +import * as jssm from '../jssm'; +const sm = jssm.sm; -import { sm } from '../jssm'; + + + + +describe('Shapes list length', () => { + + test('Shapes list is gviz shapes plus nothing in length', () => + expect(jssm.shapes.length).toBe(jssm.gviz_shapes.length) ) + +}); @@ -9,7 +19,7 @@ import { sm } from '../jssm'; describe('GraphViz Shapes', () => { - Shapes.map(shape => { + jssm.shapes.map(shape => { let mach = undefined; @@ -32,6 +42,28 @@ describe('GraphViz Shapes', () => { +describe('Named colors', () => { + + jssm.named_colors.map(color => + + test(`Color "${color}" parses as a color`, () => + expect( () => { const mach = sm`state b: { background-color: ${color}; }; a -> b;`; }).not.toThrow() ) + + ); + + jssm.named_colors.map(color => + + test(`Color "${color.toLowerCase()}" (${color} lowercased) parses as a color`, () => + expect( () => { const mach = sm`state b: { background-color: ${color.toLowerCase()}; }; a -> b;`; }).not.toThrow() ) + + ); + +}); + + + + + describe('Corners', () => { test('rounded', () => diff --git a/src/ts/version.ts b/src/ts/version.ts index e9554a59..5319754c 100644 --- a/src/ts/version.ts +++ b/src/ts/version.ts @@ -1,3 +1,3 @@ -const version: string = "5.64.0"; +const version: string = "5.64.1"; export { version };