11import type * as Compiler from "./svelte-ast-types-for-v5.js" ;
22import type * as SvAST from "./svelte-ast-types.js" ;
3+ import type * as ESTree from "estree" ;
34import type { NormalizedParserOptions } from "./parser-options.js" ;
45import { compilerVersion , svelteVersion } from "./svelte-version.js" ;
56import type { SvelteConfig } from "../svelte-config/index.js" ;
7+ import { traverseNodes } from "../traverse.js" ;
8+
9+ const runeSymbols : string [ ] = [
10+ "$state" ,
11+ "$derived" ,
12+ "$effect" ,
13+ "$props" ,
14+ "$bindable" ,
15+ "$inspect" ,
16+ "$host" ,
17+ ] as const ;
618
719/** The context for parsing. */
820export type SvelteParseContext = {
@@ -18,55 +30,76 @@ export type SvelteParseContext = {
1830 svelteConfig : SvelteConfig | null ;
1931} ;
2032
21- export function isEnableRunes (
22- svelteConfig : SvelteConfig | null ,
23- parserOptions : NormalizedParserOptions ,
24- ) : boolean {
25- if ( ! svelteVersion . gte ( 5 ) ) return false ;
26- if ( parserOptions . svelteFeatures ?. runes != null ) {
27- return Boolean ( parserOptions . svelteFeatures . runes ) ;
28- }
29- if ( svelteConfig ?. compilerOptions ?. runes != null ) {
30- return Boolean ( svelteConfig . compilerOptions . runes ) ;
31- }
32- return true ;
33- }
34-
3533export function resolveSvelteParseContextForSvelte (
3634 svelteConfig : SvelteConfig | null ,
3735 parserOptions : NormalizedParserOptions ,
3836 svelteAst : Compiler . Root | SvAST . AstLegacy ,
3937) : SvelteParseContext {
40- const svelteOptions = ( svelteAst as Compiler . Root ) . options ;
41- if ( svelteOptions ?. runes != null ) {
42- return {
43- runes : svelteOptions . runes ,
44- compilerVersion,
45- svelteConfig,
46- } ;
47- }
48-
4938 return {
50- runes : isEnableRunes ( svelteConfig , parserOptions ) ,
39+ runes : isRunes ( svelteConfig , parserOptions , svelteAst ) ,
5140 compilerVersion,
5241 svelteConfig,
5342 } ;
5443}
5544
5645export function resolveSvelteParseContextForSvelteScript (
5746 svelteConfig : SvelteConfig | null ,
58- parserOptions : NormalizedParserOptions ,
59- ) : SvelteParseContext {
60- return resolveSvelteParseContext ( svelteConfig , parserOptions ) ;
61- }
62-
63- function resolveSvelteParseContext (
64- svelteConfig : SvelteConfig | null ,
65- parserOptions : NormalizedParserOptions ,
6647) : SvelteParseContext {
6748 return {
68- runes : isEnableRunes ( svelteConfig , parserOptions ) ,
49+ // .svelte.js files are always in Runes mode for Svelte 5.
50+ runes : svelteVersion . gte ( 5 ) ,
6951 compilerVersion,
7052 svelteConfig,
7153 } ;
7254}
55+
56+ function isRunes (
57+ svelteConfig : SvelteConfig | null ,
58+ parserOptions : NormalizedParserOptions ,
59+ svelteAst : Compiler . Root | SvAST . AstLegacy ,
60+ ) : boolean {
61+ // Svelte 3/4 does not support Runes mode.
62+ if ( ! svelteVersion . gte ( 5 ) ) {
63+ return false ;
64+ }
65+
66+ // Compiler option.
67+ if ( parserOptions . svelteFeatures ?. runes != null ) {
68+ return parserOptions . svelteFeatures ?. runes ;
69+ }
70+ if ( svelteConfig ?. compilerOptions ?. runes != null ) {
71+ return svelteConfig ?. compilerOptions ?. runes ;
72+ }
73+
74+ // `<svelte:options>`.
75+ const svelteOptions = ( svelteAst as Compiler . Root ) . options ;
76+ if ( svelteOptions ?. runes != null ) {
77+ return svelteOptions ?. runes ;
78+ }
79+
80+ // Static analysis.
81+ const { module, instance } = svelteAst ;
82+ return (
83+ ( module != null && hasRuneSymbol ( module ) ) ||
84+ ( instance != null && hasRuneSymbol ( instance ) )
85+ ) ;
86+ }
87+
88+ function hasRuneSymbol ( ast : Compiler . Script | SvAST . Script ) : boolean {
89+ let hasRuneSymbol = false ;
90+ traverseNodes ( ast as unknown as ESTree . Node , {
91+ enterNode ( node ) {
92+ if ( hasRuneSymbol ) {
93+ return ;
94+ }
95+ if ( node . type === "Identifier" && runeSymbols . includes ( node . name ) ) {
96+ hasRuneSymbol = true ;
97+ }
98+ } ,
99+ leaveNode ( ) {
100+ // do nothing
101+ } ,
102+ } ) ;
103+
104+ return hasRuneSymbol ;
105+ }
0 commit comments