Skip to content

Commit 3070691

Browse files
committed
fix(language-core): don't fallthrough attributes if defineEmits exists
1 parent b2707f0 commit 3070691

File tree

11 files changed

+146
-57
lines changed

11 files changed

+146
-57
lines changed

packages/language-core/lib/codegen/script/component.ts

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -71,34 +71,34 @@ export function* generateScriptSetupOptions(
7171
scriptSetupRanges: ScriptSetupRanges,
7272
inheritAttrs: boolean
7373
): Generator<Code> {
74-
yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, inheritAttrs);
75-
yield* generateEmitsOption(options, scriptSetup, scriptSetupRanges);
76-
}
77-
78-
export function* generatePropsOption(
79-
options: ScriptCodegenOptions,
80-
ctx: ScriptCodegenContext,
81-
scriptSetup: NonNullable<Sfc['scriptSetup']>,
82-
scriptSetupRanges: ScriptSetupRanges,
83-
inheritAttrs: boolean
84-
) {
74+
const emitOptionCodes = [...generateEmitsOption(options, scriptSetup, scriptSetupRanges)];
75+
for (const code of emitOptionCodes) {
76+
yield code;
77+
}
8578

8679
if (options.vueCompilerOptions.target >= 3.5) {
8780
const types = [];
88-
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size) {
89-
types.push(`ReturnType<typeof __VLS_template>['attrs']`);
81+
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size && !emitOptionCodes.length) {
82+
types.push(`{} as ReturnType<typeof __VLS_template>['attrs']`);
9083
}
9184
if (ctx.generatedPropsType) {
9285
types.push(`{} as __VLS_PublicProps`);
9386
}
94-
if (types.length) {
95-
yield `__typeProps: ${types.join(' & ')},${newLine}`;
87+
if (types.length === 1) {
88+
yield `__typeProps: ${types[0]},${newLine}`;
89+
}
90+
else if (types.length >= 2) {
91+
yield `__typeProps: {${newLine}`;
92+
for (const type of types) {
93+
yield `...${type},${newLine}`;
94+
}
95+
yield `},${newLine}`;
9696
}
9797
}
9898
if (options.vueCompilerOptions.target < 3.5 || !ctx.generatedPropsType || scriptSetupRanges.props.withDefaults) {
9999
const codegens: (() => Generator<Code>)[] = [];
100100

101-
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size) {
101+
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size && !emitOptionCodes.length) {
102102
codegens.push(function* () {
103103
yield `{} as ${ctx.helperTypes.TypePropsToOption.name}<__VLS_PickNotAny<${ctx.helperTypes.OmitIndexSignature.name}<ReturnType<typeof __VLS_template>['attrs']>, {}>>`;
104104
});
@@ -148,25 +148,63 @@ export function* generateEmitsOption(
148148
scriptSetup: NonNullable<Sfc['scriptSetup']>,
149149
scriptSetupRanges: ScriptSetupRanges
150150
): Generator<Code> {
151-
if (!scriptSetupRanges.emits.define && !scriptSetupRanges.defineProp.some(p => p.isModel)) {
152-
return;
151+
const codes: {
152+
optionExp?: Code[],
153+
typeOptionType?: Code[],
154+
}[] = [];
155+
if (scriptSetupRanges.defineProp.some(p => p.isModel)) {
156+
codes.push({
157+
optionExp: [`{} as __VLS_NormalizeEmits<__VLS_ModelEmitsType>`],
158+
typeOptionType: [`__VLS_ModelEmitsType`],
159+
});
153160
}
154-
155-
if (options.vueCompilerOptions.target < 3.5 || scriptSetupRanges.emits.define?.arg || scriptSetupRanges.emits.define?.hasUnionTypeArg) {
156-
yield `emits: ({} as __VLS_NormalizeEmits<__VLS_ModelEmitsType`;
157-
if (scriptSetupRanges?.emits.define) {
158-
yield ` & typeof `;
159-
yield scriptSetupRanges.emits.name ?? '__VLS_emit';
161+
if (scriptSetupRanges.emits.define) {
162+
const { typeArg, hasUnionTypeArg } = scriptSetupRanges.emits.define;
163+
codes.push({
164+
optionExp: [`{} as __VLS_NormalizeEmits<typeof `, scriptSetupRanges.emits.name ?? '__VLS_emit', `>`],
165+
typeOptionType: typeArg && !hasUnionTypeArg ? [scriptSetup.content.slice(typeArg.start, typeArg.end)] : undefined,
166+
});
167+
}
168+
if (options.vueCompilerOptions.target >= 3.5 && codes.every(code => code.typeOptionType)) {
169+
if (codes.length === 1) {
170+
yield `__typeEmits: {} as `;
171+
for (const code of codes[0].typeOptionType!) {
172+
yield code;
173+
}
174+
yield `,${newLine}`;
175+
}
176+
else if (codes.length >= 2) {
177+
yield `__typeEmits: {} as `;
178+
for (const code of codes[0].typeOptionType!) {
179+
yield code;
180+
}
181+
for (let i = 1; i < codes.length; i++) {
182+
yield ` & `;
183+
for (const code of codes[i].typeOptionType!) {
184+
yield code;
185+
}
186+
}
187+
yield `,${newLine}`;
160188
}
161-
yield `>),${newLine}`;
162189
}
163-
else {
164-
yield `__typeEmits: {} as __VLS_ModelEmitsType`;
165-
const typeArg = scriptSetupRanges.emits.define?.typeArg;
166-
if (typeArg) {
167-
yield ` & `;
168-
yield scriptSetup.content.slice(typeArg.start, typeArg.end);
190+
else if (codes.every(code => code.optionExp)) {
191+
if (codes.length === 1) {
192+
yield `emits: `;
193+
for (const code of codes[0].optionExp!) {
194+
yield code;
195+
}
196+
yield `,${newLine}`;
197+
}
198+
else if (codes.length >= 2) {
199+
yield `emits: {${newLine}`;
200+
for (const code of codes) {
201+
yield `...`;
202+
for (const c of code.optionExp!) {
203+
yield c;
204+
}
205+
yield `,${newLine}`;
206+
}
207+
yield `},${newLine}`;
169208
}
170-
yield `,${newLine}`;
171209
}
172210
}

packages/language-core/lib/codegen/script/scriptSetup.ts

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,16 @@ function* generateComponentProps(
303303
scriptSetupRanges: ScriptSetupRanges,
304304
definePropMirrors: Map<string, number>
305305
): Generator<Code> {
306-
yield `const __VLS_fnComponent = `
307-
+ `(await import('${options.vueCompilerOptions.lib}')).defineComponent({${newLine}`;
306+
yield `const __VLS_fnComponent = (await import('${options.vueCompilerOptions.lib}')).defineComponent({${newLine}`;
307+
308308
if (scriptSetupRanges.props.define?.arg) {
309-
yield ` props: `;
309+
yield `props: `;
310310
yield generateSfcBlockSection(scriptSetup, scriptSetupRanges.props.define.arg.start, scriptSetupRanges.props.define.arg.end, codeFeatures.navigation);
311311
yield `,${newLine}`;
312312
}
313+
313314
yield* generateEmitsOption(options, scriptSetup, scriptSetupRanges);
315+
314316
yield `})${endOfLine}`;
315317

316318
yield `type __VLS_BuiltInPublicProps = ${options.vueCompilerOptions.target >= 3.4
@@ -418,32 +420,31 @@ function* generateModelEmits(
418420
scriptSetup: NonNullable<Sfc['scriptSetup']>,
419421
scriptSetupRanges: ScriptSetupRanges
420422
): Generator<Code> {
421-
yield `type __VLS_ModelEmitsType = `;
422-
if (scriptSetupRanges.defineProp.filter(p => p.isModel).length) {
423-
if (options.vueCompilerOptions.target < 3.5) {
424-
yield `typeof __VLS_modelEmitsType${endOfLine}`;
425-
yield `const __VLS_modelEmitsType = (await import('${options.vueCompilerOptions.lib}')).defineEmits<`;
426-
}
427-
yield `{${newLine}`;
428-
for (const defineProp of scriptSetupRanges.defineProp) {
429-
if (!defineProp.isModel) {
430-
continue;
423+
const defineModels = scriptSetupRanges.defineProp.filter(p => p.isModel);
424+
if (defineModels.length) {
425+
const generateDefineModels = function* () {
426+
for (const defineModel of defineModels) {
427+
const [propName, localName] = getPropAndLocalName(scriptSetup, defineModel);
428+
yield `'update:${propName}': [${propName}:`;
429+
yield* generateDefinePropType(scriptSetup, propName, localName, defineModel);
430+
yield `]${endOfLine}`;
431431
}
432-
433-
const [propName, localName] = getPropAndLocalName(scriptSetup, defineProp);
434-
435-
yield `'update:${propName}': [${propName}:`;
436-
yield* generateDefinePropType(scriptSetup, propName, localName, defineProp);
437-
yield `]${endOfLine}`;
432+
};
433+
if (options.vueCompilerOptions.target >= 3.5) {
434+
yield `type __VLS_ModelEmitsType = {${newLine}`;
435+
yield* generateDefineModels();
436+
yield `}${endOfLine}`;
438437
}
439-
yield `}`;
440-
if (options.vueCompilerOptions.target < 3.5) {
441-
yield `>()`;
438+
else {
439+
yield `const __VLS_modelEmitsType = (await import('${options.vueCompilerOptions.lib}')).defineEmits<{${newLine}`;
440+
yield* generateDefineModels();
441+
yield `}>()${endOfLine}`;
442+
yield `type __VLS_ModelEmitsType = typeof __VLS_modelEmitsType${endOfLine}`;
442443
}
443-
} else {
444-
yield `{}`;
445444
}
446-
yield endOfLine;
445+
else {
446+
yield `type __VLS_ModelEmitsType = {}${endOfLine}`;
447+
}
447448
}
448449

449450
function* generateStyleModules(
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script setup lang="ts">
2+
import child from './child.vue';
3+
import { exactType } from '../../shared';
4+
5+
defineEmits<{
6+
(e: 'change', value: number): void;
7+
}>();
8+
</script>
9+
10+
<template>
11+
<child @change="v => exactType(v, {} as string)" />
12+
</template>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
onChange?: (value: string) => void;
4+
}>();
5+
</script>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script setup lang="ts">
2+
import basic from './basic.vue';
3+
import { exactType } from '../../shared';
4+
</script>
5+
6+
<template>
7+
<basic @change="v => exactType(v, {} as number)" />
8+
</template>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script setup lang="ts">
2+
import child from './child.vue';
3+
4+
defineProps<{
5+
bar: number;
6+
}>();
7+
</script>
8+
9+
<template>
10+
<child bar="bar" />
11+
</template>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script setup lang="ts">
2+
import basic from './basic.vue';
3+
</script>
4+
5+
<template>
6+
<basic :bar="1" />
7+
<!-- @vue-expect-error -->
8+
<basic bar="1" />
9+
</template>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
bar: string;
4+
}>();
5+
</script>

0 commit comments

Comments
 (0)