Skip to content

Commit f2bf900

Browse files
committed
feat: support latest runes ($props.id and $inspect.trace)
1 parent 573169f commit f2bf900

File tree

8 files changed

+8232
-47
lines changed

8 files changed

+8232
-47
lines changed

Diff for: .changeset/stale-birds-win.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": minor
3+
---
4+
5+
feat: support latest runes (`$props.id` and `$inspect.trace`)

Diff for: src/parser/typescript/analyze/index.ts

+52-47
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ export function analyzeTypeScriptInSvelte(
4343
code: { script: string; rootScope: string; render: string },
4444
attrs: Record<string, string | undefined>,
4545
parserOptions: NormalizedParserOptions,
46-
context: AnalyzeTypeScriptContext,
46+
context: AnalyzeTypeScriptContext
4747
): VirtualTypeScriptContext {
4848
const ctx = new VirtualTypeScriptContext(
49-
code.script + code.render + code.rootScope,
49+
code.script + code.render + code.rootScope
5050
);
5151
ctx.appendOriginal(/^\s*/u.exec(code.script)![0].length);
5252

@@ -57,7 +57,7 @@ export function analyzeTypeScriptInSvelte(
5757
...parserOptions,
5858
// Without typings
5959
project: null,
60-
},
60+
}
6161
) as unknown as TSESParseForESLintResult;
6262

6363
ctx._beforeResult = result;
@@ -68,7 +68,7 @@ export function analyzeTypeScriptInSvelte(
6868
result,
6969
ctx,
7070
context.svelteParseContext,
71-
context.slots,
71+
context.slots
7272
);
7373

7474
analyzeRuneVariables(result, ctx, context.svelteParseContext);
@@ -78,7 +78,7 @@ export function analyzeTypeScriptInSvelte(
7878
...analyzeReactiveScopes(result),
7979
...analyzeDollarDerivedScopes(result, context.svelteParseContext),
8080
],
81-
ctx,
81+
ctx
8282
);
8383

