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

@homedev/ariel

v0.1.8

Published

A tiny Mermaid graph parser and writer with extensions.

Readme

Ariel - Tiny Mermaid Graph Parser & Writer

Ariel is a lightweight TypeScript library for parsing and building Mermaid diagrams. It provides a fluent API for programmatic graph manipulation with support for nodes, connections, groups (subgraphs), and CSS classes.

Installation

npm install @homedev/ariel
# or
bun add @homedev/ariel

Quick Start

Basic Usage - Parsing

import { Ariel } from '@homedev/ariel'

// Create a parser and parse Mermaid syntax
const ariel = Ariel
  .createParser()
  .parse(`
    graph TD
    A["Node A"]
    B["Node B"]
    A-->B
  `)

// Listen for computed events
ariel.on('node', (node) => {
  console.log(`Processing node: ${node.name}`)
})

// Compute the graph structure
ariel.compute()

// Serialize back to Mermaid format
const output = ariel.toString()
console.log(output)

Building Graphs Programmatically

const ariel = new Ariel()
ariel.type = 'graph TD'

// Add nodes
ariel.addNodes([
  { name: 'start', label: 'Start', shape: 'circle' },
  { name: 'process', label: 'Process', shape: 'square' },
  { name: 'end', label: 'End', shape: 'circle' }
])

// Connect nodes
ariel.connectNodes('start', 'process', 'proceed')
ariel.connectNodes('process', 'end', 'done')

// Compute and output
ariel.compute()
console.log(ariel.toString())

Core Concepts

Parser Events

The parser emits events during parsing:

const parser = Ariel.createParser()

parser
  .on('node', (node, state) => {
    console.log(`Found node: ${node.name}`)
  })
  .on('group', (groupName, nodes, state) => {
    console.log(`Found group: ${groupName} with ${nodes.length} nodes`)
  })
  .on('class', (className, nodes, state) => {
    console.log(`Assigning class ${className} to ${nodes.length} nodes`)
  })
  .on('line', (line, state) => {
    // Custom line parsing - return true to skip default parsing
    if (line.startsWith('custom:')) {
      console.log(`Custom line: ${line}`)
      return true
    }
    return false
  })

const ariel = parser.parse(mermaidText)

Graph Events

After parsing, listen to graph computation events:

ariel
  .on('node', (node) => {
    // Modify node properties
    if (!node.style) {
      node.style = 'fill:#f0f'
    }
  })
  .on('group', (group) => {
    // Customize group styling
    group.style = 'fill:#0f0'
  })
  .on('class', (cls) => {
    // Modify class properties
    if (cls.name === 'important') {
      cls.style = 'stroke:#f00,stroke-width:2px'
    }
  })

ariel.compute()

API Reference

Ariel

Main class for building and manipulating graphs.

Properties

  • type: string - Graph type (e.g., "graph TD")
  • nodes: ArielNode[] - Array of all nodes
  • groups: ArielGroupWithRefs[] - Array of all groups/subgraphs
  • classes: ArielClassWithRefs[] - Array of all style classes
  • connections: ArielConnection[] - Array of all connections

Methods

  • static createParser(): ArielParser - Create a new parser instance
  • addNodes(nodes: ArielNode[]): this - Add nodes to the graph
  • connectNodes(from: string, to: string, label?: string): this - Create a connection between two nodes
  • on(event: string, callback: Function): this - Listen for events
  • compute(): void - Compute the graph structure (must call before toString())
  • toString(): string - Serialize to Mermaid format

ArielNode

Represents a node in the graph.

interface ArielNode {
  name: string              // Unique node identifier
  label?: string            // Display label
  shape?: string            // Node shape (circle, square, diamond, etc.)
  link?: string             // URL link
  style?: string            // Inline CSS style
  class?: string            // CSS class name
  group?: string            // Group/subgraph name
  from?: (string | Connection)[]  // Incoming connections
  to?: (string | Connection)[]    // Outgoing connections
}

ArielConnection

Represents a connection between two nodes.

interface ArielConnection {
  from: ArielNode
  to: ArielNode
  label?: string
}

