Skip to content

Rust Setup

Pre-Release

Verter is pre-release software. APIs may change between releases — see the API Stability document.

Guide for setting up Rust development for Verter.

Prerequisites

  • rustup. Do not install a toolchain by hand: rust-toolchain.toml pins the exact compiler version, plus rustfmt, clippy, and the wasm32-unknown-unknown target, and rustup installs all of them the first time you run cargo in the repo. The pin exists in part because compile-contract .stderr fixtures byte-pin rustc's own diagnostic text; building on any other version reports failures that are not yours.
  • wasm-bindgen CLI for WASM glue generation: cargo install wasm-bindgen-cli --version 0.2.122 --locked

Verify your installation — rustc must report the version in rust-toolchain.toml:

bash
rustc --version
cargo --version
rustup show active-toolchain   # should say "overridden by .../rust-toolchain.toml"
wasm-bindgen --version         # only needed for WASM builds

Project Structure

All Rust crates are in the crates/ directory:

CratePurpose
verter_parserSFC/carrier tokenizer, parser, and AST
verter_compilerTemplate compiler -- script processing, template codegen (VDOM + Vapor), TSX generation, CSS processing
verter_semanticSemantic authority -- component surface resolution, cross-file symbol identity, binding analysis, type resolution, reactivity provenance
verter_sessionFile host -- in-memory caching, dependency tracking, multi-file compilation
verter_schedulerAsync file scheduler -- per-file Source→Analysis→Artifact stages, priority queue, blocker registry
verter_diagnosticsDiagnostic engine -- Vue SFC lint rules, rule trait, visitor, diagnostic set
verter_actionsCode actions engine -- quick fixes, refactoring (depends on verter_diagnostics + verter_semantic)
verter_lspLSP server binary -- stdio transport, feature handlers, document synchronization, TypeProvider integration (TSGO + tsserver)
verter_ffiFFI types -- shared serializable structs for NAPI and WASM boundaries
verter_napiNAPI-RS bindings -- Node.js native addon (cdylib)
verter_wasmwasm-bindgen bindings -- browser WASM module (cdylib)
verter_benchBenchmarks and profiling -- comparison examples, host-level profiling across real projects

Dependency Graph

Simplified — leaf utility crates (verter_span, verter_audit, verter_language, verter_workspace, the verter_type_expr* crates) are omitted for clarity.

verter_parser (tokenizer, parser, AST)
    |
    +-- verter_compiler (VDOM/Vapor + IDE TSX codegen, CSS processing)
    |
    +-- verter_semantic (semantic authority: surfaces, bindings, type resolution)
            |
            +-- verter_diagnostics (depends on verter_semantic + verter_workspace)
            |       |
            |       +-- verter_actions (depends on verter_diagnostics + verter_semantic)
            |
            +-- verter_session (depends on verter_compiler + verter_semantic + verter_parser + verter_scheduler)
                    |
                    +-- verter_lsp (depends on verter_session + verter_scheduler + verter_semantic + verter_diagnostics + verter_actions + verter_ffi)
                    |
                    +-- verter_ffi (depends on verter_session + verter_semantic + verter_diagnostics + verter_actions)
                            |
                            +-- verter_napi (depends on verter_ffi + verter_session + verter_compiler)
                            |
                            +-- verter_wasm (depends on verter_ffi + verter_compiler + verter_session)

verter_scheduler (depends on verter_span + verter_audit + verter_language — domain-agnostic)

verter_bench (depends on verter_compiler + verter_parser + verter_session + verter_workspace + verter_diagnostics + verter_semantic)

Building

bash
# Build all crates (debug)
cargo build --workspace

# Build native NAPI bindings (release, for use by TypeScript packages)
cargo build --release --package verter_napi

# Build LSP binary (debug, for F5 extension development)
cargo build -p verter_lsp

# Build LSP binary (release, optimized)
cargo build --release -p verter_lsp

# Build WASM (raw cargo build plus wasm-bindgen glue — same as `pnpm run build:wasm`,
# a runnable unoptimized developer artifact; no wasm-opt, no playground copy)
cargo build --release -p verter_wasm --target wasm32-unknown-unknown
wasm-bindgen --target web --out-dir packages/wasm/wasm --out-name verter_wasm target/wasm32-unknown-unknown/release/verter_wasm.wasm

