Skip to content

Commit 456cf84

Browse files
authored
fix: throw validation error when binding to each argument in runes mode (#10441)
closes #10437
1 parent 49bfb6b commit 456cf84

File tree

7 files changed

+33
-10
lines changed

7 files changed

+33
-10
lines changed

.changeset/mighty-files-hammer.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: throw validation error when binding to each argument in runes mode

packages/svelte/src/compiler/errors.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ const runes = {
207207
/** @param {string} name */
208208
'invalid-runes-mode-import': (name) => `${name} cannot be used in runes mode`,
209209
'duplicate-props-rune': () => `Cannot use $props() more than once`,
210-
'invalid-each-assignment': () => `Cannot reassign each block argument in runes mode`
210+
'invalid-each-assignment': () =>
211+
`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')`
211212
};
212213

213214
/** @satisfies {Errors} */

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { error } from '../../errors.js';
2-
import { extract_identifiers, get_parent, is_text_attribute } from '../../utils/ast.js';
2+
import { extract_identifiers, get_parent, is_text_attribute, object } from '../../utils/ast.js';
33
import { warn } from '../../warnings.js';
44
import fuzzymatch from '../1-parse/utils/fuzzymatch.js';
55
import { disallowed_parapgraph_contents, interactive_elements } from '../1-parse/utils/html.js';
@@ -341,13 +341,9 @@ const validation = {
341341
validate_no_const_assignment(node, node.expression, context.state.scope, true);
342342

343343
const assignee = node.expression;
344-
let left = assignee;
344+
const left = object(assignee);
345345

346-
while (left.type === 'MemberExpression') {
347-
left = /** @type {import('estree').MemberExpression} */ (left.object);
348-
}
349-
350-
if (left.type !== 'Identifier') {
346+
if (left === null) {
351347
error(node, 'invalid-binding-expression');
352348
}
353349

@@ -373,6 +369,10 @@ const validation = {
373369
error(node.expression, 'invalid-derived-binding');
374370
}
375371

372+
if (context.state.analysis.runes && binding.kind === 'each') {
373+
error(node, 'invalid-each-assignment');
374+
}
375+
376376
// TODO handle mutations of non-state/props in runes mode
377377
}
378378

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'invalid-each-assignment',
6+
message:
7+
"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')"
8+
}
9+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let arr = $state([1,2,3]);
3+
</script>
4+
5+
{#each arr as value}
6+
<input bind:value>
7+
{/each}

packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { test } from '../../test';
33
export default test({
44
error: {
55
code: 'invalid-each-assignment',
6-
message: 'Cannot reassign each block argument in runes mode'
6+
message:
7+
"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')"
78
}
89
});

packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/main.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
</script>
44

55
{#each arr as value}
6-
<button onclick={() => value += 1}>click</button>
6+
<button onclick={() => value += 1}>click</button>
77
{/each}

0 commit comments

Comments
 (0)