release: WRNexusJS 0.2.32

This commit is contained in:
2026-07-14 22:39:50 +05:30
parent 8b4b7ca5ac
commit 959ed24009
66 changed files with 3135 additions and 648 deletions
+756 -47
View File
@@ -1,54 +1,614 @@
# WRNexus Language Support
Language support for [WRNexus](https://wrnexusjs.dev) `.wrn` files — the SSR-first,
Bun-powered full-stack framework.
Complete VS Code language support for [WRNexus](https://wrnexusjs.dev) `.wrn` files.
WRNexus is an SSR-first, Bun-powered full-stack framework with reactive components, layouts, colocated APIs, browser functions, lifecycle hooks, state watchers, client-side navigation, and reusable UI components.
## Installation
After the first Marketplace release, search for **WRNexus Language Support** in
VS Code or run:
Search for **WRNexus Language Support** in the VS Code Extensions view or run:
```text
ext install wrnexus.wrnexus
```
For a local package, open the Command Palette, choose **Extensions: Install from
VSIX**, and select the generated `wrnexus-<version>.vsix` file.
For a local build:
1. Package the extension:
```bash
bun run package
```
2. Open the VS Code Command Palette.
3. Select **Extensions: Install from VSIX**.
4. Choose the generated `wrnexus-<version>.vsix` file.
You can also install it from the terminal:
```bash
code --install-extension ./wrnexus-0.2.7.vsix --force
```
Reload VS Code after installation:
```text
Developer: Reload Window
```
## Features
- **Syntax highlighting** ("color-full code"). Keywords (`page`, `component`,
`state`, `view`, `api`, `realtime`, …) plus **embedded highlighting** for the
languages inside each block:
- `view { … }` → HTML, with `{expr}` interpolation and `{t:key}` translations
and `@event="…"` bindings picked out.
- `style { … }` → CSS.
- `functions { … }`, `api … { … }`, `ssr`/`client`, `realtime on(…) { … }` → TypeScript.
- **WrNexus attributes in distinct colors.** A grammar injection recolors the
framework's own attributes so they pop even inside plain HTML: `@event`
bindings and `{t:…}` in one accent, runtime directives (`data-component`,
`data-for`, `data-show`, `data-text`, `data-scope`, `data-slot`, `data-on-*`,
`data-wire-*`) in another. Default colors ship with the extension; change them
under `editor.tokenColorCustomizations` (scopes
`entity.other.attribute-name.wrn.directive` and `…wire.event`).
- **Diagnostics.** Parse errors from the real `@wrnexus/compiler` are shown inline
as you type, anchored to the exact offset.
- **Formatting.** Format Document and format-on-save normalize WRN block, HTML,
CSS, and function indentation without rewriting application expressions.
- **Snippets.** `page`, `component`, `view`, `state`, `props`, `seo`, `api`,
`ssr`, `client`, `realtime`, `functions`, `style`, plus view helpers `mount`,
`for`, `show`, `t`.
- **Completions.** Block keywords at file scope, `data-*` runtime attributes and
`@event` bindings inside a `view`, and HTTP methods after `api`.
### Syntax highlighting
## Settings
The extension provides highlighting for WRNexus declarations and embedded languages.
| Setting | Default | Description |
| ---------------------------- | ------- | ----------------------------------------- |
| `wrnexus.diagnostics.enable` | `true` | Show parse errors for `.wrn` files. |
| `wrnexus.format.enable` | `true` | Enable the built-in formatter for `.wrn`. |
Supported top-level declarations:
To format automatically when saving, add this to VS Code settings:
```wrn
page HomePage {
}
component UserCard {
}
layout PublicLayout {
}
```
Supported WRNexus blocks include:
```wrn
props {
}
state count = 0
seo {
}
functions {
}
lifecycle {
}
watch count {
}
view {
}
style {
}
api GET /api/users {
}
ssr {
}
client {
}
realtime chat {
}
```
Embedded language highlighting:
- `view { ... }` uses HTML highlighting.
- `style { ... }` uses CSS highlighting.
- `functions { ... }` uses TypeScript highlighting.
- Lifecycle hook bodies use TypeScript highlighting.
- Watcher bodies use TypeScript highlighting.
- API, SSR, client, and realtime bodies use TypeScript highlighting.
- `{expression}` interpolation uses TypeScript expression highlighting.
### Pages
Create route pages with layouts, SEO metadata, state, APIs, and views:
```wrn
page UserPage {
layout = "public"
state id = ctx.params.id
seo {
title = "User profile"
description = "View user information"
}
view {
<main>
<h1>User {id}</h1>
</main>
}
}
```
Dynamic route parameters are available through:
```wrn
state id = ctx.params.id
```
For a route such as:
```text
pages/users/[id].wrn
```
autocomplete suggests:
```text
id
ctx.params.id
```
### Components
Create reusable reactive components:
```wrn
component Counter {
state count = 0
view {
<button @click="count++">
Count: {count}
</button>
}
}
```
Components support:
- props
- reactive state
- browser functions
- lifecycle hooks
- state watchers
- event handlers
- conditional classes
- reactive attributes
- reactive loops
- conditional visibility
### Layouts
Create reusable layouts:
```wrn
layout PublicLayout {
view {
<header>
<nav>Navigation</nav>
</header>
<main>
{content}
</main>
}
}
```
Layouts can also use state, props, functions, lifecycle hooks, and watchers.
## Browser functions
Functions declared inside a component or layout are available to browser events, lifecycle hooks, and watchers.
```wrn
component Counter {
state count = 0
functions {
function increment() {
count += 1
}
function reset() {
count = 0
}
}
view {
<button @click="increment()">
Increment
</button>
<button @click="reset()">
Reset
</button>
<p>{count}</p>
}
}
```
Functions may use browser APIs:
```wrn
functions {
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: "smooth"
})
}
}
```
Asynchronous functions are also supported:
```wrn
functions {
async function loadUsers() {
const response = await fetch("/api/users")
const users = await response.json()
}
}
```
## Lifecycle hooks
Components and layouts support three lifecycle hooks:
```wrn
lifecycle {
mount {
}
update {
}
unmount {
}
}
```
### `mount`
Runs once after the component is connected to the page and hydrated.
```wrn
lifecycle {
mount {
console.log("Component mounted")
}
}
```
Use it to:
- read browser state
- initialize third-party libraries
- register global event listeners
- start timers
- perform initial browser-only work
### `update`
Runs after reactive state changes.
Multiple synchronous state changes are batched into one update cycle.
```wrn
lifecycle {
update {
console.log("Component state updated")
}
}
```
### `unmount`
Runs before the component is removed.
```wrn
lifecycle {
unmount {
console.log("Component removed")
}
}
```
Use it to:
- remove global event listeners
- clear timers
- disconnect observers
- release browser resources
- clean up third-party libraries
Lifecycle cleanup also runs during WRNexus client-side navigation.
## State watchers
Watch one declared state value:
```wrn
component Menu {
state open = false
watch open {
console.log("Current value:", value)
console.log("Previous value:", previous)
}
view {
<button @click="open = !open">
Toggle menu
</button>
}
}
```
Watcher variables:
| Variable | Description |
| ---------- | -------------------- |
| `value` | Current state value |
| `previous` | Previous state value |
A watcher runs only when its declared state changes.
Invalid watcher declarations are reported:
```wrn
watch missingState {
}
```
The editor reports that `missingState` has not been declared.
## Window and document events
WRNexus supports events attached directly to `window` and `document`.
### Window events
```wrn
<div @window:scroll="updateScrollPosition()">
</div>
```
```wrn
<div @window:resize="updateViewportSize()">
</div>
```
```wrn
<div @window:keydown="handleKeyboardShortcut()">
</div>
```
### Document events
```wrn
<div @document:click="closeMenu()">
</div>
```
```wrn
<div @document:visibilitychange="handleVisibilityChange()">
</div>
```
Global event listeners created manually inside `mount` should be removed inside `unmount`.
## Complete BackToTop example
```wrn
component BackToTop {
state visible = false
functions {
function updateBackToTopVisibility() {
visible = window.scrollY > 500
}
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: "smooth"
})
}
}
lifecycle {
mount {
updateBackToTopVisibility()
window.addEventListener(
"scroll",
updateBackToTopVisibility,
{ passive: true }
)
}
unmount {
window.removeEventListener(
"scroll",
updateBackToTopVisibility
)
}
}
watch visible {
console.log(
"BackToTop visibility changed:",
value,
previous
)
}
view {
<button
type="button"
@click="scrollToTop()"
aria-label="Back to top"
class="fixed bottom-5 right-5"
class:pointer-events-none="!visible"
class:translate-y-4="!visible"
class:opacity-0="!visible"
class:pointer-events-auto="visible"
class:translate-y-0="visible"
class:opacity-100="visible"
>
Back to top
</button>
}
}
```
## Conditional classes
Use `class:<class-name>` to toggle CSS classes reactively:
```wrn
<button
class:opacity-100="visible"
class:pointer-events-auto="visible"
class:opacity-0="!visible"
class:pointer-events-none="!visible"
>
Action
</button>
```
The expression is evaluated whenever its reactive dependencies change.
## Event bindings
Standard element events:
```wrn
<button @click="submitForm()">
Submit
</button>
```
```wrn
<input @input="query = event.target.value" />
```
```wrn
<form @submit="handleSubmit()">
</form>
```
Supported completion suggestions include:
- `@click`
- `@input`
- `@change`
- `@submit`
- `@focus`
- `@blur`
- `@keydown`
- `@keyup`
- `@mouseenter`
- `@mouseleave`
- `@window:scroll`
- `@window:resize`
- `@window:keydown`
- `@document:click`
- `@document:visibilitychange`
## Reactive directives
### Conditional visibility
```wrn
<div data-show="open">
Visible when open is true
</div>
```
### Reactive loops
```wrn
<ul>
<li data-for="user in users">
{user.name}
</li>
</ul>
```
### Reactive text
```wrn
<span data-text="message"></span>
```
### Dynamic attributes
```wrn
<button disabled="{loading}">
Save
</button>
```
## Diagnostics
The extension provides two diagnostic layers.
### Editor diagnostics
Fast local validation checks:
- invalid root declarations
- unknown page, component, or layout members
- unbalanced braces, brackets, and parentheses
- unclosed strings
- invalid HTML closing tags
- missing HTML closing tags
- invalid lifecycle hooks
- duplicate lifecycle hooks
- duplicate lifecycle blocks
- undeclared watched states
- missing watcher bodies
- invalid layout usage
- missing view blocks
### Compiler diagnostics
The extension bundles the real WRNexus compiler and validates `.wrn` files as you type.
Compiler errors are attached to the reported source offset whenever available.
Disable diagnostics with:
```json
"wrnexus.diagnostics.enable": false
```
## Formatting
The built-in formatter supports:
- page, component, and layout indentation
- functions and nested function bodies
- lifecycle blocks
- watcher blocks
- multiline function calls
- object literals
- HTML elements
- multiline HTML attributes
- conditional class directives
- window and document events
- CSS blocks
- API blocks
Format a document using:
```text
Shift+Alt+F
```
Enable format-on-save:
```json
"[wrn]": {
@@ -57,29 +617,178 @@ To format automatically when saving, add this to VS Code settings:
}
```
Disable the formatter:
```json
"wrnexus.format.enable": false
```
Configure preferred line width:
```json
"wrnexus.formatting.printWidth": 100
```
## Autocomplete
Autocomplete is available for:
- pages
- components
- layouts
- state declarations
- props
- views
- SEO metadata
- functions
- lifecycle hooks
- watchers
- declared state names
- declared props
- declared functions
- watcher variables
- route parameters
- context values
- standard events
- window events
- document events
- reactive attributes
- conditional classes
After typing:
```wrn
watch
```
the extension suggests declared state names.
Inside a watcher, it suggests:
```text
value
previous
```
Declared component functions are suggested as callable snippets:
```text
updateVisibility()
scrollToTop()
```
## Go to definition
Use Ctrl+Click or **Go to Definition** for supported WRNexus symbols.
The extension can navigate to component declarations and locally declared functions when supported by the definition provider.
## Snippets
Useful snippet prefixes include:
| Prefix | Purpose |
| ------------------------ | ------------------------------------- |
| `wrn-page` | Create a page |
| `wrn-dynamic-page` | Create a dynamic route page |
| `wrn-component` | Create a component |
| `wrn-reactive-component` | Create a reactive component |
| `wrn-layout` | Create a layout |
| `wrn-state` | Declare state |
| `wrn-functions` | Create a functions block |
| `wrn-function` | Create a function |
| `wrn-async-function` | Create an async function |
| `wrn-lifecycle` | Create all lifecycle hooks |
| `wrn-mount` | Create a mount hook |
| `wrn-update` | Create an update hook |
| `wrn-unmount` | Create an unmount hook |
| `wrn-watch` | Create a watcher |
| `wrn-window-scroll` | Add a window scroll event |
| `wrn-window-resize` | Add a window resize event |
| `wrn-document-event` | Add a document event |
| `wrn-class-if` | Add a conditional class |
| `wrn-class-toggle` | Toggle two classes |
| `wrn-back-to-top` | Create a complete BackToTop component |
## Settings
| Setting | Default | Description |
| ------------------------------- | ------- | -------------------------------------- |
| `wrnexus.diagnostics.enable` | `true` | Enable editor and compiler diagnostics |
| `wrnexus.format.enable` | `true` | Enable the built-in formatter |
| `wrnexus.formatting.printWidth` | `100` | Preferred formatter line width |
Recommended VS Code configuration:
```json
{
"[wrn]": {
"editor.defaultFormatter": "wrnexus.wrnexus",
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.snippetSuggestions": "top"
},
"wrnexus.diagnostics.enable": true,
"wrnexus.format.enable": true,
"wrnexus.formatting.printWidth": 100
}
```
## Privacy
The extension does not collect telemetry and does not send source code or usage
data over the network. Formatting, completion, and diagnostics run locally.
The extension does not collect telemetry.
It does not send source code, diagnostics, formatting data, or usage information over the network.
Syntax highlighting, formatting, autocomplete, snippets, definition navigation, and diagnostics run locally.
## Development
Diagnostics use a bundled copy of the compiler. Build and validate everything
after changing the extension or `@wrnexus/compiler`:
Install dependencies:
```bash
bun install
```
Rebuild the bundled compiler:
```bash
bun run build:compiler
```
Validate the extension:
```bash
bun run check
```
Package a VSIX:
```bash
bun run package
```
`bun run package` creates `wrnexus-<version>.vsix`. The extension still
highlights, provides snippets, and completes without the compiler bundle; only
inline error reporting requires it.
This creates:
Open this folder in VS Code and press <kbd>F5</kbd> to launch an Extension
Development Host, then open any `.wrn` file.
```text
wrnexus-<version>.vsix
```
See the
[Marketplace publishing guide](https://git.workroot.in/WorkRoot/WRNexusJS/src/branch/main/editors/vscode/PUBLISHING.md)
for the release procedure.
Install the local package:
```bash
code --install-extension ./wrnexus-<version>.vsix --force
```
Open the extension folder in VS Code and press <kbd>F5</kbd> to launch an Extension Development Host.
After changing the parser or compiler, always rebuild:
```bash
bun run build:compiler
```
Without the compiler bundle, syntax highlighting, snippets, formatting, and autocomplete continue to work, but compiler diagnostics are unavailable.
See the [Marketplace publishing guide](https://git.workroot.in/WorkRoot/WRNexusJS/src/branch/main/editors/vscode/PUBLISHING.md) for publishing instructions.