@@ -940,11 +940,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont
940940 const prev = fn ;
941941
942942 fn = ( node_id ) => {
943- return serialize_bind_this (
944- /** @type {Identifier | MemberExpression } */ ( bind_this ) ,
945- context ,
946- prev ( node_id )
947- ) ;
943+ return serialize_bind_this ( bind_this , prev ( node_id ) , context ) ;
948944 } ;
949945 }
950946
@@ -997,71 +993,67 @@ function serialize_inline_component(node, component_name, context, anchor = cont
997993
998994/**
999995 * Serializes `bind:this` for components and elements.
1000- * @param {Identifier | MemberExpression } bind_this
996+ * @param {Identifier | MemberExpression } expression
997+ * @param {Expression } value
1001998 * @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('../types.js').ComponentClientTransformState> } context
1002- * @param {Expression } node
1003- * @returns
1004999 */
1005- function serialize_bind_this ( bind_this , context , node ) {
1006- const child_state = {
1007- ...context . state ,
1008- getters : { ...context . state . getters }
1009- } ;
1010-
1000+ function serialize_bind_this ( expression , value , { state, visit } ) {
10111001 /** @type {Identifier[] } */
10121002 const ids = [ ] ;
10131003
10141004 /** @type {Expression[] } */
10151005 const values = [ ] ;
10161006
1017- /** @type {string[] } */
1018- const seen = [ ] ;
1007+ /** @type {typeof state.getters } */
1008+ const getters = { } ;
10191009
10201010 // Pass in each context variables to the get/set functions, so that we can null out old values on teardown.
10211011 // Note that we only do this for each context variables, the consequence is that the value might be stale in
10221012 // some scenarios where the value is a member expression with changing computed parts or using a combination of multiple
10231013 // variables, but that was the same case in Svelte 4, too. Once legacy mode is gone completely, we can revisit this.
1024- walk ( bind_this , null , {
1014+ walk ( expression , null , {
10251015 Identifier ( node , { path } ) {
1016+ if ( Object . hasOwn ( getters , node . name ) ) return ;
1017+
10261018 const parent = /** @type {Expression } */ ( path . at ( - 1 ) ) ;
10271019 if ( ! is_reference ( node , parent ) ) return ;
10281020
1029- const binding = child_state . scope . get ( node . name ) ;
1030- if ( ! binding || seen . includes ( node . name ) ) return ;
1021+ const binding = state . scope . get ( node . name ) ;
1022+ if ( ! binding ) return ;
10311023
1032- for ( const [ owner , scope ] of child_state . scopes ) {
1024+ for ( const [ owner , scope ] of state . scopes ) {
10331025 if ( owner . type === 'EachBlock' && scope === binding . scope ) {
1034- seen . push ( node . name ) ;
1035-
10361026 ids . push ( node ) ;
1037- values . push ( /** @type {Expression } */ ( context . visit ( node ) ) ) ;
1038- child_state . getters [ node . name ] = node ;
1027+ values . push ( /** @type {Expression } */ ( visit ( node ) ) ) ;
1028+ getters [ node . name ] = node ;
10391029 break ;
10401030 }
10411031 }
10421032 }
10431033 } ) ;
10441034
1045- const expression = /** @type {Expression } */ ( context . visit ( bind_this , child_state ) ) ;
1046- const assignment = /** @type {Expression } */ (
1047- context . visit ( b . assignment ( '=' , bind_this , b . id ( '$$value' ) ) , child_state )
1035+ const child_state = { ...state , getters : { ...state . getters , ...getters } } ;
1036+
1037+ const get = /** @type {Expression } */ ( visit ( expression , child_state ) ) ;
1038+ const set = /** @type {Expression } */ (
1039+ visit ( b . assignment ( '=' , expression , b . id ( '$$value' ) ) , child_state )
10481040 ) ;
10491041
10501042 // If we're mutating a property, then it might already be non-existent.
10511043 // If we make all the object nodes optional, then it avoids any runtime exceptions.
10521044 /** @type {Expression | Super } */
1053- let bind_node = expression ;
1045+ let node = get ;
10541046
1055- while ( bind_node . type === 'MemberExpression' ) {
1056- bind_node . optional = true ;
1057- bind_node = bind_node . object ;
1047+ while ( node . type === 'MemberExpression' ) {
1048+ node . optional = true ;
1049+ node = node . object ;
10581050 }
10591051
10601052 return b . call (
10611053 '$.bind_this' ,
1062- node ,
1063- b . arrow ( [ b . id ( '$$value' ) , ...ids ] , assignment ) ,
1064- b . arrow ( [ ...ids ] , expression ) ,
1054+ value ,
1055+ b . arrow ( [ b . id ( '$$value' ) , ...ids ] , set ) ,
1056+ b . arrow ( [ ...ids ] , get ) ,
10651057 values . length > 0 && b . thunk ( b . array ( values ) )
10661058 ) ;
10671059}
@@ -2983,7 +2975,7 @@ export const template_visitors = {
29832975 break ;
29842976
29852977 case 'this' :
2986- call_expr = serialize_bind_this ( node . expression , context , state . node ) ;
2978+ call_expr = serialize_bind_this ( node . expression , state . node , context ) ;
29872979 break ;
29882980 case 'textContent' :
29892981 case 'innerHTML' :
0 commit comments