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

@m0saic/dsl

v1.0.0

Published

Core parser, validator, and algebra for the m0 layout DSL

Downloads

150

Readme

@m0saic/dsl

The m0saic DSL is a deterministic, context-free language for describing recursive spatial decompositions of a rectangle. It encodes layout as structure — not configuration.

npm install @m0saic/dsl

Zero dependencies.


Where this fits

              @m0saic/dsl            <── you are here
        the language core (zero deps)
      grammar, parser, validator, types
                    |
      +-------------+-------------+
      |                           |
  @m0saic/dsl-         @m0saic/dsl-stdlib
  file-formats           builders, transforms
  .m0  .m0c              authoring toolkit
      |                           |
      +-------------+-------------+
                    |
            @m0saic/dictionary
         curated entries + generators

The language

A m0 string describes how a rectangle is recursively subdivided.

  2(1,1)              two columns
  3[1,1,1]            three rows
  2(1,3[1,1,1])       left tile + right column of 3 rows
  1{1}                tile with overlay
  3(0,0,1)            passthrough — all space donated to last tile
  3(1,-,1)            null gap in the middle

Tokens

  1  (or F)     tile — claims one slot, consumes one source
  0  (or >)     passthrough — donates space to next claimant
  -             null — claims space, renders nothing
  N(...)        horizontal split into N children (left → right)
  N[...]        vertical split into N children (top → bottom)
  X{Y}          overlay — Y composited on top of X, same rect

Properties

  deterministic         same string + same resolution = same geometry, always
  context-free          no ambient state, no identifier resolution
  linear-time parse     O(n) validation, O(n) feasibility, O(n) parse
  composable            any valid string embeds inside any other
  resolution-independent  geometry adapts to container size
  no temporal concepts    geometry and time are orthogonal

