Skip to content

Commit 5a9bb12

Browse files
committed
refactor(language-core): rewrite generatePropsOption
1 parent 3070691 commit 5a9bb12

File tree

4 files changed

+106
-126
lines changed

4 files changed

+106
-126
lines changed

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

Lines changed: 88 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { ScriptRanges } from '../../parsers/scriptRanges';
21
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
32
import type { Code, Sfc } from '../../types';
43
import { endOfLine, generateSfcBlockSection, newLine } from '../common';
@@ -31,10 +30,15 @@ export function* generateComponent(
3130
yield `}${endOfLine}`;
3231
yield `},${newLine}`;
3332
if (!ctx.bypassDefineComponent) {
34-
yield* generateScriptSetupOptions(options, ctx, scriptSetup, scriptSetupRanges, true);
33+
const emitOptionCodes = [...generateEmitsOption(options, scriptSetup, scriptSetupRanges)];
34+
for (const code of emitOptionCodes) {
35+
yield code;
36+
}
37+
yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, !!emitOptionCodes.length, true);
3538
}
36-
if (options.sfc.script && options.scriptRanges) {
37-
yield* generateScriptOptions(options.sfc.script, options.scriptRanges);
39+
if (options.sfc.script && options.scriptRanges?.exportDefault?.args) {
40+
const { args } = options.scriptRanges.exportDefault;
41+
yield generateSfcBlockSection(options.sfc.script, args.start + 1, args.end - 1, codeFeatures.all);
3842
}
3943
if (options.vueCompilerOptions.target >= 3.5 && scriptSetupRanges.templateRefs.length) {
4044
yield `__typeRefs: {} as __VLS_Refs,${newLine}`;
@@ -55,153 +59,124 @@ export function* generateComponentSetupReturns(scriptSetupRanges: ScriptSetupRan
5559
}
5660
}
5761

58-
export function* generateScriptOptions(
59-
script: NonNullable<Sfc['script']>,
60-
scriptRanges: ScriptRanges
61-
): Generator<Code> {
62-
if (scriptRanges.exportDefault?.args) {
63-
yield generateSfcBlockSection(script, scriptRanges.exportDefault.args.start + 1, scriptRanges.exportDefault.args.end - 1, codeFeatures.all);
64-
}
65-
}
66-
67-
export function* generateScriptSetupOptions(
68-
options: ScriptCodegenOptions,
69-
ctx: ScriptCodegenContext,
70-
scriptSetup: NonNullable<Sfc['scriptSetup']>,
71-
scriptSetupRanges: ScriptSetupRanges,
72-
inheritAttrs: boolean
73-
): Generator<Code> {
74-
const emitOptionCodes = [...generateEmitsOption(options, scriptSetup, scriptSetupRanges)];
75-
for (const code of emitOptionCodes) {
76-
yield code;
77-
}
78-
79-
if (options.vueCompilerOptions.target >= 3.5) {
80-
const types = [];
81-
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size && !emitOptionCodes.length) {
82-
types.push(`{} as ReturnType<typeof __VLS_template>['attrs']`);
83-
}
84-
if (ctx.generatedPropsType) {
85-
types.push(`{} as __VLS_PublicProps`);
86-
}
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}`;
96-
}
97-
}
98-
if (options.vueCompilerOptions.target < 3.5 || !ctx.generatedPropsType || scriptSetupRanges.props.withDefaults) {
99-
const codegens: (() => Generator<Code>)[] = [];
100-
101-
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size && !emitOptionCodes.length) {
102-
codegens.push(function* () {
103-
yield `{} as ${ctx.helperTypes.TypePropsToOption.name}<__VLS_PickNotAny<${ctx.helperTypes.OmitIndexSignature.name}<ReturnType<typeof __VLS_template>['attrs']>, {}>>`;
104-
});
105-
}
106-
107-
if (ctx.generatedPropsType) {
108-
codegens.push(function* () {
109-
yield `{} as `;
110-
if (scriptSetupRanges.props.withDefaults?.arg) {
111-
yield `${ctx.helperTypes.WithDefaults.name}<`;
112-
}
113-
yield `${ctx.helperTypes.TypePropsToOption.name}<`;
114-
yield `__VLS_PublicProps>`;
115-
if (scriptSetupRanges.props.withDefaults?.arg) {
116-
yield `, typeof __VLS_withDefaultsArg>`;
117-
}
118-
});
119-
}
120-
if (scriptSetupRanges.props.define?.arg) {
121-
const { arg } = scriptSetupRanges.props.define;
122-
codegens.push(function* () {
123-
yield generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.navigation);
124-
});
125-
}
126-
127-
if (codegens.length === 1) {
128-
yield `props: `;
129-
for (const generate of codegens) {
130-
yield* generate();
131-
}
132-
yield `,${newLine}`;
133-
}
134-
else if (codegens.length >= 2) {
135-
yield `props: {${newLine}`;
136-
for (const generate of codegens) {
137-
yield `...`;
138-
yield* generate();
139-
yield `,${newLine}`;
140-
}
141-
yield `},${newLine}`;
142-
}
143-
}
144-
}
145-
14662
export function* generateEmitsOption(
14763
options: ScriptCodegenOptions,
14864
scriptSetup: NonNullable<Sfc['scriptSetup']>,
14965
scriptSetupRanges: ScriptSetupRanges
15066
): Generator<Code> {
15167
const codes: {
152-
optionExp?: Code[],
153-
typeOptionType?: Code[],
68+
optionExp?: Code,
69+
typeOptionType?: Code,
15470
}[] = [];
15571
if (scriptSetupRanges.defineProp.some(p => p.isModel)) {
15672
codes.push({
157-
optionExp: [`{} as __VLS_NormalizeEmits<__VLS_ModelEmitsType>`],
158-
typeOptionType: [`__VLS_ModelEmitsType`],
73+
optionExp: `{} as __VLS_NormalizeEmits<__VLS_ModelEmitsType>`,
74+
typeOptionType: `__VLS_ModelEmitsType`,
15975
});
16076
}
16177
if (scriptSetupRanges.emits.define) {
16278
const { typeArg, hasUnionTypeArg } = scriptSetupRanges.emits.define;
16379
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,
80+
optionExp: `{} as __VLS_NormalizeEmits<typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'}>`,
81+
typeOptionType: typeArg && !hasUnionTypeArg
82+
? scriptSetup.content.slice(typeArg.start, typeArg.end)
83+
: undefined,
16684
});
16785
}
16886
if (options.vueCompilerOptions.target >= 3.5 && codes.every(code => code.typeOptionType)) {
16987
if (codes.length === 1) {
17088
yield `__typeEmits: {} as `;
171-
for (const code of codes[0].typeOptionType!) {
172-
yield code;
173-
}
89+
yield codes[0].typeOptionType!;
17490
yield `,${newLine}`;
17591
}
17692
else if (codes.length >= 2) {
17793
yield `__typeEmits: {} as `;
178-
for (const code of codes[0].typeOptionType!) {
179-
yield code;
180-
}
94+
yield codes[0].typeOptionType!;
18195
for (let i = 1; i < codes.length; i++) {
18296
yield ` & `;
183-
for (const code of codes[i].typeOptionType!) {
184-
yield code;
185-
}
97+
yield codes[i].typeOptionType!;
18698
}
18799
yield `,${newLine}`;
188100
}
189101
}
190102
else if (codes.every(code => code.optionExp)) {
191103
if (codes.length === 1) {
192104
yield `emits: `;
193-
for (const code of codes[0].optionExp!) {
194-
yield code;
195-
}
105+
yield codes[0].optionExp!;
196106
yield `,${newLine}`;
197107
}
198108
else if (codes.length >= 2) {
199109
yield `emits: {${newLine}`;
200110
for (const code of codes) {
201111
yield `...`;
202-
for (const c of code.optionExp!) {
203-
yield c;
204-
}
112+
yield code.optionExp!;
113+
yield `,${newLine}`;
114+
}
115+
yield `},${newLine}`;
116+
}
117+
}
118+
}
119+
120+
export function* generatePropsOption(
121+
options: ScriptCodegenOptions,
122+
ctx: ScriptCodegenContext,
123+
scriptSetup: NonNullable<Sfc['scriptSetup']>,
124+
scriptSetupRanges: ScriptSetupRanges,
125+
hasEmitsOption: boolean,
126+
inheritAttrs: boolean
127+
): Generator<Code> {
128+
const optionExpCodes: Code[] = [];
129+
const typeOptionExpCodes: Code[] = [];
130+
131+
if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size && !hasEmitsOption) {
132+
optionExpCodes.push(`{} as ${ctx.helperTypes.TypePropsToOption.name}<__VLS_PickNotAny<${ctx.helperTypes.OmitIndexSignature.name}<ReturnType<typeof __VLS_template>['attrs']>, {}>>`);
133+
typeOptionExpCodes.push(`{} as ReturnType<typeof __VLS_template>['attrs']`);
134+
}
135+
if (ctx.generatedPropsType) {
136+
optionExpCodes.push([
137+
`{} as `,
138+
scriptSetupRanges.props.withDefaults?.arg ? `${ctx.helperTypes.WithDefaults.name}<` : '',
139+
`${ctx.helperTypes.TypePropsToOption.name}<__VLS_PublicProps>`,
140+
scriptSetupRanges.props.withDefaults?.arg ? `, typeof __VLS_withDefaultsArg>` : '',
141+
].join(''));
142+
typeOptionExpCodes.push(`{} as __VLS_PublicProps`);
143+
}
144+
145+
if (scriptSetupRanges.props.define?.arg) {
146+
const { arg } = scriptSetupRanges.props.define;
147+
optionExpCodes.push(generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.navigation));
148+
}
149+
150+
const useTypeOption = options.vueCompilerOptions.target >= 3.5 && typeOptionExpCodes.length;
151+
const useOption = (!useTypeOption || scriptSetupRanges.props.withDefaults) && optionExpCodes.length;
152+
153+
if (useTypeOption) {
154+
if (typeOptionExpCodes.length === 1) {
155+
yield `__typeProps: `;
156+
yield typeOptionExpCodes[0];
157+
yield `,${newLine}`;
158+
}
159+
else if (typeOptionExpCodes.length >= 2) {
160+
yield `__typeProps: {${newLine}`;
161+
for (const code of typeOptionExpCodes) {
162+
yield `...`;
163+
yield code;
164+
yield `,${newLine}`;
165+
}
166+
yield `},${newLine}`;
167+
}
168+
}
169+
if (useOption) {
170+
if (optionExpCodes.length === 1) {
171+
yield `props: `;
172+
yield optionExpCodes[0];
173+
yield `,${newLine}`;
174+
}
175+
else if (optionExpCodes.length >= 2) {
176+
yield `props: {${newLine}`;
177+
for (const code of optionExpCodes) {
178+
yield `...`;
179+
yield code;
205180
yield `,${newLine}`;
206181
}
207182
yield `},${newLine}`;

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { Code } from '../../types';
2-
import { endOfLine, newLine } from '../common';
2+
import { endOfLine, generateSfcBlockSection, newLine } from '../common';
33
import type { TemplateCodegenContext } from '../template/context';
4-
import { generateComponentSetupReturns, generateScriptOptions, generateScriptSetupOptions } from './component';
4+
import { generateComponentSetupReturns, generateEmitsOption, generatePropsOption } from './component';
55
import type { ScriptCodegenContext } from './context';
6-
import type { ScriptCodegenOptions } from './index';
6+
import { codeFeatures, type ScriptCodegenOptions } from './index';
77
import { getTemplateUsageVars } from './template';
88

99
export function* generateInternalComponent(
@@ -52,10 +52,15 @@ export function* generateInternalComponent(
5252
yield `__typeRefs: {} as __VLS_Refs,${newLine}`;
5353
}
5454
if (options.sfc.scriptSetup && options.scriptSetupRanges && !ctx.bypassDefineComponent) {
55-
yield* generateScriptSetupOptions(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges, false);
55+
const emitOptionCodes = [...generateEmitsOption(options, options.sfc.scriptSetup, options.scriptSetupRanges)];
56+
for (const code of emitOptionCodes) {
57+
yield code;
58+
}
59+
yield* generatePropsOption(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges, !!emitOptionCodes.length, false);
5660
}
57-
if (options.sfc.script && options.scriptRanges) {
58-
yield* generateScriptOptions(options.sfc.script, options.scriptRanges);
61+
if (options.sfc.script && options.scriptRanges?.exportDefault?.args) {
62+
const { args } = options.scriptRanges.exportDefault;
63+
yield generateSfcBlockSection(options.sfc.script, args.start + 1, args.end - 1, codeFeatures.all);
5964
}
6065
yield `})${endOfLine}`; // defineComponent {
6166
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,21 @@ export function* generateScriptSetup(
5757
+ ` __VLS_setup = (async () => {${newLine}`;
5858
yield* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, undefined, definePropMirrors);
5959

60-
const emitTypes = ['__VLS_ModelEmitsType'];
60+
const emitTypes: string[] = [];
6161

6262
if (scriptSetupRanges.emits.define) {
63-
emitTypes.unshift(`typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'}`);
63+
emitTypes.push(`typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'}`);
64+
}
65+
if (scriptSetupRanges.defineProp.some(p => p.isModel)) {
66+
emitTypes.push(`__VLS_ModelEmitsType`);
6467
}
6568

6669
yield ` return {} as {${newLine}`
6770
+ ` props: ${ctx.helperTypes.Prettify.name}<typeof __VLS_functionalComponentProps & __VLS_PublicProps> & __VLS_BuiltInPublicProps,${newLine}`
6871
+ ` expose(exposed: import('${options.vueCompilerOptions.lib}').ShallowUnwrapRef<${scriptSetupRanges.expose.define ? 'typeof __VLS_exposed' : '{}'}>): void,${newLine}`
6972
+ ` attrs: any,${newLine}`
7073
+ ` slots: __VLS_Slots,${newLine}`
71-
+ ` emit: ${emitTypes.join(' & ')},${newLine}`
74+
+ ` emit: ${emitTypes.length ? emitTypes.join(' & ') : `{}`},${newLine}`
7275
+ ` }${endOfLine}`;
7376
yield ` })(),${newLine}`; // __VLS_setup = (async () => {
7477
yield `) => ({} as import('${options.vueCompilerOptions.lib}').VNode & { __ctx?: Awaited<typeof __VLS_setup> }))`;
@@ -442,9 +445,6 @@ function* generateModelEmits(
442445
yield `type __VLS_ModelEmitsType = typeof __VLS_modelEmitsType${endOfLine}`;
443446
}
444447
}
445-
else {
446-
yield `type __VLS_ModelEmitsType = {}${endOfLine}`;
447-
}
448448
}
449449

450450
function* generateStyleModules(

packages/tsc/tests/__snapshots__/dts.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ exports[`vue-tsc-dts > Input: events/component-generic.vue, Output: events/compo
7878
expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
7979
attrs: any;
8080
slots: {};
81-
emit: ((evt: "foo", value: string) => void) & {};
81+
emit: (evt: "foo", value: string) => void;
8282
}>) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
8383
[key: string]: any;
8484
}> & {

0 commit comments

Comments
 (0)