@wrnexus/compiler
Partial-static rendering
Pages can select render = "partial-static" and divide their view with <Static> and
<Dynamic> boundaries. The compiler emits a build-only shell renderer that never evaluates
dynamic-boundary children. wrnexus build expands static component mounts into
dist/partial-shells.json, records byte/region evidence in build-report.json, and embeds
the shell in the production route manifest. At request time the production runtime retains
request-aware layouts, locale/theme metadata and security nonces while streaming dynamic
regions into stable placeholders.
Compiler for the
.wrnlanguage — tokenizes, parses, and lowers.wrnpage and component files to TypeScript.
Part of the WrNexus framework — an SSR-first, Bun-native full-stack web framework.
Production adapters use analyzeRuntimeImports before bundling. Edge, worker,
service-worker, and browser targets reject Node filesystem, TCP, and process
modules with WRN-RUNTIME-CAPABILITY. Package manifests can declare supported
wrnexus.runtimes and required wrnexus.requires capabilities; discovery fails
when the selected deployment cannot satisfy them.
Server actions
action createUser using CreateUserSchema {
const user = await users.create(input)
invalidate("users")
return user
}
view {
<form @submit="createUser">...</form>
}
The compiler produces a schema-aware server registry, a fully inferred action client, and progressively enhanced form metadata. The shared runtime performs validation, authentication/permission checks, CSRF verification, serialization, invalidation reporting, and browser lifecycle events.
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 WrNexus 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')}" />
}
}
Installation
bun add @wrnexus/compiler
Private package — the machine must be authenticated to the
wrnexusnpm org (a read token in~/.npmrc). Requires Bun (Node is not supported).
API
All exports come from the package root (@wrnexus/compiler).
compileWrnFile(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, compileWrnFile, 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 { compileWrnFile } from "@wrnexus/compiler";
const ts = compileWrnFile(`
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.@event name = functioninsideprops— declares a public component event. Emit it from component behavior withname(detail)or$emit("name", detail), and consume it with<Component @name="handler(event)" />.state <ident>: Type = <expr>— typed reactive state seeded from a raw JS expression, including native array and object literals. The annotation is optional for backward compatibility.view { <html> }— plain HTML with{expr}interpolation in text and attributes, JSX-style component props such asitems={items},items={[...]}, andoptions={{...}}, hyphenated attributes, boolean attributes,@event="..."client bindings, and<!-- comments -->. Structured component props are serialized safely for SSR; expressions that referencestateretain their initial value and update reactively in the browser.- Client functions automatically commit state changed by
setTimeoutcallbacks. For other deferred callbacks (observers, third-party APIs, or detached promise callbacks), call the injectedcommit()function after changing local state; returning/awaiting a promise also commits through the normal function boundary. 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 WrNexus toolchain (Node is not supported).
- Generated modules target WrNexus runtime primitives (
data-scope,data-text,data-on-*,data-for,data-component,__wrnexus*/__wrn*helpers) — consume the output within a WrNexus app, e.g. via@wrnexus/core's dev loader.