svelte_preprocess_helpers.ts

Shared helper functions for Svelte preprocessors.

Provides AST utilities for detecting static content, resolving imports, managing import statements, and escaping strings for Svelte templates. Used by svelte_preprocess_mdz in fuz_ui, svelte_preprocess_fuz_code in fuz_code, and potentially other Svelte preprocessors.

Uses import type from svelte/compiler for AST types only — no runtime Svelte dependency. Consumers must have svelte installed for type resolution.

Declarations
#

17 declarations

view source

build_static_bindings
#

svelte_preprocess_helpers.ts view source

(ast: Root): Map<string, string>

Builds a map of statically resolvable const bindings from a Svelte AST.

Scans top-level const variable declarations in both instance and module scripts. For each declarator with a plain Identifier pattern and a statically evaluable initializer, adds the binding to the map. Processes declarations in source order so that chained references resolve: const a = 'x'; const b = a; maps b to 'x'.

Skips destructuring patterns, let/var declarations, and declarations whose initializers reference dynamic values.

ast

The parsed Svelte AST root node.

type Root

returns

Map<string, string>

Map of variable names to their resolved static string values.

ConditionalChainBranch
#

svelte_preprocess_helpers.ts view source

ConditionalChainBranch

A single branch in a conditional chain extracted from nested ternary expressions.

test_source

The source text of the test expression, or null for the final else branch.

type string | null

value

The resolved static string value for this branch.

type string

escape_svelte_text
#

svelte_preprocess_helpers.ts view source

(text: string): string

Escapes text for safe embedding in Svelte template markup.

Uses a single-pass regex replacement to avoid corruption that occurs with sequential .replace() calls (where the second replace matches characters introduced by the first).

Escapes four characters: - { → {'{'} and } → {'}'} — prevents Svelte expression interpretation - < → &lt; — prevents HTML/Svelte tag interpretation - & → &amp; — prevents HTML entity interpretation

The & escaping is necessary because runtime MdzNodeView.svelte renders text with {node.content} (a Svelte expression), which auto-escapes & to &amp;. The preprocessor emits raw template text where & is NOT auto-escaped, so manual escaping is required to match the runtime behavior.

text

type string

returns

string

evaluate_static_expr
#

svelte_preprocess_helpers.ts view source

(expr: Expression, bindings?: ReadonlyMap<string, string> | undefined): string | null

Recursively evaluates an expression AST node to a static string value.

Handles string Literal, TemplateLiteral (including interpolations when all expressions resolve), BinaryExpression with +, and Identifier lookup via an optional bindings map built by build_static_bindings. Returns null for dynamic expressions, non-string literals, or unsupported node types.

expr

An ESTree expression AST node.

type Expression

bindings?

Optional map of variable names to their resolved static string values.

type ReadonlyMap<string, string> | undefined
optional

returns

string | null

The resolved static string, or null if the expression is dynamic.

extract_static_string
#

svelte_preprocess_helpers.ts view source

(value: true | ExpressionTag | (ExpressionTag | Text)[], bindings?: ReadonlyMap<string, string> | undefined): string | null

Extracts a static string value from a Svelte attribute value AST node.

Handles three forms: - Boolean true (bare attribute like inline) -- returns null. - Array with a single Text node (quoted attribute like content="text") -- returns the text data. - ExpressionTag (expression like content={'text'}) -- delegates to evaluate_static_expr.

Returns null for null literals, mixed arrays, dynamic expressions, and non-string values.

value

The attribute value from AST.Attribute['value'].

type true | ExpressionTag | (ExpressionTag | Text)[]

bindings?

Optional map of variable names to their resolved static string values.

type ReadonlyMap<string, string> | undefined
optional

returns

string | null

The resolved static string, or null if the value is dynamic.

find_attribute
#

svelte_preprocess_helpers.ts view source

(node: Component, name: string): Attribute | undefined

Finds an attribute by name on a component AST node.

Iterates the node's attributes array and returns the first Attribute node whose name matches. Skips SpreadAttribute, directive, and other node types.

node

The component AST node to search.

type Component

name

The attribute name to find.

type string

returns

Attribute | undefined

The matching Attribute node, or undefined if not found.

find_import_insert_position
#

svelte_preprocess_helpers.ts view source

(script: Script): number

Finds the position to insert new import statements within a script block.

Returns the end position of the last ImportDeclaration, or the start of the script body content if no imports exist.

script

The parsed AST.Script node.

type Script

returns

number

The character position where new imports should be inserted.

generate_import_lines
#

svelte_preprocess_helpers.ts view source

(imports: Map<string, PreprocessImportInfo>, indent?: string): string

Generates indented import statement lines from an import map.

Default imports produce import Name from 'path'; lines. Named imports are grouped by path into import {a, b} from 'path'; lines.

imports

Map of local names to their import info.

type Map<string, PreprocessImportInfo>

indent

Indentation prefix for each line.

type string
default '\t'

returns

string

A string of newline-separated import statements.

handle_preprocess_error
#

svelte_preprocess_helpers.ts view source

(error: unknown, prefix: string, filename: string | undefined, on_error: "log" | "throw"): void

Handles errors during Svelte preprocessing with configurable behavior.

error

The caught error.

type unknown

prefix

Log prefix (e.g. '[fuz-mdz]', '[fuz-code]').

type string

filename

The file being processed.

type string | undefined

on_error

'throw' to re-throw as a new Error, 'log' to console.error.

type "log" | "throw"

returns

void

has_identifier_in_tree
#

svelte_preprocess_helpers.ts view source

(node: unknown, name: string, skip?: Set<unknown> | undefined): boolean

