diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 2ea2f58de85b..6d4f31480d6e 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.36.4 + +### Patch Changes + +- fix: avoid microtask in flushSync ([#16394](https://github.com/sveltejs/svelte/pull/16394)) + +- fix: ensure compiler state is reset before compilation ([#16396](https://github.com/sveltejs/svelte/pull/16396)) + ## 5.36.3 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 119c4142cfda..3e9022a0910f 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.36.3", + "version": "5.36.4", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index 9ba23c148595..a378af34eedc 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -20,7 +20,7 @@ export { default as preprocess } from './preprocess/index.js'; */ export function compile(source, options) { source = remove_bom(source); - state.reset_warnings(options.warningFilter); + state.reset({ warning: options.warningFilter, filename: options.filename }); const validated = validate_component_options(options, ''); let parsed = _parse(source); @@ -63,7 +63,7 @@ export function compile(source, options) { */ export function compileModule(source, options) { source = remove_bom(source); - state.reset_warnings(options.warningFilter); + state.reset({ warning: options.warningFilter, filename: options.filename }); const validated = validate_module_options(options, ''); const analysis = analyze_module(source, validated); @@ -111,7 +111,7 @@ export function compileModule(source, options) { */ export function parse(source, { modern, loose } = {}) { source = remove_bom(source); - state.reset_warnings(() => false); + state.reset({ warning: () => false, filename: undefined }); 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 0e2fe019ed34..6b2e6cda70a4 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_warnings } from '../state.js'; +import { reset, UNKNOWN_FILENAME } from '../state.js'; import { extract_identifiers, extract_all_identifiers_from_expression, @@ -134,7 +134,7 @@ export function migrate(source, { filename, use_ts } = {}) { return start + style_placeholder + end; }); - reset_warnings(() => false); + reset({ warning: () => false, filename }); let parsed = parse(source); @@ -145,7 +145,7 @@ export function migrate(source, { filename, use_ts } = {}) { ...validate_component_options({}, ''), ...parsed_options, customElementOptions, - filename: filename ?? '(unknown)', + filename: filename ?? UNKNOWN_FILENAME, experimental: { async: true } diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 258b59018a6c..d407b4455639 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -279,9 +279,8 @@ export function analyze_module(source, options) { classes: new Map() }; - state.reset({ + state.adjust({ dev: options.dev, - filename: options.filename, rootDir: options.rootDir, runes: true }); @@ -531,12 +530,11 @@ export function analyze_component(root, source, options) { async_deriveds: new Set() }; - state.reset({ + state.adjust({ component_name: analysis.name, dev: options.dev, - filename: options.filename, rootDir: options.rootDir, - runes: true + runes }); if (!runes) { diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js index b87f082de0ea..652a447165c8 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js @@ -3,7 +3,7 @@ import { visit_component } from './shared/component.js'; import * as e from '../../../errors.js'; import * as w from '../../../warnings.js'; -import { filename } from '../../../state.js'; +import { filename, UNKNOWN_FILENAME } from '../../../state.js'; /** * @param {AST.SvelteSelf} node @@ -23,9 +23,9 @@ export function SvelteSelf(node, context) { } if (context.state.analysis.runes) { - const name = filename === '(unknown)' ? 'Self' : context.state.analysis.name; + const name = filename === UNKNOWN_FILENAME ? 'Self' : context.state.analysis.name; const basename = - filename === '(unknown)' + filename === UNKNOWN_FILENAME ? 'Self.svelte' : /** @type {string} */ (filename.split(/[/\\]/).pop()); diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 5eb25dd6bb15..725d03b802de 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -16,6 +16,11 @@ export let warnings = []; */ export let filename; +/** + * This is the fallback used when no filename is specified. + */ +export const UNKNOWN_FILENAME = '(unknown)'; + /** * The name of the component that is used in the `export default function ...` statement. */ @@ -80,15 +85,6 @@ export function pop_ignore() { ignore_stack.pop(); } -/** - * - * @param {(warning: Warning) => boolean} fn - */ -export function reset_warnings(fn = () => true) { - warning_filter = fn; - warnings = []; -} - /** * @param {AST.SvelteNode | NodeLike} node * @param {import('../constants.js').IGNORABLE_RUNTIME_WARNINGS[number]} code @@ -99,21 +95,36 @@ export function is_ignored(node, code) { } /** + * Call this to reset the compiler state. Should be called before each compilation. + * @param {{ warning?: (warning: Warning) => boolean; filename: string | undefined }} state + */ +export function reset(state) { + dev = false; + runes = false; + component_name = UNKNOWN_FILENAME; + source = ''; + locator = () => undefined; + filename = (state.filename ?? UNKNOWN_FILENAME).replace(/\\/g, '/'); + warning_filter = state.warning ?? (() => true); + warnings = []; +} + +/** + * Adjust the compiler state based on the provided state object. + * Call this after parsing and basic analysis happened. * @param {{ * dev: boolean; - * filename: string; * component_name?: string; * rootDir?: string; * runes: boolean; * }} state */ -export function reset(state) { +export function adjust(state) { const root_dir = state.rootDir?.replace(/\\/g, '/'); - filename = state.filename.replace(/\\/g, '/'); dev = state.dev; runes = state.runes; - component_name = state.component_name ?? '(unknown)'; + component_name = state.component_name ?? UNKNOWN_FILENAME; if (typeof root_dir === 'string' && filename.startsWith(root_dir)) { // make filename relative to rootDir diff --git a/packages/svelte/src/compiler/utils/compile_diagnostic.js b/packages/svelte/src/compiler/utils/compile_diagnostic.js index db938cf2bdb3..c5df49e01cee 100644 --- a/packages/svelte/src/compiler/utils/compile_diagnostic.js +++ b/packages/svelte/src/compiler/utils/compile_diagnostic.js @@ -61,7 +61,7 @@ export class CompileDiagnostic { this.code = code; this.message = message; - if (state.filename) { + if (state.filename !== state.UNKNOWN_FILENAME) { this.filename = state.filename; } diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index f881330e90df..1d08b5c3d82b 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -416,19 +416,21 @@ export class Batch { return (this.#deferred ??= deferred()).promise; } - static ensure() { + static ensure(autoflush = true) { if (current_batch === null) { const batch = (current_batch = new Batch()); batches.add(current_batch); - queueMicrotask(() => { - if (current_batch !== batch) { - // a flushSync happened in the meantime - return; - } + if (autoflush) { + queueMicrotask(() => { + if (current_batch !== batch) { + // a flushSync happened in the meantime + return; + } - batch.flush(); - }); + batch.flush(); + }); + } } return current_batch; @@ -449,7 +451,7 @@ export function flushSync(fn) { var result; - const batch = Batch.ensure(); + const batch = Batch.ensure(false); if (fn) { batch.flush_effects(); diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index e8b0e6f1ee71..f8d23b44b1e5 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.36.3'; +export const VERSION = '5.36.4'; export const PUBLIC_VERSION = '5'; diff --git a/packages/svelte/tests/compiler-errors/test.ts b/packages/svelte/tests/compiler-errors/test.ts index 5e57a3a03286..13b9280dde4f 100644 --- a/packages/svelte/tests/compiler-errors/test.ts +++ b/packages/svelte/tests/compiler-errors/test.ts @@ -1,5 +1,5 @@ import * as fs from 'node:fs'; -import { assert, expect } from 'vitest'; +import { assert, expect, it } from 'vitest'; import { compile, compileModule, type CompileError } from 'svelte/compiler'; import { suite, type BaseTest } from '../suite'; import { read_file } from '../helpers.js'; @@ -78,3 +78,15 @@ const { test, run } = suite((config, cwd) => { export { test }; await run(__dirname); + +it('resets the compiler state including filename', () => { + // start with something that succeeds + compile('
hello
', { filename: 'foo.svelte' }); + // then try something that fails in the parsing stage + try { + compile('

hello

invalid

', { filename: 'bar.svelte' }); + expect.fail('Expected an error'); + } catch (e: any) { + expect(e.toString()).toContain('bar.svelte'); + } +}); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy