Skip to content

Commit af3c5f4

Browse files
committed
fix: unwrap args in case of spread
1 parent 7c387a8 commit af3c5f4

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { ClassBody, Expression, Identifier, Literal, MethodDefinition, PrivateIdentifier, PropertyDefinition } from 'estree' */
1+
/** @import { ClassBody, Expression, Identifier, Literal, MethodDefinition, PrivateIdentifier, PropertyDefinition, SpreadElement } from 'estree' */
22
/** @import { } from '#compiler' */
33
/** @import { Context, StateField } from '../types' */
44
import { dev, is_ignored } from '../../../../state.js';
@@ -113,23 +113,37 @@ export function ClassBody(node, context) {
113113
let value = null;
114114

115115
if (definition.value.arguments.length > 0) {
116-
const init = /** @type {Expression} **/ (
116+
let init = /** @type {Expression | SpreadElement} **/ (
117117
context.visit(definition.value.arguments[0], child_state)
118118
);
119119

120120
if (field.kind === 'state' || field.kind === 'raw_state') {
121-
const onchange = get_onchange(
122-
/** @type {Expression} */ (definition.value.arguments[1]),
123-
// @ts-ignore mismatch between Context and ComponentContext. TODO look into
124-
context
125-
);
121+
let onchange;
122+
if (
123+
/** @type {Expression | SpreadElement} */ (/** @type {unknown} */ (init)).type ===
124+
'SpreadElement'
125+
) {
126+
const argument = init.argument;
127+
init = b.member(argument, '0', true);
128+
onchange = b.member(b.member(argument, '1', true), 'onchange', false, true);
129+
}
130+
if (!onchange) {
131+
onchange = get_onchange(
132+
/** @type {Expression} */ (definition.value.arguments[1]),
133+
// @ts-ignore mismatch between Context and ComponentContext. TODO look into
134+
context
135+
);
136+
}
126137

127138
value =
128139
field.kind === 'state' && should_proxy(init, context.state.scope)
129140
? b.call('$.assignable_proxy', init, onchange)
130141
: b.call('$.state', init, onchange);
131142
} else {
132-
value = b.call('$.derived', field.kind === 'derived_by' ? init : b.thunk(init));
143+
value = b.call(
144+
'$.derived',
145+
field.kind === 'derived_by' ? init : b.thunk(/** @type {Expression} */ (init))
146+
);
133147
}
134148
} else {
135149
// if no arguments, we know it's state as `$derived()` is a compile error

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator } from 'estree' */
1+
/** @import { CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator, SpreadElement } from 'estree' */
22
/** @import { Binding } from '#compiler' */
33
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */
44
import { dev } from '../../../../state.js';
@@ -117,9 +117,20 @@ export function VariableDeclaration(node, context) {
117117
}
118118

119119
const args = /** @type {CallExpression} */ (init).arguments;
120-
const value = args.length > 0 ? /** @type {Expression} */ (context.visit(args[0])) : b.void0;
121-
122-
const onchange = get_onchange(/** @type {Expression} */ (args[1]), context);
120+
let value =
121+
args.length > 0
122+
? /** @type {Expression | SpreadElement} */ (context.visit(args[0]))
123+
: b.void0;
124+
let onchange;
125+
126+
if (value.type === 'SpreadElement') {
127+
const argument = value.argument;
128+
value = b.member(argument, '0', true);
129+
onchange = b.member(b.member(argument, '1', true), 'onchange', false, true);
130+
}
131+
if (!onchange) {
132+
onchange = get_onchange(/** @type {Expression} */ (args[1]), context);
133+
}
123134

124135
if (rune === '$state' || rune === '$state.raw') {
125136
/**

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
/** @import { Expression, Property } from 'estree' */
1+
/** @import { Expression, Property, SpreadElement } from 'estree' */
22
/** @import { ComponentContext } from '../../types' */
33
import * as b from '../../../../../utils/builders.js';
44

55
/**
66
* Extract the `onchange` callback from the options passed to `$state`
7-
* @param {Expression} options
7+
* @param {Expression | SpreadElement} options
88
* @param {ComponentContext} context
99
* @returns {Expression | undefined}
1010
*/
@@ -27,5 +27,9 @@ export function get_onchange(options, context) {
2727
return /** @type {Expression} */ (context.visit(onchange.value));
2828
}
2929

30+
if (options.type === 'SpreadElement') {
31+
return b.member(b.member(options.argument, '0', true), 'onchange');
32+
}
33+
3034
return b.member(/** @type {Expression} */ (context.visit(options)), 'onchange');
3135
}

0 commit comments

Comments
 (0)