Checks if an identifier with the given name appears anywhere in an AST subtree.

Recursively walks all object and array properties of the tree, matching ESTree Identifier nodes ({type: 'Identifier', name}). Nodes in the skip set are excluded from traversal — used to skip ImportDeclaration nodes so the import's own specifier identifier doesn't false-positive.

Skips Identifier nodes in non-reference positions defined by NON_REFERENCE_FIELDS — for example, obj.Mdz (non-computed member property), { Mdz: value } (non-computed object key), and statement labels.

Safe for Svelte template ASTs: Component.name is a plain string property (not an Identifier node), so <Mdz> tags do not produce false matches.

node

The AST subtree to search.

type unknown

name

The identifier name to look for.

type string

skip?

Set of AST nodes to skip during traversal.

type Set<unknown> | undefined
optional

returns

boolean

true if a matching Identifier node is found.

PreprocessImportInfo
#

svelte_preprocess_helpers.ts view source

PreprocessImportInfo

Import metadata for a single import specifier.

path

The module path to import from.

type string

kind

Whether this is a default or named import.

type 'default' | 'named'

remove_import_declaration
#

svelte_preprocess_helpers.ts view source

(s: { remove: (start: number, end: number) => unknown; }, import_node: ImportDeclaration & { start: number; end: number; }, source: string): void

Removes an ImportDeclaration from source using MagicString.

Consumes leading whitespace (tabs/spaces) and trailing newline to avoid leaving blank lines.

s

The MagicString instance to modify.

type { remove: (start: number, end: number) => unknown; }

import_node

The ImportDeclaration AST node with Svelte position data.

type ImportDeclaration & { start: number; end: number; }

source

The original source string.

type string

returns

void

remove_import_specifier
#

svelte_preprocess_helpers.ts view source

(s: { overwrite: (start: number, end: number, content: string) => unknown; }, node: ImportDeclaration & { start: number; end: number; }, specifier_to_remove: ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier, source: string, additional_lines?: string): void

Removes a specifier from a multi-specifier import declaration by reconstructing the statement without the removed specifier.

Overwrites the entire declaration range to avoid character-level comma surgery.

Handles: - import Mdz, {other} from '...' → import {other} from '...' - import {default as Mdz, other} from '...' → import {other} from '...' - import {Mdz, other} from '...' → import {other} from '...'

s

The MagicString instance to modify.

type { overwrite: (start: number, end: number, content: string) => unknown; }

node

The positioned ImportDeclaration AST node.

type ImportDeclaration & { start: number; end: number; }

specifier_to_remove

The specifier to remove from the import.

type ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier

source

The original source string.

type string

additional_lines

Extra content appended after the reconstructed import (used to bundle new imports into the overwrite to avoid MagicString boundary conflicts).

type string
default ''

returns

void

remove_variable_declaration
#

svelte_preprocess_helpers.ts view source

(s: { remove: (start: number, end: number) => unknown; }, declaration_node: VariableDeclaration & { start: number; end: number; }, source: string): void

Removes a single-declarator VariableDeclaration from source using MagicString.

Consumes leading whitespace (tabs/spaces) and trailing newline to avoid leaving blank lines. Only safe for single-declarator statements (const x = 'val';); callers must verify node.declarations.length === 1 before calling.

s

The MagicString instance to modify.

type { remove: (start: number, end: number) => unknown; }

declaration_node

The VariableDeclaration AST node with Svelte position data.

type VariableDeclaration & { start: number; end: number; }

source

The original source string.

type string

returns

void

resolve_component_names
#

svelte_preprocess_helpers.ts view source

(ast: Root, component_imports: string[]): Map<string, ResolvedComponentImport>

Resolves local names that import from specified source paths.

Scans ImportDeclaration nodes in both the instance and module scripts. Handles default, named, and aliased imports. Skips namespace imports and import type declarations (both whole-declaration and per-specifier). Returns import node references alongside names to support import removal.

ast

The parsed Svelte AST root node.

type Root

component_imports

Array of import source paths to match against.

type string[]

returns

Map<string, ResolvedComponentImport>

Map of local names to their resolved import info.

ResolvedComponentImport
#

svelte_preprocess_helpers.ts view source

ResolvedComponentImport

Information about a resolved component import.

import_node

The ImportDeclaration AST node that provides this name.

type ImportDeclaration

specifier

The specific import specifier for this name.

type ImportSpecifier | ImportDefaultSpecifier

try_extract_conditional_chain
#

svelte_preprocess_helpers.ts view source

(value: true | ExpressionTag | (ExpressionTag | Text)[], source: string, bindings: ReadonlyMap<string, string>): ConditionalChainBranch[] | null

Extracts a chain of conditional expressions where all leaf values are static strings.

Handles nested ternaries like a ? 'x' : b ? 'y' : 'z' by iteratively walking the right-recursive ConditionalExpression chain. At each level, evaluates the consequent via evaluate_static_expr and continues into the alternate if it is another ConditionalExpression. The final alternate is the else branch.

Returns null if the attribute value is not an ExpressionTag containing a ConditionalExpression, if any leaf fails to resolve to a static string, or if the chain exceeds 10 branches (safety limit).

A 2-branch result covers the simple ternary case (a ? 'x' : 'y').

value

The attribute value from AST.Attribute['value'].

type true | ExpressionTag | (ExpressionTag | Text)[]

source

The full source string (needed to slice test expression source text).

type string

bindings

Map of variable names to their resolved static string values.

type ReadonlyMap<string, string>

returns

ConditionalChainBranch[] | null

Array of conditional chain branches, or null if not extractable.