@@ -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' ) {
0 commit comments