npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

melusine

v0.1.0

Published

Compile Mermaid journey flowcharts into framework-agnostic test plans.

Downloads

133

Readme

melusine

melusine runs Mermaid journey charts as tests.

You write:

  1. A Markdown file with YAML frontmatter and a Mermaid flowchart.
  2. A reusable JavaScript catalog with task(...) and scorer(...) functions.

Melusine parses the chart, validates the graph, runs the catalog functions in graph order, passes task results through context, records gaps, and reports whether the journey passed.

Install

npm install --save-dev melusine

For this repository:

npm install
npm test

Start a Project

Create starter files in an existing JS/Node project:

npx melusine init

This creates:

  • melusine.catalog.js
  • journeys/example.journey.md
  • melusine:validate and melusine:test package scripts when package.json exists

Run the starter:

npm run melusine:validate
npm run melusine:test

Build a Journey

Save this as checkout.journey.md:

---
journey: checkout-happy-path
nodes:
  start:
    as: checkout
  addItem:
    args: ["book", 1]
  pay:
    args: ["card"]
---

# Checkout happy path

```mermaid
graph TD
  start(["Customer opens checkout"]) --> addItem
  addItem["Add item"] --> payable
  payable{"Cart is payable?"}
  payable -->|yes| pay
  payable -->|no| blocked
  pay["Pay"] --> paid
  paid(["Order paid"])
  blocked(["Payment blocked"])
```

GitHub and GitLab can render Mermaid diagrams in Markdown. Useful Mermaid links:

Write a Catalog

Save this as checkout.catalog.js:

import { scorer, task } from 'melusine';
import { Checkout } from './checkout.js';

export default {
  start: task(() => new Checkout(), { as: 'checkout' }),

  addItem: task(({ args, context }) => {
    context.checkout.addItem(args[0], args[1]);
  }, { requiredArgs: 2 }),

  payable: scorer(({ context }) => context.checkout.total > 0),

  pay: task(({ args, context }) => {
    context.checkout.pay(args[0]);
  }, { requiredArgs: 1 }),

  paid: scorer(({ context }) => ({
    pass: context.checkout.status === 'paid',
    actual: context.checkout.status,
    expected: 'paid',
    message: 'checkout should be paid',
  })),

  blocked: scorer(() => ({
    pass: false,
    message: 'checkout should have been payable',
  })),
};

Catalog entries are reusable. Multiple journey files can reference the same addItem, pay, and paid entries by node id.

Frontmatter

Frontmatter is the YAML block at the top of the journey file.

---
journey: checkout-happy-path
nodes:
  start:
    as: checkout
  addItem:
    args: ["book", 1]
  alternateAdd:
    use: addItem
    args: ["pen", 2]
---

nodes is keyed by Mermaid node id.

  • args becomes input.args for the catalog function.
  • as stores a task result under that context key.
  • use points one node at a different catalog key.
  • Extra fields become input.config.options.

Everything outside nodes becomes input.meta.

Graph Rules

Use a Mermaid graph or flowchart block:

graph TD
  start(["Start"]) --> step
  step["Do something"] --> decision
  decision{"Choose?"}
  decision -->|yes| done
  decision -->|no| failed
  done(["Done"])
  failed(["Failed"])

Supported in v1:

| Shape | Example | Meaning | | --- | --- | --- | | Terminal | start(["Start"]) | Start or final outcome | | Process | step["Do something"] | Task | | Decision | ok{"Ready?"} | Branch scorer | | Edge | A --> B | Next node | | Labeled edge | A -->|yes| B | Decision branch |

Rules:

  • There must be one start node: a terminal with no incoming edges.
  • Process nodes must map to tasks.
  • Decision nodes must map to scorers.
  • Final terminal nodes must map to scorers.
  • Every completed path needs an outcome scorer by default.
  • Branches cannot merge back together in v1.
  • Only --> edges are supported.

CLI

melusine validate <journey.md> [--catalog <catalog.js>] [--export <name>] [--json]
melusine test <journey.md> --catalog <catalog.js> [--export <name>] [--json]
melusine compile <journey.md> --catalog <catalog.js> [--export <name>] --out <file>
melusine init [--force]

Common workflow:

npx melusine validate checkout.journey.md --catalog checkout.catalog.js
npx melusine test checkout.journey.md --catalog checkout.catalog.js
npx melusine compile checkout.journey.md --catalog checkout.catalog.js --out checkout.test.mjs
node --test checkout.test.mjs

test runs the journey directly. compile writes a small node:test wrapper that reads the journey file, imports the catalog, and calls the same runner.

Library API

import { parse, runText, scorer, task } from 'melusine';

const result = await runText(markdown, catalog);

Important exports:

  • task(fn, options) defines a reusable action.
  • scorer(fn, options) defines a reusable check.
  • runText(text, catalog) parses and executes a journey.
  • parse(text) returns the graph, frontmatter, and diagnostics.
  • generateTest(options) creates a generated wrapper string.

Scorers can return:

true
false
{ pass: true, message: 'ok', actual, expected }
0.8
{ score: 0.8, threshold: 0.7 }

Numeric scores pass when score >= threshold. The default threshold is 1.

Examples

The examples/ directory has complete runnable examples:

  • examples/onboarding/ shows a linear flow.
  • examples/vending/ shows one decision branch.
  • examples/order-fulfillment/ shows nested decisions.

Run all examples:

npm run generate:examples
node --test examples/*/generated/*.test.mjs

Gaps

A catalog entry can return todo(reason) or hole(reason). Melusine also creates a hole when a required arg or option is missing.

Gaps make the run fail and appear in result.gaps. They are never converted into passing assertions.