Skip to content

Commit d4417cb

Browse files
committed
clean up diff
1 parent 9c9a1a8 commit d4417cb

File tree

4 files changed

+71
-78
lines changed

4 files changed

+71
-78
lines changed

packages/svelte/src/compiler/phases/1-parse/state/element.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -818,9 +818,8 @@ function read_sequence(parser, done, location) {
818818

819819
parser.allow_whitespace();
820820

821-
const has_spread = parser.match('...');
821+
const has_spread = parser.eat('...');
822822
if (has_spread) {
823-
parser.eat('...', true);
824823
parser.allow_whitespace();
825824
}
826825

packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ export function BindDirective(node, context) {
253253
node.metadata = {
254254
binding_group_name: group_name,
255255
parent_each_blocks: each_blocks,
256-
spread_binding: false
256+
spread_binding: node.metadata.spread_binding
257257
};
258258
}
259259

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

Lines changed: 68 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,35 @@ export function build_component(node, component_name, context) {
197197
push_prop(b.init(attribute.name, value));
198198
}
199199
} else if (attribute.type === 'BindDirective') {
200+
const expression = /** @type {Expression} */ (context.visit(attribute.expression));
201+
202+
if (
203+
dev &&
204+
attribute.name !== 'this' &&
205+
!is_ignored(node, 'ownership_invalid_binding') &&
206+
// bind:x={() => x.y, y => x.y = y} and bind:x={...[() => x.y, y => x.y = y]}
207+
// will be handled by the assignment expression binding validation
208+
attribute.expression.type !== 'SequenceExpression' &&
209+
!attribute.metadata.spread_binding
210+
) {
211+
const left = object(attribute.expression);
212+
const binding = left && context.state.scope.get(left.name);
213+
214+
if (binding?.kind === 'bindable_prop' || binding?.kind === 'prop') {
215+
context.state.analysis.needs_mutation_validation = true;
216+
binding_initializers.push(
217+
b.stmt(
218+
b.call(
219+
'$$ownership_validator.binding',
220+
b.literal(binding.node.name),
221+
b.id(is_component_dynamic ? intermediate_name : component_name),
222+
b.thunk(expression)
223+
)
224+
)
225+
);
226+
}
227+
}
228+
200229
if (attribute.metadata.spread_binding) {
201230
const { get, set } = init_spread_bindings(attribute.expression, context);
202231

@@ -209,91 +238,57 @@ export function build_component(node, component_name, context) {
209238
push_prop(b.get(attribute.name, [b.return(b.call(get))]), true);
210239
push_prop(b.set(attribute.name, [b.stmt(b.call(set, b.id('$$value')))]), true);
211240
}
212-
} else {
213-
const expression = /** @type {Expression} */ (context.visit(attribute.expression));
241+
} else if (expression.type === 'SequenceExpression') {
242+
if (attribute.name === 'this') {
243+
bind_this = attribute.expression;
244+
} else {
245+
const [get, set] = expression.expressions;
246+
const get_id = b.id(context.state.scope.generate('bind_get'));
247+
const set_id = b.id(context.state.scope.generate('bind_set'));
214248

249+
context.state.init.push(b.var(get_id, get));
250+
context.state.init.push(b.var(set_id, set));
251+
252+
push_prop(b.get(attribute.name, [b.return(b.call(get_id))]));
253+
push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))]));
254+
}
255+
} else {
215256
if (
216257
dev &&
217-
attribute.name !== 'this' &&
218-
!is_ignored(node, 'ownership_invalid_binding') &&
219-
// bind:x={() => x.y, y => x.y = y} will be handled by the assignment expression binding validation
220-
attribute.expression.type !== 'SequenceExpression'
258+
expression.type === 'MemberExpression' &&
259+
context.state.analysis.runes &&
260+
!is_ignored(node, 'binding_property_non_reactive')
221261
) {
222-
const left = object(attribute.expression);
223-
const binding = left && context.state.scope.get(left.name);
224-
225-
if (binding?.kind === 'bindable_prop' || binding?.kind === 'prop') {
226-
context.state.analysis.needs_mutation_validation = true;
227-
binding_initializers.push(
228-
b.stmt(
229-
b.call(
230-
'$$ownership_validator.binding',
231-
b.literal(binding.node.name),
232-
b.id(is_component_dynamic ? intermediate_name : component_name),
233-
b.thunk(expression)
234-
)
235-
)
236-
);
237-
}
262+
validate_binding(context.state, attribute, expression);
238263
}
239264

240-
if (expression.type === 'SequenceExpression') {
241-
if (attribute.name === 'this') {
242-
bind_this = attribute.expression;
243-
} else {
244-
const [get, set] = expression.expressions;
245-
const get_id = b.id(context.state.scope.generate('bind_get'));
246-
const set_id = b.id(context.state.scope.generate('bind_set'));
247-
248-
context.state.init.push(b.var(get_id, get));
249-
context.state.init.push(b.var(set_id, set));
250-
251-
push_prop(b.get(attribute.name, [b.return(b.call(get_id))]));
252-
push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))]));
253-
}
265+
if (attribute.name === 'this') {
266+
bind_this = attribute.expression;
254267
} else {
255-
if (
256-
dev &&
257-
expression.type === 'MemberExpression' &&
258-
context.state.analysis.runes &&
259-
!is_ignored(node, 'binding_property_non_reactive')
260-
) {
261-
validate_binding(context.state, attribute, expression);
262-
}
263-
264-
if (attribute.name === 'this') {
265-
bind_this = attribute.expression;
266-
} else {
267-
const is_store_sub =
268-
attribute.expression.type === 'Identifier' &&
269-
context.state.scope.get(attribute.expression.name)?.kind === 'store_sub';
270-
271-
// Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
272-
if (is_store_sub) {
273-
push_prop(
274-
b.get(attribute.name, [
275-
b.stmt(b.call('$.mark_store_binding')),
276-
b.return(expression)
277-
]),
278-
true
279-
);
280-
} else {
281-
push_prop(b.get(attribute.name, [b.return(expression)]), true);
282-
}
283-
284-
const assignment = b.assignment(
285-
'=',
286-
/** @type {Pattern} */ (attribute.expression),
287-
b.id('$$value')
288-
);
268+
const is_store_sub =
269+
attribute.expression.type === 'Identifier' &&
270+
context.state.scope.get(attribute.expression.name)?.kind === 'store_sub';
289271

272+
// Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
273+
if (is_store_sub) {
290274
push_prop(
291-
b.set(attribute.name, [
292-
b.stmt(/** @type {Expression} */ (context.visit(assignment)))
293-
]),
275+
b.get(attribute.name, [b.stmt(b.call('$.mark_store_binding')), b.return(expression)]),
294276
true
295277
);
278+
} else {
279+
push_prop(b.get(attribute.name, [b.return(expression)]), true);
296280
}
281+
282+
const assignment = b.assignment(
283+
'=',
284+
/** @type {Pattern} */ (attribute.expression),
285+
b.id('$$value')
286+
);
287+
288+
push_prop(
289+
b.set(attribute.name, [b.stmt(/** @type {Expression} */ (context.visit(assignment)))]),
290+
true
291+
);
297292
}
298293
}
299294
} else if (attribute.type === 'AttachTag') {

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ import type {
1515
Program,
1616
ChainExpression,
1717
SimpleCallExpression,
18-
SequenceExpression,
19-
SpreadElement
18+
SequenceExpression
2019
} from 'estree';
2120
import type { Scope } from '../phases/scope';
2221
import type { _CSS } from './css';

0 commit comments

Comments
 (0)