feat: remove `$.unwrap` calls from `bind:group` (#12642)

* add each.metadata.keyed

* simplify

* feat: remove `$.unwrap` from `bind:group` code

* changeset

* regenerate types
pull/12641/head
Rich Harris 5 months ago committed by GitHub
parent 219ba6a71b
commit 5d82cf1f03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: remove `$.unwrap` calls from `bind:group`

@ -1547,6 +1547,13 @@ const common_visitors = {
},
RenderTag(node, context) {
context.next({ ...context.state, render_tag: node });
},
EachBlock(node) {
if (node.key) {
// treat `{#each items as item, i (i)}` as a normal indexed block, everything else as keyed
node.metadata.keyed =
node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index;
}
}
};

@ -2409,10 +2409,7 @@ export const template_visitors = {
let flags = 0;
if (
node.key &&
(node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index)
) {
if (node.metadata.keyed) {
flags |= EACH_KEYED;
if (node.index) {
@ -2421,7 +2418,7 @@ export const template_visitors = {
// In runes mode, if key === item, we don't need to wrap the item in a source
const key_is_item =
node.key.type === 'Identifier' &&
/** @type {Expression} */ (node.key).type === 'Identifier' &&
node.context.type === 'Identifier' &&
node.context.name === node.key.name;
@ -2614,8 +2611,11 @@ export const template_visitors = {
/** @type {Expression} */
let key_function = b.id('$.index');
if (node.key) {
const expression = /** @type {Expression} */ (context.visit(node.key, key_state));
if (node.metadata.keyed) {
const expression = /** @type {Expression} */ (
context.visit(/** @type {Expression} */ (node.key), key_state)
);
key_function = b.arrow([node.context, index], expression);
}
@ -3049,11 +3049,12 @@ export const template_visitors = {
call_expr = b.call(`$.bind_focused`, state.node, setter);
break;
case 'group': {
/** @type {CallExpression[]} */
const indexes = [];
for (const parent_each_block of node.metadata.parent_each_blocks) {
indexes.push(b.call('$.unwrap', parent_each_block.metadata.index));
}
const indexes = node.metadata.parent_each_blocks.map((each) => {
// if we have a keyed block with an index, the index is wrapped in a source
return each.metadata.keyed && each.index
? b.call('$.get', each.metadata.index)
: each.metadata.index;
});
// We need to additionally invoke the value attribute signal to register it as a dependency,
// so that when the value is updated, the group binding is updated

@ -592,6 +592,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
}
node.metadata = {
keyed: false,
contains_group_binding: false,
array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null,
index: scope.root.unique('$$index'),

@ -393,6 +393,7 @@ export interface EachBlock extends BaseNode {
index?: string;
key?: Expression;
metadata: {
keyed: boolean;
contains_group_binding: boolean;
/** Set if something in the array expression is shadowed within the each block */
array_name: Identifier | null;

@ -73,13 +73,8 @@ export function bind_group(inputs, group_index, input, get_value, update) {
if (group_index !== null) {
for (var index of group_index) {
var group = binding_group;
// @ts-ignore
binding_group = group[index];
if (binding_group === undefined) {
// @ts-ignore
binding_group = group[index] = [];
}
// @ts-expect-error
binding_group = binding_group[index] ??= [];
}
}

@ -1845,6 +1845,7 @@ declare module 'svelte/compiler' {
index?: string;
key?: Expression;
metadata: {
keyed: boolean;
contains_group_binding: boolean;
/** Set if something in the array expression is shadowed within the each block */
array_name: Identifier | null;

Loading…
Cancel
Save