@@ -940,11 +940,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont
940
940
const prev = fn ;
941
941
942
942
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 ) ;
948
944
} ;
949
945
}
950
946
@@ -997,71 +993,67 @@ function serialize_inline_component(node, component_name, context, anchor = cont
997
993
998
994
/**
999
995
* Serializes `bind:this` for components and elements.
1000
- * @param {Identifier | MemberExpression } bind_this
996
+ * @param {Identifier | MemberExpression } expression
997
+ * @param {Expression } value
1001
998
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('../types.js').ComponentClientTransformState> } context
1002
- * @param {Expression } node
1003
- * @returns
1004
999
*/
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 } ) {
1011
1001
/** @type {Identifier[] } */
1012
1002
const ids = [ ] ;
1013
1003
1014
1004
/** @type {Expression[] } */
1015
1005
const values = [ ] ;
1016
1006
1017
- /** @type {string[] } */
1018
- const seen = [ ] ;
1007
+ /** @type {typeof state.getters } */
1008
+ const getters = { } ;
1019
1009
1020
1010
// Pass in each context variables to the get/set functions, so that we can null out old values on teardown.
1021
1011
// Note that we only do this for each context variables, the consequence is that the value might be stale in
1022
1012
// some scenarios where the value is a member expression with changing computed parts or using a combination of multiple
1023
1013
// 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 , {
1025
1015
Identifier ( node , { path } ) {
1016
+ if ( Object . hasOwn ( getters , node . name ) ) return ;
1017
+
1026
1018
const parent = /** @type {Expression } */ ( path . at ( - 1 ) ) ;
1027
1019
if ( ! is_reference ( node , parent ) ) return ;
1028
1020
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 ;
1031
1023
1032
- for ( const [ owner , scope ] of child_state . scopes ) {
1024
+ for ( const [ owner , scope ] of state . scopes ) {
1033
1025
if ( owner . type === 'EachBlock' && scope === binding . scope ) {
1034
- seen . push ( node . name ) ;
1035
-
1036
1026
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 ;
1039
1029
break ;
1040
1030
}
1041
1031
}
1042
1032
}
1043
1033
} ) ;
1044
1034
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 )
1048
1040
) ;
1049
1041
1050
1042
// If we're mutating a property, then it might already be non-existent.
1051
1043
// If we make all the object nodes optional, then it avoids any runtime exceptions.
1052
1044
/** @type {Expression | Super } */
1053
- let bind_node = expression ;
1045
+ let node = get ;
1054
1046
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 ;
1058
1050
}
1059
1051
1060
1052
return b . call (
1061
1053
'$.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 ) ,
1065
1057
values . length > 0 && b . thunk ( b . array ( values ) )
1066
1058
) ;
1067
1059
}
@@ -2983,7 +2975,7 @@ export const template_visitors = {
2983
2975
break ;
2984
2976
2985
2977
case 'this' :
2986
- call_expr = serialize_bind_this ( node . expression , context , state . node ) ;
2978
+ call_expr = serialize_bind_this ( node . expression , state . node , context ) ;
2987
2979
break ;
2988
2980
case 'textContent' :
2989
2981
case 'innerHTML' :
0 commit comments