Skip to content

Commit 2feb963

Browse files
committed
fix: recognize script as module for Typescript type checking
1 parent 10a218c commit 2feb963

23 files changed

+1858
-7
lines changed

.changeset/purple-otters-hammer.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": patch
3+
---
4+
5+
fix: recognize script as module for Typescript type checking

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@
9595
"eslint-plugin-regexp": "^2.7.0",
9696
"eslint-plugin-svelte": "^2.46.1",
9797
"eslint-plugin-yml": "^1.15.0",
98-
"estree-walker": "^3.0.3",
9998
"globals": "^15.12.0",
10099
"locate-character": "^3.0.0",
101100
"magic-string": "^0.30.14",

src/parser/typescript/analyze/index.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ export function analyzeTypeScriptInSvelte(
8080

8181
analyzeRenderScopes(code, ctx);
8282

83+
// When performing type checking on TypeScript code that is not a module, the error `Cannot redeclare block-scoped variable 'xxx'`. occurs. To fix this, add an `export`.
84+
// see: https://github.com/sveltejs/svelte-eslint-parser/issues/557
85+
if (!hasExportDeclaration(result.ast)) {
86+
ctx.appendVirtualScript("export {};");
87+
}
88+
8389
ctx.appendOriginalToEnd();
8490

8591
return ctx;
@@ -118,6 +124,18 @@ export function analyzeTypeScript(
118124
return ctx;
119125
}
120126

127+
function hasExportDeclaration(ast: TSESParseForESLintResult["ast"]): boolean {
128+
for (const node of ast.body) {
129+
if (
130+
node.type === "ExportNamedDeclaration" ||
131+
node.type === "ExportDefaultDeclaration"
132+
) {
133+
return true;
134+
}
135+
}
136+
return false;
137+
}
138+
121139
/**
122140
* Analyze the store reference names.
123141
* Insert type definitions code to provide correct type information for variables that begin with `$`.
@@ -380,7 +398,7 @@ function analyzeRuneVariables(
380398
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2615
381399
case "$props": {
382400
// Use type parameters to avoid `@typescript-eslint/no-unsafe-assignment` errors.
383-
appendDeclareFunctionVirtualScripts(globalName, ["<T>(): T"]);
401+
appendDeclareFunctionVirtualScripts(globalName, ["(): any"]);
384402
break;
385403
}
386404
// See https://github.com/sveltejs/svelte/blob/41b5cd6f5daae3970a9927e062f42b6b62440d16/packages/svelte/types/index.d.ts#L2626

tests/fixtures/parser/ast/svelte5/docs/runes/08-$props-ts-output.json

+21
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,27 @@
502502
"column": 57
503503
}
504504
}
505+
},
506+
{
507+
"type": "ExportNamedDeclaration",
508+
"declaration": null,
509+
"exportKind": "value",
510+
"source": null,
511+
"specifiers": [],
512+
"range": [
513+
108,
514+
108
515+
],
516+
"loc": {
517+
"start": {
518+
"line": 5,
519+
"column": 0
520+
},
521+
"end": {
522+
"line": 5,
523+
"column": 0
524+
}
525+
}
505526
}
506527
],
507528
"endTag": {

tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-output.json

+21
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,27 @@
427427
"column": 75
428428
}
429429
}
430+
},
431+
{
432+
"type": "ExportNamedDeclaration",
433+
"declaration": null,
434+
"exportKind": "value",
435+
"source": null,
436+
"specifiers": [],
437+
"range": [
438+
105,
439+
105
440+
],
441+
"loc": {
442+
"start": {
443+
"line": 4,
444+
"column": 0
445+
},
446+
"end": {
447+
"line": 4,
448+
"column": 0
449+
}
450+
}
430451
}
431452
],
432453
"endTag": {

tests/fixtures/parser/ast/svelte5/docs/runes/11-3-$inspect-ts-output.json

+21
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,27 @@
394394
"column": 38
395395
}
396396
}
397+
},
398+
{
399+
"type": "ExportNamedDeclaration",
400+
"declaration": null,
401+
"exportKind": "value",
402+
"source": null,
403+
"specifiers": [],
404+
"range": [
405+
94,
406+
94
407+
],
408+
"loc": {
409+
"start": {
410+
"line": 6,
411+
"column": 0
412+
},
413+
"end": {
414+
"line": 6,
415+
"column": 0
416+
}
417+
}
397418
}
398419
],
399420
"endTag": {

tests/fixtures/parser/ast/svelte5/docs/snippets/10-typing-snippets-type-output.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
data: any[]; // data: any[]
66
children: Snippet; // Snippet: Snippet<Parameters>, children: Snippet<[]>
77
row: Snippet<[any]>; // Snippet: Snippet<Parameters>, row: Snippet<[any]>
8-
} = $props(); // $props(): { data: any[]; children: Snippet<[]>; row: Snippet<[any]>; }
8+
} = $props(); // $props(): any
99
</script>
1010

1111
<table>

tests/fixtures/parser/ast/svelte5/docs/snippets/11-typing-snippets-type-output.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
data: T[]; // T: unknown, data: unknown[]
66
children: Snippet; // Snippet: Snippet<Parameters>, children: Snippet<[]>
77
row: Snippet<[T]>; // Snippet: Snippet<Parameters>, T: unknown, row: Snippet<[unknown]>
8-
} = $props(); // $props(): { data: unknown[]; children: Snippet<[]>; row: Snippet<[unknown]>; }
8+
} = $props(); // $props(): any
99
</script>
1010

1111
<table>

tests/fixtures/parser/ast/svelte5/generics01-snippets-type-output.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
data: A[]; // A: unknown, data: unknown[]
77
children: Snippet; // Snippet: Snippet<Parameters>, children: Snippet<[]>
88
row: Snippet<[A]>; // Snippet: Snippet<Parameters>, A: unknown, row: Snippet<[unknown]>
9-
} = $props(); // $props(): { data: unknown[]; children: Snippet<[]>; row: Snippet<[unknown]>; }
9+
} = $props(); // $props(): any
1010
</script>
1111

1212
<table>

tests/fixtures/parser/ast/svelte5/ts-$props01-type-output.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
c: boolean; // c: boolean
66
d: number; // d: number
77
}
8-
let { a, b, c, ...everythingElse }: MyProps = $props(); // a: number, a: number, b: string, b: string, c: boolean, c: boolean, everythingElse: { d: number; }, MyProps: MyProps, $props(): MyProps
8+
let { a, b, c, ...everythingElse }: MyProps = $props(); // a: number, a: number, b: string, b: string, c: boolean, c: boolean, everythingElse: { d: number; }, MyProps: MyProps, $props(): any
99
</script>
1010

1111
{a} <!-- a: number -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script lang="ts">
2+
let { name }: { name: string } = $props();
3+
</script>
4+
5+
{name}

0 commit comments

Comments
 (0)