🧛🏻‍♀️ Lucy language

A concise language for describing Finite State Machines.

Expressive
Complex sets of events, guards, actions, and destination states can be expressed in a single line. Nesting machines gives you a hierarchical machine.
Plain JavaScript
Lucy compiles each machine to a small, readable JavaScript module with no dependencies and no runtime library. What runs is a handful of ordinary functions, so the code you ship is tiny and stack traces stay shallow.
Fast
Lucy is written in C, so compiling is quick: lucyc is a native command-line compiler, and the same compiler is built to WebAssembly for easy use in JavaScript projects. At run time, sending an event is a lookup and a function call.

toggle.lucy

state enabled {
  toggle => disabled
}

initial state disabled {
  toggle => enabled
}

out.js

export default function createMachine({ context = {} } = {}) {
  const listeners = new Set();
  const states = {
    enabled: {
      toggle() {
        machine.state = 'disabled';
      }
    },
    disabled: {
      toggle() {
        machine.state = 'enabled';
      }
    }
  };
  function notify() {
    for(const listener of listeners) {
      listener(machine);
    }
  }
  const machine = {
    state: 'disabled',
    context,
    send(event) {
      if(typeof event === 'string') {
        event = { type: event };
      }
      const handler = states[machine.state][event.type];
      if(handler) {
        handler(event);
        notify();
      }
    },
    subscribe(listener) {
      listeners.add(listener);
      return () => listeners.delete(listener);
    },
    start() {
      notify();
      return machine;
    },
    stop() {
      listeners.clear();
    }
  };
  return machine;
}

Install

See the install page for detailed instructions on the various ways you can use Lucy, such as with popular JavaScript build tools.

To use the command-line compiler install with:

curl -sSf https://lucy.spooky.click/install.sh | bash