Files
WRNexusJS/docs/WRN-LANGUAGE-SPEC-1.0.md
T

199 lines
5.0 KiB
Markdown

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