Grammar rules

  1( and 1[ are illegal             ILLEGAL_ONE_SPLIT
  }{ is illegal (overlay chains)    OVERLAY_CHAIN — normalize with dsl-stdlib
  trailing 0 is illegal             PASSTHROUGH_TO_NOTHING
  empty layouts are illegal         NO_SOURCES
  empty overlay bodies illegal      ZERO_SOURCE_OVERLAY
  whitespace is stripped globally
  aliases normalized: F→1, >→0      canonical form

API overview

  ┌─────────────────────────────────────────────────────────────────┐
  │                        @m0saic/dsl                              │
  │                                                                 │
  │  VALIDATE              PARSE                 FORMAT             │
  │  ─────────             ─────                 ──────             │
  │  validateM0String  parseM0StringTo      toCanonicalM0String │
  │  isValidM0String   RenderFrames          toPrettyM0String    │
  │                        LogicalFrames                            │
  │                        FullGraph             EQUALITY           │
  │                        FullGraphWith         ────────           │
  │  COMPLEXITY            Traversal             areM0Strings       │
  │  ──────────            Complete              CanonicalEqual     │
  │  getComplexityMetrics                        areM0Strings       │
  │  getComplexityMetrics  FEASIBILITY           FrameEqual         │
  │  Fast                  ───────────                              │
  │  getFrameCount         computeFeasibility    HELPERS            │
  │  getPassthroughCount   computePrecision      ───────            │
  │  getNodeCount          FromString            assertOk           │
  │  getPrecisionCost                                               │
  └─────────────────────────────────────────────────────────────────┘

Validation

import { validateM0String, isValidM0String } from "@m0saic/dsl";

// Boolean check
isValidM0String("2(1,1)");    // true
isValidM0String("1(1)");      // false — ILLEGAL_ONE_SPLIT

// Structured result
const result = validateM0String("2(1,1,1)");
if (!result.ok) {
  console.log(result.error.code);      // "TOKEN_COUNT"
  console.log(result.error.kind);      // "SEMANTIC"
  console.log(result.error.position);  // exact character offset
  console.log(result.error.span);      // { start, end }
}

All validation is O(n). Canonicalizes input first (whitespace + aliases).

Error codes

  SYNTAX errors           SEMANTIC errors          ANTIPATTERN errors
  ─────────────           ───────────────          ──────────────────
  INVALID_CHAR            TOKEN_COUNT              PASSTHROUGH_TO_NOTHING
  INVALID_EMPTY           NO_SOURCES               ILLEGAL_ONE_SPLIT
  UNBALANCED              ZERO_SOURCE_OVERLAY      SPLIT_EXCEEDS_AXIS
  TOKEN_RULE              OVERLAY_CHAIN

Each error includes code, kind, message, position, and span.


Parsing

Three tiers. Choose the cheapest that gives you what you need.

Tier 1: Render frames (fastest)

import { parseM0StringToRenderFrames } from "@m0saic/dsl";

const frames = parseM0StringToRenderFrames("2(1,1)", 1920, 1080);
// [
//   { x: 0, y: 0, width: 960, height: 1080, paintOrder: 0, logicalIndex: 0, meta: {...} },
//   { x: 960, y: 0, width: 960, height: 1080, paintOrder: 1, logicalIndex: 1, meta: {...} },
// ]

End geometry only. Synthetic stableKeys (f0, f1). Use for previews, thumbnails, feasibility checks.

Tier 2: Logical frames (with identity)

import { parseM0StringToLogicalFrames } from "@m0saic/dsl";

const frames = parseM0StringToLogicalFrames("2(1,1)", 1920, 1080);
// Real stableKeys, parent keys, spans. Source-order (logicalIndex).

Use for templates, builders, anything needing stable identity.

Tier 3: Full structural graph

import { parseM0StringComplete, assertOk } from "@m0saic/dsl";

const result = parseM0StringComplete("2(1,1)", 1920, 1080);
assertOk(result);  // type-narrows to success

result.ir.renderFrames;     // RenderFrame[] in paint order
result.ir.editorFrames;     // EditorFrame[] — ALL nodes (root, groups, frames, passthroughs, nulls)
result.precision;           // M0Precision
result.warnings;            // M0Warning[]

Use for editor, inspector, tree dock, structural analysis.


String formatting

import { toCanonicalM0String, toPrettyM0String } from "@m0saic/dsl";

toCanonicalM0String("2( F, F )");  // "2(1,1)"  — canonical form
toPrettyM0String("2(1,0,1)");      // "2(F,>,F)" — presentation form

Canonical form: no whitespace, 1 not F, 0 not >.


Complexity analysis

Two paths — choose based on your constraints:

  getComplexityMetricsFast(s)     getComplexityMetrics(s)
  ──────────────────────────      ──────────────────────
  never validates                 validates first
  never returns null              returns null if invalid
  never throws                    never throws
  < 1ms on any input              ~13ms for 130K chars
  use for: UI, badges,            use for: reports,
  real-time keystroke analysis    validated analysis
import { getComplexityMetricsFast } from "@m0saic/dsl";

const m = getComplexityMetricsFast("3[2(1,1),2(1,1),2(1,1)]");
// {
//   frameCount: 6,
//   passthroughCount: 0,
//   nullCount: 0,
//   groupCount: 4,
//   nodeCount: 10,
//   precisionCost: 3,
//   precision: { maxSplitX: 2, maxSplitY: 3, maxSplitAny: 3 }
// }

Feasibility analysis

Exact minimum resolution at which a layout is parseable (no 0-size frames).

import { computeFeasibility } from "@m0saic/dsl";

computeFeasibility("2(5(1,1,1,1,1),5(1,1,1,1,1))");
// { minWidthPx: 10, minHeightPx: 1 }
// nested: outer 2-split × inner 5-split = 10 minimum width

computeFeasibility("3[3(1,1,1),3(1,1,1),3(1,1,1)]");
// { minWidthPx: 3, minHeightPx: 3 }

O(n) structural analysis — no repeated parse probing.

Precision vs Feasibility

  M0Precision                    M0Feasibility
  (structural split metrics)         (exact minimum resolution)
  ──────────────────────             ─────────────────────────
  maxSplitX: 5                       minWidthPx: 10
  maxSplitY: 1                       minHeightPx: 1
  maxSplitAny: 5

  O(n) character scan                O(n) structural analysis
  single-level max                   accounts for nesting
  cheap, always available            exact, authoritative

Use computePrecisionFromString for quick structural metrics. Use computeFeasibility for exact minimum pixel dimensions.


Equality

import { areM0StringsCanonicalEqual, areM0StringsFrameEqual } from "@m0saic/dsl";

// Same canonical program?
areM0StringsCanonicalEqual("2(F,F)", "2(1,1)");  // true

// Same rendered geometry?
areM0StringsFrameEqual("1", "2(0,1)");      // true

Frame equality parses both strings at the maximum of their feasibility requirements and compares all frame rects.


Key types

RenderFrame

  RenderFrame
  +-- x, y, width, height        pixel geometry
  +-- paintOrder: number          0-based, back to front
  +-- logicalIndex: number        0-based, DFS source order
  +-- meta: M0NodeIdentity    stableKey, parentStableKey, span

EditorFrame

  EditorFrame
  +-- x, y, width, height        pixel geometry
  +-- kind: M0NodeKind        "root" | "group" | "frame" | "passthrough" | "null"
  +-- axis?: M0Axis           "row" | "col" (groups/root only)
  +-- overlayDepth: number        0 = base layer, 1+ = inside overlay
  +-- meta: M0NodeIdentity    stableKey, parentStableKey, structuralDepth, span
  +-- logicalIndex?: number       source index (frames only)
  +-- passthroughOwner?           which frame received donated space

StableKey

Branded string encoding structural traversal path. Survives edits that don't change ancestry.

  r                   root
  r/growc0            first child of root, group split (row axis)
  r/growc0/fc1        second child of that group, a frame
  r/growc0/fc1/ov1c0  overlay on that frame

Branded M0String

type M0String = string & { readonly __m0Brand: unique symbol };

Construction contract:

  1. toCanonicalM0String(raw) — normalize
  2. validateM0StringCanonical(canonical) — must succeed
  3. Brand the result

If input may contain overlay chains (}{), normalize first with rewriteOverlayChains from @m0saic/dsl-stdlib.


Performance

All public functions are O(n).

  Operation                          130K chars / 55K nodes
  ─────────                          ──────────────────────
  getComplexityMetricsFast           < 1ms
  computeFeasibility                 < 1ms
  validateM0String               ~13ms
  parseM0StringToRenderFrames    ~400ms
  parseM0StringComplete          ~500ms

splitEven remainder distribution

When splitting an integer pixel length into parts, remainders are distributed outside-in:

  splitEven(1080, 7)
  base = 154, remainder = 2
  distribution order: index 0, index 6, index 1, index 5, ...
  result: [155, 154, 154, 154, 154, 154, 155]

Symmetric from edges inward. Deterministic. Visually balanced.


File formats

.m0 and .m0c file format APIs are in @m0saic/dsl-file-formats.

import { parseM0File, serializeM0File } from "@m0saic/dsl-file-formats";

License

Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.