fix: make each items reassignable (#12257)

* chore: make each items reassignable

* add failing test

* update test

* transform reassigned getters inside each block

* Update .changeset/thirty-guests-flow.md

* comment

* add note

* tidy up

* Update packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js
main
Rich Harris 1 day ago committed by GitHub
parent f81f4feab8
commit 9e511b141c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: make each items reassignable in legacy mode

@ -186,8 +186,23 @@ export function EachBlock(node, context) {
if (invalidate_store) sequence.push(invalidate_store); if (invalidate_store) sequence.push(invalidate_store);
if (node.context.type === 'Identifier') { if (node.context.type === 'Identifier') {
const binding = /** @type {Binding} */ (context.state.scope.get(node.context.name));
child_state.transform[node.context.name] = { child_state.transform[node.context.name] = {
read: (flags & EACH_ITEM_REACTIVE) !== 0 ? get_value : (node) => node, read: (node) => {
if (binding.reassigned) {
// we need to do `array[$$index]` instead of `$$item` or whatever
// TODO 6.0 this only applies in legacy mode, reassignments are
// forbidden in runes mode
return b.member(
each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection,
index,
true
);
}
return (flags & EACH_ITEM_REACTIVE) !== 0 ? get_value(node) : node;
},
assign: (_, value) => { assign: (_, value) => {
uses_index = true; uses_index = true;

@ -21,7 +21,7 @@ export function EachBlock(node, context) {
state.init.push(b.const(array_id, b.call('$.ensure_array_like', collection))); state.init.push(b.const(array_id, b.call('$.ensure_array_like', collection)));
/** @type {Statement[]} */ /** @type {Statement[]} */
const each = [b.const(/** @type {Pattern} */ (node.context), b.member(array_id, index, true))]; const each = [b.let(/** @type {Pattern} */ (node.context), b.member(array_id, index, true))];
if (index.name !== node.index && node.index != null) { if (index.name !== node.index && node.index != null) {
each.push(b.let(node.index, index)); each.push(b.let(node.index, index));

@ -0,0 +1,7 @@
<script>
export let value;
value += 1;
</script>
<p>{value}</p>

@ -0,0 +1,19 @@
import { test } from '../../test';
export default test({
html: `
<p>2, 3, 4</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>2, 3, 4</p>
`,
ssrHtml: `
<p>1, 2, 3</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>1, 2, 3</p>
`
});

@ -0,0 +1,13 @@
<script>
import Child from './Child.svelte';
let numbers = [1, 2, 3];
</script>
<p>{numbers.join(', ')}</p>
{#each numbers as n}
<Child bind:value={n} />
{/each}
<p>{numbers.join(', ')}</p>

@ -6,7 +6,7 @@ export default function Each_string_template($$payload) {
$$payload.out += `<!--[-->`; $$payload.out += `<!--[-->`;
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
const thing = each_array[$$index]; let thing = each_array[$$index];
$$payload.out += `<!---->${$.escape(thing)}, `; $$payload.out += `<!---->${$.escape(thing)}, `;
} }

Loading…
Cancel
Save