diff --git a/.changeset/kind-houses-work.md b/.changeset/kind-houses-work.md new file mode 100644 index 00000000..8bd55045 --- /dev/null +++ b/.changeset/kind-houses-work.md @@ -0,0 +1,5 @@ +--- +"svelte-eslint-parser": minor +--- + +feat: add support for `$bindable()` scope analysis diff --git a/src/parser/analyze-scope.ts b/src/parser/analyze-scope.ts index 3731cf8d..12bd2a4c 100644 --- a/src/parser/analyze-scope.ts +++ b/src/parser/analyze-scope.ts @@ -169,26 +169,82 @@ export function analyzePropsScope( } for (const node of body.body) { - if (node.type !== "ExportNamedDeclaration") { - continue; - } - if (node.declaration) { - if (node.declaration.type === "VariableDeclaration") { - for (const decl of node.declaration.declarations) { - if (decl.id.type === "Identifier") { - addPropsReference(decl.id, moduleScope); + if (node.type === "ExportNamedDeclaration") { + // Process for Svelte v4 style props. e.g. `export let x`; + if (node.declaration) { + if (node.declaration.type === "VariableDeclaration") { + for (const decl of node.declaration.declarations) { + for (const pattern of extractPattern(decl.id)) { + if (pattern.type === "Identifier") { + addPropReference(pattern, moduleScope); + } + } + } + } + } else { + for (const spec of node.specifiers) { + addPropReference(spec.local, moduleScope); + } + } + } else if (node.type === "VariableDeclaration") { + // Process for Svelte v5 Runes props. e.g. `let { x = $bindable() } = $props()`; + for (const decl of node.declarations) { + if ( + decl.init?.type === "CallExpression" && + decl.init.callee.type === "Identifier" && + decl.init.callee.name === "$props" && + decl.id.type === "ObjectPattern" + ) { + for (const pattern of extractPattern(decl.id)) { + if ( + pattern.type === "AssignmentPattern" && + pattern.left.type === "Identifier" && + pattern.right.type === "CallExpression" && + pattern.right.callee.type === "Identifier" && + pattern.right.callee.name === "$bindable" + ) { + addPropReference(pattern.left, moduleScope); + } } } } - } else { - for (const spec of node.specifiers) { - addPropsReference(spec.local, moduleScope); + } + } + + function* extractPattern(node: ESTree.Pattern): Iterable { + yield node; + if (node.type === "Identifier") { + return; + } + if (node.type === "ObjectPattern") { + for (const prop of node.properties) { + if (prop.type === "Property") { + yield* extractPattern(prop.value); + } else { + yield* extractPattern(prop); + } + } + return; + } + if (node.type === "ArrayPattern") { + for (const elem of node.elements) { + if (elem) { + yield* extractPattern(elem); + } } + return; + } + if (node.type === "AssignmentPattern") { + yield* extractPattern(node.left); + return; + } + if (node.type === "RestElement") { + yield* extractPattern(node.argument); } } - /** Add virtual props reference */ - function addPropsReference(node: ESTree.Identifier, scope: Scope) { + /** Add virtual prop reference */ + function addPropReference(node: ESTree.Identifier, scope: Scope) { for (const variable of scope.variables) { if (variable.name !== node.name) { continue; diff --git a/src/parser/index.ts b/src/parser/index.ts index 34c75371..0a8cdf1c 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -138,7 +138,7 @@ function parseAsSvelte( analyzeStoreScope(resultScript.scopeManager!); analyzeReactiveScope(resultScript.scopeManager!); analyzeStoreScope(resultScript.scopeManager!); // for reactive vars - analyzeSnippetsScope(ctx.snippets, resultScript.scopeManager!); // for reactive vars + analyzeSnippetsScope(ctx.snippets, resultScript.scopeManager!); // Add $$xxx variable addGlobalVariables(resultScript.scopeManager!, globals); diff --git a/tests/fixtures/parser/ast/svelte5/$bindable-used-input.svelte b/tests/fixtures/parser/ast/svelte5/$bindable-used-input.svelte new file mode 100644 index 00000000..280d18f6 --- /dev/null +++ b/tests/fixtures/parser/ast/svelte5/$bindable-used-input.svelte @@ -0,0 +1,9 @@ + + + diff --git a/tests/fixtures/parser/ast/svelte5/$bindable-used-output.json b/tests/fixtures/parser/ast/svelte5/$bindable-used-output.json new file mode 100644 index 00000000..f1c51781 --- /dev/null +++ b/tests/fixtures/parser/ast/svelte5/$bindable-used-output.json @@ -0,0 +1,1407 @@ +{ + "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": [], + "selfClosing": false, + "range": [ + 0, + 8 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 8 + } + } + }, + "body": [ + { + "type": "VariableDeclaration", + "kind": "let", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "ObjectPattern", + "properties": [ + { + "type": "Property", + "kind": "init", + "computed": false, + "key": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "method": false, + "shorthand": true, + "value": { + "type": "AssignmentPattern", + "left": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "right": { + "type": "CallExpression", + "arguments": [], + "callee": { + "type": "Identifier", + "name": "$bindable", + "range": [ + 20, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "optional": false, + "range": [ + 20, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "range": [ + 16, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "range": [ + 16, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 22 + } + } + } + ], + "range": [ + 14, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 24 + } + } + }, + "init": { + "type": "CallExpression", + "arguments": [], + "callee": { + "type": "Identifier", + "name": "$props", + "range": [ + 36, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + "optional": false, + "range": [ + 36, + 44 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 35 + } + } + }, + "range": [ + 14, + 44 + ], + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 35 + } + } + } + ], + "range": [ + 10, + 45 + ], + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 36 + } + } + }, + { + "type": "FunctionDeclaration", + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "UpdateExpression", + "argument": { + "type": "Identifier", + "name": "b", + "range": [ + 71, + 72 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + } + }, + "operator": "++", + "prefix": false, + "range": [ + 71, + 74 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 5 + } + } + }, + "range": [ + 71, + 75 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 6 + } + } + } + ], + "range": [ + 67, + 78 + ], + "loc": { + "start": { + "line": 4, + "column": 20 + }, + "end": { + "line": 6, + "column": 2 + } + } + }, + "expression": false, + "generator": false, + "id": { + "type": "Identifier", + "name": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + }, + "params": [], + "range": [ + 48, + 78 + ], + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 6, + "column": 2 + } + } + } + ], + "endTag": { + "type": "SvelteEndTag", + "range": [ + 79, + 88 + ], + "loc": { + "start": { + "line": 7, + "column": 0 + }, + "end": { + "line": 7, + "column": 9 + } + } + }, + "range": [ + 0, + 88 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 7, + "column": 9 + } + } + }, + { + "type": "SvelteText", + "value": "\n\n", + "range": [ + 88, + 90 + ], + "loc": { + "start": { + "line": 7, + "column": 9 + }, + "end": { + "line": 9, + "column": 0 + } + } + }, + { + "type": "SvelteElement", + "kind": "html", + "name": { + "type": "SvelteName", + "name": "button", + "range": [ + 91, + 97 + ], + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 9, + "column": 7 + } + } + }, + "startTag": { + "type": "SvelteStartTag", + "attributes": [ + { + "type": "SvelteAttribute", + "key": { + "type": "SvelteName", + "name": "onclick", + "range": [ + 98, + 105 + ], + "loc": { + "start": { + "line": 9, + "column": 8 + }, + "end": { + "line": 9, + "column": 15 + } + } + }, + "boolean": false, + "value": [ + { + "type": "SvelteMustacheTag", + "kind": "text", + "expression": { + "type": "Identifier", + "name": "handler", + "range": [ + 107, + 114 + ], + "loc": { + "start": { + "line": 9, + "column": 17 + }, + "end": { + "line": 9, + "column": 24 + } + } + }, + "range": [ + 106, + 115 + ], + "loc": { + "start": { + "line": 9, + "column": 16 + }, + "end": { + "line": 9, + "column": 25 + } + } + } + ], + "range": [ + 98, + 115 + ], + "loc": { + "start": { + "line": 9, + "column": 8 + }, + "end": { + "line": 9, + "column": 25 + } + } + } + ], + "selfClosing": false, + "range": [ + 90, + 116 + ], + "loc": { + "start": { + "line": 9, + "column": 0 + }, + "end": { + "line": 9, + "column": 26 + } + } + }, + "children": [ + { + "type": "SvelteText", + "value": "Click Me!", + "range": [ + 116, + 125 + ], + "loc": { + "start": { + "line": 9, + "column": 26 + }, + "end": { + "line": 9, + "column": 35 + } + } + } + ], + "endTag": { + "type": "SvelteEndTag", + "range": [ + 125, + 134 + ], + "loc": { + "start": { + "line": 9, + "column": 35 + }, + "end": { + "line": 9, + "column": 44 + } + } + }, + "range": [ + 90, + 134 + ], + "loc": { + "start": { + "line": 9, + "column": 0 + }, + "end": { + "line": 9, + "column": 44 + } + } + } + ], + "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": "Punctuator", + "value": ">", + "range": [ + 7, + 8 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + } + }, + { + "type": "Keyword", + "value": "let", + "range": [ + 10, + 13 + ], + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 4 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 6 + } + } + }, + { + "type": "Identifier", + "value": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + { + "type": "Punctuator", + "value": "=", + "range": [ + 18, + 19 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + } + }, + { + "type": "Identifier", + "value": "$bindable", + "range": [ + 20, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 21 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 30, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 32, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 23 + }, + "end": { + "line": 2, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": "=", + "range": [ + 34, + 35 + ], + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 26 + } + } + }, + { + "type": "Identifier", + "value": "$props", + "range": [ + 36, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 42, + 43 + ], + "loc": { + "start": { + "line": 2, + "column": 33 + }, + "end": { + "line": 2, + "column": 34 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 43, + 44 + ], + "loc": { + "start": { + "line": 2, + "column": 34 + }, + "end": { + "line": 2, + "column": 35 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 44, + 45 + ], + "loc": { + "start": { + "line": 2, + "column": 35 + }, + "end": { + "line": 2, + "column": 36 + } + } + }, + { + "type": "Keyword", + "value": "function", + "range": [ + 48, + 56 + ], + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 4, + "column": 9 + } + } + }, + { + "type": "Identifier", + "value": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 64, + 65 + ], + "loc": { + "start": { + "line": 4, + "column": 17 + }, + "end": { + "line": 4, + "column": 18 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 65, + 66 + ], + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 19 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 67, + 68 + ], + "loc": { + "start": { + "line": 4, + "column": 20 + }, + "end": { + "line": 4, + "column": 21 + } + } + }, + { + "type": "Identifier", + "value": "b", + "range": [ + 71, + 72 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + } + }, + { + "type": "Punctuator", + "value": "++", + "range": [ + 72, + 74 + ], + "loc": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 5 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 74, + 75 + ], + "loc": { + "start": { + "line": 5, + "column": 5 + }, + "end": { + "line": 5, + "column": 6 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 77, + 78 + ], + "loc": { + "start": { + "line": 6, + "column": 1 + }, + "end": { + "line": 6, + "column": 2 + } + } + }, + { + "type": "Punctuator", + "value": "<", + "range": [ + 79, + 80 + ], + "loc": { + "start": { + "line": 7, + "column": 0 + }, + "end": { + "line": 7, + "column": 1 + } + } + }, + { + "type": "Punctuator", + "value": "/", + "range": [ + 80, + 81 + ], + "loc": { + "start": { + "line": 7, + "column": 1 + }, + "end": { + "line": 7, + "column": 2 + } + } + }, + { + "type": "HTMLIdentifier", + "value": "script", + "range": [ + 81, + 87 + ], + "loc": { + "start": { + "line": 7, + "column": 2 + }, + "end": { + "line": 7, + "column": 8 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 87, + 88 + ], + "loc": { + "start": { + "line": 7, + "column": 8 + }, + "end": { + "line": 7, + "column": 9 + } + } + }, + { + "type": "HTMLText", + "value": "\n\n", + "range": [ + 88, + 90 + ], + "loc": { + "start": { + "line": 7, + "column": 9 + }, + "end": { + "line": 9, + "column": 0 + } + } + }, + { + "type": "Punctuator", + "value": "<", + "range": [ + 90, + 91 + ], + "loc": { + "start": { + "line": 9, + "column": 0 + }, + "end": { + "line": 9, + "column": 1 + } + } + }, + { + "type": "HTMLIdentifier", + "value": "button", + "range": [ + 91, + 97 + ], + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 9, + "column": 7 + } + } + }, + { + "type": "HTMLIdentifier", + "value": "onclick", + "range": [ + 98, + 105 + ], + "loc": { + "start": { + "line": 9, + "column": 8 + }, + "end": { + "line": 9, + "column": 15 + } + } + }, + { + "type": "Punctuator", + "value": "=", + "range": [ + 105, + 106 + ], + "loc": { + "start": { + "line": 9, + "column": 15 + }, + "end": { + "line": 9, + "column": 16 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 106, + 107 + ], + "loc": { + "start": { + "line": 9, + "column": 16 + }, + "end": { + "line": 9, + "column": 17 + } + } + }, + { + "type": "Identifier", + "value": "handler", + "range": [ + 107, + 114 + ], + "loc": { + "start": { + "line": 9, + "column": 17 + }, + "end": { + "line": 9, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 114, + 115 + ], + "loc": { + "start": { + "line": 9, + "column": 24 + }, + "end": { + "line": 9, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 115, + 116 + ], + "loc": { + "start": { + "line": 9, + "column": 25 + }, + "end": { + "line": 9, + "column": 26 + } + } + }, + { + "type": "HTMLText", + "value": "Click", + "range": [ + 116, + 121 + ], + "loc": { + "start": { + "line": 9, + "column": 26 + }, + "end": { + "line": 9, + "column": 31 + } + } + }, + { + "type": "HTMLText", + "value": " ", + "range": [ + 121, + 122 + ], + "loc": { + "start": { + "line": 9, + "column": 31 + }, + "end": { + "line": 9, + "column": 32 + } + } + }, + { + "type": "HTMLText", + "value": "Me!", + "range": [ + 122, + 125 + ], + "loc": { + "start": { + "line": 9, + "column": 32 + }, + "end": { + "line": 9, + "column": 35 + } + } + }, + { + "type": "Punctuator", + "value": "<", + "range": [ + 125, + 126 + ], + "loc": { + "start": { + "line": 9, + "column": 35 + }, + "end": { + "line": 9, + "column": 36 + } + } + }, + { + "type": "Punctuator", + "value": "/", + "range": [ + 126, + 127 + ], + "loc": { + "start": { + "line": 9, + "column": 36 + }, + "end": { + "line": 9, + "column": 37 + } + } + }, + { + "type": "HTMLIdentifier", + "value": "button", + "range": [ + 127, + 133 + ], + "loc": { + "start": { + "line": 9, + "column": 37 + }, + "end": { + "line": 9, + "column": 43 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 133, + 134 + ], + "loc": { + "start": { + "line": 9, + "column": 43 + }, + "end": { + "line": 9, + "column": 44 + } + } + } + ], + "range": [ + 0, + 135 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 10, + "column": 0 + } + } +} \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/$bindable-used-scope-output.json b/tests/fixtures/parser/ast/svelte5/$bindable-used-scope-output.json new file mode 100644 index 00000000..1745da8f --- /dev/null +++ b/tests/fixtures/parser/ast/svelte5/$bindable-used-scope-output.json @@ -0,0 +1,1028 @@ +{ + "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": [ + 36, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + "from": "module", + "init": null, + "resolved": null + } + ] + }, + { + "name": "$bindable", + "identifiers": [], + "defs": [], + "references": [ + { + "identifier": { + "type": "Identifier", + "name": "$bindable", + "range": [ + 20, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "from": "module", + "init": null, + "resolved": null + } + ] + }, + { + "name": "$inspect", + "identifiers": [], + "defs": [], + "references": [] + }, + { + "name": "$host", + "identifiers": [], + "defs": [], + "references": [] + } + ], + "references": [], + "childScopes": [ + { + "type": "module", + "variables": [ + { + "name": "b", + "identifiers": [ + { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + ], + "defs": [ + { + "type": "Variable", + "name": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "node": { + "type": "VariableDeclarator", + "id": { + "type": "ObjectPattern", + "properties": [ + { + "type": "Property", + "kind": "init", + "computed": false, + "key": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "method": false, + "shorthand": true, + "value": { + "type": "AssignmentPattern", + "left": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "right": { + "type": "CallExpression", + "arguments": [], + "callee": { + "type": "Identifier", + "name": "$bindable", + "range": [ + 20, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "optional": false, + "range": [ + 20, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "range": [ + 16, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "range": [ + 16, + 31 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 22 + } + } + } + ], + "range": [ + 14, + 33 + ], + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 24 + } + } + }, + "init": { + "type": "CallExpression", + "arguments": [], + "callee": { + "type": "Identifier", + "name": "$props", + "range": [ + 36, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + "optional": false, + "range": [ + 36, + 44 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 35 + } + } + }, + "range": [ + 14, + 44 + ], + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 35 + } + } + } + } + ], + "references": [ + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "from": "module", + "init": true, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + }, + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "from": "module", + "init": true, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + }, + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "from": "module", + "init": null, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + }, + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 71, + 72 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + } + }, + "from": "function", + "init": false, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + } + ] + }, + { + "name": "handler", + "identifiers": [ + { + "type": "Identifier", + "name": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + } + ], + "defs": [ + { + "type": "FunctionName", + "name": { + "type": "Identifier", + "name": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + }, + "node": { + "type": "FunctionDeclaration", + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "UpdateExpression", + "argument": { + "type": "Identifier", + "name": "b", + "range": [ + 71, + 72 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + } + }, + "operator": "++", + "prefix": false, + "range": [ + 71, + 74 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 5 + } + } + }, + "range": [ + 71, + 75 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 6 + } + } + } + ], + "range": [ + 67, + 78 + ], + "loc": { + "start": { + "line": 4, + "column": 20 + }, + "end": { + "line": 6, + "column": 2 + } + } + }, + "expression": false, + "generator": false, + "id": { + "type": "Identifier", + "name": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + }, + "params": [], + "range": [ + 48, + 78 + ], + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 6, + "column": 2 + } + } + } + } + ], + "references": [ + { + "identifier": { + "type": "Identifier", + "name": "handler", + "range": [ + 107, + 114 + ], + "loc": { + "start": { + "line": 9, + "column": 17 + }, + "end": { + "line": 9, + "column": 24 + } + } + }, + "from": "module", + "init": null, + "resolved": { + "type": "Identifier", + "name": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + } + } + ] + } + ], + "references": [ + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "from": "module", + "init": true, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + }, + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + "from": "module", + "init": true, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + }, + { + "identifier": { + "type": "Identifier", + "name": "$bindable", + "range": [ + 20, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "from": "module", + "init": null, + "resolved": null + }, + { + "identifier": { + "type": "Identifier", + "name": "$props", + "range": [ + 36, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + "from": "module", + "init": null, + "resolved": null + }, + { + "identifier": { + "type": "Identifier", + "name": "handler", + "range": [ + 107, + 114 + ], + "loc": { + "start": { + "line": 9, + "column": 17 + }, + "end": { + "line": 9, + "column": 24 + } + } + }, + "from": "module", + "init": null, + "resolved": { + "type": "Identifier", + "name": "handler", + "range": [ + 57, + 64 + ], + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 17 + } + } + } + } + ], + "childScopes": [ + { + "type": "function", + "variables": [ + { + "name": "arguments", + "identifiers": [], + "defs": [], + "references": [] + } + ], + "references": [ + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 71, + 72 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + } + }, + "from": "function", + "init": false, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + } + ], + "childScopes": [], + "through": [ + { + "identifier": { + "type": "Identifier", + "name": "b", + "range": [ + 71, + 72 + ], + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + } + }, + "from": "function", + "init": false, + "resolved": { + "type": "Identifier", + "name": "b", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + } + } + } + ] + } + ], + "through": [ + { + "identifier": { + "type": "Identifier", + "name": "$bindable", + "range": [ + 20, + 29 + ], + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "from": "module", + "init": null, + "resolved": null + }, + { + "identifier": { + "type": "Identifier", + "name": "$props", + "range": [ + 36, + 42 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + "from": "module", + "init": null, + "resolved": null + } + ] + } + ], + "through": [] +} \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-no-unused-vars-result.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-no-unused-vars-result.json deleted file mode 100644 index 5b4d90df..00000000 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-no-unused-vars-result.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "ruleId": "no-unused-vars", - "code": "bindableProp", - "line": 2, - "column": 8 - } -] \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-prefer-const-result.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-prefer-const-result.json deleted file mode 100644 index ecab88c6..00000000 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-prefer-const-result.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "ruleId": "prefer-const", - "code": "bindableProp", - "line": 2, - "column": 8 - } -] \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-scope-output.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-scope-output.json index e12c25b3..de8685a5 100644 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-scope-output.json +++ b/tests/fixtures/parser/ast/svelte5/docs/runes/08-2-$bindable-scope-output.json @@ -424,6 +424,46 @@ } } } + }, + { + "identifier": { + "type": "Identifier", + "name": "bindableProp", + "range": [ + 16, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 19 + } + } + }, + "from": "module", + "init": null, + "resolved": { + "type": "Identifier", + "name": "bindableProp", + "range": [ + 16, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 19 + } + } + } } ] } diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-no-unused-vars-result.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-no-unused-vars-result.json deleted file mode 100644 index 5b4d90df..00000000 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-no-unused-vars-result.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "ruleId": "no-unused-vars", - "code": "bindableProp", - "line": 2, - "column": 8 - } -] \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-prefer-const-result.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-prefer-const-result.json deleted file mode 100644 index ecab88c6..00000000 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-prefer-const-result.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "ruleId": "prefer-const", - "code": "bindableProp", - "line": 2, - "column": 8 - } -] \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-scope-output.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-scope-output.json index 776375d6..a5e835bf 100644 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-scope-output.json +++ b/tests/fixtures/parser/ast/svelte5/docs/runes/08-3-$bindable-scope-output.json @@ -444,6 +444,46 @@ } } } + }, + { + "identifier": { + "type": "Identifier", + "name": "bindableProp", + "range": [ + 16, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 19 + } + } + }, + "from": "module", + "init": null, + "resolved": { + "type": "Identifier", + "name": "bindableProp", + "range": [ + 16, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 19 + } + } + } } ] } diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-no-unused-vars-result.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-no-unused-vars-result.json deleted file mode 100644 index 5b4d90df..00000000 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-no-unused-vars-result.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "ruleId": "no-unused-vars", - "code": "bindableProp", - "line": 2, - "column": 8 - } -] \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-prefer-const-result.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-prefer-const-result.json deleted file mode 100644 index ecab88c6..00000000 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-prefer-const-result.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "ruleId": "prefer-const", - "code": "bindableProp", - "line": 2, - "column": 8 - } -] \ No newline at end of file diff --git a/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-scope-output.json b/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-scope-output.json index 834afcef..ffd1771e 100644 --- a/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-scope-output.json +++ b/tests/fixtures/parser/ast/svelte5/docs/runes/08-4-$bindable-ts-scope-output.json @@ -550,6 +550,46 @@ } } } + }, + { + "identifier": { + "type": "Identifier", + "name": "bindableProp", + "range": [ + 26, + 38 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 19 + } + } + }, + "from": "module", + "init": null, + "resolved": { + "type": "Identifier", + "name": "bindableProp", + "range": [ + 26, + 38 + ], + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 19 + } + } + } } ] }