Script AST Transformations
Relevant source files
The following files were used as context for generating this wiki page:
The Script AST Transformation system is a core component of Svelte Effect Runtime (SER) responsible for lowering effectful syntax within Svelte <script> blocks. It specifically targets top-level yield* expressions, transforming them into Svelte-compatible reactive declarations or dependency-tracked $effect blocks. This allows developers to use synchronous-looking effect generators within a reactive Svelte context.
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:25-30, modules/svelte-effect-runtime/src/runtime/transform.ts:50-55
Transformation Pipeline
The transformation process is structured into several distinct phases that validate, analyze, and rewrite the TypeScript AST.
The pipeline begins by scanning the source to identify script regions and potential effect attributes. If an effect attribute is detected on a script tag, the transformation logic is invoked.
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:77-150, modules/svelte-effect-runtime/src/runtime/transform.ts:59-75
Phase 1: Import Detection and Binding
The system first identifies existing imports for effect, get_dispatcher, and untrack. It uses a name_allocator to reserve collision-free identifiers for runtime helpers, ensuring that generated code does not conflict with user-defined variables.
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:77-106
Phase 2: Statement Lowering
This phase iterates through all top-level statements in the script. It validates that yield* is used in supported positions and performs the actual AST rewriting.
| Step | Action | Description |
|---|---|---|
| Rune Validation | validate_rune_yield_usage | Ensures yield* only appears in compatible Svelte runes (e.g., $state, $derived). |
| Boundary Check | validate_script_yield_boundaries | Prevents usage of yield* inside class members or invalid scopes. |
| AST Rewrite | lower_statement | Lowers yield* expressions into runtime helper calls and extracts dependency tracking information. |
| State Injection | magic.appendLeft | Injects generated $state temporary variables for asynchronous results. |
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:121-160, modules/svelte-effect-runtime/src/script-transform/runes.ts:27-35
Phase 3 & 4: Finalization
If effects were detected, the system injects the necessary runtime imports and appends a lifecycle wiring block (the "runtime program"). This block manages the execution and cancellation of the fibers generated from the lowered effects.
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:168-185
Validation Rules
The transformation enforces strict rules on where yield* can appear to maintain the reactive contract of Svelte 5.
Rune Compatibility
The system distinguishes between runes that can handle asynchronous expressions and those that require synchronous callbacks.
- Supported Async Runes:
$state,$state.raw,$state.snapshot,$derived,$bindable. - Unsupported Callback Runes:
$derived.by,$effect,$effect.pre,$effect.root. Usingyield*inside these results in anAsyncEffectInSyncRuneError.
Sources: modules/svelte-effect-runtime/src/script-transform/runes.ts:7-21, modules/svelte-effect-runtime/src/script-transform/runes.ts:53-65
Structural Constraints
- Class Members:
yield*cannot be used inside class fields or methods, as these are not considered top-level reactive work. - Top-level Await: The system explicitly checks for top-level
awaitwithin statements containingyield*. If both are present, anAwaitInEffectWorkErroris thrown to prevent conflicting concurrency models.
Sources: modules/svelte-effect-runtime/src/script-transform/index.ts:145-148, modules/svelte-effect-runtime/src/script-transform/index.ts:314-332
Data Structures
The transformation relies on several key interfaces to track state and results.
| Type | Purpose |
|---|---|
BlockRef | Tracks generated blocks (script, value, run) for cache lookups and HMR. |
Relocation | Maps original source offsets to generated code offsets to preserve editor features like hover and go-to-definition. |
TempBinding | Describes a generated $state variable used to store the result of an effect. |
ScriptLoweringContext | Provides shared services for identifier reservation and type emission settings. |
Sources: modules/svelte-effect-runtime/src/script-transform/types.ts:23-45, modules/svelte-effect-runtime/src/script-transform/types.ts:114-135
Conclusion
The Script AST Transformation module enables a seamless integration of Effect-TS style generators within Svelte components. By carefully validating rune usage and rewriting top-level statements into managed fibers, it allows for complex asynchronous logic to be written as if it were synchronous, while maintaining full compatibility with Svelte's reactivity system and editor tooling through sophisticated relocation mapping.