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

@codedia/parser

v0.2.0

Published

An LLM-first, validated UI language with a deterministic compiler: express screens in .aui, get validated canonical IR and readable React/TSX. Small grammar, host-owned registry, measured token savings.

Downloads

388

Readme

@codedia/parser

An LLM-first, validated UI language with a deterministic compiler, in one package. Express screens in .aui — a small DSL that is the UI tree itself — then run a deterministic pipeline: parse, validate against a host-owned registry, normalize to a canonical IR, and compile to React + TypeScript. This is a DSL plus a compiler, not a token-compression trick: the token savings are a measured consequence of the small grammar.

npm install @codedia/parser

npm version License: MIT Website


Why

Ask an LLM to build a screen and it emits React + JSX + imports + className strings + CSS — a large, error-prone surface. .aui is the opposite: the source is the UI tree, expressed in a small, predictable DSL. The compiler — not the model — owns every decision an LLM is bad at: imports, JSX syntax, binding resolution, event wiring, and output formatting.

Card max=md pad=lg
  Stack gap=md
    Heading level=2 "Welcome back"
    Text tone=muted "Continue where you left off."
    Button variant=primary action=continue "Continue"

The language has no arbitrary JavaScript, CSS, or invented imports. In strict mode, every component, prop, token, and import is constrained by the registry you own.

Quickstart

import { compile, defineRegistry, CORE_REGISTRY, extendRegistry, formatDiagnostics } from '@codedia/parser';

// Extend the core registry with your design system and third-party components.
const registry = extendRegistry(CORE_REGISTRY, {
  AreaChart: {
    imports: { source: '@company/charts', export: 'AreaChart' },
    props: { data: { type: 'binding' }, height: { type: 'number' } },
    children: 'nodes',
  },
});

const result = compile(`
Page Dashboard data=$metrics
  Stack gap=md
    Heading level=1 "Overview"
    Metric label="Active users" value=$metrics.active
    Button variant=primary action=refresh "Refresh"
`, { registry, strict: true });

if (!result.ok) {
  console.error(formatDiagnostics(result.diagnostics));
} else {
  console.log(result.code); // deterministic React + TSX
}

compile(source, options) runs the whole pipeline — parse → validate → normalize → compile — and refuses to emit code in strict mode when error-level diagnostics exist. You never sequence low-level calls to get safe output.

Pipeline & API

source → lexer/parser → RawDocument → validate() → normalize() → CanonicalDocument → compileReact() → TSX

| Export | Description | |---|---| | parse(source): RawDocument | Parse .aui into the raw syntax tree (typed raw values, line numbers). | | validate(source, opts?): Diagnostic[] | Registry, structural, indentation, identifier, binding, and resource-limit checks. | | normalize(doc, opts?): Result<CanonicalDocument> | Raw → canonical IR: typed values, explicit If/For nodes, unified def params. | | compile(source, opts?): CompileResult | High-level pipeline ({ code?, rawAst, ast?, diagnostics, ok }). strict: true refuses to emit code on errors. | | compileReact(doc, opts?): string | Low-level canonical IR → React + TSX (also accepts raw docs for migration). | | printAui(doc): string | Canonical .aui printer — deterministic, round-trip friendly. | | defineRegistry(defs) / extendRegistry(base, extra) | Host-owned registry of nodes, props, tokens, events, and imports. | | CORE_REGISTRY | The default/design-system-neutral registry shipped with the package. | | formatDiagnostics(diags) / formatDiagnosticsForLLM(diags, source?) | Line-anchored reports designed for LLM repair loops. | | tokenize, scan, tokenizeText, interpolateText, resolvePath, stringifyResolved, resolveBindingValue | Lexing and text/binding helpers. |

Registry — the safety boundary

The registry is how third-party components and your design system enter the language. strict compilation is registry-only by default: models write AreaChart data=$series and the compiler derives import { AreaChart } from "@company/charts" — models never write import lines and cannot invent dependencies. Explicit import lines are an advanced/compatibility mode:

// Advanced: allow explicit imports from a specific allowlist.
compile(source, { imports: { mode: 'explicit', allow: ['recharts'] } });
// Or fully permissive (documented as unsafe):
compile(source, { imports: { unsafeImports: true } });

Semantic events

.aui uses framework-neutral event names; the registry owns the target mapping:

Input value=$form.email change=emailChanged
Checkbox checked=$form.remember change=rememberChanged "Remember me"

compiles to (for a React target):

<Input value={data.form.email} onChange={(e) => onAction('emailChanged', e.target.value)} />
<Checkbox checked={data.form.remember} onChange={(e) => onAction('rememberChanged', e.target.checked)}>Remember me</Checkbox>

events: { change: { target: 'onChange', payload: 'target.value' } } lives in the registry, so the language never hard-codes React event objects.

Diagnostics

Diagnostics carry a stable machine-readable code, severity, line (and column where feasible), message, and optional fix hint — intentionally easy to feed back to an LLM for one-shot repair:

line 7: AUI_INVALID_TOKEN error: <Button> prop "variant=purple" is invalid. Expected one of: primary, secondary, ghost, danger. (suggestion: use variant=primary)

Token efficiency

Measured with the real GPT tokenizers (o200k_base primary, cl100k_base legacy — pinned explicitly, no approximation), six real screens save 1,140 tokens (o200k_base) — 50% fewer, 2.0× smaller than hand-written React, under a functional-equivalence gate (every scenario declares a feature contract; the validator fails if either implementation is missing a declared feature). Reproduce with npm run validate:tokens in apps/www. See docs/token-methodology.md.

Grammar at a glance

Page Dashboard data=$metrics              # root; label becomes component name
  Stack gap=md
    Heading level=2 "Overview"            # quoted text content
    Metric label="Active users" value=$metrics.active
    Input value=$form.email change=emailChanged   # semantic events
    If condition=$user.admin              # conditional branch
      Badge tone=success "Admin"
    Else
      Badge tone=muted "Member"
    For each=$tasks                       # loop over a binding
      Row
        Text "Task $item.title"           # bindings interpolate inside text
  • NodesPage Stack Row Grid Card Section Spacer Heading Text Image Icon Divider Button Link Input Select Checkbox Switch Alert Badge Spinner Metric Field (+ structural If Else For; State is reserved).
  • Propskey=value; bare values (gap=md, variant=primary) are semantic tokens; $path are data bindings; quoted strings (label="Active users") are literal (a quoted "$user.name" is a literal string, not a binding).
  • Bindings$user.namedata.user.name; $item / $index inside For; $param inside def bodies; $root.path for explicit absolute access.
  • Actionsaction=name only, routed through onAction("name").
  • defdef StatCard label value tone=default declares a reusable template; params are one unified model (required + defaulted).
  • Imports — via the registry in strict mode (advanced: allowlisted explicit imports). Side-effect imports are supported in compat mode.
  • No arbitrary JS, CSS, className, or eval — ever.

Full spec: docs/grammar.md · docs/api.md · docs/compiler.md

Development

git clone https://github.com/fahimc/ai-ui-ast.git
cd ai-ui-ast
npm install          # installs workspaces, builds @codedia/parser
npm test -w @codedia/parser

Run the playground locally:

npm run dev -w www   # http://localhost:5173

Links

License

MIT © Fahim Chowdhury. See LICENSE.