Skip to content

Commit 59ebc40

Browse files
authored
fix(language-core): include event modifiers in duplicate listener checks (#6097)
1 parent 043a77b commit 59ebc40

4 files changed

Lines changed: 47 additions & 40 deletions

File tree

packages/language-core/lib/codegen/names.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ const raw = {
6060
FunctionalComponentProps: '',
6161
IsAny: '',
6262
IsFunction: '',
63-
NormalizeComponentEvent: '',
6463
NormalizeEmits: '',
6564
OverloadUnion: '',
6665
OverloadUnionInner: '',
6766
PickNotAny: '',
6867
PrettifyGlobal: '',
6968
ResolveDirectives: '',
7069
ResolveEmits: '',
70+
ResolveEvent: '',
7171
ShortEmits: '',
7272
ShortEmitsToObject: '',
7373
SpreadMerge: '',

packages/language-core/lib/codegen/template/elementEvents.ts

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ export function* generateElementEvents(
1919
getCtxVar: () => string,
2020
getPropsVar: () => string,
2121
): Generator<Code> {
22-
const definitions: {
23-
prop: CompilerDOM.DirectiveNode;
24-
source: string;
25-
offset: number | undefined;
26-
emitPrefix: string;
22+
const definitions: Record<string, {
2723
propPrefix: string;
24+
emitPrefix: string;
2825
propName: string;
2926
emitName: string;
30-
}[] = [];
27+
items: {
28+
prop: CompilerDOM.DirectiveNode;
29+
source: string;
30+
offset: number | undefined;
31+
}[];
32+
}> = {};
3133

3234
for (const prop of node.props) {
3335
if (
@@ -56,55 +58,57 @@ export function* generateElementEvents(
5658
}
5759
const propName = camelize(propPrefix + source);
5860
const emitName = emitPrefix + source;
61+
const key = propName + (
62+
prop.modifiers.length
63+
? `.${prop.modifiers.map(modifier => modifier.content).join('.')}`
64+
: ''
65+
);
5966

60-
definitions.push({
61-
prop,
62-
source,
63-
offset,
64-
emitPrefix,
67+
definitions[key] ??= {
6568
propPrefix,
69+
emitPrefix,
6670
propName,
6771
emitName,
72+
items: [],
73+
};
74+
definitions[key].items.push({
75+
prop,
76+
source,
77+
offset,
6878
});
6979
}
7080
}
7181

72-
if (!definitions.length) {
82+
if (!Object.keys(definitions).length) {
7383
return;
7484
}
7585

7686
const emitsVar = ctx.getInternalVariable();
7787
yield `let ${emitsVar}!: ${names.ResolveEmits}<typeof ${componentOriginalVar}, typeof ${getCtxVar()}.emit>${endOfLine}`;
7888

79-
yield `const ${ctx.getInternalVariable()}: `;
80-
for (let i = 0; i < definitions.length; i++) {
81-
const { propName, emitName } = definitions[i]!;
82-
if (i > 0) {
83-
yield ` & `;
84-
}
85-
yield `${names.NormalizeComponentEvent}<typeof ${getPropsVar()}, typeof ${emitsVar}, '${propName}', '${emitName}', '${
89+
for (const { propPrefix, emitPrefix, propName, emitName, items } of Object.values(definitions)) {
90+
yield `const ${ctx.getInternalVariable()}: ${names.ResolveEvent}<typeof ${getPropsVar()}, typeof ${emitsVar}, '${propName}', '${emitName}', '${
8691
camelize(emitName)
87-
}'>`;
88-
}
89-
yield ` = {${newLine}`;
90-
for (const { prop, source, offset, emitPrefix, propPrefix, propName } of definitions) {
91-
if (prop.name === 'on') {
92-
yield `...{ `;
93-
yield* generateEventArg(options, source, offset!, emitPrefix.slice(0, -1), codeFeatures.navigation);
94-
yield `: {} as any } as typeof ${emitsVar},${newLine}`;
95-
}
96-
if (prop.name === 'on') {
97-
yield* generateEventArg(options, source, offset!, propPrefix.slice(0, -1));
98-
yield `: `;
99-
yield* generateEventExpression(options, ctx, prop);
100-
}
101-
else {
102-
yield `'${propName}': `;
103-
yield* generateModelEventExpression(options, ctx, prop);
92+
}'> = {${newLine}`;
93+
for (const { prop, source, offset } of items) {
94+
if (prop.name === 'on') {
95+
yield `/** @type {typeof ${emitsVar}.`;
96+
yield* generateEventArg(options, source, offset!, emitPrefix.slice(0, -1), codeFeatures.navigation);
97+
yield `} */${newLine}`;
98+
}
99+
if (prop.name === 'on') {
100+
yield* generateEventArg(options, source, offset!, propPrefix.slice(0, -1));
101+
yield `: `;
102+
yield* generateEventExpression(options, ctx, prop);
103+
}
104+
else {
105+
yield `'${propName}': `;
106+
yield* generateModelEventExpression(options, ctx, prop);
107+
}
108+
yield `,${newLine}`;
104109
}
105-
yield `,${newLine}`;
110+
yield `}${endOfLine}`;
106111
}
107-
yield `}${endOfLine}`;
108112
}
109113

110114
export function* generateEventArg(

packages/language-core/types/template-helpers.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ declare global {
5454
: true
5555
: false
5656
: false;
57-
type __VLS_NormalizeComponentEvent<
57+
type __VLS_ResolveEvent<
5858
Props,
5959
Emits,
6060
onEvent extends keyof Props,

test-workspace/tsc/#6094/main.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ declare function Comp(props: {
77
<template>
88
<!-- @vue-expect-error -->
99
<Comp @foo-bar="void 0" @fooBar="void 0" />
10+
<!-- @vue-expect-error -->
11+
<Comp @foo-bar.up="void 0" @fooBar.up="void 0" />
12+
<Comp @foo-bar.up="void 0" @fooBar.down="void 0" />
1013
</template>

0 commit comments

Comments
 (0)