address feedback

pull/12563/head
Dominic Gannaway 2 years ago
parent 2d4fb36c40
commit 312b1a0a40

@ -714,7 +714,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
} else if (attribute.type === 'OnDirective') { } else if (attribute.type === 'OnDirective') {
events[attribute.name] ||= []; events[attribute.name] ||= [];
let handler = serialize_event_handler(attribute, context); let handler = serialize_event_handler(attribute, null, context);
if (attribute.modifiers.includes('once')) { if (attribute.modifiers.includes('once')) {
handler = b.call('$.once', handler); handler = b.call('$.once', handler);
} }
@ -1122,9 +1122,10 @@ function serialize_render_stmt(update) {
/** /**
* Serializes the event handler function of the `on:` directive * Serializes the event handler function of the `on:` directive
* @param {Pick<import('#compiler').OnDirective, 'name' | 'modifiers' | 'expression'>} node * @param {Pick<import('#compiler').OnDirective, 'name' | 'modifiers' | 'expression'>} node
* @param {null | { contains_call_expression: boolean; dynamic: boolean; } | null} metadata
* @param {import('../types.js').ComponentContext} context * @param {import('../types.js').ComponentContext} context
*/ */
function serialize_event_handler(node, { state, visit }) { function serialize_event_handler(node, metadata, { state, visit }) {
/** @type {Expression} */ /** @type {Expression} */
let handler; let handler;
@ -1147,28 +1148,6 @@ function serialize_event_handler(node, { state, visit }) {
]) ])
); );
const derived_dynamic_handler = () => {
const id = b.id(state.scope.generate('event_handler'));
state.init.push(
b.var(id, b.call('$.derived', b.thunk(/** @type {Expression} */ (visit(handler)))))
);
return b.function(
null,
[b.rest(b.id('$$args'))],
b.block([
b.return(
b.call(
b.member(b.call('$.get', id), b.id('apply'), false, true),
b.this,
b.id('$$args')
)
)
])
);
};
if (handler.type === 'Identifier' || handler.type === 'MemberExpression') { if (handler.type === 'Identifier' || handler.type === 'MemberExpression') {
const id = object(handler); const id = object(handler);
const binding = id === null ? null : state.scope.get(id.name); const binding = id === null ? null : state.scope.get(id.name);
@ -1187,8 +1166,33 @@ function serialize_event_handler(node, { state, visit }) {
} else { } else {
handler = /** @type {Expression} */ (visit(handler)); handler = /** @type {Expression} */ (visit(handler));
} }
} else if (handler.type === 'CallExpression') { } else if (
handler = derived_dynamic_handler(); metadata?.contains_call_expression &&
!(
(handler.type === 'ArrowFunctionExpression' || handler.type === 'FunctionExpression') &&
handler.metadata.hoistable
)
) {
// Create a derived dynamic event handler
const id = b.id(state.scope.generate('event_handler'));
state.init.push(
b.var(id, b.call('$.derived', b.thunk(/** @type {Expression} */ (visit(handler)))))
);
handler = b.function(
null,
[b.rest(b.id('$$args'))],
b.block([
b.return(
b.call(
b.member(b.call('$.get', id), b.id('apply'), false, true),
b.this,
b.id('$$args')
)
)
])
);
} else if (handler.type === 'ConditionalExpression' || handler.type === 'LogicalExpression') { } else if (handler.type === 'ConditionalExpression' || handler.type === 'LogicalExpression') {
handler = dynamic_handler(); handler = dynamic_handler();
} else { } else {
@ -1227,16 +1231,17 @@ function serialize_event_handler(node, { state, visit }) {
/** /**
* Serializes an event handler function of the `on:` directive or an attribute starting with `on` * Serializes an event handler function of the `on:` directive or an attribute starting with `on`
* @param {{name: string;modifiers: string[];expression: Expression | null;delegated?: import('#compiler').DelegatedEvent | null;}} node * @param {{name: string;modifiers: string[];expression: Expression | null;delegated?: import('#compiler').DelegatedEvent | null;}} node
* @param {null | { contains_call_expression: boolean; dynamic: boolean; }} metadata
* @param {import('../types.js').ComponentContext} context * @param {import('../types.js').ComponentContext} context
*/ */
function serialize_event(node, context) { function serialize_event(node, metadata, context) {
const state = context.state; const state = context.state;
/** @type {Statement} */ /** @type {Statement} */
let statement; let statement;
if (node.expression) { if (node.expression) {
let handler = serialize_event_handler(node, context); let handler = serialize_event_handler(node, metadata, context);
const event_name = node.name; const event_name = node.name;
const delegated = node.delegated; const delegated = node.delegated;
@ -1305,7 +1310,12 @@ function serialize_event(node, context) {
statement = b.stmt(b.call('$.event', ...args)); statement = b.stmt(b.call('$.event', ...args));
} else { } else {
statement = b.stmt( statement = b.stmt(
b.call('$.event', b.literal(node.name), state.node, serialize_event_handler(node, context)) b.call(
'$.event',
b.literal(node.name),
state.node,
serialize_event_handler(node, metadata, context)
)
); );
} }
@ -1343,6 +1353,7 @@ function serialize_event_attribute(node, context) {
modifiers, modifiers,
delegated: node.metadata.delegated delegated: node.metadata.delegated
}, },
!Array.isArray(node.value) && node.value?.type === 'ExpressionTag' ? node.value.metadata : null,
context context
); );
} }
@ -2817,7 +2828,7 @@ export const template_visitors = {
context.next({ ...context.state, in_constructor: false }); context.next({ ...context.state, in_constructor: false });
}, },
OnDirective(node, context) { OnDirective(node, context) {
serialize_event(node, context); serialize_event(node, null, context);
}, },
UseDirective(node, { state, next, visit }) { UseDirective(node, { state, next, visit }) {
const params = [b.id('$$node')]; const params = [b.id('$$node')];

Loading…
Cancel
Save