--- name: architecture description: "Verter codebase architecture: high-level module map, TypeScript packages, plugin system, CSS analysis, MCP server, static analysis types" --- # Verter Architecture Reference For domain-specific detail, see: `/type-resolution`, `/type-cache-architecture`, `/component-meta`, `/compiler-codegen`, `/host-session`. ## Shared Substrate Principle Verter is one shared optimized codebase. Consumers reuse lower-level crates instead of separate semantic pipelines. - Put reusable parsing, analysis, type-resolution, caching, and import-following behavior in the shared owner crate. - `verter_language` is the zero-dependency leaf routing authority: `FileLanguage`, `FrameworkAdapterId`, `LanguageId`, `CapabilityId`, and the pure static `LanguageRegistry` (`classify_static(path)` — never reads project config). Host-gated classification (static registry × `ProjectCapabilitySnapshot`) is owned by `verter_session::framework::HostLanguageClassifier`; scheduler/workspace consumers reach it only through session-implemented trait objects (`SourceLoader::classify` / `WorkspaceAccess::classify_file`). The crate is a `verter_span`-only leaf (its design allowance — spans for the parse-artifact regions; strings stay crate-interned) and keeps a crate-local id-intern table: no lower crate exposes a reusable interning facility, and the id set is bounded by registered languages. It also owns the framework-neutral parse payload: `FrameworkParseArtifact` (typed `FrameworkParseCommon` — `ScriptRegion { span, source_type, kind }` / template / style regions, external links, `LanguageDiagnostic`s — plus a PRIVATE erased `Arc`), with the raw downcast confined to each adapter's own bridge module (no capability token — a foreign artifact's erased payload is a DIFFERENT concrete `CarrierParse` type, so the `Any` downcast already fails structurally for it); the session's blessed accessors are `FrameworkAdapterCtx::carrier_for::` (routed through each adapter's registered-projector opener, e.g. `open_vue_carrier`) and the Vue adapter's `vue_parse()`; the concrete `VueParseCarrier` + Vue producer live in `verter_compiler::framework_common::vue_bridge`. - `verter_session` is the shared host/session/cache boundary for host-backed consumers. - `verter_semantic` and `verter_compiler` own reusable semantics, lowering, and codegen. - `verter_resolution` owns the reusable workspace module-resolution implementation: project routing, candidate/probe precedence, sealed observations, resolve frames and operational attempt/retention state. `verter_session_query::resolution` owns the supplied configuration, identities, requests/results, shared observation records, immutable budget policy and lexical path operations. Workspace, session and LSP consumers import each owner directly; the query boundary has no dependency on the implementation. - `verter_analyzer_mint` holds restricted construction authorities (today `MemberListAnchorMint`). Rust has no crate-to-crate visibility, so a record type in `verter_session_query` whose production producer is the `verter_semantic` analyzer takes this authority in its constructor; the authority has no value-producing trait impl, so obtaining it requires naming this crate. `workspace_dependency_layers` pins its direct dependents to exactly `verter_semantic` (the production producer) and `verter_session_query` (the record crate, whose tests mint too) — the mint is held by both, not by the analyzer alone. This is restricted constructor access, not proof of syntax-tree provenance. - `verter_session::resolver_core` owns the host-backed resolver stack and type-resolution orchestration. Resolver-path methods receive `ctx: &dyn ResolverContext` (sealed super-trait at `resolver_core/resolver_context.rs`) — the sealed `RequestBoundAdapter` carrier implements it over the request lifecycle alone, so the engine holds no host, store or config field. The rails that enforce that are the carrier field's `pub(super)` visibility plus the engine's exclusive use of `&dyn ResolverContext` (the `resolver_core/adapter_field_set_witness` module adds only a compile-time arity pin on the carrier's field set); the five request-bound ports in `resolver_core/request_ports.rs` (with the engine-owned `RequestSnapshot` carrying the per-node cancellation, project-generation and clock reads) are the boundary, witnessed by the `engine_ports_*` compile-contract fixtures. - `verter_protocol` owns transport-facing schema DTOs; `verter_ffi` stays a thin native/WASM adapter layer. - Consumer packages and apps stay adapter-oriented: thin wrappers, public API shaping, transport glue, UX-specific behavior. Bug or slowdown in one surface → fix in shared substrate so other consumers benefit. ## TypeScript Packages | Package | Purpose | Entry Point | | ------- | ------- | ----------- | | **`@verter/types`** | TypeScript utility types (`PatchHidden`, `ExtractHidden`, `EmitsToProps`, etc.). Has `/string` export with `$V_` prefixed types for LSP injection | `src/index.ts` | | **`@verter/language-shared`** | Shared custom protocol types between VS Code client and Rust LSP binary | `src/index.ts` | | **`@verter/typescript-plugin`** | TypeScript plugin resolving `.vue` imports in TS/JS files. Intercepts module resolution to return transformed TSX | `src/index.ts` | | **`verter-vscode`** | VS Code extension. Launches Rust `verter-lsp` binary over stdio, bundles TS plugin, handles extension activation | `src/extension.ts` | | **`@verter/unplugin`** | Universal bundler plugin (Vite, Rollup, webpack, esbuild, rspack, Rolldown, Farm). Compiles `.vue` files via `@verter/native`. Supports `preCompile` for build-start cache warming | `src/index.ts` | ## Unplugin Configuration (`packages/unplugin/`) `@verter/unplugin` provides a `VerterPluginOptions` interface: | Option | Type | Default | Description | | ------ | ---- | ------- | ----------- | | `componentId` | `(filename, source, isProd) => string` | hash-based | Custom component ID generator | | `include` | `string \| RegExp \| (string \| RegExp)[]` | `[/\.vue$/]` | File patterns to include | | `preCompile` | `boolean` | `false` | Pre-compile all `.vue` files during `buildStart`. Scans project root, upserts files into host cache (including type dependencies for macros), and compiles them. When `transform()` later receives same content, host returns cached result instantly. `node_modules` excluded from scanning. | | `crossFileOptimize` | `boolean` | `false` | Cross-file prop constness optimization. Requires `preCompile: true`. After pre-compilation, analyzes render tree to determine which props are always passed constant values, skipping dynamic tracking in compiled output. | | `template` | `object` | — | Template compiler options (compat with `@vitejs/plugin-vue`) | **`preCompile` architecture:** During `buildStart()`, scans project root for `.vue` files (excluding `node_modules` and dot-directories). For each file: upserts into host, resolves external `src` attributes and macro type dependencies (e.g., `import type { Props } from './types'` used in `defineProps()`), then triggers compilation. When another plugin modifies the file before `transform()`, host detects content change via internal hashing and recompiles. Third-party `.vue` files in `node_modules` compile on-demand during `transform()` — no pre-compilation overhead. **Macro type resolution invariant:** cross-file macro type resolution must only follow imports reachable from the requested type's local declaration graph. Unrelated imports in the same file are out of scope; plain imports are not implicit re-exports. ## CSS Analysis & Selector Matching (`crates/verter_semantic/src/analysis/`) `verter_css_syntax` is the shared lossless token/event authority for CSS, SCSS, indented Sass, Less, and Stylus. `StyleSyntaxIrSink` and `LosslessCstSink` are peers over the same parser event stream. Semantic style analysis projects only complete, static selector nodes into selectors, classes, IDs, custom properties, and at-rules; interpolation, recovery, and evaluation-dependent selectors fail closed. Each `AnalyzedCssClass` carries `selector_index` (exact class → comma-part selector join) and each `AnalyzedSelector` carries `rule_body_span` (brace- or indentation-delimited body span). Vue's planner separately consumes trusted IR for authored-dialect `v-bind()` and post-preprocess plain-CSS module hashing/scoping; Svelte consumes the IR as a trust gate for its distinct plain-CSS matcher/scoper. Svelte's carrier/CSS parser remains the compatibility owner until exact Svelte 5.56.10 error-code, offset, and read-past-close parity is proven. Style `v-bind()` usage is discovered through the same dialect-aware planner IR, then OXC-derived `expr_roots`/`roots_complete` remain the liveness facts consumed by `mark_bindings_used_in_style` and compile-input assembly. `StyleSyntaxIr` retains positioned containment and balanced values without evaluating or compiling preprocessors. Imports, modules, plugins, guards, mixin/function arguments, and control expressions remain opaque-but-positioned. `StyleSyntaxIr::dependencies()` is the parse-minted inclusion inventory (`@import`/`@use`/`@forward`/`@plugin`, in source order, each with its keyword span and quote/`url()`-stripped specifier span), so no consumer walks the at-rules again to find out which sheets a block pulls in; `dependency_pulls_in_unparsed_bytes` is the same owner's answer to whether an inclusion actually brings foreign bytes with it (Sass's built-in `sass:` modules do not). `verter_css_syntax::stage` owns the identity every style consumer shares — `StyleStage`, `StyleProducer`, `StyleDiagnostic`, `StyleDependency`, `QualifiedStyleResult`, and the `PreprocessedStyle` admission witness — plus the single `lang="…"` spelling → `CssDialect` mapping (`CssDialect::from_lang`, byte-exact) and the single "is this already CSS" predicate (`CssDialect::requires_external_preprocessing`). Style bytes leave the compiler as a `QualifiedStyleResult` and enter it as a `PreprocessedStyle` carrying its producer, never as a bare string. The carrier parser's `StyleLang::from_bytes` and the carrier-level `StyleDialect` are the deliberately larger universe (they also name `postcss`, plus an unrecognised state), owned by the carrier parse projection and read by the consumers that serve a dialect the rewrite pipeline refuses. See `/compiler-codegen` → "Stage-Qualified Style Identity". Stylesheet parser mode is deterministic by dialect and structural tokens. CSS always uses brace grammar. Sass and Stylus use the layout-capable grammar, which also recognizes explicit braced blocks. SCSS and Less use brace grammar whenever the lexer emits any plain `LeftBrace`; only a brace-free source with an actual deeper-indented line pair uses layout grammar. Closing-brace indentation and other incidental formatting never select the parser. Selector trust folds every component descendant and functional-pseudo selector list; class/ID collection descends those lists and gates each component independently, so complete literal class components may still publish from an otherwise evaluation-dependent selector such as `&.active` or `:global(.a .#{$x})`. A textually certain `:deep`/`:global`/`:slotted` kind publishes independently of argument trust, while every class inside its argument remains subject to the same per-component gate. Ambiguous optional-syntax statements remain locally typed and diagnosed without recovering intact ancestor rules. A declaration may own a retained `StyleBlock` (for example, an indented Sass nested-property namespace); the IR sink never discards such a block. **Module structure:** ``` style.rs # Semantic style projection types and specificity computation style_syntax.rs # Five-dialect syntax-to-semantic projection selector_match.rs # Three-valued selector matching against template elements template.rs # Template element analysis, dynamic class extraction, :style CSS var extraction ``` **Key types:** | Type | Location | Purpose | | ---- | -------- | ------- | | `StructuredSelector` | `style.rs` | Parsed CSS selector (compounds + combinators) | | `CompoundSelector` | `style.rs` | Single compound: element, classes, id, attributes, pseudo-classes | | `SelectorCombinator` | `style.rs` | Descendant / Child / NextSibling / LaterSibling | | `MatchResult` | `selector_match.rs` | Three-valued: `Matches`, `MaybeMatches`, `NoMatch` | | `DomQueryCallSite` | `types.rs` | DOM query call with parsed selector and spans | | `StyleBlockAnalysis` | `style.rs` | Per-`