Quick Rebuild for Native Bindings

When iterating on Rust code used by TypeScript packages:

bash
# Build and copy native binary (Windows example)
cargo build --release --package verter_napi && \
  rm -f packages/native/dist/verter-native.win32-x64-msvc.node && \
  cp target/release/verter_napi.dll packages/native/dist/verter-native.win32-x64-msvc.node

Or use the project's build scripts:

bash
pnpm run build:native    # Build + copy native bindings
pnpm run build:lsp       # Build LSP binary (debug)
pnpm run build:wasm      # Build WASM (bindgen only, no wasm-opt, no playground copy)
pnpm dist                # Publication-ready artifacts (native release, LSP, optimized WASM, TS)

Testing

bash
# Run the canonical provider-free core Rust gate
node scripts/gate.mjs

# Run compile-fail Cargo contracts outside test discovery
node scripts/compile-contracts.mjs

# Run tests for a specific crate
cargo test --package verter_compiler --verbose

# Run a specific test by name
cargo test --package verter_compiler test_name

# Run tests with output (useful for debugging)
cargo test --package verter_compiler -- --nocapture

TDD Required

Test-Driven Development is mandatory for all Rust changes.

  1. Write failing tests first -- before implementing any feature or fix, write tests that demonstrate the expected behavior and verify they fail
  2. Implement the minimum code to make the failing tests pass
  3. Refactor while keeping tests green

Assertion Requirements

Every test must verify both what SHOULD be present AND what should NOT be present:

rust
// GOOD: Both positive and negative assertions
let result = compile(input);
assert!(result.contains("_createElementVNode"), "should emit vdom call");
assert!(!result.contains("v-if"), "v-if must not appear in output");

// BAD: Only positive -- passes even if output contains broken content
let result = compile(input);
assert!(result.contains("_createElementVNode"), "should emit vdom call");

Codegen Test Pattern

All codegen tests must validate that the output is syntactically valid JavaScript using the OXC parser:

rust
use crate::test_utils::gen_and_validate;

#[test]
fn test_my_feature() {
    let result = gen_and_validate(r#"<template><div>hello</div></template>"#);
    assert!(result.contains("expected output"));
    assert!(!result.contains("unexpected content"));
}

Code Quality

Run these before committing:

bash
# Lint with clippy (treat warnings as errors)
cargo clippy --fix --allow-dirty --allow-staged --workspace -- -D warnings

# Format all Rust code
cargo fmt --all

Key Modules

When working on specific areas, these are the primary entry points:

AreaEntry Point
Compilation pipelinecrates/verter_compiler/src/compile/mod.rs
SFC tokenizercrates/verter_parser/src/tokenizer/byte.rs
Template ASTcrates/verter_parser/src/ast/
VDOM codegencrates/verter_compiler/src/template/code_gen/vdom/
Vapor codegencrates/verter_compiler/src/template/code_gen/vapor/
TSX codegen (LSP)crates/verter_compiler/src/ide/template/mod.rs
Script processingcrates/verter_compiler/src/script/process.rs
CSS processingcrates/verter_compiler/src/css/mod.rs
Semantic analysiscrates/verter_semantic/src/lib.rs
LSP servercrates/verter_lsp/src/server/
TSGO type providercrates/verter_lsp/src/tsgo/ipc.rs
tsserver type providercrates/verter_lsp/src/tsserver/ipc.rs
Diagnosticscrates/verter_diagnostics/src/lib.rs

Two Template Codegen Paths

The Rust compiler has two separate template codegen paths. Modifying one does NOT affect the other:

PathModulePurposeOutput
VDOM/Vaportemplate/code_gen/vdom/Runtime render functions for bundler output_createElementVNode(...) calls
IDEide/template/Valid JSX/TSX for LSP/TSGO type checking<div prop={expr}> JSX elements

The LSP uses the TSX path. Changes to VDOM codegen do not affect LSP hover, completions, or diagnostics.

Released under the MIT License.