From 4f31b169bfda01055ddbeed5f9c68cfd8db46865 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 17 Dec 2024 01:13:44 +0800 Subject: [PATCH 1/3] feat(language-core): type support of `useSlots` and `$slots` --- .../lib/codegen/script/scriptSetup.ts | 11 +++ .../lib/codegen/script/template.ts | 2 +- .../lib/codegen/template/index.ts | 69 ++++++++++--------- .../lib/parsers/scriptSetupRanges.ts | 7 ++ packages/language-core/lib/types.ts | 1 + packages/language-core/lib/utils/ts.ts | 1 + .../schemas/vue-tsconfig.schema.json | 16 ++++- .../tsc/passedFixtures/vue3/slots/main.vue | 10 ++- 8 files changed, 78 insertions(+), 39 deletions(-) diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index d8235fd792..51ada941a7 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -234,6 +234,17 @@ function* generateSetupFunction( callExp.end ]); } + for (const { callExp } of scriptSetupRanges.useSlots) { + setupCodeModifies.push([ + [`(`], + callExp.start, + callExp.start + ], [ + [` as __VLS_TemplateResult['slots'])`], + callExp.end, + callExp.end + ]) + } const isTs = options.lang !== 'js' && options.lang !== 'jsx'; for (const { callExp, exp, arg } of scriptSetupRanges.useTemplateRef) { const templateRefType = arg ? [ diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index ad493af3b3..348e1f0dd5 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -62,7 +62,7 @@ function* generateTemplateComponents(options: ScriptCodegenOptions): Generator { ` + getSlotsPropertyName(options.vueCompilerOptions.target) - + ` : typeof ${options.scriptSetupRanges?.defineSlots?.name ?? `__VLS_slots`} }) }` + + `: typeof ${options.scriptSetupRanges?.defineSlots?.name ?? `__VLS_slots`} }) }` ); } diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index 17ddef19d8..7383d40fe4 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -1,6 +1,7 @@ import * as CompilerDOM from '@vue/compiler-dom'; import type * as ts from 'typescript'; import type { Code, Sfc, VueCompilerOptions } from '../../types'; +import { getSlotsPropertyName } from '../../utils/shared'; import { endOfLine, newLine, wrapWith } from '../utils'; import { generateStringLiteralKey } from '../utils/stringLiteralKey'; import { TemplateCodegenContext, createTemplateCodegenContext } from './context'; @@ -34,9 +35,10 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator { - for (const { expVar, varName } of ctx.dynamicSlots) { - ctx.hasSlot = true; - yield `Partial, (_: typeof ${varName}) => any>> &${newLine}`; - } - yield `{${newLine}`; - for (const slot of ctx.slots) { - ctx.hasSlot = true; - if (slot.name && slot.loc !== undefined) { - yield* generateObjectProperty( - options, - ctx, - slot.name, - slot.loc, - ctx.codeFeatures.withoutHighlightAndCompletion, - slot.nodeLoc - ); + if (!options.hasDefineSlots) { + yield `var __VLS_slots!: `; + for (const { expVar, varName } of ctx.dynamicSlots) { + ctx.hasSlot = true; + yield `Partial, (_: typeof ${varName}) => any>> &${newLine}`; } - else { - yield* wrapWith( - slot.tagRange[0], - slot.tagRange[1], - ctx.codeFeatures.withoutHighlightAndCompletion, - `default` - ); + yield `{${newLine}`; + for (const slot of ctx.slots) { + ctx.hasSlot = true; + if (slot.name && slot.loc !== undefined) { + yield* generateObjectProperty( + options, + ctx, + slot.name, + slot.loc, + ctx.codeFeatures.withoutHighlightAndCompletion, + slot.nodeLoc + ); + } + else { + yield* wrapWith( + slot.tagRange[0], + slot.tagRange[1], + ctx.codeFeatures.withoutHighlightAndCompletion, + `default` + ); + } + yield `?(_: typeof ${slot.varName}): any,${newLine}`; } - yield `?(_: typeof ${slot.varName}): any,${newLine}`; + yield `}${endOfLine}`; } - yield `}`; + const name = getSlotsPropertyName(options.vueCompilerOptions.target); + yield `var ${name}!: typeof ${options.slotsAssignName ?? '__VLS_slots'}${endOfLine}`; } function* generateInheritedAttrs(ctx: TemplateCodegenContext): Generator { diff --git a/packages/language-core/lib/parsers/scriptSetupRanges.ts b/packages/language-core/lib/parsers/scriptSetupRanges.ts index 5866612611..7c1b40bd14 100644 --- a/packages/language-core/lib/parsers/scriptSetupRanges.ts +++ b/packages/language-core/lib/parsers/scriptSetupRanges.ts @@ -54,6 +54,8 @@ type UseAttrs = CallExpressionRange; type UseCssModule = CallExpressionRange; +type UseSlots = CallExpressionRange; + type UseTemplateRef = CallExpressionRange & { name?: string; } @@ -74,6 +76,7 @@ export function parseScriptSetupRanges( let defineOptions: DefineOptions | undefined; const useAttrs: UseAttrs[] = []; const useCssModule: UseCssModule[] = []; + const useSlots: UseSlots[] = []; const useTemplateRef: UseTemplateRef[] = []; const definePropProposalA = vueCompilerOptions.experimentalDefinePropProposal === 'kevinEdition' || ast.text.trimStart().startsWith('// @experimentalDefinePropProposal=kevinEdition'); const definePropProposalB = vueCompilerOptions.experimentalDefinePropProposal === 'johnsonEdition' || ast.text.trimStart().startsWith('// @experimentalDefinePropProposal=johnsonEdition'); @@ -145,6 +148,7 @@ export function parseScriptSetupRanges( defineOptions, useAttrs, useCssModule, + useSlots, useTemplateRef, }; @@ -390,6 +394,9 @@ export function parseScriptSetupRanges( else if (vueCompilerOptions.composables.useCssModule.includes(callText)) { useCssModule.push(parseCallExpression(node)); } + else if (vueCompilerOptions.composables.useSlots.includes(callText)) { + useSlots.push(parseCallExpression(node)); + } else if ( vueCompilerOptions.composables.useTemplateRef.includes(callText) && !node.typeArguments?.length diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 46c91ba83c..bcee20d441 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -46,6 +46,7 @@ export interface VueCompilerOptions { composables: { useAttrs: string[]; useCssModule: string[]; + useSlots: string[]; useTemplateRef: string[]; }; plugins: VueLanguagePlugin[]; diff --git a/packages/language-core/lib/utils/ts.ts b/packages/language-core/lib/utils/ts.ts index 1b308acfc9..e3607ba6bb 100644 --- a/packages/language-core/lib/utils/ts.ts +++ b/packages/language-core/lib/utils/ts.ts @@ -254,6 +254,7 @@ export function resolveVueCompilerOptions(vueOptions: Partial - @@ -38,8 +37,15 @@ declare const Comp: new (props: { value: T; }) => { From 8935f0ae5a05c355b69be5caf185904c0c71c0d8 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 17 Dec 2024 01:18:46 +0800 Subject: [PATCH 2/3] chore: rename --- packages/language-core/lib/codegen/template/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index 7383d40fe4..4818b253e1 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -47,18 +47,16 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator { +function* generateSlots(options: TemplateCodegenOptions, ctx: TemplateCodegenContext): Generator { if (!options.hasDefineSlots) { yield `var __VLS_slots!: `; for (const { expVar, varName } of ctx.dynamicSlots) { From 4554780d0a0de5e85de86d2b23965ea467a022e6 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 17 Dec 2024 01:21:22 +0800 Subject: [PATCH 3/3] chore: lint --- packages/language-core/lib/codegen/script/scriptSetup.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index 51ada941a7..8b21666f86 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -211,7 +211,7 @@ function* generateSetupFunction( [` as __VLS_TemplateResult['attrs'] & Record)`], callExp.end, callExp.end - ]) + ]); } for (const { callExp, exp, arg } of scriptSetupRanges.useCssModule) { setupCodeModifies.push([ @@ -243,7 +243,7 @@ function* generateSetupFunction( [` as __VLS_TemplateResult['slots'])`], callExp.end, callExp.end - ]) + ]); } const isTs = options.lang !== 'js' && options.lang !== 'jsx'; for (const { callExp, exp, arg } of scriptSetupRanges.useTemplateRef) {