Skip to content

Commit 5d82cf1

Browse files
authored
feat: remove $.unwrap calls from bind:group (#12642)
* add each.metadata.keyed * simplify * feat: remove `$.unwrap` from `bind:group` code * changeset * regenerate types
1 parent 219ba6a commit 5d82cf1

File tree

7 files changed

+30
-19
lines changed

7 files changed

+30
-19
lines changed

.changeset/three-donkeys-jump.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: remove `$.unwrap` calls from `bind:group`

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,13 @@ const common_visitors = {
15471547
},
15481548
RenderTag(node, context) {
15491549
context.next({ ...context.state, render_tag: node });
1550+
},
1551+
EachBlock(node) {
1552+
if (node.key) {
1553+
// treat `{#each items as item, i (i)}` as a normal indexed block, everything else as keyed
1554+
node.metadata.keyed =
1555+
node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index;
1556+
}
15501557
}
15511558
};
15521559

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2409,10 +2409,7 @@ export const template_visitors = {
24092409

24102410
let flags = 0;
24112411

2412-
if (
2413-
node.key &&
2414-
(node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index)
2415-
) {
2412+
if (node.metadata.keyed) {
24162413
flags |= EACH_KEYED;
24172414

24182415
if (node.index) {
@@ -2421,7 +2418,7 @@ export const template_visitors = {
24212418

24222419
// In runes mode, if key === item, we don't need to wrap the item in a source
24232420
const key_is_item =
2424-
node.key.type === 'Identifier' &&
2421+
/** @type {Expression} */ (node.key).type === 'Identifier' &&
24252422
node.context.type === 'Identifier' &&
24262423
node.context.name === node.key.name;
24272424

@@ -2614,8 +2611,11 @@ export const template_visitors = {
26142611
/** @type {Expression} */
26152612
let key_function = b.id('$.index');
26162613

2617-
if (node.key) {
2618-
const expression = /** @type {Expression} */ (context.visit(node.key, key_state));
2614+
if (node.metadata.keyed) {
2615+
const expression = /** @type {Expression} */ (
2616+
context.visit(/** @type {Expression} */ (node.key), key_state)
2617+
);
2618+
26192619
key_function = b.arrow([node.context, index], expression);
26202620
}
26212621

@@ -3049,11 +3049,12 @@ export const template_visitors = {
30493049
call_expr = b.call(`$.bind_focused`, state.node, setter);
30503050
break;
30513051
case 'group': {
3052-
/** @type {CallExpression[]} */
3053-
const indexes = [];
3054-
for (const parent_each_block of node.metadata.parent_each_blocks) {
3055-
indexes.push(b.call('$.unwrap', parent_each_block.metadata.index));
3056-
}
3052+
const indexes = node.metadata.parent_each_blocks.map((each) => {
3053+
// if we have a keyed block with an index, the index is wrapped in a source
3054+
return each.metadata.keyed && each.index
3055+
? b.call('$.get', each.metadata.index)
3056+
: each.metadata.index;
3057+
});
30573058

30583059
// We need to additionally invoke the value attribute signal to register it as a dependency,
30593060
// so that when the value is updated, the group binding is updated

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
592592
}
593593

594594
node.metadata = {
595+
keyed: false,
595596
contains_group_binding: false,
596597
array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null,
597598
index: scope.root.unique('$$index'),

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ export interface EachBlock extends BaseNode {
393393
index?: string;
394394
key?: Expression;
395395
metadata: {
396+
keyed: boolean;
396397
contains_group_binding: boolean;
397398
/** Set if something in the array expression is shadowed within the each block */
398399
array_name: Identifier | null;

packages/svelte/src/internal/client/dom/elements/bindings/input.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,8 @@ export function bind_group(inputs, group_index, input, get_value, update) {
7373

7474
if (group_index !== null) {
7575
for (var index of group_index) {
76-
var group = binding_group;
77-
// @ts-ignore
78-
binding_group = group[index];
79-
if (binding_group === undefined) {
80-
// @ts-ignore
81-
binding_group = group[index] = [];
82-
}
76+
// @ts-expect-error
77+
binding_group = binding_group[index] ??= [];
8378
}
8479
}
8580

packages/svelte/types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,7 @@ declare module 'svelte/compiler' {
18451845
index?: string;
18461846
key?: Expression;
18471847
metadata: {
1848+
keyed: boolean;
18481849
contains_group_binding: boolean;
18491850
/** Set if something in the array expression is shadowed within the each block */
18501851
array_name: Identifier | null;

0 commit comments

Comments
 (0)