199 lines
5.0 KiB
Markdown
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.
|