Virtual Documents & Mapping
Relevant source files
The following files were used as context for generating this wiki page:
- modules/svelte-effect-runtime-language-server/src/patch-language-server/virtual-document.ts
- modules/svelte-effect-runtime-language-server/src/patch-language-server/document-mappers/script-content.ts
- modules/svelte-effect-runtime-language-server/src/patch-language-server/types.ts
- modules/svelte-effect-runtime-language-server/src/patch-language-server/patches.ts
- modules/svelte-effect-runtime-language-server/src/patch-language-server/transform-results.ts
- modules/svelte-effect-runtime/src/compiler/source-scan.ts
Virtual Documents and Mappings form the bridge between the custom Svelte Effect Runtime (SER) syntax and standard Svelte/TypeScript language tooling. Because SER introduces non-standard syntax like yield* in markup and <script effect> blocks, the language server must project these files into "virtual" versions that the underlying Svelte and TypeScript compilers can understand, while maintaining a precise bidirectional map to report errors and provide completions at the correct source locations.
This system intercepts the document lifecycle within the Svelte language server, applying a series of transformations (Normalization, Global TypeScript injection, Markup transformation, and Script transformation) to create a valid virtual document.
System Architecture & Pipeline
The virtual document generation process follows a sequential pipeline where each step potentially modifies the code and contributes a Mapper to a SequentialDocumentMapper. This ensures that a position in the final generated TypeScript or Svelte code can be traced back through every intermediate transformation to the original user source.
The diagram shows the sequential flow of transformations and how each stage generates a mapper that is eventually aggregated.
Sources: virtual-document.ts:18-112, patches.ts:74-91
Transformation Stages
1. Source Scanning & Normalization
Before transformation, the source is scanned to identify lexical facts such as script regions, style tags, and markup expressions. A specific normalization step ensures that "bare" declaration tags (e.g., {const x = 1}) are projected with an @ symbol ({@const x = 1}) to satisfy standard Svelte parser expectations.
Sources: source-scan.ts:153-176, virtual-document.ts:185-207
2. Global TypeScript Injection
The language server ensures that script tags are treated as TypeScript by the underlying tooling. If a script tag lacks a lang attribute, the system appends lang="ts". If no script tag exists, it prepends a default <script lang="ts"></script>.
Sources: virtual-document.ts:149-178
3. Markup and Script Transformation
The system applies SER-specific transformations to the markup and script sections.
- Markup: Converts
yield*expressions into generated dispatcher calls. - Script: Lowers top-level
yield*in<script effect>into Svelte-compatible reactive declarations.
| Transform | Target | Purpose |
|---|---|---|
transformEffectMarkup | Svelte Markup | Lowers yield* in HTML/Components to dispatcher events. |
transformEffectScript | <script effect> | Rewrites async logic into reactive state/effects. |
Sources: virtual-document.ts:40-84, types.ts:114-118
Document Mapping Logic
Mapping is handled by the Mapper interface, which provides bidirectional translation between original and generated positions. For complex script transformations, a specialized create_script_content_mapper is used to handle nested fragments and relocations.
Position Mapping Flow
When the language server requests an original position from a generated one, the mapper chain is traversed in reverse:
The sequence shows how nested script content mappers coordinate with fragment mappers and relocation logic to find source positions.
Sources: script-content.ts:46-85, types.ts:25-30
Key Mapping Components
| Component | Description |
|---|---|
DocumentPosition | A simple object containing line and character. |
Relocation | Represents a range shift where code was moved rather than just transformed (e.g., helpers injected). |
SequentialDocumentMapper | Composites multiple mappers into a single unit that applies them in order. |
FragmentMapper | Handles the offset logic for content inside <script> or <style> tags. |
Sources: types.ts:10-18, types.ts:55-65, document-mappers.ts:1-9
Error Handling and Diagnostics
The system utilizes "Safe Transforms" to prevent the language server from crashing when SER syntax is temporarily invalid (e.g., during typing). Instead of failing, the safe_transform_result functions catch errors and generate a virtual document containing a TypeScript diagnostic (a const declaration with the error message as a string) that appears in the editor.
Sources: transform-results.ts:77-105, transform-results.ts:161-170
/** Example of a generated diagnostic in a virtual script */
const __SER_language_server_transform_error: never =
"yield* is not supported inside class members.";
Sources: transform-results.ts:186-191
Summary
The Virtual Document system allows the Svelte Effect Runtime to provide a seamless IDE experience. By intercepting document creation and layering transformations—each with its own source mapping—it enables standard TypeScript and Svelte tooling to operate on non-standard SER source code while maintaining perfect diagnostic and navigation fidelity.
Sources: patches.ts:74-100, virtual-document.ts:101-112