Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>WRNexus Language SupportNew to Visual Studio Code? Get it now.
WRNexus Language Support

WRNexus Language Support

WRNexus

|
3 installs
| (0) | Free
Complete WRNexus v0.8.3 language support for typed imports, props, state, outputs, runtime functions, stores, diagnostics, formatting, navigation, and migration assistance.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

WRNexus Language Support

For AI tools that support Model Context Protocol, run wrnexus mcp <app-dir> (or bunx wrnexus-mcp --root=<app-dir>). The same read-only framework context works from VS Code, JetBrains IDEs, Neovim and standalone MCP clients.

Complete VS Code language support for WRNexus .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.

Typed declarations work across props, state, and functions:

component UserCard {
  types {
    interface User { id: string; name: string }
  }
  props {
    user: User
    compact: boolean = false
  }
  state selected: boolean = false
  functions {
    function select(user: User): void {
      selected = true
    }
  }
  view { <article>{user.name}</article> }
}

The extension shows declared prop types and reports missing required props and incompatible values. Typed prop and state expressions passed into nested components retain their declared type.

Top-level imports are supported before page, component, or layout. Imported helpers can be used in server-rendered prop expressions:

import { appUrl } from "@wrnexus/helpers";

layout PublicLayout {
  view {
    <PublicHeader signInHref="{appUrl('sso', '/sign-in')}" />
  }
}

Installation

Search for WRNexus Language Support in the VS Code Extensions view or run:

ext install wrnexus.wrnexus

For a local build:

  1. Package the extension:
bun run package
  1. Open the VS Code Command Palette.
  2. Select Extensions: Install from VSIX.
  3. Choose the generated wrnexus-<version>.vsix file.

You can also install it from the terminal:

code --install-extension ./wrnexus-0.2.7.vsix --force

Reload VS Code after installation:

Developer: Reload Window

Features

Syntax highlighting

The extension provides highlighting for WRNexus declarations and embedded languages.

Supported top-level declarations:

page HomePage {
}

component UserCard {
}

layout PublicLayout {
}

Supported WRNexus blocks include:

props {
}

state count = 0

seo {
}

functions {
}

lifecycle {
}

watch count {
}

view {
}

style {
}

api GET /api/users {
}

ssr {
}

client {
}

realtime chat {
}

Put // @required immediately above a prop when callers must provide it while retaining a typed runtime fallback. propName = undefined is also treated as required when no fallback is appropriate. The editor shows required props first in completion lists and reports an error when a component mount omits one. Prop types are inferred from defaults, and string options used in component comparisons are offered as completion choices.

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:

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:

state id = ctx.params.id

For a route such as:

pages/users/[id].wrn

autocomplete suggests:

id
ctx.params.id

Components

Create reusable reactive components:

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:

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.

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:

functions {
    function scrollToTop() {
        window.scrollTo({
            top: 0,
            behavior: "smooth"
        })
    }
}

Asynchronous functions are also supported:

functions {
    async function loadUsers() {
        const response = await fetch("/api/users")
        const users = await response.json()
    }
}

Lifecycle hooks

Components and layouts support three lifecycle hooks:

lifecycle {
    mount {
    }

    update {
    }

    unmount {
    }
}

mount

Runs once after the component is connected to the page and hydrated.

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.

lifecycle {
    update {
        console.log("Component state updated")
    }
}

unmount

Runs before the component is removed.

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:

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:

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

<div @window:scroll="updateScrollPosition()">
</div>
<div @window:resize="updateViewportSize()">
</div>
<div @window:keydown="handleKeyboardShortcut()">
</div>

Document events

<div @document:click="closeMenu()">
</div>
<div @document:visibilitychange="handleVisibilityChange()">
</div>

Global event listeners created manually inside mount should be removed inside unmount.

Complete BackToTop example

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:

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

<button @click="submitForm()">
    Submit
</button>
<input @input="query = event.target.value" />
<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

<div data-show="open">
    Visible when open is true
</div>

Reactive loops

<ul>
    <li data-for="user in users">
        {user.name}
    </li>
</ul>

Reactive text

<span data-text="message"></span>

Dynamic attributes

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

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

Shift+Alt+F

Enable format-on-save:

"[wrn]": {
  "editor.defaultFormatter": "wrnexus.wrnexus",
  "editor.formatOnSave": true
}

Disable the formatter:

"wrnexus.format.enable": false

Configure preferred line width:

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

watch

the extension suggests declared state names.

Inside a watcher, it suggests:

value
previous

Declared component functions are suggested as callable snippets:

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:

{
  "[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
}

Troubleshooting language detection

Files ending in .wrn should show WRNexus in the VS Code status bar. If an older workspace setting maps *.wrn to the legacy wrn language ID, replace it with:

"files.associations": {
  "*.wrn": "wrn"
}

Then run Developer: Reload Window. The extension also repairs open .wrn documents that VS Code classified as Plain Text or as the legacy wrn language.

Privacy

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

Install dependencies:

bun install

Rebuild the bundled compiler:

bun run build:compiler

Validate the extension:

bun run check

Package a VSIX:

bun run package

This creates:

wrnexus-<version>.vsix

Install the local package:

code --install-extension ./wrnexus-<version>.vsix --force

Open the extension folder in VS Code and press F5 to launch an Extension Development Host.

After changing the parser or compiler, always rebuild:

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 for publishing instructions. The extension now runs the same bundled @wrnexus/language-server used by other editors. Diagnostics, accessibility checks, formatting, completion, hover, definitions, references, rename, symbols, and quick fixes therefore share the canonical parser. Set wrnexus.languageServer.enable to false only to use the legacy in-extension fallback providers.

The extension activates only after a WRN document is used. Workspace indexing ignores dependency, generated, build, cache, and coverage directories; applies file/count/size limits; and reuses a short-lived bounded index. Type diagnostics are debounced while typing to prevent repeated TypeScript compiler graphs from causing memory spikes.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft