From 73b77cc7442b3187b29d72405277bdb6874f7550 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 30 Jun 2025 12:59:25 -0400 Subject: [PATCH 1/6] break out locator stuff from the rest of global state --- packages/svelte/src/compiler/index.js | 6 ++++-- packages/svelte/src/compiler/phases/1-parse/index.js | 3 +++ packages/svelte/src/compiler/state.js | 8 +++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index 429c6b4a6f78..b6b0b019eaca 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -96,6 +96,7 @@ export function compileModule(source, options) { * @returns {Record} */ +// TODO 6.0 remove unused `filename` /** * The parse function parses a component, returning only its abstract syntax tree. * @@ -104,14 +105,15 @@ export function compileModule(source, options) { * * The `loose` option, available since 5.13.0, tries to always return an AST even if the input will not successfully compile. * + * The `filename` option is unused and will be removed in Svelte 6.0. + * * @param {string} source * @param {{ filename?: string; rootDir?: string; modern?: boolean; loose?: boolean }} [options] * @returns {AST.Root | LegacyRoot} */ -export function parse(source, { filename, rootDir, modern, loose } = {}) { +export function parse(source, { modern, loose } = {}) { source = remove_bom(source); state.reset_warning_filter(() => false); - state.reset(source, { filename: filename ?? '(unknown)', rootDir }); const ast = _parse(source, loose); return to_public_ast(source, ast, modern); diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index b8ae8199ebc4..77cc2bf3fa43 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -9,6 +9,7 @@ import { create_fragment } from './utils/create.js'; import read_options from './read/options.js'; import { is_reserved } from '../../../utils.js'; import { disallow_children } from '../2-analyze/visitors/shared/special-element.js'; +import * as state from '../../state.js'; const regex_position_indicator = / \(\d+:\d+\)$/; @@ -301,6 +302,8 @@ export class Parser { * @returns {AST.Root} */ export function parse(template, loose = false) { + state.set_source(template); + const parser = new Parser(template, loose); return parser.root; } diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 1db3db917f9d..4eaa3f3b12b9 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -30,6 +30,12 @@ export let dev; export let locator = getLocator('', { offsetLine: 1 }); +/** @param {string} value */ +export function set_source(value) { + source = value; + locator = getLocator(source, { offsetLine: 1 }); +} + /** * @param {AST.SvelteNode & { start?: number | undefined }} node */ @@ -100,7 +106,7 @@ export function reset(_source, options) { filename = filename.replace(root_dir, '').replace(/^[/\\]/, ''); } - locator = getLocator(source, { offsetLine: 1 }); + set_source(source); warnings = []; ignore_stack = []; ignore_map.clear(); From ab823c8ffa395ddd8fc43ad2ef7a7de64f84200e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 30 Jun 2025 13:13:46 -0400 Subject: [PATCH 2/6] move some stuff around --- packages/svelte/src/compiler/index.js | 8 +++----- packages/svelte/src/compiler/migrate/index.js | 6 +++--- packages/svelte/src/compiler/phases/2-analyze/index.js | 6 ++++++ packages/svelte/src/compiler/state.js | 9 +++------ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index b6b0b019eaca..9ba23c148595 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -20,9 +20,8 @@ export { default as preprocess } from './preprocess/index.js'; */ export function compile(source, options) { source = remove_bom(source); - state.reset_warning_filter(options.warningFilter); + state.reset_warnings(options.warningFilter); const validated = validate_component_options(options, ''); - state.reset(source, validated); let parsed = _parse(source); @@ -64,9 +63,8 @@ export function compile(source, options) { */ export function compileModule(source, options) { source = remove_bom(source); - state.reset_warning_filter(options.warningFilter); + state.reset_warnings(options.warningFilter); const validated = validate_module_options(options, ''); - state.reset(source, validated); const analysis = analyze_module(source, validated); return transform_module(analysis, source, validated); @@ -113,7 +111,7 @@ export function compileModule(source, options) { */ export function parse(source, { modern, loose } = {}) { source = remove_bom(source); - state.reset_warning_filter(() => false); + state.reset_warnings(() => false); const ast = _parse(source, loose); return to_public_ast(source, ast, modern); diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index 5ca9adb98be3..7610d4024343 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -9,7 +9,7 @@ import { parse } from '../phases/1-parse/index.js'; import { regex_valid_component_name } from '../phases/1-parse/state/element.js'; import { analyze_component } from '../phases/2-analyze/index.js'; import { get_rune } from '../phases/scope.js'; -import { reset, reset_warning_filter } from '../state.js'; +import { reset, reset_warnings } from '../state.js'; import { extract_identifiers, extract_all_identifiers_from_expression, @@ -134,8 +134,8 @@ export function migrate(source, { filename, use_ts } = {}) { return start + style_placeholder + end; }); - reset_warning_filter(() => false); - reset(source, { filename: filename ?? '(unknown)' }); + reset_warnings(() => false); + reset({ filename: filename ?? '(unknown)' }); let parsed = parse(source); diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index be1f1ee5bb94..a0e984301401 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -76,6 +76,7 @@ import { UseDirective } from './visitors/UseDirective.js'; import { VariableDeclarator } from './visitors/VariableDeclarator.js'; import is_reference from 'is-reference'; import { mark_subtree_dynamic } from './visitors/shared/fragment.js'; +import * as state from '../../state.js'; /** * @type {Visitors} @@ -240,6 +241,7 @@ export function analyze_module(source, options) { /** @type {AST.JSComment[]} */ const comments = []; + state.set_source(source); const ast = parse(source, comments, false, false); const { scope, scopes } = create_scopes(ast, new ScopeRoot(), false, null); @@ -269,6 +271,8 @@ export function analyze_module(source, options) { classes: new Map() }; + state.reset(options); + walk( /** @type {Node} */ (ast), { @@ -506,6 +510,8 @@ export function analyze_component(root, source, options) { snippets: new Set() }; + state.reset(options); + if (!runes) { // every exported `let` or `var` declaration becomes a prop, everything else becomes an export for (const node of instance.ast.body) { diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 4eaa3f3b12b9..172e6f76771e 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -77,8 +77,9 @@ export function pop_ignore() { * * @param {(warning: Warning) => boolean} fn */ -export function reset_warning_filter(fn = () => true) { +export function reset_warnings(fn = () => true) { warning_filter = fn; + warnings = []; } /** @@ -91,11 +92,9 @@ export function is_ignored(node, code) { } /** - * @param {string} _source * @param {{ dev?: boolean; filename: string; rootDir?: string }} options */ -export function reset(_source, options) { - source = _source; +export function reset(options) { const root_dir = options.rootDir?.replace(/\\/g, '/'); filename = options.filename.replace(/\\/g, '/'); @@ -106,8 +105,6 @@ export function reset(_source, options) { filename = filename.replace(root_dir, '').replace(/^[/\\]/, ''); } - set_source(source); - warnings = []; ignore_stack = []; ignore_map.clear(); } From 431d0683db2a443dccfa67aad95650872b2db9f9 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 30 Jun 2025 13:25:30 -0400 Subject: [PATCH 3/6] tighten up --- packages/svelte/src/compiler/migrate/index.js | 2 +- .../svelte/src/compiler/phases/2-analyze/index.js | 12 ++++++++++-- packages/svelte/src/compiler/state.js | 10 +++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index 7610d4024343..8ec6bbbbaef2 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -135,7 +135,7 @@ export function migrate(source, { filename, use_ts } = {}) { }); reset_warnings(() => false); - reset({ filename: filename ?? '(unknown)' }); + reset({ dev: false, filename: filename ?? '(unknown)' }); let parsed = parse(source); diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index a0e984301401..0737b47aeabc 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -271,7 +271,11 @@ export function analyze_module(source, options) { classes: new Map() }; - state.reset(options); + state.reset({ + dev: options.dev, + filename: options.filename, + rootDir: options.rootDir + }); walk( /** @type {Node} */ (ast), @@ -510,7 +514,11 @@ export function analyze_component(root, source, options) { snippets: new Set() }; - state.reset(options); + state.reset({ + dev: options.dev, + filename: options.filename, + rootDir: options.rootDir + }); if (!runes) { // every exported `let` or `var` declaration becomes a prop, everything else becomes an export diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 172e6f76771e..cfcd2ac48049 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -92,13 +92,13 @@ export function is_ignored(node, code) { } /** - * @param {{ dev?: boolean; filename: string; rootDir?: string }} options + * @param {{ dev: boolean; filename: string; rootDir?: string }} state */ -export function reset(options) { - const root_dir = options.rootDir?.replace(/\\/g, '/'); - filename = options.filename.replace(/\\/g, '/'); +export function reset(state) { + const root_dir = state.rootDir?.replace(/\\/g, '/'); + filename = state.filename.replace(/\\/g, '/'); - dev = !!options.dev; + dev = !!state.dev; if (typeof root_dir === 'string' && filename.startsWith(root_dir)) { // make filename relative to rootDir From 13f7fbdb9b4d927059f5a7337451798dbc8f9a3e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 30 Jun 2025 13:31:14 -0400 Subject: [PATCH 4/6] make runes globally available --- packages/svelte/src/compiler/phases/2-analyze/index.js | 6 ++++-- packages/svelte/src/compiler/phases/types.d.ts | 1 + packages/svelte/src/compiler/state.js | 10 +++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 0737b47aeabc..fcfc6c15aa0f 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -274,7 +274,8 @@ export function analyze_module(source, options) { state.reset({ dev: options.dev, filename: options.filename, - rootDir: options.rootDir + rootDir: options.rootDir, + runes: true }); walk( @@ -517,7 +518,8 @@ export function analyze_component(root, source, options) { state.reset({ dev: options.dev, filename: options.filename, - rootDir: options.rootDir + rootDir: options.rootDir, + runes: true }); if (!runes) { diff --git a/packages/svelte/src/compiler/phases/types.d.ts b/packages/svelte/src/compiler/phases/types.d.ts index 661f363991f6..876363bd16d6 100644 --- a/packages/svelte/src/compiler/phases/types.d.ts +++ b/packages/svelte/src/compiler/phases/types.d.ts @@ -35,6 +35,7 @@ export interface ReactiveStatement { export interface Analysis { module: Js; name: string; // TODO should this be filename? it's used in `compileModule` as well as `compile` + /** @deprecated use `runes` from `state.js` instead */ runes: boolean; immutable: boolean; tracing: boolean; diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index cfcd2ac48049..633611e6951a 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -28,6 +28,8 @@ export let source; */ export let dev; +export let runes = false; + export let locator = getLocator('', { offsetLine: 1 }); /** @param {string} value */ @@ -92,13 +94,19 @@ export function is_ignored(node, code) { } /** - * @param {{ dev: boolean; filename: string; rootDir?: string }} state + * @param {{ + * dev: boolean; + * filename: string; + * rootDir?: string; + * runes: boolean; + * }} state */ export function reset(state) { const root_dir = state.rootDir?.replace(/\\/g, '/'); filename = state.filename.replace(/\\/g, '/'); dev = !!state.dev; + runes = !!state.runes; if (typeof root_dir === 'string' && filename.startsWith(root_dir)) { // make filename relative to rootDir From be3226467335da14f358868c508b873bbed8dfd0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 30 Jun 2025 13:37:17 -0400 Subject: [PATCH 5/6] make component_name globally available --- packages/svelte/src/compiler/phases/2-analyze/index.js | 1 + packages/svelte/src/compiler/phases/types.d.ts | 2 ++ packages/svelte/src/compiler/state.js | 8 ++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index fcfc6c15aa0f..d73e273ec2b5 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -516,6 +516,7 @@ export function analyze_component(root, source, options) { }; state.reset({ + component_name: analysis.name, dev: options.dev, filename: options.filename, rootDir: options.rootDir, diff --git a/packages/svelte/src/compiler/phases/types.d.ts b/packages/svelte/src/compiler/phases/types.d.ts index 876363bd16d6..dba2559a17e7 100644 --- a/packages/svelte/src/compiler/phases/types.d.ts +++ b/packages/svelte/src/compiler/phases/types.d.ts @@ -34,6 +34,7 @@ export interface ReactiveStatement { */ export interface Analysis { module: Js; + /** @deprecated use `component_name` from `state.js` instead */ name: string; // TODO should this be filename? it's used in `compileModule` as well as `compile` /** @deprecated use `runes` from `state.js` instead */ runes: boolean; @@ -91,6 +92,7 @@ export interface ComponentAnalysis extends Analysis { keyframes: string[]; has_global: boolean; }; + /** @deprecated use `source` from `state.js` instead */ source: string; undefined_exports: Map; /** diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 633611e6951a..9095651ced27 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -16,6 +16,8 @@ export let warnings = []; */ export let filename; +export let component_name = ''; + /** * The original source code * @type {string} @@ -97,6 +99,7 @@ export function is_ignored(node, code) { * @param {{ * dev: boolean; * filename: string; + * component_name?: string; * rootDir?: string; * runes: boolean; * }} state @@ -105,8 +108,9 @@ export function reset(state) { const root_dir = state.rootDir?.replace(/\\/g, '/'); filename = state.filename.replace(/\\/g, '/'); - dev = !!state.dev; - runes = !!state.runes; + dev = state.dev; + runes = state.runes; + component_name = state.component_name ?? '(unknown)'; if (typeof root_dir === 'string' && filename.startsWith(root_dir)) { // make filename relative to rootDir From 7fc6240addbad7aa509fe7ea99bf41e772e49a3b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 30 Jun 2025 13:47:55 -0400 Subject: [PATCH 6/6] unused --- packages/svelte/src/compiler/migrate/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index 8ec6bbbbaef2..fdc9734f858f 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -135,7 +135,6 @@ export function migrate(source, { filename, use_ts } = {}) { }); reset_warnings(() => false); - reset({ dev: false, filename: filename ?? '(unknown)' }); let parsed = parse(source);