// finite state language · v1.4.0

impossible  unrepresentable

fsl is a tiny DSL for JavaScript and TypeScript. Draw your program as a graph of states and arrows; the parser emits JSON, jssm runs it, and every move not on the picture is refused.

abc
// arrows

Write the picture

An fsl file is the graph you'd draw. States, arrows, named actions. The compiler reads what you wrote, not what you meant.

case 'idle': ✓case 'paid': ✓case 'aborted': ✗ missing
// refusal

Bad moves stop at the door

If there's no edge from `at` to where you want to go, jssm refuses — when the graph is loaded, and again at runtime.

red'next'green;green'next'yellow;yellow'next'red;
// one state

Always exactly one

`m.state()` returns a single declared state. No nullable enum, no half-loaded transition. Render off it without defensive code.

// install

One package. No runtime, no codegen.

jssm ships as one library. Write your graph inline as a tagged template — sm`...` — or keep long graphs in a .fsl file. No codegen, no build step.

$ npm i --save-dev jssm
>fsl is a graph DSL — jssm parses it to JSON, then runs it. No type-level magic; refusal happens at load and at runtime.
requirements
node≥ 18
runtimejssm
size~30 kb min+gz
licenseMIT
// examples

Drive a real machine.

Each example is a real jssm machine, written inline as a tagged template. Send events to the running machine; rejected events show what jssm refuses when the graph is loaded.

A linear cycle. red → green → yellow → red, on a single shared verb.

View full recipe →
diagram
'next''next''next'redgreenyellow
request
at: red
no transitions yet
traffic.tsjssm + fsl
const light = sm`
  red    'next'  green;
  green  'next'  yellow;
  yellow 'next'  red;
`;
// learn

Five ideas. That's the main language.

fsl is small on purpose. Read these five pages and you'll know enough to ship a machine in production.

1/5
// graphs · idea 1 of 5

Define graphs with arrows.

An fsl program is a graph. States are nodes, arrows are edges — usually written inline as a tagged template. (You can also keep them in a `.fsl` file when they get long.)

import { sm } from 'jssm';

const light = sm`
  red  green  yellow  red;
`;
redgreenyellow
continue with the full guide:language reference →diagnostic catalogue →cookbook →
// diagnostics

Errors that point at the bug.

Diagnostics are written for the engineer who has to fix them. Name the problem, point at the location, suggest the next move.

fsl check
$ fsl check src/traffic.fsl

error[E024]: no edge from 'red' on action 'stop'
  --> src/controller.ts:42:14
   |
 42 |   light.request('stop');
   |                  ^^^^^^ action not declared at 'red'
   = note: 'red' only accepts 'next'
   = help: add an arrow red 'stop'  red; or call 'next'

warning[W007]: state 'amber' is unreachable — no inbound edge
  --> src/traffic.fsl:8:1

1 error, 1 warning · checked 4 files in 0.31s
// community

Talk it through on Discord.

Questions, design feedback, machines you've built. The fsl & jssm server is the one place to find the people working on this.

fsl & jssm Discorddiscord.com/invite/9P95USqnMK
Join the server