diff --git a/.changeset/purple-otters-hammer.md b/.changeset/purple-otters-hammer.md
new file mode 100644
index 00000000..6f1a7496
--- /dev/null
+++ b/.changeset/purple-otters-hammer.md
@@ -0,0 +1,5 @@
+---
+"svelte-eslint-parser": patch
+---
+
+fix: recognize script as module for Typescript type checking
diff --git a/package.json b/package.json
index a2cf3f8a..e48dc2b1 100644
--- a/package.json
+++ b/package.json
@@ -95,7 +95,6 @@
"eslint-plugin-regexp": "^2.7.0",
"eslint-plugin-svelte": "^2.46.1",
"eslint-plugin-yml": "^1.15.0",
- "estree-walker": "^3.0.3",
"globals": "^15.12.0",
"locate-character": "^3.0.0",
"magic-string": "^0.30.14",
diff --git a/src/parser/typescript/analyze/index.ts b/src/parser/typescript/analyze/index.ts
index 09c014f9..6530e396 100644
--- a/src/parser/typescript/analyze/index.ts
+++ b/src/parser/typescript/analyze/index.ts
@@ -80,6 +80,12 @@ export function analyzeTypeScriptInSvelte(
analyzeRenderScopes(code, ctx);
+ // 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`.
+ // see: https://github.com/sveltejs/svelte-eslint-parser/issues/557
+ if (!hasExportDeclaration(result.ast)) {
+ appendDummyExport(ctx);
+ }
+
ctx.appendOriginalToEnd();
return ctx;
@@ -118,6 +124,18 @@ export function analyzeTypeScript(
return ctx;
}
+function hasExportDeclaration(ast: TSESParseForESLintResult["ast"]): boolean {
+ for (const node of ast.body) {
+ if (
+ node.type === "ExportNamedDeclaration" ||
+ node.type === "ExportDefaultDeclaration"
+ ) {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Analyze the store reference names.
* Insert type definitions code to provide correct type information for variables that begin with `$`.
@@ -319,6 +337,34 @@ function analyzeDollarDollarVariables(
}
}
+/** Append dummy export */
+function appendDummyExport(ctx: VirtualTypeScriptContext) {
+ ctx.appendVirtualScript(`export namespace SvelteEslintParserModuleMarker {}`);
+ ctx.restoreContext.addRestoreStatementProcess((node, result) => {
+ if (
+ node.type !== "ExportNamedDeclaration" ||
+ node.declaration?.type !== "TSModuleDeclaration" ||
+ node.declaration.kind !== "namespace" ||
+ node.declaration.id.type !== "Identifier" ||
+ node.declaration.id.name !== "SvelteEslintParserModuleMarker"
+ ) {
+ return false;
+ }
+ const program = result.ast;
+ program.body.splice(program.body.indexOf(node), 1);
+
+ const scopeManager = result.scopeManager as ScopeManager;
+
+ // Remove `declare` variable
+ removeAllScopeAndVariableAndReference(node, {
+ visitorKeys: result.visitorKeys,
+ scopeManager,
+ });
+
+ return true;
+ });
+}
+
/**
* Analyze Runes.
* Insert type definitions code to provide correct type information for Runes.
@@ -569,24 +615,29 @@ function analyzeRenderScopes(
) {
ctx.appendOriginal(code.script.length);
const renderFunctionName = ctx.generateUniqueId("render");
- ctx.appendVirtualScript(`function ${renderFunctionName}(){`);
+ ctx.appendVirtualScript(`export function ${renderFunctionName}(){`);
ctx.appendOriginal(code.script.length + code.render.length);
ctx.appendVirtualScript(`}`);
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
if (
- node.type !== "FunctionDeclaration" ||
- node.id.name !== renderFunctionName
+ node.type !== "ExportNamedDeclaration" ||
+ node.declaration?.type !== "FunctionDeclaration" ||
+ node.declaration?.id?.name !== renderFunctionName
) {
return false;
}
const program = result.ast;
- program.body.splice(program.body.indexOf(node), 1, ...node.body.body);
- for (const body of node.body.body) {
+ program.body.splice(
+ program.body.indexOf(node),
+ 1,
+ ...node.declaration.body.body,
+ );
+ for (const body of node.declaration.body.body) {
body.parent = program;
}
const scopeManager = result.scopeManager as ScopeManager;
- removeFunctionScope(node, scopeManager);
+ removeFunctionScope(node.declaration, scopeManager);
return true;
});
}
@@ -843,7 +894,7 @@ function transformForReactiveStatement(
const functionId = ctx.generateUniqueId("reactiveStatementScopeFunction");
const originalBody = statement.body;
ctx.appendOriginal(originalBody.range[0]);
- ctx.appendVirtualScript(`function ${functionId}(){`);
+ ctx.appendVirtualScript(`export function ${functionId}(){`);
ctx.appendOriginal(originalBody.range[1]);
ctx.appendVirtualScript(`}`);
ctx.appendOriginal(statement.range[1]);
@@ -854,14 +905,18 @@ function transformForReactiveStatement(
}
const reactiveStatement = node as TSESTree.LabeledStatement;
const body = reactiveStatement.body;
- if (body.type !== "FunctionDeclaration" || body.id.name !== functionId) {
+ if (
+ body.type !== "ExportNamedDeclaration" ||
+ body.declaration?.type !== "FunctionDeclaration" ||
+ body.declaration?.id?.name !== functionId
+ ) {
return false;
}
- reactiveStatement.body = body.body.body[0];
+ reactiveStatement.body = body.declaration.body.body[0];
reactiveStatement.body.parent = reactiveStatement;
const scopeManager = result.scopeManager as ScopeManager;
- removeFunctionScope(body, scopeManager);
+ removeFunctionScope(body.declaration, scopeManager);
return true;
});
}
diff --git a/tests/fixtures/parser/ast/svelte5/ts-$props02-input.svelte b/tests/fixtures/parser/ast/svelte5/ts-$props02-input.svelte
new file mode 100644
index 00000000..5ba2e0a0
--- /dev/null
+++ b/tests/fixtures/parser/ast/svelte5/ts-$props02-input.svelte
@@ -0,0 +1,5 @@
+
+
+{name}
diff --git a/tests/fixtures/parser/ast/svelte5/ts-$props02-output.json b/tests/fixtures/parser/ast/svelte5/ts-$props02-output.json
new file mode 100644
index 00000000..c84ba774
--- /dev/null
+++ b/tests/fixtures/parser/ast/svelte5/ts-$props02-output.json
@@ -0,0 +1,1021 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "SvelteScriptElement",
+ "name": {
+ "type": "SvelteName",
+ "name": "script",
+ "range": [
+ 1,
+ 7
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 1
+ },
+ "end": {
+ "line": 1,
+ "column": 7
+ }
+ }
+ },
+ "startTag": {
+ "type": "SvelteStartTag",
+ "attributes": [
+ {
+ "type": "SvelteAttribute",
+ "key": {
+ "type": "SvelteName",
+ "name": "lang",
+ "range": [
+ 8,
+ 12
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 8
+ },
+ "end": {
+ "line": 1,
+ "column": 12
+ }
+ }
+ },
+ "boolean": false,
+ "value": [
+ {
+ "type": "SvelteLiteral",
+ "value": "ts",
+ "range": [
+ 14,
+ 16
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 14
+ },
+ "end": {
+ "line": 1,
+ "column": 16
+ }
+ }
+ }
+ ],
+ "range": [
+ 8,
+ 17
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 8
+ },
+ "end": {
+ "line": 1,
+ "column": 17
+ }
+ }
+ }
+ ],
+ "selfClosing": false,
+ "range": [
+ 0,
+ 18
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 18
+ }
+ }
+ },
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "kind": "let",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "ObjectPattern",
+ "properties": [
+ {
+ "type": "Property",
+ "kind": "init",
+ "computed": false,
+ "key": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "method": false,
+ "shorthand": true,
+ "value": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ ],
+ "typeAnnotation": {
+ "type": "TSTypeAnnotation",
+ "typeAnnotation": {
+ "type": "TSTypeLiteral",
+ "members": [
+ {
+ "type": "TSPropertySignature",
+ "computed": false,
+ "key": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 37,
+ 41
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 18
+ },
+ "end": {
+ "line": 2,
+ "column": 22
+ }
+ }
+ },
+ "typeAnnotation": {
+ "type": "TSTypeAnnotation",
+ "typeAnnotation": {
+ "type": "TSStringKeyword",
+ "range": [
+ 43,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 24
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ },
+ "range": [
+ 41,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 22
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ },
+ "range": [
+ 37,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 18
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ }
+ ],
+ "range": [
+ 35,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 16
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "range": [
+ 33,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 14
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "range": [
+ 25,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 6
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "init": {
+ "type": "CallExpression",
+ "arguments": [],
+ "callee": {
+ "type": "Identifier",
+ "name": "$props",
+ "range": [
+ 54,
+ 60
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ "optional": false,
+ "range": [
+ 54,
+ 62
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 43
+ }
+ }
+ },
+ "range": [
+ 25,
+ 62
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 6
+ },
+ "end": {
+ "line": 2,
+ "column": 43
+ }
+ }
+ }
+ ],
+ "range": [
+ 21,
+ 63
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 2
+ },
+ "end": {
+ "line": 2,
+ "column": 44
+ }
+ }
+ }
+ ],
+ "endTag": {
+ "type": "SvelteEndTag",
+ "range": [
+ 64,
+ 73
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 0
+ },
+ "end": {
+ "line": 3,
+ "column": 9
+ }
+ }
+ },
+ "range": [
+ 0,
+ 73
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 3,
+ "column": 9
+ }
+ }
+ },
+ {
+ "type": "SvelteText",
+ "value": "\n\n",
+ "range": [
+ 73,
+ 75
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 9
+ },
+ "end": {
+ "line": 5,
+ "column": 0
+ }
+ }
+ },
+ {
+ "type": "SvelteMustacheTag",
+ "kind": "text",
+ "expression": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 76,
+ 80
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 1
+ },
+ "end": {
+ "line": 5,
+ "column": 5
+ }
+ }
+ },
+ "range": [
+ 75,
+ 81
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 0
+ },
+ "end": {
+ "line": 5,
+ "column": 6
+ }
+ }
+ }
+ ],
+ "sourceType": "module",
+ "comments": [],
+ "tokens": [
+ {
+ "type": "Punctuator",
+ "value": "<",
+ "range": [
+ 0,
+ 1
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 1
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "script",
+ "range": [
+ 1,
+ 7
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 1
+ },
+ "end": {
+ "line": 1,
+ "column": 7
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "lang",
+ "range": [
+ 8,
+ 12
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 8
+ },
+ "end": {
+ "line": 1,
+ "column": 12
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 12,
+ 13
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 12
+ },
+ "end": {
+ "line": 1,
+ "column": 13
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 13,
+ 14
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 13
+ },
+ "end": {
+ "line": 1,
+ "column": 14
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "ts",
+ "range": [
+ 14,
+ 16
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 14
+ },
+ "end": {
+ "line": 1,
+ "column": 16
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 16,
+ 17
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 16
+ },
+ "end": {
+ "line": 1,
+ "column": 17
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ">",
+ "range": [
+ 17,
+ 18
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 17
+ },
+ "end": {
+ "line": 1,
+ "column": 18
+ }
+ }
+ },
+ {
+ "type": "Keyword",
+ "value": "let",
+ "range": [
+ 21,
+ 24
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 2
+ },
+ "end": {
+ "line": 2,
+ "column": 5
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "{",
+ "range": [
+ 25,
+ 26
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 6
+ },
+ "end": {
+ "line": 2,
+ "column": 7
+ }
+ }
+ },
+ {
+ "type": "Identifier",
+ "value": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "}",
+ "range": [
+ 32,
+ 33
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 13
+ },
+ "end": {
+ "line": 2,
+ "column": 14
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ":",
+ "range": [
+ 33,
+ 34
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 14
+ },
+ "end": {
+ "line": 2,
+ "column": 15
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "{",
+ "range": [
+ 35,
+ 36
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 16
+ },
+ "end": {
+ "line": 2,
+ "column": 17
+ }
+ }
+ },
+ {
+ "type": "Identifier",
+ "value": "name",
+ "range": [
+ 37,
+ 41
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 18
+ },
+ "end": {
+ "line": 2,
+ "column": 22
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ":",
+ "range": [
+ 41,
+ 42
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 22
+ },
+ "end": {
+ "line": 2,
+ "column": 23
+ }
+ }
+ },
+ {
+ "type": "Identifier",
+ "value": "string",
+ "range": [
+ 43,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 24
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "}",
+ "range": [
+ 50,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 31
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 52,
+ 53
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 33
+ },
+ "end": {
+ "line": 2,
+ "column": 34
+ }
+ }
+ },
+ {
+ "type": "Identifier",
+ "value": "$props",
+ "range": [
+ 54,
+ 60
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "(",
+ "range": [
+ 60,
+ 61
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 41
+ },
+ "end": {
+ "line": 2,
+ "column": 42
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ")",
+ "range": [
+ 61,
+ 62
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 42
+ },
+ "end": {
+ "line": 2,
+ "column": 43
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ";",
+ "range": [
+ 62,
+ 63
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 43
+ },
+ "end": {
+ "line": 2,
+ "column": 44
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "<",
+ "range": [
+ 64,
+ 65
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 0
+ },
+ "end": {
+ "line": 3,
+ "column": 1
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "/",
+ "range": [
+ 65,
+ 66
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 1
+ },
+ "end": {
+ "line": 3,
+ "column": 2
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "script",
+ "range": [
+ 66,
+ 72
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 2
+ },
+ "end": {
+ "line": 3,
+ "column": 8
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ">",
+ "range": [
+ 72,
+ 73
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 8
+ },
+ "end": {
+ "line": 3,
+ "column": 9
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "\n\n",
+ "range": [
+ 73,
+ 75
+ ],
+ "loc": {
+ "start": {
+ "line": 3,
+ "column": 9
+ },
+ "end": {
+ "line": 5,
+ "column": 0
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "{",
+ "range": [
+ 75,
+ 76
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 0
+ },
+ "end": {
+ "line": 5,
+ "column": 1
+ }
+ }
+ },
+ {
+ "type": "Identifier",
+ "value": "name",
+ "range": [
+ 76,
+ 80
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 1
+ },
+ "end": {
+ "line": 5,
+ "column": 5
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "}",
+ "range": [
+ 80,
+ 81
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 5
+ },
+ "end": {
+ "line": 5,
+ "column": 6
+ }
+ }
+ }
+ ],
+ "range": [
+ 0,
+ 82
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 6,
+ "column": 0
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/fixtures/parser/ast/svelte5/ts-$props02-prefer-const-result.json b/tests/fixtures/parser/ast/svelte5/ts-$props02-prefer-const-result.json
new file mode 100644
index 00000000..9f2b37ad
--- /dev/null
+++ b/tests/fixtures/parser/ast/svelte5/ts-$props02-prefer-const-result.json
@@ -0,0 +1,8 @@
+[
+ {
+ "ruleId": "prefer-const",
+ "code": "name",
+ "line": 2,
+ "column": 9
+ }
+]
\ No newline at end of file
diff --git a/tests/fixtures/parser/ast/svelte5/ts-$props02-requirements.json b/tests/fixtures/parser/ast/svelte5/ts-$props02-requirements.json
new file mode 100644
index 00000000..14189c9d
--- /dev/null
+++ b/tests/fixtures/parser/ast/svelte5/ts-$props02-requirements.json
@@ -0,0 +1,8 @@
+{
+ "test": {
+ "@typescript-eslint/parser": ">=6.5.0"
+ },
+ "scope": {
+ "@typescript-eslint/parser": ">=6.5.0"
+ }
+}
diff --git a/tests/fixtures/parser/ast/svelte5/ts-$props02-scope-output.json b/tests/fixtures/parser/ast/svelte5/ts-$props02-scope-output.json
new file mode 100644
index 00000000..e158999e
--- /dev/null
+++ b/tests/fixtures/parser/ast/svelte5/ts-$props02-scope-output.json
@@ -0,0 +1,593 @@
+{
+ "type": "global",
+ "variables": [
+ {
+ "name": "$$slots",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$$props",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$$restProps",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$state",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$derived",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$effect",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$props",
+ "identifiers": [],
+ "defs": [],
+ "references": [
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "$props",
+ "range": [
+ 54,
+ 60
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ "from": "module",
+ "init": null,
+ "resolved": null
+ }
+ ]
+ },
+ {
+ "name": "$bindable",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$inspect",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$host",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ }
+ ],
+ "references": [],
+ "childScopes": [
+ {
+ "type": "module",
+ "variables": [
+ {
+ "name": "name",
+ "identifiers": [
+ {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ ],
+ "defs": [
+ {
+ "type": "Variable",
+ "name": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "node": {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "ObjectPattern",
+ "properties": [
+ {
+ "type": "Property",
+ "kind": "init",
+ "computed": false,
+ "key": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "method": false,
+ "shorthand": true,
+ "value": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ ],
+ "typeAnnotation": {
+ "type": "TSTypeAnnotation",
+ "typeAnnotation": {
+ "type": "TSTypeLiteral",
+ "members": [
+ {
+ "type": "TSPropertySignature",
+ "computed": false,
+ "key": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 37,
+ 41
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 18
+ },
+ "end": {
+ "line": 2,
+ "column": 22
+ }
+ }
+ },
+ "typeAnnotation": {
+ "type": "TSTypeAnnotation",
+ "typeAnnotation": {
+ "type": "TSStringKeyword",
+ "range": [
+ 43,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 24
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ },
+ "range": [
+ 41,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 22
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ },
+ "range": [
+ 37,
+ 49
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 18
+ },
+ "end": {
+ "line": 2,
+ "column": 30
+ }
+ }
+ }
+ ],
+ "range": [
+ 35,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 16
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "range": [
+ 33,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 14
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "range": [
+ 25,
+ 51
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 6
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "init": {
+ "type": "CallExpression",
+ "arguments": [],
+ "callee": {
+ "type": "Identifier",
+ "name": "$props",
+ "range": [
+ 54,
+ 60
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ "optional": false,
+ "range": [
+ 54,
+ 62
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 43
+ }
+ }
+ },
+ "range": [
+ 25,
+ 62
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 6
+ },
+ "end": {
+ "line": 2,
+ "column": 43
+ }
+ }
+ }
+ }
+ ],
+ "references": [
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "from": "module",
+ "init": true,
+ "resolved": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ },
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 76,
+ 80
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 1
+ },
+ "end": {
+ "line": 5,
+ "column": 5
+ }
+ }
+ },
+ "from": "module",
+ "init": null,
+ "resolved": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ },
+ "from": "module",
+ "init": true,
+ "resolved": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ },
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "$props",
+ "range": [
+ 54,
+ 60
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ "from": "module",
+ "init": null,
+ "resolved": null
+ },
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 76,
+ 80
+ ],
+ "loc": {
+ "start": {
+ "line": 5,
+ "column": 1
+ },
+ "end": {
+ "line": 5,
+ "column": 5
+ }
+ }
+ },
+ "from": "module",
+ "init": null,
+ "resolved": {
+ "type": "Identifier",
+ "name": "name",
+ "range": [
+ 27,
+ 31
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 8
+ },
+ "end": {
+ "line": 2,
+ "column": 12
+ }
+ }
+ }
+ }
+ ],
+ "childScopes": [],
+ "through": [
+ {
+ "identifier": {
+ "type": "Identifier",
+ "name": "$props",
+ "range": [
+ 54,
+ 60
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 35
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ "from": "module",
+ "init": null,
+ "resolved": null
+ }
+ ]
+ }
+ ],
+ "through": []
+}
\ No newline at end of file
diff --git a/tests/fixtures/parser/ast/svelte5/ts-$props02-type-output.svelte b/tests/fixtures/parser/ast/svelte5/ts-$props02-type-output.svelte
new file mode 100644
index 00000000..82485298
--- /dev/null
+++ b/tests/fixtures/parser/ast/svelte5/ts-$props02-type-output.svelte
@@ -0,0 +1,5 @@
+
+
+{name}