@@ -197,6 +197,35 @@ export function build_component(node, component_name, context) {
197
197
push_prop ( b . init ( attribute . name , value ) ) ;
198
198
}
199
199
} 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
+
200
229
if ( attribute . metadata . spread_binding ) {
201
230
const { get, set } = init_spread_bindings ( attribute . expression , context ) ;
202
231
@@ -209,91 +238,57 @@ export function build_component(node, component_name, context) {
209
238
push_prop ( b . get ( attribute . name , [ b . return ( b . call ( get ) ) ] ) , true ) ;
210
239
push_prop ( b . set ( attribute . name , [ b . stmt ( b . call ( set , b . id ( '$$value' ) ) ) ] ) , true ) ;
211
240
}
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' ) ) ;
214
248
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 {
215
256
if (
216
257
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' )
221
261
) {
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 ) ;
238
263
}
239
264
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 ;
254
267
} 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' ;
289
271
272
+ // Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
273
+ if ( is_store_sub ) {
290
274
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 ) ] ) ,
294
276
true
295
277
) ;
278
+ } else {
279
+ push_prop ( b . get ( attribute . name , [ b . return ( expression ) ] ) , true ) ;
296
280
}
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
+ ) ;
297
292
}
298
293
}
299
294
} else if ( attribute . type === 'AttachTag' ) {
0 commit comments