Skip to content

Commit 37f58cf

Browse files
authored
fix: apply dynamic event fixes to OnDirective (#12582)
* fix: apply dynamic event fixes to OnDirective * build
1 parent 528d346 commit 37f58cf

File tree

9 files changed

+70
-5
lines changed

9 files changed

+70
-5
lines changed

.changeset/honest-phones-flash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: apply dynamic event fixes to OnDirective

packages/svelte/src/compiler/phases/1-parse/state/element.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,11 @@ function read_attribute(parser) {
612612
type,
613613
name: directive_name,
614614
modifiers,
615-
expression
615+
expression,
616+
metadata: {
617+
dynamic: false,
618+
contains_call_expression: false
619+
}
616620
};
617621

618622
if (directive.type === 'ClassDirective') {

packages/svelte/src/compiler/phases/2-analyze/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,9 @@ const common_visitors = {
12991299
CallExpression(node, context) {
13001300
const { expression, render_tag } = context.state;
13011301
if (
1302-
(expression?.type === 'ExpressionTag' || expression?.type === 'SpreadAttribute') &&
1302+
(expression?.type === 'ExpressionTag' ||
1303+
expression?.type === 'SpreadAttribute' ||
1304+
expression?.type === 'OnDirective') &&
13031305
!is_known_safe_call(node, context)
13041306
) {
13051307
expression.metadata.contains_call_expression = true;
@@ -1367,7 +1369,7 @@ const common_visitors = {
13671369
if (parent?.type === 'SvelteElement' || parent?.type === 'RegularElement') {
13681370
state.analysis.event_directive_node ??= node;
13691371
}
1370-
next();
1372+
next({ ...state, expression: node });
13711373
},
13721374
BindDirective(node, context) {
13731375
let i = context.path.length;

packages/svelte/src/compiler/phases/2-analyze/types.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { ComponentAnalysis, ReactiveStatement } from '../types.js';
33
import type {
44
ClassDirective,
55
ExpressionTag,
6+
OnDirective,
67
RenderTag,
78
SpreadAttribute,
89
SvelteNode,
@@ -20,7 +21,7 @@ export interface AnalysisState {
2021
/** Which slots the current parent component has */
2122
component_slots: Set<string>;
2223
/** The current {expression}, if any */
23-
expression: ExpressionTag | ClassDirective | SpreadAttribute | null;
24+
expression: ExpressionTag | ClassDirective | OnDirective | SpreadAttribute | null;
2425
/** The current {@render ...} tag, if any */
2526
render_tag: null | RenderTag;
2627
private_derived_state: string[];

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2838,7 +2838,7 @@ export const template_visitors = {
28382838
context.next({ ...context.state, in_constructor: false });
28392839
},
28402840
OnDirective(node, context) {
2841-
serialize_event(node, null, context);
2841+
serialize_event(node, node.metadata, context);
28422842
},
28432843
UseDirective(node, { state, next, visit }) {
28442844
const params = [b.id('$$node')];

packages/svelte/src/compiler/types/template.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ export interface OnDirective extends BaseNode {
211211
/** The 'y' in `on:x={y}` */
212212
expression: null | Expression;
213213
modifiers: string[]; // TODO specify
214+
metadata: {
215+
contains_call_expression: boolean;
216+
dynamic: boolean;
217+
};
214218
}
215219

216220
export type DelegatedEvent =
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: '<button>Tama</button><button>Pochi</button><br><button>Change Function</button>',
5+
6+
test({ assert, logs, target }) {
7+
const [b1, b2, b3] = target.querySelectorAll('button');
8+
9+
b1?.click();
10+
b2?.click();
11+
b3?.click();
12+
b1?.click();
13+
b2?.click();
14+
15+
assert.deepEqual(logs, [
16+
'creating "Hello" handler for Tama',
17+
'Hello Tama',
18+
'creating "Hello" handler for Pochi',
19+
'Hello Pochi',
20+
'creating "Bye" handler for Tama',
21+
'Bye Tama',
22+
'creating "Bye" handler for Pochi',
23+
'Bye Pochi'
24+
]);
25+
}
26+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<script>
2+
let saySomething = $state(name => {
3+
console.log('creating "Hello" handler for ' + name);
4+
return { handler: () => console.log('Hello ' + name) };
5+
});
6+
7+
function change() {
8+
saySomething = name => {
9+
console.log('creating "Bye" handler for ' + name);
10+
return { handler: () => console.log('Bye ' + name) };
11+
}
12+
}
13+
</script>
14+
15+
<button on:click={saySomething('Tama').handler}>Tama</button>
16+
<button on:click={saySomething('Pochi').handler}>Pochi</button>
17+
18+
<br>
19+
<button on:click={change}>Change Function</button>

packages/svelte/types/index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,10 @@ declare module 'svelte/compiler' {
16361636
/** The 'y' in `on:x={y}` */
16371637
expression: null | Expression;
16381638
modifiers: string[]; // TODO specify
1639+
metadata: {
1640+
contains_call_expression: boolean;
1641+
dynamic: boolean;
1642+
};
16391643
}
16401644

16411645
type DelegatedEvent =

0 commit comments

Comments
 (0)