Skip to content

Commit 8d08da8

Browse files
KazariEXso1vejohnsoncodehk
authored
fix(language-core): correct type inference of defineModel & defineEmits in generic (#4823)
Co-authored-by: Ray <[email protected]> Co-authored-by: Johnson Chu <[email protected]>
1 parent 1e04fc9 commit 8d08da8

File tree

7 files changed

+162
-130
lines changed

7 files changed

+162
-130
lines changed

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

+4-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function* generateComponent(
3030
yield `}${endOfLine}`;
3131
yield `},${newLine}`;
3232
if (!ctx.bypassDefineComponent) {
33-
const emitOptionCodes = [...generateEmitsOption(options, scriptSetup, scriptSetupRanges)];
33+
const emitOptionCodes = [...generateEmitsOption(options, scriptSetupRanges)];
3434
for (const code of emitOptionCodes) {
3535
yield code;
3636
}
@@ -64,7 +64,6 @@ export function* generateComponentSetupReturns(scriptSetupRanges: ScriptSetupRan
6464

6565
export function* generateEmitsOption(
6666
options: ScriptCodegenOptions,
67-
scriptSetup: NonNullable<Sfc['scriptSetup']>,
6867
scriptSetupRanges: ScriptSetupRanges
6968
): Generator<Code> {
7069
const codes: {
@@ -75,16 +74,16 @@ export function* generateEmitsOption(
7574
}[] = [];
7675
if (scriptSetupRanges.defineProp.some(p => p.isModel)) {
7776
codes.push({
78-
optionExp: `{} as __VLS_NormalizeEmits<__VLS_ModelEmitsType>`,
79-
typeOptionType: `__VLS_ModelEmitsType`,
77+
optionExp: `{} as __VLS_NormalizeEmits<typeof __VLS_modelEmit>`,
78+
typeOptionType: `__VLS_ModelEmit`,
8079
});
8180
}
8281
if (scriptSetupRanges.emits.define) {
8382
const { typeArg, hasUnionTypeArg } = scriptSetupRanges.emits.define;
8483
codes.push({
8584
optionExp: `{} as __VLS_NormalizeEmits<typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'}>`,
8685
typeOptionType: typeArg && !hasUnionTypeArg
87-
? scriptSetup.content.slice(typeArg.start, typeArg.end)
86+
? `__VLS_Emit`
8887
: undefined,
8988
});
9089
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export function* generateComponentSelf(
4848
yield `}${endOfLine}`; // return {
4949
yield `},${newLine}`; // setup() {
5050
if (options.sfc.scriptSetup && options.scriptSetupRanges && !ctx.bypassDefineComponent) {
51-
const emitOptionCodes = [...generateEmitsOption(options, options.sfc.scriptSetup, options.scriptSetupRanges)];
51+
const emitOptionCodes = [...generateEmitsOption(options, options.scriptSetupRanges)];
5252
for (const code of emitOptionCodes) {
5353
yield code;
5454
}

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

+101-106
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export function* generateScriptSetup(
6464
emitTypes.push(`typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'}`);
6565
}
6666
if (scriptSetupRanges.defineProp.some(p => p.isModel)) {
67-
emitTypes.push(`__VLS_ModelEmitsType`);
67+
emitTypes.push(`typeof __VLS_modelEmit`);
6868
}
6969

7070
yield ` return {} as {${newLine}`
@@ -130,45 +130,15 @@ function* generateSetupFunction(
130130
ctx.scriptSetupGeneratedOffset = options.getGeneratedLength() - scriptSetupRanges.importSectionEndOffset;
131131

132132
let setupCodeModifies: [Code[], number, number][] = [];
133-
const propsRange = scriptSetupRanges.props.withDefaults ?? scriptSetupRanges.props.define;
134-
if (propsRange && scriptSetupRanges.props.define) {
135-
const statement = scriptSetupRanges.props.define.statement;
136-
if (scriptSetupRanges.props.define.typeArg) {
137-
setupCodeModifies.push([[
138-
`let __VLS_typeProps!: `,
139-
generateSfcBlockSection(scriptSetup, scriptSetupRanges.props.define.typeArg.start, scriptSetupRanges.props.define.typeArg.end, codeFeatures.all),
140-
endOfLine,
141-
], statement.start, statement.start]);
142-
setupCodeModifies.push([[`typeof __VLS_typeProps`], scriptSetupRanges.props.define.typeArg.start, scriptSetupRanges.props.define.typeArg.end]);
143-
}
144-
if (!scriptSetupRanges.props.name) {
145-
if (statement.start === propsRange.start && statement.end === propsRange.end) {
146-
setupCodeModifies.push([[`const __VLS_props = `], propsRange.start, propsRange.start]);
147-
}
148-
else {
149-
if (scriptSetupRanges.props.define.typeArg) {
150-
setupCodeModifies.push([[
151-
`const __VLS_props = `,
152-
generateSfcBlockSection(scriptSetup, propsRange.start, scriptSetupRanges.props.define.typeArg.start, codeFeatures.all),
153-
], statement.start, scriptSetupRanges.props.define.typeArg.start]);
154-
setupCodeModifies.push([[
155-
generateSfcBlockSection(scriptSetup, scriptSetupRanges.props.define.typeArg.end, propsRange.end, codeFeatures.all),
156-
`${endOfLine}`,
157-
generateSfcBlockSection(scriptSetup, statement.start, propsRange.start, codeFeatures.all),
158-
`__VLS_props`,
159-
], scriptSetupRanges.props.define.typeArg.end, propsRange.end]);
160-
}
161-
else {
162-
setupCodeModifies.push([[
163-
`const __VLS_props = `,
164-
generateSfcBlockSection(scriptSetup, propsRange.start, propsRange.end, codeFeatures.all),
165-
`${endOfLine}`,
166-
generateSfcBlockSection(scriptSetup, statement.start, propsRange.start, codeFeatures.all),
167-
`__VLS_props`,
168-
], statement.start, propsRange.end]);
169-
}
170-
}
171-
}
133+
if (scriptSetupRanges.props.define) {
134+
setupCodeModifies.push(...generateDefineWithType(
135+
scriptSetup,
136+
scriptSetupRanges.props.name,
137+
scriptSetupRanges.props.define,
138+
scriptSetupRanges.props.withDefaults ?? scriptSetupRanges.props.define,
139+
'__VLS_props',
140+
'__VLS_Props'
141+
));
172142
}
173143
if (scriptSetupRanges.slots.define) {
174144
if (scriptSetupRanges.slots.isObjectBindingPattern) {
@@ -181,8 +151,15 @@ function* generateSetupFunction(
181151
setupCodeModifies.push([[`const __VLS_slots = `], scriptSetupRanges.slots.define.start, scriptSetupRanges.slots.define.start]);
182152
}
183153
}
184-
if (scriptSetupRanges.emits.define && !scriptSetupRanges.emits.name) {
185-
setupCodeModifies.push([[`const __VLS_emit = `], scriptSetupRanges.emits.define.start, scriptSetupRanges.emits.define.start]);
154+
if (scriptSetupRanges.emits.define) {
155+
setupCodeModifies.push(...generateDefineWithType(
156+
scriptSetup,
157+
scriptSetupRanges.emits.name,
158+
scriptSetupRanges.emits.define,
159+
scriptSetupRanges.emits.define,
160+
'__VLS_emit',
161+
'__VLS_Emit'
162+
));
186163
}
187164
if (scriptSetupRanges.expose.define) {
188165
if (scriptSetupRanges.expose.define?.typeArg) {
@@ -217,30 +194,21 @@ function* generateSetupFunction(
217194
}
218195
if (scriptSetupRanges.cssModules.length) {
219196
for (const { exp, arg } of scriptSetupRanges.cssModules) {
220-
if (arg) {
221-
setupCodeModifies.push([
222-
[
223-
` as Omit<__VLS_StyleModules, '$style'>[`,
224-
generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.all),
225-
`]`
226-
],
227-
exp.end,
228-
exp.end
229-
]);
230-
}
231-
else {
232-
setupCodeModifies.push([
233-
[
234-
` as __VLS_StyleModules[`,
235-
['', scriptSetup.name, exp.start, codeFeatures.verification],
236-
`'$style'`,
237-
['', scriptSetup.name, exp.end, codeFeatures.verification],
238-
`]`
239-
],
240-
exp.end,
241-
exp.end
242-
]);
243-
}
197+
setupCodeModifies.push([
198+
arg ? [
199+
` as Omit<__VLS_StyleModules, '$style'>[`,
200+
generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.all),
201+
`]`
202+
] : [
203+
` as __VLS_StyleModules[`,
204+
['', scriptSetup.name, exp.start, codeFeatures.verification],
205+
`'$style'`,
206+
['', scriptSetup.name, exp.end, codeFeatures.verification],
207+
`]`
208+
],
209+
exp.end,
210+
exp.end
211+
]);
244212
}
245213
}
246214
for (const { define } of scriptSetupRanges.templateRefs) {
@@ -258,25 +226,15 @@ function* generateSetupFunction(
258226
}
259227
setupCodeModifies = setupCodeModifies.sort((a, b) => a[1] - b[1]);
260228

261-
if (setupCodeModifies.length) {
262-
yield generateSfcBlockSection(scriptSetup, scriptSetupRanges.importSectionEndOffset, setupCodeModifies[0][1], codeFeatures.all);
263-
while (setupCodeModifies.length) {
264-
const [codes, _start, end] = setupCodeModifies.shift()!;
265-
for (const code of codes) {
266-
yield code;
267-
}
268-
if (setupCodeModifies.length) {
269-
const nextStart = setupCodeModifies[0][1];
270-
yield generateSfcBlockSection(scriptSetup, end, nextStart, codeFeatures.all);
271-
}
272-
else {
273-
yield generateSfcBlockSection(scriptSetup, end, scriptSetup.content.length, codeFeatures.all);
274-
}
229+
let nextStart = scriptSetupRanges.importSectionEndOffset;
230+
for (const [codes, start, end] of setupCodeModifies) {
231+
yield generateSfcBlockSection(scriptSetup, nextStart, start, codeFeatures.all);
232+
for (const code of codes) {
233+
yield code;
275234
}
235+
nextStart = end;
276236
}
277-
else {
278-
yield generateSfcBlockSection(scriptSetup, scriptSetupRanges.importSectionEndOffset, scriptSetup.content.length, codeFeatures.all);
279-
}
237+
yield generateSfcBlockSection(scriptSetup, nextStart, scriptSetup.content.length, codeFeatures.all);
280238

281239
yield* generateScriptSectionPartiallyEnding(scriptSetup.name, scriptSetup.content.length, '#3632/scriptSetup.vue');
282240

@@ -288,7 +246,7 @@ function* generateSetupFunction(
288246
}
289247

290248
yield* generateComponentProps(options, ctx, scriptSetup, scriptSetupRanges, definePropMirrors);
291-
yield* generateModelEmits(options, scriptSetup, scriptSetupRanges);
249+
yield* generateModelEmit(scriptSetup, scriptSetupRanges);
292250
yield `function __VLS_template() {${newLine}`;
293251
const templateCodegenCtx = yield* generateTemplate(options, ctx);
294252
yield `}${endOfLine}`;
@@ -311,6 +269,54 @@ function* generateSetupFunction(
311269
}
312270
}
313271

272+
function* generateDefineWithType(
273+
scriptSetup: NonNullable<Sfc['scriptSetup']>,
274+
name: string | undefined,
275+
define: {
276+
statement: TextRange,
277+
typeArg?: TextRange
278+
},
279+
expression: TextRange,
280+
defaultName: string,
281+
typeName: string
282+
): Generator<[Code[], number, number]> {
283+
const { statement, typeArg } = define;
284+
if (typeArg) {
285+
yield [[
286+
`type ${typeName} = `,
287+
generateSfcBlockSection(scriptSetup, typeArg.start, typeArg.end, codeFeatures.all),
288+
endOfLine,
289+
], statement.start, statement.start];
290+
yield [[typeName], typeArg.start, typeArg.end];
291+
}
292+
if (!name) {
293+
if (statement.start === expression.start && statement.end === expression.end) {
294+
yield [[`const ${defaultName} = `], expression.start, expression.start];
295+
}
296+
else if (typeArg) {
297+
yield [[
298+
`const ${defaultName} = `,
299+
generateSfcBlockSection(scriptSetup, expression.start, typeArg.start, codeFeatures.all)
300+
], statement.start, typeArg.start];
301+
yield [[
302+
generateSfcBlockSection(scriptSetup, typeArg.end, expression.end, codeFeatures.all),
303+
endOfLine,
304+
generateSfcBlockSection(scriptSetup, statement.start, expression.start, codeFeatures.all),
305+
defaultName
306+
], typeArg.end, expression.end];
307+
}
308+
else {
309+
yield [[
310+
`const ${defaultName} = `,
311+
generateSfcBlockSection(scriptSetup, expression.start, expression.end, codeFeatures.all),
312+
endOfLine,
313+
generateSfcBlockSection(scriptSetup, statement.start, expression.start, codeFeatures.all),
314+
defaultName
315+
], statement.start, expression.end];
316+
}
317+
}
318+
}
319+
314320
function* generateComponentProps(
315321
options: ScriptCodegenOptions,
316322
ctx: ScriptCodegenContext,
@@ -326,7 +332,7 @@ function* generateComponentProps(
326332
yield `,${newLine}`;
327333
}
328334

329-
yield* generateEmitsOption(options, scriptSetup, scriptSetupRanges);
335+
yield* generateEmitsOption(options, scriptSetupRanges);
330336

331337
yield `})${endOfLine}`;
332338

@@ -422,40 +428,29 @@ function* generateComponentProps(
422428
yield ` & `;
423429
}
424430
ctx.generatedPropsType = true;
425-
yield `typeof __VLS_typeProps`;
431+
yield `__VLS_Props`;
426432
}
427433
if (!ctx.generatedPropsType) {
428434
yield `{}`;
429435
}
430436
yield endOfLine;
431437
}
432438

433-
function* generateModelEmits(
434-
options: ScriptCodegenOptions,
439+
function* generateModelEmit(
435440
scriptSetup: NonNullable<Sfc['scriptSetup']>,
436441
scriptSetupRanges: ScriptSetupRanges
437442
): Generator<Code> {
438443
const defineModels = scriptSetupRanges.defineProp.filter(p => p.isModel);
439444
if (defineModels.length) {
440-
const generateDefineModels = function* () {
441-
for (const defineModel of defineModels) {
442-
const [propName, localName] = getPropAndLocalName(scriptSetup, defineModel);
443-
yield `'update:${propName}': [${propName}:`;
444-
yield* generateDefinePropType(scriptSetup, propName, localName, defineModel);
445-
yield `]${endOfLine}`;
446-
}
447-
};
448-
if (options.vueCompilerOptions.target >= 3.5) {
449-
yield `type __VLS_ModelEmitsType = {${newLine}`;
450-
yield* generateDefineModels();
451-
yield `}${endOfLine}`;
452-
}
453-
else {
454-
yield `const __VLS_modelEmitsType = (await import('${options.vueCompilerOptions.lib}')).defineEmits<{${newLine}`;
455-
yield* generateDefineModels();
456-
yield `}>()${endOfLine}`;
457-
yield `type __VLS_ModelEmitsType = typeof __VLS_modelEmitsType${endOfLine}`;
445+
yield `type __VLS_ModelEmit = {${newLine}`;
446+
for (const defineModel of defineModels) {
447+
const [propName, localName] = getPropAndLocalName(scriptSetup, defineModel);
448+
yield `'update:${propName}': [${propName}:`;
449+
yield* generateDefinePropType(scriptSetup, propName, localName, defineModel);
450+
yield `]${endOfLine}`;
458451
}
452+
yield `}${endOfLine}`;
453+
yield `const __VLS_modelEmit = defineEmits<__VLS_ModelEmit>()${endOfLine}`;
459454
}
460455
}
461456

0 commit comments

Comments
 (0)