8484
analyzeRenderScopes(code, ctx);
@@ -102,7 +102,7 @@ export function analyzeTypeScript(
102102
code: string,
103103
attrs: Record<string, string | undefined>,
104104
parserOptions: NormalizedParserOptions,
105-
svelteParseContext: SvelteParseContext,
105+
svelteParseContext: SvelteParseContext
106106
): VirtualTypeScriptContext {
107107
const ctx = new VirtualTypeScriptContext(code);
108108
ctx.appendOriginal(/^\s*/u.exec(code)![0].length);
@@ -119,7 +119,7 @@ export function analyzeTypeScript(
119119

120120
applyTransforms(
121121
[...analyzeDollarDerivedScopes(result, svelteParseContext)],
122-
ctx,
122+
ctx
123123
);
124124

125125
ctx.appendOriginalToEnd();
@@ -146,7 +146,7 @@ function hasExportDeclaration(ast: TSESParseForESLintResult["ast"]): boolean {
146146
function analyzeStoreReferenceNames(
147147
result: TSESParseForESLintResult,
148148
svelteParseContext: SvelteParseContext,
149-
ctx: VirtualTypeScriptContext,
149+
ctx: VirtualTypeScriptContext
150150
) {
151151
const globals = getGlobalsForSvelte(svelteParseContext);
152152
const scopeManager = result.scopeManager;
@@ -175,7 +175,7 @@ function analyzeStoreReferenceNames(
175175
? F extends (value: infer V, ...args: any) => any
176176
? V
177177
: never
178-
: T;`,
178+
: T;`
179179
);
180180
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
181181
if (
@@ -199,7 +199,7 @@ function analyzeStoreReferenceNames(
199199
for (const nm of maybeStoreRefNames) {
200200
const realName = nm.slice(1);
201201
ctx.appendVirtualScript(
202-
`declare let ${nm}: ${storeValueTypeName}<typeof ${realName}>;`,
202+
`declare let ${nm}: ${storeValueTypeName}<typeof ${realName}>;`
203203
);
204204
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
205205
if (
@@ -236,14 +236,14 @@ function analyzeDollarDollarVariables(
236236
result: TSESParseForESLintResult,
237237
ctx: VirtualTypeScriptContext,
238238
svelteParseContext: SvelteParseContext,
239-
slots: Set<SvelteHTMLElement>,
239+
slots: Set<SvelteHTMLElement>
240240
) {
241241
const globals = getGlobalsForSvelte(svelteParseContext);
242242
const scopeManager = result.scopeManager;
243243
for (const globalName of globals) {
244244
if (
245245
!scopeManager.globalScope!.through.some(
246-
(reference) => reference.identifier.name === globalName,
246+
(reference) => reference.identifier.name === globalName
247247
)
248248
) {
249249
continue;
@@ -260,7 +260,7 @@ function analyzeDollarDollarVariables(
260260
for (const slot of slots) {
261261
const nameAttr = slot.startTag.attributes.find(
262262
(attr): attr is SvelteAttribute =>
263-
attr.type === "SvelteAttribute" && attr.key.name === "name",
263+
attr.type === "SvelteAttribute" && attr.key.name === "name"
264264
);
265265
if (!nameAttr || nameAttr.value.length === 0) {
266266
nameTypes.add('"default"');
@@ -281,17 +281,17 @@ function analyzeDollarDollarVariables(
281281
.map((value) =>
282282
value.type === "SvelteLiteral"
283283
? value.value.replace(/([$`])/gu, "\\$1")
284-
: "${string}",
284+
: "${string}"
285285
)
286-
.join("")}\``,
286+
.join("")}\``
287287
);
288288
}
289289

290290
appendDeclareVirtualScript(
291291
globalName,
292292
`Record<${
293293
nameTypes.size > 0 ? [...nameTypes].join(" | ") : "any"
294-
}, boolean>`,
294+
}, boolean>`
295295
);
296296
break;
297297
}
@@ -375,7 +375,7 @@ function appendDummyExport(ctx: VirtualTypeScriptContext) {
375375
function analyzeRuneVariables(
376376
result: TSESParseForESLintResult,
377377
ctx: VirtualTypeScriptContext,
378-
svelteParseContext: SvelteParseContext,
378+
svelteParseContext: SvelteParseContext
379379
) {
380380
// No processing is needed if the user is determined not to be in Runes mode.
381381
if (svelteParseContext.runes === false) {
@@ -385,13 +385,13 @@ function analyzeRuneVariables(
385385
for (const globalName of globalsForRunes) {
386386
if (
387387
!scopeManager.globalScope!.through.some(
388-
(reference) => reference.identifier.name === globalName,
388+
(reference) => reference.identifier.name === globalName
389389
)
390390
) {
391391
continue;
392392
}
393393
switch (globalName) {
394-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2299
394+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L2679
395395
case "$state": {
396396
appendDeclareFunctionVirtualScripts(globalName, [
397397
"<T>(initial: T): T",
@@ -407,7 +407,7 @@ function analyzeRuneVariables(
407407

408408
break;
409409
}
410-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2453
410+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L2833
411411
case "$derived": {
412412
appendDeclareFunctionVirtualScripts(globalName, [
413413
"<T>(expression: T): T",
@@ -417,7 +417,7 @@ function analyzeRuneVariables(
417417
]);
418418
break;
419419
}
420-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2513
420+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L2893
421421
case "$effect": {
422422
appendDeclareFunctionVirtualScripts(globalName, [
423423
"(fn: () => void | (() => void)): void",
@@ -429,27 +429,33 @@ function analyzeRuneVariables(
429429
]);
430430
break;
431431
}
432-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2615
432+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L2997
433433
case "$props": {
434434
// Use type parameters to avoid `@typescript-eslint/no-unsafe-assignment` errors.
435435
appendDeclareFunctionVirtualScripts(globalName, ["<T>(): T"]);
436+
appendDeclareNamespaceVirtualScripts(globalName, [
437+
"export function id(): string;",
438+
]);
436439
break;
437440
}
438-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2626
441+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L3038
439442
case "$bindable": {
440443
appendDeclareFunctionVirtualScripts(globalName, [
441444
"<T>(fallback?: T): T",
442445
]);
443446
break;
444447
}
445-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2646
448+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L3081
446449
case "$inspect": {
447450
appendDeclareFunctionVirtualScripts(globalName, [
448451
`<T extends any[]>(...values: T): { with: (fn: (type: 'init' | 'update', ...values: T) => void) => void }`,
449452
]);
453+
appendDeclareNamespaceVirtualScripts(globalName, [
454+
"export function trace(name?: string): void;",
455+
]);
450456
break;
451457
}
452-
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2669
458+
// See https://github.com/sveltejs/svelte/blob/3c4a8d425b8192dc11ea2af256d531c51c37ba5d/packages/svelte/types/index.d.ts#L3144
453459
case "$host": {
454460
appendDeclareFunctionVirtualScripts(globalName, [
455461
`<El extends HTMLElement = HTMLElement>(): El`,
@@ -494,7 +500,7 @@ function analyzeRuneVariables(
494500

495501
function appendDeclareNamespaceVirtualScripts(
496502
name: string,
497-
scripts: string[],
503+
scripts: string[]
498504
) {
499505
for (const script of scripts) {
500506
ctx.appendVirtualScript(`declare namespace ${name} { ${script} }`);
@@ -529,11 +535,11 @@ function analyzeRuneVariables(
529535
* Transform source code to provide the correct type information in the `$:` statements.
530536
*/
531537
function* analyzeReactiveScopes(
532-
result: TSESParseForESLintResult,
538+
result: TSESParseForESLintResult
533539
): Iterable<TransformInfo> {
534540
const scopeManager = result.scopeManager;
535541
const throughIds = scopeManager.globalScope!.through.map(
536-
(reference) => reference.identifier,
542+
(reference) => reference.identifier
537543
);
538544
for (const statement of result.ast.body) {
539545
if (statement.type === "LabeledStatement" && statement.label.name === "$") {
@@ -550,8 +556,7 @@ function* analyzeReactiveScopes(
550556
const left = statement.body.expression.left;
551557
if (
552558
throughIds.some(
553-
(id) =>
554-
left.range[0] <= id.range[0] && id.range[1] <= left.range[1],
559+
(id) => left.range[0] <= id.range[0] && id.range[1] <= left.range[1]
555560
)
556561
) {
557562
const node = statement;
@@ -564,7 +569,7 @@ function* analyzeReactiveScopes(
564569
left,
565570
expression,
566571
result.ast.tokens,
567-
ctx,
572+
ctx
568573
),
569574
};
570575
continue;
@@ -584,13 +589,13 @@ function* analyzeReactiveScopes(
584589
*/
585590
function* analyzeDollarDerivedScopes(
586591
result: TSESParseForESLintResult,
587-
svelteParseContext: SvelteParseContext,
592+
svelteParseContext: SvelteParseContext
588593
): Iterable<TransformInfo> {
589594
// No processing is needed if the user is determined not to be in Runes mode.
590595
if (svelteParseContext.runes === false) return;
591596
const scopeManager = result.scopeManager;
592597
const derivedReferences = scopeManager.globalScope!.through.filter(
593-
(reference) => reference.identifier.name === "$derived",
598+
(reference) => reference.identifier.name === "$derived"
594599
);
595600
if (!derivedReferences.length) {
596601
return;
@@ -618,7 +623,7 @@ function* analyzeDollarDerivedScopes(
618623
*/
619624
function analyzeRenderScopes(
620625
code: { script: string; render: string; rootScope: string },
621-
ctx: VirtualTypeScriptContext,
626+
ctx: VirtualTypeScriptContext
622627
) {
623628
ctx.appendOriginal(code.script.length);
624629
const renderFunctionName = ctx.generateUniqueId("render");
@@ -637,7 +642,7 @@ function analyzeRenderScopes(
637642
program.body.splice(
638643
program.body.indexOf(node),
639644
1,
640-
...node.declaration.body.body,
645+
...node.declaration.body.body
641646
);
642647
for (const body of node.declaration.body.body) {
643648
body.parent = program;
@@ -655,7 +660,7 @@ function analyzeRenderScopes(
655660
*/
656661
function applyTransforms(
657662
transforms: TransformInfo[],
658-
ctx: VirtualTypeScriptContext,
663+
ctx: VirtualTypeScriptContext
659664
) {
660665
transforms.sort((a, b) => a.node.range[0] - b.node.range[0]);
661666

@@ -677,7 +682,7 @@ function transformForDeclareReactiveVar(
677682
id: TSESTree.Identifier | TSESTree.ArrayPattern | TSESTree.ObjectPattern,
678683
expression: TSESTree.AssignmentExpression,
679684
tokens: TSESTree.Token[],
680-
ctx: VirtualTypeScriptContext,
685+
ctx: VirtualTypeScriptContext
681686
): void {
682687
// e.g.
683688
// From:
@@ -721,7 +726,7 @@ function transformForDeclareReactiveVar(
721726
let expressionCloseParen: TSESTree.Token | null = null;
722727
const startIndex = sortedLastIndex(
723728
tokens,
724-
(target) => target.range[0] - statement.range[0],
729+
(target) => target.range[0] - statement.range[0]
725730
);
726731
for (let index = startIndex; index < tokens.length; index++) {
727732
const token = tokens[index];
@@ -761,7 +766,7 @@ function transformForDeclareReactiveVar(
761766
ctx.appendVirtualScript("let ");
762767
ctx.appendOriginal(eq ? eq.range[1] : expression.right.range[0]);
763768
ctx.appendVirtualScript(
764-
`${functionId}();\nfunction ${functionId}(){let ${tmpVarId};return (${tmpVarId} = `,
769+
`${functionId}();\nfunction ${functionId}(){let ${tmpVarId};return (${tmpVarId} = `
765770
);
766771
ctx.appendOriginal(expression.right.range[1]);
767772
ctx.appendVirtualScript(`)`);
@@ -867,7 +872,7 @@ function transformForDeclareReactiveVar(
867872
addElementsToSortedArray(
868873
program.tokens,
869874
[...openParens, ...closeParens],
870-
(a, b) => a.range[0] - b.range[0],
875+
(a, b) => a.range[0] - b.range[0]
871876
);
872877

873878
const scopeManager = result.scopeManager as ScopeManager;
@@ -896,7 +901,7 @@ function transformForDeclareReactiveVar(
896901
*/
897902
function transformForReactiveStatement(
898903
statement: TSESTree.LabeledStatement,
899-
ctx: VirtualTypeScriptContext,
904+
ctx: VirtualTypeScriptContext
900905
) {
901906
const functionId = ctx.generateUniqueId("reactiveStatementScopeFunction");
902907
const originalBody = statement.body;
@@ -933,13 +938,13 @@ function transformForReactiveStatement(
933938
*/
934939
function transformForDollarDerived(
935940
derivedCall: TSESTree.CallExpression,
936-
ctx: VirtualTypeScriptContext,
941+
ctx: VirtualTypeScriptContext
937942
) {
938943
const functionId = ctx.generateUniqueId("$derivedArgument");
939944
const expression = derivedCall.arguments[0];
940945
ctx.appendOriginal(expression.range[0]);
941946
ctx.appendVirtualScript(
942-
`(()=>{return ${functionId}();function ${functionId}(){return `,
947+
`(()=>{return ${functionId}();function ${functionId}(){return `
943948
);
944949
ctx.appendOriginal(expression.range[1]);
945950
ctx.appendVirtualScript(`}})()`);
@@ -988,7 +993,7 @@ function transformForDollarDerived(
988993
removeFunctionScope(arg.callee.body.body[1], scopeManager);
989994
removeIdentifierReference(
990995
arg.callee.body.body[0].argument.callee,
991-
scopeManager.acquire(arg.callee)!,
996+
scopeManager.acquire(arg.callee)!
992997
);
993998
removeFunctionScope(arg.callee, scopeManager);
994999
return true;
@@ -1002,7 +1007,7 @@ function removeFunctionScope(
10021007
| TSESTree.FunctionDeclaration
10031008
| TSESTree.FunctionExpression
10041009
| TSESTree.ArrowFunctionExpression,
1005-
scopeManager: ScopeManager,
1010+
scopeManager: ScopeManager
10061011
) {
10071012
const scope = scopeManager.acquire(node)!;
10081013
const upper = scope.upper!;
@@ -1024,12 +1029,12 @@ function removeFunctionScope(
10241029
addElementsToSortedArray(
10251030
upperVariable.identifiers,
10261031
variable.identifiers,
1027-
(a, b) => a.range![0] - b.range![0],
1032+
(a, b) => a.range![0] - b.range![0]
10281033
);
10291034
addElementsToSortedArray(
10301035
upperVariable.defs,
10311036
variable.defs,
1032-
(a, b) => a.node.range![0] - b.node.range![0],
1037+
(a, b) => a.node.range![0] - b.node.range![0]
10331038
);
10341039
addAllReferences(upperVariable.references, variable.references);
10351040
} else {

0 commit comments

Comments
 (0)