diff --git a/.changeset/mighty-files-hammer.md b/.changeset/mighty-files-hammer.md new file mode 100644 index 0000000000..889e3482d3 --- /dev/null +++ b/.changeset/mighty-files-hammer.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: throw validation error when binding to each argument in runes mode diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 6588e71d97..9ecd141416 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -207,7 +207,8 @@ const runes = { /** @param {string} name */ 'invalid-runes-mode-import': (name) => `${name} cannot be used in runes mode`, 'duplicate-props-rune': () => `Cannot use $props() more than once`, - 'invalid-each-assignment': () => `Cannot reassign each block argument in runes mode` + 'invalid-each-assignment': () => + `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')` }; /** @satisfies {Errors} */ diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index ca6bc00efe..8af0a29402 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -1,5 +1,5 @@ import { error } from '../../errors.js'; -import { extract_identifiers, get_parent, is_text_attribute } from '../../utils/ast.js'; +import { extract_identifiers, get_parent, is_text_attribute, object } from '../../utils/ast.js'; import { warn } from '../../warnings.js'; import fuzzymatch from '../1-parse/utils/fuzzymatch.js'; import { disallowed_parapgraph_contents, interactive_elements } from '../1-parse/utils/html.js'; @@ -341,13 +341,9 @@ const validation = { validate_no_const_assignment(node, node.expression, context.state.scope, true); const assignee = node.expression; - let left = assignee; + const left = object(assignee); - while (left.type === 'MemberExpression') { - left = /** @type {import('estree').MemberExpression} */ (left.object); - } - - if (left.type !== 'Identifier') { + if (left === null) { error(node, 'invalid-binding-expression'); } @@ -373,6 +369,10 @@ const validation = { error(node.expression, 'invalid-derived-binding'); } + if (context.state.analysis.runes && binding.kind === 'each') { + error(node, 'invalid-each-assignment'); + } + // TODO handle mutations of non-state/props in runes mode } diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js new file mode 100644 index 0000000000..55eb0280ae --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'invalid-each-assignment', + message: + "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')" + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/main.svelte new file mode 100644 index 0000000000..abf6d202a7 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/main.svelte @@ -0,0 +1,7 @@ + + +{#each arr as value} + +{/each} diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js index eee6ca5c8d..55eb0280ae 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js @@ -3,6 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'invalid-each-assignment', - message: 'Cannot reassign each block argument in runes mode' + message: + "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')" } }); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/main.svelte index f9744c08de..41999d53bb 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/main.svelte +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/main.svelte @@ -3,5 +3,5 @@ {#each arr as value} - + {/each}