Skip to content

Commit

Permalink
feat: add support for $bindable() scope analysis (#527)
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi authored Jun 10, 2024
1 parent 7124bff commit d92287d
Show file tree
Hide file tree
Showing 15 changed files with 2,639 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .changeset/kind-houses-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-eslint-parser": minor
---

feat: add support for `$bindable()` scope analysis
82 changes: 69 additions & 13 deletions src/parser/analyze-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ESTree.Pattern> {
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;
Expand Down
2 changes: 1 addition & 1 deletion src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions tests/fixtures/parser/ast/svelte5/$bindable-used-input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
let { b = $bindable() } = $props();
function handler() {
b++;
}
</script>

<button onclick={handler}>Click Me!</button>
Loading

0 comments on commit d92287d

Please sign in to comment.