diff --git a/.changeset/brown-owls-bow.md b/.changeset/brown-owls-bow.md new file mode 100644 index 00000000..204a2540 --- /dev/null +++ b/.changeset/brown-owls-bow.md @@ -0,0 +1,5 @@ +--- +"svelte-eslint-parser": patch +--- + +fix: correct detection of runes mode in parsed files diff --git a/src/parser/index.ts b/src/parser/index.ts index 877b1a64..641468cf 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -50,6 +50,7 @@ import type { NormalizedParserOptions } from "./parser-options.js"; import { isTypeScript, normalizeParserOptions } from "./parser-options.js"; import { getFragmentFromRoot } from "./compat.js"; import { + hasRunesSymbol, resolveSvelteParseContextForSvelte, resolveSvelteParseContextForSvelteScript, type SvelteParseContext, @@ -142,6 +143,7 @@ function parseAsSvelte( ctx, parserOptions, ); + const svelteParseContext = resolveSvelteParseContextForSvelte( svelteConfig, parserOptions, @@ -161,6 +163,7 @@ function parseAsSvelte( scripts.attrs, parserOptions, ); + ctx.scriptLet.restore(resultScript); ctx.tokens.push(...resultScript.ast.tokens); ctx.comments.push(...resultScript.ast.comments); @@ -254,7 +257,11 @@ function parseAsSvelte( styleNodeLoc, styleNodeRange, styleSelectorNodeLoc, - svelteParseContext, + svelteParseContext: { + ...svelteParseContext, + // The compiler decides if runes mode is used after parsing. + runes: svelteParseContext.runes ?? hasRunesSymbol(resultScript.ast), + }, }); resultScript.visitorKeys = Object.assign({}, KEYS, resultScript.visitorKeys); diff --git a/src/parser/svelte-parse-context.ts b/src/parser/svelte-parse-context.ts index 19871f00..36aaca8d 100644 --- a/src/parser/svelte-parse-context.ts +++ b/src/parser/svelte-parse-context.ts @@ -1,10 +1,10 @@ import type * as Compiler from "./svelte-ast-types-for-v5.js"; import type * as SvAST from "./svelte-ast-types.js"; -import type * as ESTree from "estree"; import type { NormalizedParserOptions } from "./parser-options.js"; import { compilerVersion, svelteVersion } from "./svelte-version.js"; import type { SvelteConfig } from "../svelte-config/index.js"; import { traverseNodes } from "../traverse.js"; +import type { ESLintProgram } from "./index.js"; const runeSymbols: string[] = [ "$state", @@ -19,11 +19,16 @@ const runeSymbols: string[] = [ /** The context for parsing. */ export type SvelteParseContext = { /** - * Whether to use Runes mode. - * May be `true` if the user is using Svelte v5. - * Resolved from `svelte.config.js` or `parserOptions`, but may be overridden by ``. + * Determines if the file is in Runes mode. + * + * - Svelte 3/4 does not support Runes mode. + * - Checks if `runes` configuration exists in: + * - `parserOptions` + * - `svelte.config.js` + * - `` in the Svelte file. + * - Returns `true` if the `runes` symbol is present in the Svelte file. */ - runes: boolean; + runes?: boolean; /** The version of "svelte/compiler". */ compilerVersion: string; /** The result of static analysis of `svelte.config.js`. */ @@ -36,7 +41,7 @@ export function resolveSvelteParseContextForSvelte( svelteAst: Compiler.Root | SvAST.AstLegacy, ): SvelteParseContext { return { - runes: isRunes(svelteConfig, parserOptions, svelteAst), + runes: isRunesAsParseContext(svelteConfig, parserOptions, svelteAst), compilerVersion, svelteConfig, }; @@ -53,11 +58,11 @@ export function resolveSvelteParseContextForSvelteScript( }; } -function isRunes( +function isRunesAsParseContext( svelteConfig: SvelteConfig | null, parserOptions: NormalizedParserOptions, svelteAst: Compiler.Root | SvAST.AstLegacy, -): boolean { +): boolean | undefined { // Svelte 3/4 does not support Runes mode. if (!svelteVersion.gte(5)) { return false; @@ -77,17 +82,12 @@ function isRunes( return svelteOptions?.runes; } - // Static analysis. - const { module, instance } = svelteAst; - return ( - (module != null && hasRuneSymbol(module)) || - (instance != null && hasRuneSymbol(instance)) - ); + return undefined; } -function hasRuneSymbol(ast: Compiler.Script | SvAST.Script): boolean { +export function hasRunesSymbol(ast: ESLintProgram): boolean { let hasRuneSymbol = false; - traverseNodes(ast as unknown as ESTree.Node, { + traverseNodes(ast, { enterNode(node) { if (hasRuneSymbol) { return;