From 42ce088c53228c34db8e18d2ceb298e56e541444 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Tue, 14 Nov 2023 22:16:37 +0100 Subject: [PATCH] don't hoist identifiers when one of them is used in an event that is not delegateable --- .../src/compiler/phases/2-analyze/index.js | 45 +++++++++++++------ .../event-attribute-not-hoistable/_config.js | 18 ++++++++ .../event-attribute-not-hoistable/main.svelte | 11 +++++ 3 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index ee085674bc..4ca2d456f8 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -104,19 +104,28 @@ function get_delegated_event(node, context) { return non_hoistable; } - const element = - parent.type === 'OnDirective' - ? path.at(-2) - : parent.type === 'ExpressionTag' && - is_event_attribute(/** @type {import('#compiler').Attribute} */ (path.at(-2))) - ? path.at(-3) - : null; - - if (element) { + /** @type {import('#compiler').RegularElement | null} */ + let element = null; + /** @type {string | null} */ + let event_name = null; + if (parent.type === 'OnDirective') { + element = /** @type {import('#compiler').RegularElement} */ (path.at(-2)); + event_name = parent.name; + } else if ( + parent.type === 'ExpressionTag' && + is_event_attribute(/** @type {import('#compiler').Attribute} */ (path.at(-2))) + ) { + element = /** @type {import('#compiler').RegularElement} */ (path.at(-3)); + const attribute = /** @type {import('#compiler').Attribute} */ (path.at(-2)); + event_name = get_attribute_event_name(attribute.name); + } + + if (element && event_name) { if ( element.type !== 'RegularElement' || !determine_element_spread_and_delegatable(element).metadata.can_delegate_events || - (element.metadata.has_spread && node.type === 'Attribute') + (element.metadata.has_spread && node.type === 'Attribute') || + !DelegatedEvents.includes(event_name) ) { return non_hoistable; } @@ -1036,10 +1045,7 @@ function determine_element_spread_and_delegatable(node) { ) { let event_name = attribute.name; if (attribute.type === 'Attribute') { - if (is_capture_event(event_name)) { - event_name = event_name.slice(0, -7); - } - event_name = event_name.slice(2); + event_name = get_attribute_event_name(event_name); } events.set(event_name, (events.get(event_name) || 0) + 1); if (!has_on && attribute.type === 'OnDirective') { @@ -1066,6 +1072,17 @@ function determine_element_spread_and_delegatable(node) { return node; } +/** + * @param {string} event_name + */ +function get_attribute_event_name(event_name) { + if (is_capture_event(event_name)) { + event_name = event_name.slice(0, -7); + } + event_name = event_name.slice(2); + return event_name; +} + /** * @param {string} name * @returns boolean diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js new file mode 100644 index 0000000000..ce79b44f49 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +// Checks that event handlers are not hoisted when one of them is not delegateable +export default test({ + html: ``, + + async test({ assert, target }) { + const [button] = target.querySelectorAll('button'); + + button.click(); + await Promise.resolve(); + assert.htmlEqual(target.innerHTML, ''); + + button.dispatchEvent(new MouseEvent('mouseenter')); + await Promise.resolve(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte new file mode 100644 index 0000000000..6f8766411b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte @@ -0,0 +1,11 @@ + + +