@wrnexus/compiler
Parser and code generators for the .wrn language.
Install the package
After WorkRoot approves private registry access, install the release-aligned package:
bun add @wrnexus/compiler@0.3.1Request preview access. Never put registry tokens in source control.
Compiler for the.wrnlanguage — tokenizes, parses, and lowers.wrnpage and component files to TypeScript.
Part of the WRNexusJS framework — an SSR-first, Bun-native full-stack web framework.
Overview
@wrnexus/compiler turns .wrn source into TypeScript that targets the framework's runtime primitives. A .wrn file declares either a page (a route) or a component (a reusable, prop-driven fragment) with blocks for state, view (plain HTML), seo, style, functions, api, ssr/client data bindings, and realtime websocket handlers. The pipeline is source → Lexer → parse() → PageAst → generate() → TypeScript. It is a build/server-side library — the WRNexusJS dev loader calls it to compile .wrn files on the fly, surfacing ParseError as a readable error page.
Static ES module imports may appear before the root declaration. Imported values are available to server-rendered expressions, including component props:
import { appUrl } from "@wrnexus/helpers";
layout PublicLayout {
view {
<PublicHeader signInHref="{appUrl('sso', '/sign-in')}" />
}
}
bun add @wrnexus/compiler
Private package — the machine must be authenticated to the wrnexus npm org
(a read token in ~/.npmrc). Requires Bun (Node is not supported).
API
All exports come from the package root (@wrnexus/compiler).
compileWireFile(source: string): string
Compile .wrn source to a TypeScript module string. Throws ParseError on invalid input. The output is prefixed with a // compiled from .wrn comment.
compile(source: string): CompileResult
Richer entry point that returns the generated code, the AST, and any diagnostics.
interface CompileResult {
code: string;
ast: PageAst;
diagnostics: string[];
}
On a ParseError it pushes the message into diagnostics and re-throws.
parse(source: string): PageAst
Run the lexer + recursive-descent parser and return the AST. Throws ParseError (lexer LexErrors are caught and rethrown as ParseError).
generate(ast: PageAst): string
Lower a PageAst to TypeScript. page ASTs become a default-export page component (plus meta, optional layout, __wrnexusApi/method handlers, websocket, and SSR/CSR data bindings); component ASTs become a module exporting render(props) and __wrnexusComponent.
Lexer
On-demand lexer for .wrn. Yields structural tokens and exposes raw-span readers for the parser.
class Lexer {
pos: number;
constructor(src: string);
next(): Token; // consume next structural token
peek(): Token; // look ahead without consuming
readPath(): string; // route path, e.g. /users/[id]
readToLineEnd(): string; // rest of line (state/prop initializers)
readBalancedBraces(): string; // inner text of a { ... } block, string-aware
}
Token is { type: TokenType; value: string; pos: number }, where TokenType is one of ident, string, lbrace, rbrace, lparen, rparen, at, eq, comma, eof.
Errors
| Class | Thrown by | Meaning |
|---|---|---|
ParseError | parse, compile, compileWireFile, generate | Invalid .wrn grammar or (rewrapped) lex failure. |
LexError | Lexer | Unexpected character / unterminated string / unbalanced braces. |
AST types
Exported type-only symbols describing the parsed tree:
| Type | Description | |
|---|---|---|
PageAst | Root node including top-level imports, kind, name, types, typed props, typed states, view, styles, functions, data APIs, lifecycle, and routes. | |
ViewNode | { type: "text"; value } or { type: "element"; tag; attrs; children }. | |
Attr | { name; value; event; boolean? } — event marks @event bindings. | |
StateDecl | { name; valueType?; expr } — a typed state x: Type = <expr> declaration. | |
PropDecl | { name; valueType?; required; default } — a typed prop declaration. | |
SeoBlock | Record<string, string> from the seo { ... } block. | |
ApiBlock | { method; path; body } — a top-level api METHOD /path { ... }. | |
DataApiBlock | { mode; name; method; path; body } — an api inside an ssr/client block. | |
DataMode | `"ssr" \ | "client"`. |
ModeFunctionsBlock | { mode; body } — a functions { ... } inside an ssr/client block. | |
RealtimeBlock | { name; handlers } — a realtime <name> { on evt(args) { ... } } block. |
Usage
Compile a page:
import { compileWireFile } from "@wrnexus/compiler";
const ts = compileWireFile(`
page Home {
state count = 0
seo { title = "Home" description = "Welcome" }
view {
<button @click="count++">Clicked {count} times</button>
}
}
`);
// ts is a TypeScript module: exports `meta`, and a default page component
// returning an HTML string, wrapped in a data-scope for the reactive runtime.
Inspect the AST and diagnostics:
import { compile, ParseError } from "@wrnexus/compiler";
try {
const { code, ast, diagnostics } = compile(source);
console.log(ast.kind, ast.name, ast.states.length);
} catch (err) {
if (err instanceof ParseError) console.error(err.message);
}
Drive the parse/codegen stages directly:
import { parse, generate } from "@wrnexus/compiler";
const ast = parse(componentSource); // ast.kind === "component"
const module = generate(ast); // exports render(props) + __wrnexusComponent
Use the lexer standalone:
import { Lexer } from "@wrnexus/compiler";
const lx = new Lexer("page Home {");
lx.next(); // { type: "ident", value: "page", pos: 0 }
lx.next(); // { type: "ident", value: "Home", pos: 5 }
lx.next(); // { type: "lbrace", value: "{", pos: 10 }
The .wrn language (as parsed)
A file opens with page <Name> or component <Name> followed by a { ... } body containing zero or more members:
layout = "<name>"— selectsapp/layouts/<name>.wrn(pages only).types { <TypeScript declarations> }— reusable interfaces and aliases for the current file.props { name: Type = <default> ... }— typed component props. Omit= <default>to make a prop required. Legacy inferred props remain supported.state <ident>: Type = <expr>— typed reactive state seeded from a raw JS expression. The annotation is optional for backward compatibility.view { <html> }— plain HTML with{expr}interpolation in text and attributes, hyphenated attributes, boolean attributes,@event="..."client bindings, and<!-- comments -->. Attribute expressions that referencestatekeep an SSR value and update reactively in the browser.seo { key = "value" ... }— metadata merged into the generatedmeta.style { <raw css> }— inlined page/component stylesheet (repeatable).functions { <TypeScript> }— helpers with typed parameters and return values. Types remain in server output and are safely erased from browser behavior code.api <METHOD> <path> { <raw js> }— route handler, lowered to aMETHODexport (repeatable).ssr { ... }/client { ... }— data blocks holdingapi <name> <METHOD> <path> { ... }bindings and their ownfunctions { ... }.realtime <name> { on <evt>(<args>) { <raw js> } ... }— websocket handlers, lowered to awebsocketexport.
view markup is parsed by a lenient dedicated HTML parser (parseHtmlView); HTML void elements (<br>, <img>, …) take no closing tag. Line comments (//) are skipped by the lexer.
Requirements / Notes
- Pure TypeScript with no runtime dependencies; runs under Bun as part of the WRNexusJS toolchain (Node is not supported).
- Generated modules target WRNexusJS runtime primitives (
data-scope,data-text,data-on-*,data-for,data-component,__wrnexus*/__wire*helpers) — consume the output within a WRNexusJS app, e.g. via@wrnexus/core's dev loader.
Complete TypeScript API
Generated from the exact installed package declarations.
import { PageAst as PageAst$1, WrnDiagnostic } from '@wrnexus/syntax';
export { ActionBlock, ApiBlock, Attr, ComputedDecl, DataApiBlock, DataMode, EffectBlock, LexError, Lexer, LoadBlock, ModeFunctionsBlock, PageAst, ParseError, PropDecl, RealtimeBlock, SeoBlock, StateDecl, ViewNode, WrnDiagnostic, assertValidAst, diagnose, diagnosticFromError, eraseFunctionTypes, formatDiagnostic, inferredRuntimeType, parse, runtimeTypeOf } from '@wrnexus/syntax';
import { PageAst } from '@wrnexus/syntax/parser';
/**
* Code generation: lower a `.wrn` AST to TypeScript that targets the framework's
* existing primitives.
*
* state -> a `data-scope` declaration consumed by the runtime
* view -> an HTML string returned by a page component
* @event="..." -> data-on-<event>="..."
* "...{expr}..." -> text kept verbatim ({expr} is mustache for runtime)
* api="<name>" -> SSR/client data binding declared in a mode block
* ssrGet/ssrText -> legacy server-side API fetch + render
* csrGet/csrText -> legacy browser-side API fetch + render
* style -> an inline page stylesheet
* functions -> server-only helpers for API/realtime code
* api M /p {b} -> export const M = async (ctx) => { b }
* realtime {..} -> export const websocket = { evt(ws, ...args) { b } }
*/
declare function generate(ast: PageAst): string;
declare class NativeCompileError extends Error {
constructor(message: string);
}
/** Compile a parsed `.wrn` page to an Expo Router React Native screen. */
declare function generateNative(ast: PageAst): string;
/**
* @wrnexus/compiler — the `.wrn` language compiler.
*
* Parsing and language diagnostics are provided by the canonical
* `@wrnexus/syntax` package. This package owns platform-specific codegen.
*/
interface CompileResult {
code: string;
ast: PageAst$1;
/** Backward-compatible plain diagnostic messages. */
diagnostics: string[];
/** Structured diagnostics for editors, CI, and the DevToolbar. */
richDiagnostics: WrnDiagnostic[];
}
/** Compile `.wrn` source into an Expo Router React Native screen. */
declare function compileNativeWireFile(source: string): string;
/**
* Compile `.wrn` source into TypeScript source. Errors include a stable code,
* source location, code frame, and actionable hint whenever available.
*/
declare function compileWireFile(source: string, filePath?: string): string;
/** Richer entry point returning the AST and structured diagnostics. */
declare function compile(source: string, filePath?: string): CompileResult;
export { type CompileResult, NativeCompileError, compile, compileNativeWireFile, compileWireFile, generate, generateNative };
Examples
Copy-ready examples from the installed package documentation.
Compile a page
import { compileWireFile } from "@wrnexus/compiler";
const ts = compileWireFile(`
page Home {
state count = 0
seo { title = "Home" description = "Welcome" }
view {
<button @click="count++">Clicked {count} times</button>
}
}
`);
// ts is a TypeScript module: exports `meta`, and a default page component
// returning an HTML string, wrapped in a data-scope for the reactive runtime.Inspect the AST and diagnostics
import { compile, ParseError } from "@wrnexus/compiler";
try {
const { code, ast, diagnostics } = compile(source);
console.log(ast.kind, ast.name, ast.states.length);
} catch (err) {
if (err instanceof ParseError) console.error(err.message);
}Drive the parse/codegen stages directly
import { parse, generate } from "@wrnexus/compiler";
const ast = parse(componentSource); // ast.kind === "component"
const module = generate(ast); // exports render(props) + __wrnexusComponentUse the lexer standalone
import { Lexer } from "@wrnexus/compiler";
const lx = new Lexer("page Home {");
lx.next(); // { type: "ident", value: "page", pos: 0 }
lx.next(); // { type: "ident", value: "Home", pos: 5 }
lx.next(); // { type: "lbrace", value: "{", pos: 10 }