# @wrnexus/compiler > Compiler for the `.wrn` language — tokenizes, parses, and lowers `.wrn` page and component files to TypeScript. Part of the **WrNexus** 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 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: ```wrn import { appUrl } from "@wrnexus/helpers"; layout PublicLayout { view { } } ``` ## Installation ```bash 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. ```ts 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 `LexError`s 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. ```ts 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 = ` declaration. | | `PropDecl` | `{ name; valueType?; required; default }` — a typed prop declaration. | | `SeoBlock` | `Record` 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 { on evt(args) { ... } }` block. | ## Usage Compile a page: ```ts import { compileWireFile } from "@wrnexus/compiler"; const ts = compileWireFile(` page Home { state count = 0 seo { title = "Home" description = "Welcome" } view { } } `); // 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: ```ts 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: ```ts 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: ```ts 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 ` or `component ` followed by a `{ ... }` body containing zero or more members: - `layout = ""` — selects `app/layouts/.wrn` (pages only). - `types { }` — reusable interfaces and aliases for the current file. - `props { name: Type = ... }` — typed component props. Omit `= ` to make a prop required. Legacy inferred props remain supported. - `state : Type = ` — typed reactive state seeded from a raw JS expression. The annotation is optional for backward compatibility. - `view { }` — plain HTML with `{expr}` interpolation in text and attributes, hyphenated attributes, boolean attributes, `@event="..."` client bindings, and ``. Attribute expressions that reference `state` keep an SSR value and update reactively in the browser. - `seo { key = "value" ... }` — metadata merged into the generated `meta`. - `style { }` — inlined page/component stylesheet (repeatable). - `functions { }` — helpers with typed parameters and return values. Types remain in server output and are safely erased from browser behavior code. - `api { }` — route handler, lowered to a `METHOD` export (repeatable). - `ssr { ... }` / `client { ... }` — data blocks holding `api { ... }` bindings and their own `functions { ... }`. - `realtime { on () { } ... }` — websocket handlers, lowered to a `websocket` export. `view` markup is parsed by a lenient dedicated HTML parser (`parseHtmlView`); HTML void elements (`
`, ``, …) 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*`/`__wire*` helpers) — consume the output within a WrNexus app, e.g. via `@wrnexus/core`'s dev loader.