release: WRNexusJS 0.3.0
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
# 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.
|
||||
Dynamic attribute expressions should be single-quoted so braces remain unambiguous:
|
||||
|
||||
```wrn
|
||||
<FeatureList items='{items}' primaryAction='{{ label: "Open" }}' />
|
||||
```
|
||||
|
||||
The 0.3 updater only rewrites simple, unambiguous `prop={expression}` values. Nested
|
||||
brace expressions are left unchanged and reported for manual review.
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
A prop without an initializer is required. State always requires an initializer.
|
||||
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.
|
||||
Reference in New Issue
Block a user