Skip to content

Commit a092899

Browse files
feat: update error message for snippet binding and assignments (#11168)
* feat: update error message for snippet binding and assignments * make invalid-snippet-assignment apply in non-runes mode too * update tests * update types --------- Co-authored-by: Rich Harris <[email protected]>
1 parent d1976c0 commit a092899

File tree

10 files changed

+51
-8
lines changed

10 files changed

+51
-8
lines changed

.changeset/wicked-wasps-allow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
feat: update error message for snippet binding and assignments

packages/svelte/src/compiler/errors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ const runes = {
214214
'duplicate-props-rune': () => `Cannot use $props() more than once`,
215215
'invalid-each-assignment': () =>
216216
`Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. 'array[i] = value' instead of 'entry = value')`,
217+
'invalid-snippet-assignment': () => `Cannot reassign or bind to snippet parameter`,
217218
'invalid-derived-call': () => `$derived.call(...) has been replaced with $derived.by(...)`,
218219
'conflicting-property-name': () =>
219220
`Cannot have a property and a component export with the same name`

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ const validation = {
352352
if (context.state.analysis.runes && binding.kind === 'each') {
353353
error(node, 'invalid-each-assignment');
354354
}
355+
356+
if (binding.kind === 'snippet') {
357+
error(node, 'invalid-snippet-assignment');
358+
}
355359
}
356360

357361
if (node.name === 'group') {
@@ -1011,14 +1015,21 @@ function validate_no_const_assignment(node, argument, scope, is_binding) {
10111015
function validate_assignment(node, argument, state) {
10121016
validate_no_const_assignment(node, argument, state.scope, false);
10131017

1014-
if (state.analysis.runes && argument.type === 'Identifier') {
1018+
if (argument.type === 'Identifier') {
10151019
const binding = state.scope.get(argument.name);
1016-
if (binding?.kind === 'derived') {
1017-
error(node, 'invalid-derived-assignment');
1020+
1021+
if (state.analysis.runes) {
1022+
if (binding?.kind === 'derived') {
1023+
error(node, 'invalid-derived-assignment');
1024+
}
1025+
1026+
if (binding?.kind === 'each') {
1027+
error(node, 'invalid-each-assignment');
1028+
}
10181029
}
10191030

1020-
if (binding?.kind === 'each') {
1021-
error(node, 'invalid-each-assignment');
1031+
if (binding?.kind === 'snippet') {
1032+
error(node, 'invalid-snippet-assignment');
10221033
}
10231034
}
10241035

packages/svelte/src/compiler/phases/scope.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
649649

650650
for (const param of node.parameters) {
651651
for (const id of extract_identifiers(param)) {
652-
child_scope.declare(id, 'each', 'let');
652+
child_scope.declare(id, 'snippet', 'let');
653653
}
654654
}
655655

packages/svelte/src/compiler/types/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ export interface Binding {
253253
* - `rest_prop`: A rest prop
254254
* - `state`: A state variable
255255
* - `derived`: A derived variable
256-
* - `each`: An each block context variable
256+
* - `each`: An each block parameter
257+
* - `snippet`: A snippet parameter
257258
* - `store_sub`: A $store value
258259
* - `legacy_reactive`: A `$:` declaration
259260
* - `legacy_reactive_import`: An imported binding that is mutated inside the component
@@ -267,6 +268,7 @@ export interface Binding {
267268
| 'frozen_state'
268269
| 'derived'
269270
| 'each'
271+
| 'snippet'
270272
| 'store_sub'
271273
| 'legacy_reactive'
272274
| 'legacy_reactive_import';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'invalid-snippet-assignment',
6+
message: 'Cannot reassign or bind to snippet parameter'
7+
}
8+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{#snippet foo(value)}
2+
<input bind:value={value}>
3+
{/snippet}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'invalid-snippet-assignment',
6+
message: 'Cannot reassign or bind to snippet parameter'
7+
}
8+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{#snippet foo(value)}
2+
<button onclick={() => value += 1}>click</button>
3+
{/snippet}

packages/svelte/types/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,8 @@ declare module 'svelte/compiler' {
718718
* - `rest_prop`: A rest prop
719719
* - `state`: A state variable
720720
* - `derived`: A derived variable
721-
* - `each`: An each block context variable
721+
* - `each`: An each block parameter
722+
* - `snippet`: A snippet parameter
722723
* - `store_sub`: A $store value
723724
* - `legacy_reactive`: A `$:` declaration
724725
* - `legacy_reactive_import`: An imported binding that is mutated inside the component
@@ -732,6 +733,7 @@ declare module 'svelte/compiler' {
732733
| 'frozen_state'
733734
| 'derived'
734735
| 'each'
736+
| 'snippet'
735737
| 'store_sub'
736738
| 'legacy_reactive'
737739
| 'legacy_reactive_import';

0 commit comments

Comments
 (0)