@@ -59,35 +59,31 @@ function get_component_name(filename) {
5959}
6060
6161/**
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
6365 * @param {import('./types').Context } context
6466 * @returns {null | import('#compiler').DelegatedEvent }
6567 */
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 ) {
7069 // 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 ) ) {
7271 return null ;
7372 }
73+
7474 // If we are not working with a RegularElement, then bail-out.
7575 const element = context . path . at ( - 1 ) ;
7676 if ( element ?. type !== 'RegularElement' ) {
7777 return null ;
7878 }
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- }
8379
8480 /** @type {import('#compiler').DelegatedEvent } */
8581 const non_hoistable = { type : 'non-hoistable' } ;
8682 /** @type {import('estree').FunctionExpression | import('estree').FunctionDeclaration | import('estree').ArrowFunctionExpression | null } */
8783 let target_function = null ;
8884 let binding = null ;
8985
90- if ( node . type === 'Attribute' && element . metadata . has_spread ) {
86+ if ( element . metadata . has_spread ) {
9187 // event attribute becomes part of the dynamic spread array
9288 return non_hoistable ;
9389 }
@@ -123,8 +119,7 @@ function get_delegated_event(node, context) {
123119 if ( element && event_name ) {
124120 if (
125121 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 ||
128123 ! DelegatedEvents . includes ( event_name )
129124 ) {
130125 return non_hoistable ;
@@ -183,7 +178,8 @@ function get_delegated_event(node, context) {
183178 ) {
184179 return non_hoistable ;
185180 }
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.
187183 if ( binding !== null && binding . initial ?. type === 'EachBlock' ) {
188184 return non_hoistable ;
189185 }
@@ -204,6 +200,7 @@ function get_delegated_event(node, context) {
204200 }
205201 visited_references . add ( reference ) ;
206202 }
203+
207204 return { type : 'hoistable' , function : target_function } ;
208205}
209206
@@ -858,21 +855,9 @@ const common_visitors = {
858855 } ) ;
859856
860857 if ( is_event_attribute ( node ) ) {
861- /** @type {string[] } */
862- const modifiers = [ ] ;
863858 const expression = node . value [ 0 ] . expression ;
864859
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 ) ;
876861
877862 if ( delegated_event !== null ) {
878863 if ( delegated_event . type === 'hoistable' ) {
@@ -1032,18 +1017,6 @@ const common_visitors = {
10321017 )
10331018 } ;
10341019 } ,
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- } ,
10471020 ArrowFunctionExpression : function_visitor ,
10481021 FunctionExpression : function_visitor ,
10491022 FunctionDeclaration : function_visitor ,
@@ -1052,7 +1025,7 @@ const common_visitors = {
10521025 node . metadata . svg = true ;
10531026 }
10541027
1055- determine_element_spread_and_delegatable ( node ) ;
1028+ determine_element_spread ( node ) ;
10561029
10571030 // Special case: Move the children of <textarea> into a value attribute if they are dynamic
10581031 if (
@@ -1110,51 +1083,15 @@ const common_visitors = {
11101083} ;
11111084
11121085/**
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).
11171086 * @param {import('#compiler').RegularElement } node
11181087 */
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 ) {
11251089 let has_spread = false ;
1126- let has_on = false ;
1127- let has_action_or_bind = false ;
11281090 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' ) {
11421092 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 ;
11491093 }
11501094 }
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 ) ;
11581095 node . metadata . has_spread = has_spread ;
11591096
11601097 return node ;
0 commit comments