diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js index 5a87d72dbc..56792d8dac 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js @@ -6,7 +6,7 @@ import { is_text_attribute } from '../../../../utils/ast.js'; import * as b from '#compiler/builders'; import { binding_properties } from '../../../bindings.js'; import { build_attribute_value } from './shared/element.js'; -import { build_bind_this, validate_binding } from './shared/utils.js'; +import { build_bind_this, validate_binding, handle_spread_binding } from './shared/utils.js'; /** * @param {AST.BindDirective} node @@ -17,16 +17,9 @@ export function BindDirective(node, context) { // Handle SpreadElement by creating a variable declaration before visiting if (node.expression.type === 'SpreadElement') { - // Generate a unique variable name for this spread binding - const id = b.id(context.state.scope.generate('$$bindings')); - - // Store the spread expression in a variable at the component init level - const spread_expression = /** @type {Expression} */ (context.visit(node.expression.argument)); - context.state.init.push(b.const(id, spread_expression)); - - // Use member access to get getter and setter - get = b.member(id, b.literal(0), true); - set = b.member(id, b.literal(1), true); + const { get: getter, set: setter } = handle_spread_binding(node.expression, context.state, context.visit); + get = getter; + set = setter; } else { const expression = /** @type {Expression} */ (context.visit(node.expression)); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js index 2fd6277660..bac446cc0c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js @@ -202,6 +202,25 @@ export function parse_directive_name(name) { return expression; } +/** + * Handles SpreadElement by creating a variable declaration and returning getter/setter expressions + * @param {SpreadElement} spread_expression + * @param {ComponentClientTransformState} state + * @param {function} visit + * @returns {{get: Expression, set: Expression}} + */ +export function handle_spread_binding(spread_expression, state, visit) { + // Generate a unique variable name for this spread binding + const id = b.id(state.scope.generate('$$bindings')); + + const visited_expression = /** @type {Expression} */ (visit(spread_expression.argument)); + state.init.push(b.const(id, visited_expression)); + + const get = b.member(id, b.literal(0), true); + const set = b.member(id, b.literal(1), true); + return { get, set }; +} + /** * Serializes `bind:this` for components and elements. * @param {Identifier | MemberExpression | SequenceExpression | SpreadElement} expression @@ -210,16 +229,7 @@ export function parse_directive_name(name) { */ export function build_bind_this(expression, value, { state, visit }) { if (expression.type === 'SpreadElement') { - // Generate a unique variable name for this spread binding - const id = b.id(state.scope.generate('$$bindings')); - - // Store the spread expression in a variable at the component init level - const spread_expression = /** @type {Expression} */ (visit(expression.argument)); - state.init.push(b.const(id, spread_expression)); - - // Use member access to get getter and setter - const get = b.member(id, b.literal(0), true); - const set = b.member(id, b.literal(1), true); + const { get, set } = handle_spread_binding(expression, state, visit); return b.call('$.bind_this', value, set, get); } @@ -304,7 +314,10 @@ export function build_bind_this(expression, value, { state, visit }) { * @param {MemberExpression} expression */ export function validate_binding(state, binding, expression) { - if (binding.expression.type === 'SequenceExpression' || binding.expression.type === 'SpreadElement') { + if ( + binding.expression.type === 'SequenceExpression' || + binding.expression.type === 'SpreadElement' + ) { return; } // If we are referencing a $store.foo then we don't need to add validation