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

@wireweave/core

v2.0.1

Published

Core parser and renderer for wireweave

Readme

Installation

npm install @wireweave/core
# or
pnpm add @wireweave/core
# or
yarn add @wireweave/core

Quick Start

import { parse, render, renderToSvg, renderToHtml } from '@wireweave/core';

const source = `
  page "Hello" {
    card p=4 {
      title "Welcome"
      text "Hello, wireweave!"
      button "Get Started" primary
    }
  }
`;

// Parse DSL to AST
const doc = parse(source);

// Render to HTML + CSS
const { html, css } = render(doc);

// Render to complete HTML document
const fullHtml = renderToHtml(doc);

// Render to SVG
const { svg, width, height } = renderToSvg(doc);

API Reference

Parser

parse(source: string): WireframeDocument

Parses wireframe DSL source code into an AST (Abstract Syntax Tree).

import { parse } from '@wireweave/core';

const doc = parse('page { text "Hello" }');
console.log(doc.children[0].type); // 'Page'

Throws: ParseError if the source contains syntax errors.

HTML Renderer

render(doc: WireframeDocument, options?: RenderOptions): RenderResult

Renders the AST to HTML and CSS.

import { parse, render } from '@wireweave/core';

const doc = parse('page { card { text "Hello" } }');
const { html, css } = render(doc);

Options: | Option | Type | Default | Description | |--------|------|---------|-------------| | theme | 'light' \| 'dark' | 'light' | Color theme |

Returns: { html: string, css: string }

renderToHtml(doc: WireframeDocument, options?: RenderOptions): string

Renders the AST to a complete HTML document with embedded CSS.

import { parse, renderToHtml } from '@wireweave/core';

const doc = parse('page "Test" { text "Hello" }');
const html = renderToHtml(doc, { theme: 'dark' });
// Returns: <!DOCTYPE html><html>...</html>

SVG Renderer

renderToSvg(doc: WireframeDocument, options?: SvgRenderOptions): SvgRenderResult

Renders the AST to SVG format.

import { parse, renderToSvg } from '@wireweave/core';

const doc = parse('page { button "Click" primary }');
const { svg, width, height } = renderToSvg(doc, {
  width: 800,
  padding: 20
});

Options: | Option | Type | Default | Description | |--------|------|---------|-------------| | width | number | 1200 | SVG width in pixels | | padding | number | 24 | Padding around content | | theme | 'light' \| 'dark' | 'light' | Color theme |

Returns: { svg: string, width: number, height: number }

Analysis

analyze(doc: WireframeDocument, options?: AnalysisOptions): AnalysisResult

Analyzes a wireframe document and returns comprehensive statistics.

import { parse, analyze } from '@wireweave/core';

const doc = parse('page { card { text "Hello" button "Click" } }');
const result = analyze(doc);

console.log(result.summary);
// { totalComponents: 4, uniqueTypes: 4, mostUsedType: 'Page', ... }

console.log(result.tree);
// { totalNodes: 4, maxDepth: 3, avgDepth: 2, ... }

console.log(result.accessibility);
// { score: 100, imagesWithAlt: 0, inputsWithLabels: 0, ... }

console.log(result.complexity);
// { score: 2, level: 'simple', interactiveElements: 1, ... }

Options: | Option | Type | Default | Description | |--------|------|---------|-------------| | includeComponentBreakdown | boolean | true | Include component statistics | | includeAccessibility | boolean | true | Include accessibility metrics | | includeComplexity | boolean | true | Include complexity analysis | | includeLayout | boolean | true | Include layout analysis | | includeContent | boolean | true | Include content analysis |

Diff (Document Comparison)

diff(oldDoc: WireframeDocument, newDoc: WireframeDocument, options?: DiffOptions): DiffResult

Compares two wireframe documents and returns detailed differences.

import { parse, diff } from '@wireweave/core';

const oldDoc = parse('page { text "Hello" }');
const newDoc = parse('page { text "Hello" button "Click" }');

const result = diff(oldDoc, newDoc);

console.log(result.identical); // false
console.log(result.description); // "Added 1 component(s): Button."
console.log(result.summary);
// { addedCount: 1, removedCount: 0, changedCount: 0, ... }

areIdentical(oldDoc: WireframeDocument, newDoc: WireframeDocument): boolean

Quick check if two documents are identical.

import { parse, areIdentical } from '@wireweave/core';

const doc1 = parse('page { text "Hello" }');
const doc2 = parse('page { text "Hello" }');

console.log(areIdentical(doc1, doc2)); // true

getChangeSummary(oldDoc: WireframeDocument, newDoc: WireframeDocument): string

Returns a human-readable summary of changes.

import { parse, getChangeSummary } from '@wireweave/core';

const oldDoc = parse('page { text "A" }');
const newDoc = parse('page { text "B" }');

console.log(getChangeSummary(oldDoc, newDoc));
// "Modified 1 component(s)."

Export

exportToJson(doc: WireframeDocument, options?: ExportOptions): JsonExportResult

Exports wireframe to JSON format.

import { parse, exportToJson } from '@wireweave/core';

const doc = parse('page { card { text "Hello" } }');
const result = exportToJson(doc);

