@@ -59,35 +59,31 @@ function get_component_name(filename) {
59
59
}
60
60
61
61
/**
62
- * @param {Pick<import('#compiler').OnDirective, 'expression'| 'name' | 'modifiers'> & { type: string } } node
62
+ * Checks if given event attribute can be delegated/hoisted and returns the corresponding info if so
63
+ * @param {string } event_name
64
+ * @param {import('estree').Expression | null } handler
63
65
* @param {import('./types').Context } context
64
66
* @returns {null | import('#compiler').DelegatedEvent }
65
67
*/
66
- function get_delegated_event ( node , context ) {
67
- const handler = node . expression ;
68
- const event_name = node . name ;
69
-
68
+ function get_delegated_event ( event_name , handler , context ) {
70
69
// Handle delegated event handlers. Bail-out if not a delegated event.
71
- if ( ! handler || node . modifiers . includes ( 'capture' ) || ! DelegatedEvents . includes ( event_name ) ) {
70
+ if ( ! handler || ! DelegatedEvents . includes ( event_name ) ) {
72
71
return null ;
73
72
}
73
+
74
74
// If we are not working with a RegularElement, then bail-out.
75
75
const element = context . path . at ( - 1 ) ;
76
76
if ( element ?. type !== 'RegularElement' ) {
77
77
return null ;
78
78
}
79
- // If element says we can't delegate because we have multiple OnDirectives of the same type, bail-out.
80
- if ( ! element . metadata . can_delegate_events ) {
81
- return null ;
82
- }
83
79
84
80
/** @type {import('#compiler').DelegatedEvent } */
85
81
const non_hoistable = { type : 'non-hoistable' } ;
86
82
/** @type {import('estree').FunctionExpression | import('estree').FunctionDeclaration | import('estree').ArrowFunctionExpression | null } */
87
83
let target_function = null ;
88
84
let binding = null ;
89
85
90
- if ( node . type === 'Attribute' && element . metadata . has_spread ) {
86
+ if ( element . metadata . has_spread ) {
91
87
// event attribute becomes part of the dynamic spread array
92
88
return non_hoistable ;
93
89
}
@@ -123,8 +119,7 @@ function get_delegated_event(node, context) {
123
119
if ( element && event_name ) {
124
120
if (
125
121
element . type !== 'RegularElement' ||
126
- ! determine_element_spread_and_delegatable ( element ) . metadata . can_delegate_events ||
127
- ( element . metadata . has_spread && node . type === 'Attribute' ) ||
122
+ determine_element_spread ( element ) . metadata . has_spread ||
128
123
! DelegatedEvents . includes ( event_name )
129
124
) {
130
125
return non_hoistable ;
@@ -183,7 +178,8 @@ function get_delegated_event(node, context) {
183
178
) {
184
179
return non_hoistable ;
185
180
}
186
- // If we referebnce the index within an each block, then bail-out.
181
+
182
+ // If we reference the index within an each block, then bail-out.
187
183
if ( binding !== null && binding . initial ?. type === 'EachBlock' ) {
188
184
return non_hoistable ;
189
185
}
@@ -204,6 +200,7 @@ function get_delegated_event(node, context) {
204
200
}
205
201
visited_references . add ( reference ) ;
206
202
}
203
+
207
204
return { type : 'hoistable' , function : target_function } ;
208
205
}
209
206
@@ -858,21 +855,9 @@ const common_visitors = {
858
855
} ) ;
859
856
860
857
if ( is_event_attribute ( node ) ) {
861
- /** @type {string[] } */
862
- const modifiers = [ ] ;
863
858
const expression = node . value [ 0 ] . expression ;
864
859
865
- let name = node . name . slice ( 2 ) ;
866
-
867
- if ( is_capture_event ( name ) ) {
868
- name = name . slice ( 0 , - 7 ) ;
869
- modifiers . push ( 'capture' ) ;
870
- }
871
-
872
- const delegated_event = get_delegated_event (
873
- { type : node . type , name, expression, modifiers } ,
874
- context
875
- ) ;
860
+ const delegated_event = get_delegated_event ( node . name . slice ( 2 ) , expression , context ) ;
876
861
877
862
if ( delegated_event !== null ) {
878
863
if ( delegated_event . type === 'hoistable' ) {
@@ -1032,18 +1017,6 @@ const common_visitors = {
1032
1017
)
1033
1018
} ;
1034
1019
} ,
1035
- OnDirective ( node , context ) {
1036
- node . metadata = { delegated : null } ;
1037
- context . next ( ) ;
1038
- const delegated_event = get_delegated_event ( node , context ) ;
1039
-
1040
- if ( delegated_event !== null ) {
1041
- if ( delegated_event . type === 'hoistable' ) {
1042
- delegated_event . function . metadata . hoistable = true ;
1043
- }
1044
- node . metadata . delegated = delegated_event ;
1045
- }
1046
- } ,
1047
1020
ArrowFunctionExpression : function_visitor ,
1048
1021
FunctionExpression : function_visitor ,
1049
1022
FunctionDeclaration : function_visitor ,
@@ -1052,7 +1025,7 @@ const common_visitors = {
1052
1025
node . metadata . svg = true ;
1053
1026
}
1054
1027
1055
- determine_element_spread_and_delegatable ( node ) ;
1028
+ determine_element_spread ( node ) ;
1056
1029
1057
1030
// Special case: Move the children of <textarea> into a value attribute if they are dynamic
1058
1031
if (
@@ -1110,51 +1083,15 @@ const common_visitors = {
1110
1083
} ;
1111
1084
1112
1085
/**
1113
- * Check if events on this element can theoretically be delegated. They can if there's no
1114
- * possibility of an OnDirective and an event attribute on the same element, and if there's
1115
- * no OnDirectives of the same type (the latter is a bit too strict because `on:click on:click on:keyup`
1116
- * means that `on:keyup` can be delegated but we gloss over this edge case).
1117
1086
* @param {import('#compiler').RegularElement } node
1118
1087
*/
1119
- function determine_element_spread_and_delegatable ( node ) {
1120
- if ( typeof node . metadata . can_delegate_events === 'boolean' ) {
1121
- return node ; // did this already
1122
- }
1123
-
1124
- let events = new Map ( ) ;
1088
+ function determine_element_spread ( node ) {
1125
1089
let has_spread = false ;
1126
- let has_on = false ;
1127
- let has_action_or_bind = false ;
1128
1090
for ( const attribute of node . attributes ) {
1129
- if (
1130
- attribute . type === 'OnDirective' ||
1131
- ( attribute . type === 'Attribute' && is_event_attribute ( attribute ) )
1132
- ) {
1133
- let event_name = attribute . name ;
1134
- if ( attribute . type === 'Attribute' ) {
1135
- event_name = get_attribute_event_name ( event_name ) ;
1136
- }
1137
- events . set ( event_name , ( events . get ( event_name ) || 0 ) + 1 ) ;
1138
- if ( ! has_on && attribute . type === 'OnDirective' ) {
1139
- has_on = true ;
1140
- }
1141
- } else if ( ! has_spread && attribute . type === 'SpreadAttribute' ) {
1091
+ if ( ! has_spread && attribute . type === 'SpreadAttribute' ) {
1142
1092
has_spread = true ;
1143
- } else if (
1144
- ! has_action_or_bind &&
1145
- ( ( attribute . type === 'BindDirective' && attribute . name !== 'this' ) ||
1146
- attribute . type === 'UseDirective' )
1147
- ) {
1148
- has_action_or_bind = true ;
1149
1093
}
1150
1094
}
1151
- node . metadata . can_delegate_events =
1152
- // Actions/bindings need the old on:-events to fire in order
1153
- ! has_action_or_bind &&
1154
- // spreading events means we don't know if there's an event attribute with the same name as an on:-event
1155
- ! ( has_spread && has_on ) &&
1156
- // multiple on:-events/event attributes with the same name
1157
- ! [ ...events . values ( ) ] . some ( ( count ) => count > 1 ) ;
1158
1095
node . metadata . has_spread = has_spread ;
1159
1096
1160
1097
return node ;
0 commit comments