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.tomlpins the exact compiler version, plusrustfmt,clippy, and thewasm32-unknown-unknowntarget, and rustup installs all of them the first time you runcargoin the repo. The pin exists in part because compile-contract.stderrfixtures 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:
rustc --version
cargo --version
rustup show active-toolchain # should say "overridden by .../rust-toolchain.toml"
wasm-bindgen --version # only needed for WASM buildsProject Structure
All Rust crates are in the crates/ directory:
| Crate | Purpose |
|---|---|
verter_parser | SFC/carrier tokenizer, parser, and AST |
verter_compiler | Template compiler -- script processing, template codegen (VDOM + Vapor), TSX generation, CSS processing |
verter_semantic | Semantic authority -- component surface resolution, cross-file symbol identity, binding analysis, type resolution, reactivity provenance |
verter_session | File host -- in-memory caching, dependency tracking, multi-file compilation |
verter_scheduler | Async file scheduler -- per-file Source→Analysis→Artifact stages, priority queue, blocker registry |
verter_diagnostics | Diagnostic engine -- Vue SFC lint rules, rule trait, visitor, diagnostic set |
verter_actions | Code actions engine -- quick fixes, refactoring (depends on verter_diagnostics + verter_semantic) |
verter_lsp | LSP server binary -- stdio transport, feature handlers, document synchronization, TypeProvider integration (TSGO + tsserver) |
verter_ffi | FFI types -- shared serializable structs for NAPI and WASM boundaries |
verter_napi | NAPI-RS bindings -- Node.js native addon (cdylib) |
verter_wasm | wasm-bindgen bindings -- browser WASM module (cdylib) |
verter_bench | Benchmarks 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
# 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.wasmQuick Rebuild for Native Bindings
When iterating on Rust code used by TypeScript packages:
# 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.nodeOr use the project's build scripts:
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
# 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 -- --nocaptureTDD Required
Test-Driven Development is mandatory for all Rust changes.
- Write failing tests first -- before implementing any feature or fix, write tests that demonstrate the expected behavior and verify they fail
- Implement the minimum code to make the failing tests pass
- Refactor while keeping tests green
Assertion Requirements
Every test must verify both what SHOULD be present AND what should NOT be present:
// 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:
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:
# Lint with clippy (treat warnings as errors)
cargo clippy --fix --allow-dirty --allow-staged --workspace -- -D warnings
# Format all Rust code
cargo fmt --allKey Modules
When working on specific areas, these are the primary entry points:
| Area | Entry Point |
|---|---|
| Compilation pipeline | crates/verter_compiler/src/compile/mod.rs |
| SFC tokenizer | crates/verter_parser/src/tokenizer/byte.rs |
| Template AST | crates/verter_parser/src/ast/ |
| VDOM codegen | crates/verter_compiler/src/template/code_gen/vdom/ |
| Vapor codegen | crates/verter_compiler/src/template/code_gen/vapor/ |
| TSX codegen (LSP) | crates/verter_compiler/src/ide/template/mod.rs |
| Script processing | crates/verter_compiler/src/script/process.rs |
| CSS processing | crates/verter_compiler/src/css/mod.rs |
| Semantic analysis | crates/verter_semantic/src/lib.rs |
| LSP server | crates/verter_lsp/src/server/ |
| TSGO type provider | crates/verter_lsp/src/tsgo/ipc.rs |
| tsserver type provider | crates/verter_lsp/src/tsserver/ipc.rs |
| Diagnostics | crates/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:
| Path | Module | Purpose | Output |
|---|---|---|---|
| VDOM/Vapor | template/code_gen/vdom/ | Runtime render functions for bundler output | _createElementVNode(...) calls |
| IDE | ide/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.