Files
WRNexusJS/docs/WRN-LANGUAGE-SPEC-1.0.md
Clintchiz f199385204
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
Make if and each blocks reactive on the client
2026-08-19 00:22:00 +05:30

5.2 KiB

WRN Language Specification 1.0

This document is the canonical public contract for .wrn files in WRNexusJS 0.3.x. The executable source of truth is @wrnexus/syntax; the compiler re-exports its parser and AST for compatibility.

Compatibility promise

WRNexusJS 0.3 keeps all previously supported declarations, including:

  • page, component, and layout roots
  • layout = "...", types, props, state, view, seo, and style
  • functions, lifecycle, and watch
  • api, ssr, client, and realtime
  • data-for, {#each}, conditions, interpolations, events, and class:*

New syntax is additive. Existing projects do not need to adopt it immediately. Since WRNexusJS 0.5.1, dynamic component props may use JSX-style unquoted expressions. Quoted expression attributes remain supported for compatibility:

state items = [{"label":"Accessibility","href":"/accessibility"}]

<FeatureList items={items} />
<FeatureList items={[{"label":"Accessibility","href":"/accessibility"}]} />
<FeatureList primaryAction={{"label":"Open","href":"/open"}} />
<FeatureList items="{items}" />

Expression-valued component props serialize arrays and objects as JSON while preserving booleans, numbers, and strings. Literal HTML attributes continue to require quotes.

File structure

A file may begin with TypeScript imports and must contain one root declaration:

import { appUrl } from "@wrnexus/helpers";

page Home {
    view {
        <main>Home</main>
    }
}

Root names are JavaScript identifiers. The valid root kinds are page, component, and layout.

Execution declarations

runtime = "universal"
hydrate = "visible"

Runtime targets:

  • server: never emits an interactive browser scope
  • client: intended for browser execution
  • universal: server-rendered and optionally hydrated

Hydration strategies:

  • load
  • idle
  • visible
  • interaction
  • none
  • media:<media-query>

client = "..." remains an alias for a hydration declaration. The existing client { ... } mode block remains valid.

Props and state

props {
    title: string
    count: number = 0
    enabled: boolean = false
}

state open: boolean = false
state links = [{"label":"Home","href":"/"}]
state options = {"dense":true}

A prop without an initializer is required. State always requires an initializer. State initializers are JavaScript expressions, including native arrays and objects. Typed initializers are validated when their literal type can be determined.

Computed values and effects

computed {
    total = price * quantity
    label = `${quantity} items`
}

effect {
    document.title = label
}

Computed values are dependency-tracked and cached. Effects rerun after a batched reactive update when a referenced state or computed value changes.

Data loading and actions

load server {
    return await repository.list(ctx.tenant?.id)
}

load client {
    return await fetch("/api/live").then((response) => response.json())
}

action save(input) {
    return await repository.save(input)
}

Server and client loaders are exported separately by the compiler. Named actions are exported individually and through __wrnexusActions for framework adapters.

Security metadata

security {
    auth = "required"
    csrf = "true"
    roles = "admin,editor"
    rateLimit = "strict"
}

The compiler exports this metadata as __wrnexusSecurity. Runtime middleware or plugins can enforce organization-specific policy. Metadata does not replace global security headers or API validation.

View syntax

view {
    <button
        type="button"
        class:opacity-50='loading'
        @click='save()'
    >
        {loading ? "Saving..." : title}
    </button>
}

Supported view features include:

  • HTML and component tags
  • escaped {expression} interpolation
  • event attributes such as @click, @window:scroll, and @document:click
  • conditional class:* attributes
  • data-show
  • data-for="item, index in items", optionally keyed with key item.id or data-key="item.id"
  • {#if}, {:else if}, {:else}, and {/if}
  • {#each items as item, index key item.id}, optional keys, and optional {:empty} branches
  • comments and scoped styles

{#if} and {#each} are rendered on the server for the initial response and remain reactive after hydration. Browser state changes switch conditional branches and rerender loop rows, including the {:empty} branch.

Output is escaped by default. Explicit raw HTML APIs must be treated as security boundaries.

Stable diagnostics

Canonical diagnostics use stable identifiers such as:

  • WRN-PARSE-001
  • WRN-PARSE-MEMBER
  • WRN-PROP-INITIALIZER
  • WRN-SYMBOL-DUPLICATE
  • WRN-HYDRATE-STRATEGY
  • WRN-RUNTIME-TARGET
  • WRN-RUNTIME-SERVER-INTERACTIVE
  • WRN-A11Y-001

Compiler, doctor, build, and future language-server integrations should consume @wrnexus/syntax diagnostics rather than implementing independent parsers.

AST ownership

The canonical packages are:

@wrnexus/syntax   lexer, parser, AST, specification, diagnostics
@wrnexus/compiler code generation and compatibility re-exports

Direct imports from compiler internals are deprecated. Public imports from @wrnexus/compiler continue to work in 0.3.x.