Supported Shapes

  • circle / round - Circle
  • square / rect / rectangle - Square
  • diamond / decision - Diamond
  • hexagon / hex - Hexagon
  • cylinder / database - Cylinder
  • stadium - Stadium
  • subroutine - Subroutine
  • trapezoid - Trapezoid
  • parallelogram - Parallelogram

Examples

Complete Workflow

import { Ariel } from '@homedev/ariel'

// Parse existing Mermaid diagram
const mermaidText = `
  graph TD
    subgraph Team
      Alice["Alice"]
      Bob["Bob"]
    end
    
    subgraph Tasks
      T1["Task 1"]
      T2["Task 2"]
    end
    
    Alice-->|assigns|T1
    Bob-->|works on|T2
    
    class Alice,Bob person
    class T1,T2 task
    classDef person fill:#f9f,stroke:#f0f
    classDef task fill:#fbf,stroke:#faf
`

const ariel = Ariel.createParser().parse(mermaidText)

// Customize nodes during computation
ariel
  .on('node', (node) => {
    node.style = 'stroke-width:2px'
  })
  .on('group', (group) => {
    if (group.name === 'Team') {
      group.style = 'fill:#eee'
    }
  })

ariel.compute()

// Get the Mermaid output
const output = ariel.toString()
console.log(output)

Custom Node Creation

const ariel = Ariel.createParser()
  .on('line', (line, state) => {
    // Custom syntax: actor: name
    if (line.startsWith('actor:')) {
      const name = line.substring(6).trim()
      state.result.nodes.push({
        name,
        shape: 'circle',
        style: 'fill:#ffb6c1'
      })
      return true // Skip default parsing
    }
    return false
  })
  .parse(`
    graph TD
    actor: Alice
    actor: Bob
  `)

ariel.compute()
console.log(ariel.toString())

TypeScript Support

Ariel is fully typed and includes comprehensive type definitions for all public APIs:

import { 
  Ariel, 
  ArielNode, 
  ArielConnection, 
  ArielParser 
} from '@homedev/ariel'

const node: ArielNode = {
  name: 'mynode',
  label: 'My Node',
  shape: 'circle'
}

const ariel: Ariel = new Ariel()
ariel.addNodes([node])

Performance

Ariel is optimized for small to medium graphs (typically under 1000 nodes). It uses:

  • Efficient event emitter pattern (Node.js EventEmitter)
  • Synchronous processing (no async overhead)
  • Minimal dependencies
  • Tree-shaking friendly

Testing

Run the test suite with:

bun test

Development & Publishing

Build Structure

Ariel uses a hierarchical build structure for clean npm publishing:

project/
├── package.json (development - contains devDependencies, scripts)
├── src/ (source TypeScript files)
├── tests/ (test files)
└── release/ (auto-generated during build)
    ├── package.json (publishing version - clean, no devDeps)
    └── dist/
        ├── index.js (compiled & minified code)
        └── index.d.ts (bundled type definitions)

Build Process

The build pipeline consists of several steps:

# Full build (recommended)
bun run build

# Individual steps:
bun run build:js         # Compile TypeScript to JavaScript
bun run build:types      # Generate .d.ts files
bun run build:bundle-types # Merge type definitions
bun run prepare-publish  # Generate clean release/package.json

Why separate package.json files?

  • Root package.json: Contains all development tools (devDependencies) and build scripts
  • release/package.json: Clean version for npm publishing (no devDeps, no scripts)
  • This ensures published packages are lightweight and don't include unnecessary development tooling

Publishing to npm

# Build and publish (uses prepublishOnly hook)
bun push

# Manual alternative
bun run build
npm publish ./release

When you run npm publish (or bun push):

  1. The prepublishOnly hook triggers bun run build
  2. TypeScript is compiled to release/dist/
  3. Type definitions are bundled to release/dist/index.d.ts
  4. A clean release/package.json is generated
  5. npm publishes the release/ folder as the package

File Organization

  • src/: Source TypeScript files (all exported in index.ts)
  • release/: Publishing artifacts (generated, git-ignored)
  • .temp/: Temporary TypeScript output (generated, cleaned up automatically)
  • config/: ESLint configuration
  • tests/: Unit tests for all modules

The library includes comprehensive unit tests for:

  • Parser functionality
  • Graph building and manipulation
  • Node styling and shaping
  • Connection management
  • Event emissions
  • Serialization

License

MIT