# 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:

```wrn
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:

```wrn
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

```wrn
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

```wrn
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

```wrn
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

```wrn
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

```wrn
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

```wrn
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:

```text
@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.
