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

.changeset/stale-birds-win.md

Lines changed: 5 additions & 0 deletions
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`)

src/parser/typescript/analyze/index.ts

Lines changed: 52 additions & 47 deletions
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)
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