diff --git a/.changeset/shiny-rats-heal.md b/.changeset/shiny-rats-heal.md new file mode 100644 index 0000000000..8c87fb572f --- /dev/null +++ b/.changeset/shiny-rats-heal.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +feat: add warning when using `$bindable` rune without calling it diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 7d77003c9d..60e0ef46e9 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -1174,6 +1174,15 @@ export const validation_runes = merge(validation, a11y_validators, { } } }, + AssignmentPattern(node, { state, path }) { + if ( + node.right.type === 'Identifier' && + node.right.name === '$bindable' && + !state.scope.get('bindable') + ) { + warn(state.analysis.warnings, node, path, 'invalid-bindable-declaration'); + } + }, // TODO this is a code smell. need to refactor this stuff ClassBody: validation_runes_js.ClassBody, ClassDeclaration: validation_runes_js.ClassDeclaration, diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index 8f0e81d9c0..3e36df1677 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -39,7 +39,9 @@ const runes = { 'derived-iife': () => `Use \`$derived.by(() => {...})\` instead of \`$derived((() => {...})());\``, 'invalid-props-declaration': () => - `Component properties are declared using $props() in runes mode. Did you forget to call the function?` + `Component properties are declared using $props() in runes mode. Did you forget to call the function?`, + 'invalid-bindable-declaration': () => + `Bindable component properties are declared using $bindable() in runes mode. Did you forget to call the function?` }; /** @satisfies {Warnings} */ diff --git a/packages/svelte/tests/validator/samples/runes-bindable-not-called/_config.js b/packages/svelte/tests/validator/samples/runes-bindable-not-called/_config.js new file mode 100644 index 0000000000..f47bee71df --- /dev/null +++ b/packages/svelte/tests/validator/samples/runes-bindable-not-called/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/validator/samples/runes-bindable-not-called/input.svelte b/packages/svelte/tests/validator/samples/runes-bindable-not-called/input.svelte new file mode 100644 index 0000000000..7bf756a603 --- /dev/null +++ b/packages/svelte/tests/validator/samples/runes-bindable-not-called/input.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/validator/samples/runes-bindable-not-called/warnings.json b/packages/svelte/tests/validator/samples/runes-bindable-not-called/warnings.json new file mode 100644 index 0000000000..ebcd065f31 --- /dev/null +++ b/packages/svelte/tests/validator/samples/runes-bindable-not-called/warnings.json @@ -0,0 +1,14 @@ +[ + { + "code": "invalid-bindable-declaration", + "message": "Bindable component properties are declared using $bindable() in runes mode. Did you forget to call the function?", + "start": { + "column": 7, + "line": 2 + }, + "end": { + "column": 20, + "line": 2 + } + } +]