console.log(result.version); // "1.0.0"
console.log(result.pages); // [{ type: 'page', children: [...] }]
console.log(result.metadata);
// { exportedAt: '...', nodeCount: 3, componentTypes: ['card', 'page', 'text'] }

exportToJsonString(doc: WireframeDocument, options?: ExportOptions): string

Exports wireframe to JSON string.

import { parse, exportToJsonString } from '@wireweave/core';

const doc = parse('page { text "Hello" }');
const json = exportToJsonString(doc, { prettyPrint: true });

exportToFigma(doc: WireframeDocument): FigmaExportResult

Exports wireframe to Figma-compatible format.

import { parse, exportToFigma } from '@wireweave/core';

const doc = parse('page { card { text "Hello" } }');
const result = exportToFigma(doc);

console.log(result.document); // Figma-compatible node tree
console.log(result.componentMappings);
// { page: 'CANVAS', card: 'FRAME', text: 'TEXT' }

AST Utilities

walk(node: ASTNode, callback: WalkCallback): void

Traverses the AST tree depth-first.

import { parse } from '@wireweave/core';
import { walk } from '@wireweave/core/ast';

const doc = parse('page { card { text "A" text "B" } }');
walk(doc.children[0], (node, parent, depth) => {
  console.log(`${node.type} at depth ${depth}`);
});

find(node: ASTNode, predicate: (n: ASTNode) => boolean): ASTNode | undefined

Finds the first node matching the predicate.

import { find } from '@wireweave/core/ast';

const button = find(doc.children[0], n => n.type === 'Button');

findAll(node: ASTNode, predicate: (n: ASTNode) => boolean): ASTNode[]

Finds all nodes matching the predicate.

import { findAll } from '@wireweave/core/ast';

const buttons = findAll(doc.children[0], n => n.type === 'Button');

findByType<T>(node: ASTNode, type: string): T[]

Finds all nodes of a specific type.

import { findByType } from '@wireweave/core/ast';
import type { ButtonNode } from '@wireweave/core';

const buttons = findByType<ButtonNode>(doc.children[0], 'Button');

countNodes(node: ASTNode): number

Counts all nodes in the tree.

getMaxDepth(node: ASTNode): number

Returns the maximum nesting depth.

cloneNode<T>(node: T): T

Creates a deep copy of a node.

Type Definitions

WireframeDocument

interface WireframeDocument {
  type: 'Document';
  children: PageNode[];
}

PageNode

interface PageNode {
  type: 'Page';
  title?: string;
  children: ASTNode[];
  // ... spacing attributes
}

Common Node Properties

All nodes include:

  • type: string - Node type (e.g., 'Button', 'Card')
  • location?: Location - Source location info
  • Spacing: p, px, py, pt, pr, pb, pl, m, mx, my, mt, mr, mb, ml
  • Size: w, h

Component-Specific Properties

// Button
interface ButtonNode {
  type: 'Button';
  content: string;
  primary?: boolean;
  secondary?: boolean;
  outline?: boolean;
  ghost?: boolean;
  danger?: boolean;
  disabled?: boolean;
}

// Input
interface InputNode {
  type: 'Input';
  label?: string;
  placeholder?: string;
  inputType?: 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number';
  required?: boolean;
  disabled?: boolean;
}

// Card
interface CardNode {
  type: 'Card';
  title?: string;
  children: ASTNode[];
}

// Col
interface ColNode {
  type: 'Col';
  span?: number;
  sm?: number;
  md?: number;
  lg?: number;
  xl?: number;
  children: ASTNode[];
}

DSL Syntax Reference

Page Structure

page "Title" {
  header { }
  main { }
  footer { }
  sidebar { }
  aside { }
}

Layout

// Grid columns (12-column system)
row {
  col span=6 { }   // 50% width
  col span=6 { }   // 50% width
}

// Responsive breakpoints
col span=12 sm=6 md=4 lg=3 xl=2 { }

// Flexbox
row flex justify=center align=center gap=4 wrap { }
// justify: start, end, center, between, around, evenly
// align: start, end, center, stretch, baseline
// direction: row, row-reverse, column, column-reverse

Spacing Scale

Values use a 4px base: 1 = 4px, 2 = 8px, 4 = 16px, etc.

card p=4 m=2 { }    // padding: 16px, margin: 8px
button mt=4 mb=2    // margin-top: 16px, margin-bottom: 8px

Size

image w=400 h=300   // width: 400px, height: 300px
card w=full         // width: 100%

Comments

// Single line comment

/* Multi-line
   comment */

page {
  // Comment inside block
  text "Hello"
}

Error Handling

import { parse } from '@wireweave/core';

try {
  const doc = parse('page { invalid }');
} catch (error) {
  if (error.name === 'ParseError') {
    console.log(error.message);
    // "Syntax error at line 1, column 8: ..."
    console.log(error.location);
    // { start: { line: 1, column: 8 }, end: { ... } }
  }
}

Browser Support

The core library works in both Node.js and browser environments. For browser usage:

<script type="module">
  import { parse, render } from '@wireweave/core';

  const doc = parse('page { text "Hello" }');
  const { html, css } = render(doc);

  document.body.innerHTML = `<style>${css}</style>${html}`;
</script>

License

MIT