Skip to content

Commit 9e511b1

Browse files
authored
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
1 parent f81f4fe commit 9e511b1

File tree

7 files changed

+62
-3
lines changed

7 files changed

+62
-3
lines changed

.changeset/thirty-guests-flow.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+
fix: make each items reassignable in legacy mode

packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,23 @@ export function EachBlock(node, context) {
186186
if (invalidate_store) sequence.push(invalidate_store);
187187

188188
if (node.context.type === 'Identifier') {
189+
const binding = /** @type {Binding} */ (context.state.scope.get(node.context.name));
190+
189191
child_state.transform[node.context.name] = {
190-
read: (flags & EACH_ITEM_REACTIVE) !== 0 ? get_value : (node) => node,
192+
read: (node) => {
193+
if (binding.reassigned) {
194+
// we need to do `array[$$index]` instead of `$$item` or whatever
195+
// TODO 6.0 this only applies in legacy mode, reassignments are
196+
// forbidden in runes mode
197+
return b.member(
198+
each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection,
199+
index,
200+
true
201+
);
202+
}
203+
204+
return (flags & EACH_ITEM_REACTIVE) !== 0 ? get_value(node) : node;
205+
},
191206
assign: (_, value) => {
192207
uses_index = true;
193208

packages/svelte/src/compiler/phases/3-transform/server/visitors/EachBlock.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function EachBlock(node, context) {
2121
state.init.push(b.const(array_id, b.call('$.ensure_array_like', collection)));
2222

2323
/** @type {Statement[]} */
24-
const each = [b.const(/** @type {Pattern} */ (node.context), b.member(array_id, index, true))];
24+
const each = [b.let(/** @type {Pattern} */ (node.context), b.member(array_id, index, true))];
2525

2626
if (index.name !== node.index && node.index != null) {
2727
each.push(b.let(node.index, index));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
export let value;
3+
4+
value += 1;
5+
</script>
6+
7+
<p>{value}</p>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: `
5+
<p>2, 3, 4</p>
6+
<p>2</p>
7+
<p>3</p>
8+
<p>4</p>
9+
<p>2, 3, 4</p>
10+
`,
11+
12+
ssrHtml: `
13+
<p>1, 2, 3</p>
14+
<p>2</p>
15+
<p>3</p>
16+
<p>4</p>
17+
<p>1, 2, 3</p>
18+
`
19+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
4+
let numbers = [1, 2, 3];
5+
</script>
6+
7+
<p>{numbers.join(', ')}</p>
8+
9+
{#each numbers as n}
10+
<Child bind:value={n} />
11+
{/each}
12+
13+
<p>{numbers.join(', ')}</p>

packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default function Each_string_template($$payload) {
66
$$payload.out += `<!--[-->`;
77

88
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
9-
const thing = each_array[$$index];
9+
let thing = each_array[$$index];
1010

1111
$$payload.out += `<!---->${$.escape(thing)}, `;
1212
}

0 commit comments

Comments
 (0)