diff --git a/packages/vue-language-core/src/generators/script.ts b/packages/vue-language-core/src/generators/script.ts index 735a7ae16e..9133ef0643 100644 --- a/packages/vue-language-core/src/generators/script.ts +++ b/packages/vue-language-core/src/generators/script.ts @@ -57,10 +57,11 @@ export function generate( leadingCommentEndOffset: 0, importSectionEndOffset: 0, defineProps: undefined, + defineSlots: undefined, + slotsAssignName: undefined, propsAssignName: undefined, propsRuntimeArg: undefined, propsTypeArg: undefined, - slotsTypeArg: undefined, withDefaultsArg: undefined, defineProp: [], }; @@ -383,11 +384,9 @@ export function generate( } codes.push(`}`); } - if (scriptSetupRanges.slotsTypeArg && vueCompilerOptions.jsxSlots) { + if (scriptSetupRanges.defineSlots && vueCompilerOptions.jsxSlots) { usedHelperTypes.PropsChildren = true; - codes.push(` & __VLS_PropsChildren<`); - addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.slotsTypeArg.start, scriptSetupRanges.slotsTypeArg.end); - codes.push('>'); + codes.push(` & __VLS_PropsChildren`); } codes.push(`;\n`); //#endregion @@ -490,7 +489,14 @@ declare function defineProp(value?: T | (() => T), required?: boolean, rest?: const scriptSetupGeneratedOffset = muggle.getLength(codes) - scriptSetupRanges.importSectionEndOffset; - addVirtualCode('scriptSetup', scriptSetupRanges.importSectionEndOffset); + if (scriptSetupRanges.defineSlots && !scriptSetupRanges.slotsAssignName) { + addVirtualCode('scriptSetup', scriptSetupRanges.importSectionEndOffset, scriptSetupRanges.defineSlots.start); + codes.push(`const __VLS_slots = `); + addVirtualCode('scriptSetup', scriptSetupRanges.defineSlots.start); + } + else { + addVirtualCode('scriptSetup', scriptSetupRanges.importSectionEndOffset); + } if (scriptSetupRanges.propsTypeArg && scriptSetupRanges.withDefaultsArg) { // fix https://github.com/vuejs/language-tools/issues/1187 @@ -655,7 +661,7 @@ declare function defineProp(value?: T | (() => T), required?: boolean, rest?: codes.push('export default '); } if (mode === 'return' || mode === 'export') { - if (!vueCompilerOptions.skipTemplateCodegen && (htmlGen?.hasSlot || scriptSetupRanges?.slotsTypeArg)) { + if (!vueCompilerOptions.skipTemplateCodegen && (htmlGen?.hasSlot || scriptSetupRanges?.defineSlots)) { usedHelperTypes.WithTemplateSlots = true; codes.push(`{} as __VLS_WithTemplateSlots>;`); } @@ -678,12 +684,6 @@ declare function defineProp(value?: T | (() => T), required?: boolean, rest?: generateExportOptions(); generateConstNameOption(); - if (scriptSetupRanges?.slotsTypeArg && sfc.scriptSetup) { - codes.push(`var __VLS_slots!: `); - addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.slotsTypeArg.start, scriptSetupRanges.slotsTypeArg.end); - codes.push(';\n'); - }; - codes.push(`function __VLS_template() {\n`); const templateGened = generateTemplateContext(); @@ -837,7 +837,7 @@ declare function defineProp(value?: T | (() => T), required?: boolean, rest?: /* Components */ codes.push('/* Components */\n'); codes.push(`let __VLS_otherComponents!: NonNullable & typeof __VLS_componentsOption;\n`); - codes.push(`let __VLS_own!: __VLS_SelfComponent { ${getSlotsPropertyName(vueCompilerOptions.target)}: typeof __VLS_slots })>;\n`); + codes.push(`let __VLS_own!: __VLS_SelfComponent { ${getSlotsPropertyName(vueCompilerOptions.target)}: typeof ${scriptSetupRanges?.slotsAssignName ?? '__VLS_slots'} })>;\n`); codes.push(`let __VLS_localComponents!: typeof __VLS_otherComponents & Omit;\n`); codes.push(`let __VLS_components!: typeof __VLS_localComponents & __VLS_GlobalComponents & typeof __VLS_ctx;\n`); // for html completion, TS references... @@ -878,17 +878,12 @@ declare function defineProp(value?: T | (() => T), required?: boolean, rest?: if (!htmlGen) { codes.push(`// no template\n`); - if (scriptSetupRanges?.slotsTypeArg && sfc.scriptSetup) { - codes.push(`let __VLS_slots!: `); - addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.slotsTypeArg.start, scriptSetupRanges.slotsTypeArg.end); - codes.push(`;\n`); - } - else { + if (!scriptSetupRanges?.defineSlots) { codes.push(`const __VLS_slots = {};\n`); } } - codes.push(`return __VLS_slots;\n`); + codes.push(`return ${scriptSetupRanges?.slotsAssignName ?? '__VLS_slots'};\n`); return { cssIds }; diff --git a/packages/vue-language-core/src/generators/template.ts b/packages/vue-language-core/src/generators/template.ts index 02d945ad7e..1bfcbbcdfa 100644 --- a/packages/vue-language-core/src/generators/template.ts +++ b/packages/vue-language-core/src/generators/template.ts @@ -73,6 +73,7 @@ export function generate( sourceLang: string, sfc: Sfc, hasScriptSetupSlots: boolean, + slotsAssignName: string | undefined, codegenStack: boolean, ) { @@ -1644,7 +1645,7 @@ export function generate( codes.push( '__VLS_normalizeSlot(', ['', 'template', node.loc.start.offset, capabilitiesPresets.diagnosticOnly], - '__VLS_slots[', + `${slotsAssignName ?? '__VLS_slots'}[`, ['', 'template', node.loc.start.offset, capabilitiesPresets.diagnosticOnly], slotNameExpNode?.content ?? `('${getSlotName()}' as const)`, ['', 'template', node.loc.end.offset, capabilitiesPresets.diagnosticOnly], diff --git a/packages/vue-language-core/src/parsers/scriptSetupRanges.ts b/packages/vue-language-core/src/parsers/scriptSetupRanges.ts index 18f8a76832..2c0153d4ab 100644 --- a/packages/vue-language-core/src/parsers/scriptSetupRanges.ts +++ b/packages/vue-language-core/src/parsers/scriptSetupRanges.ts @@ -16,7 +16,8 @@ export function parseScriptSetupRanges( let defineProps: TextRange | undefined; let propsRuntimeArg: TextRange | undefined; let propsTypeArg: TextRange | undefined; - let slotsTypeArg: TextRange | undefined; + let defineSlots: TextRange | undefined; + let slotsAssignName: string | undefined; let emitsAssignName: string | undefined; let emitsRuntimeArg: TextRange | undefined; let emitsTypeArg: TextRange | undefined; @@ -65,10 +66,11 @@ export function parseScriptSetupRanges( bindings, withDefaultsArg, defineProps, + defineSlots, propsAssignName, propsRuntimeArg, propsTypeArg, - slotsTypeArg, + slotsAssignName, emitsAssignName, emitsRuntimeArg, emitsTypeArg, @@ -170,6 +172,12 @@ export function parseScriptSetupRanges( if (vueCompilerOptions.macros.defineProps.includes(callText)) { defineProps = _getStartEnd(node); } + if (vueCompilerOptions.macros.defineSlots.includes(callText)) { + defineSlots = _getStartEnd(node); + if (ts.isVariableDeclaration(parent)) { + slotsAssignName = parent.name.getText(ast); + } + } if (node.arguments.length) { const runtimeArg = node.arguments[0]; if (vueCompilerOptions.macros.defineProps.includes(callText)) { @@ -196,10 +204,7 @@ export function parseScriptSetupRanges( propsAssignName = parent.name.getText(ast); } } - if (vueCompilerOptions.macros.defineSlots.includes(callText)) { - slotsTypeArg = _getStartEnd(typeArg); - } - else if (vueCompilerOptions.macros.defineEmits.includes(callText)) { + if (vueCompilerOptions.macros.defineEmits.includes(callText)) { emitsTypeArg = _getStartEnd(typeArg); if (ts.isTypeLiteralNode(typeArg)) { emitsTypeNums = typeArg.members.length; diff --git a/packages/vue-language-core/src/plugins/vue-tsx.ts b/packages/vue-language-core/src/plugins/vue-tsx.ts index 3f791abdb3..ec53a84684 100644 --- a/packages/vue-language-core/src/plugins/vue-tsx.ts +++ b/packages/vue-language-core/src/plugins/vue-tsx.ts @@ -151,12 +151,19 @@ function createTsx(fileName: string, _sfc: Sfc, { vueCompilerOptions, compilerOp _sfc.template?.lang ?? 'html', _sfc, hasScriptSetupSlots.value, + slotsAssignName.value, codegenStack, ); }); - const hasScriptSetupSlots = ref(false); // remove when https://github.com/vuejs/core/pull/5912 merged + + //#region remove when https://github.com/vuejs/core/pull/5912 merged + const hasScriptSetupSlots = ref(false); + const slotsAssignName = ref(); + //#endregion + const tsxGen = computed(() => { - hasScriptSetupSlots.value = !!scriptSetupRanges.value?.slotsTypeArg; + hasScriptSetupSlots.value = !!scriptSetupRanges.value?.defineSlots; + slotsAssignName.value = scriptSetupRanges.value?.slotsAssignName; return genScript( ts, fileName, diff --git a/packages/vue-test-workspace/vue-tsc/non-strict-template/components/main.vue b/packages/vue-test-workspace/vue-tsc/non-strict-template/components/main.vue index e86d190ac3..caed2156cf 100644 --- a/packages/vue-test-workspace/vue-tsc/non-strict-template/components/main.vue +++ b/packages/vue-test-workspace/vue-tsc/non-strict-template/components/main.vue @@ -20,8 +20,8 @@ const ScriptSetupExact = defineComponent({ // https://vuejs.org/api/sfc-script-setup.html#defineexpose const ScriptSetupExposeExact = defineComponent({ setup() { - const a = 1 - const b = ref(2) + const a = 1; + const b = ref(2); return { a, b @@ -67,13 +67,13 @@ declare const ScriptSetupGenericExact: ( _ctx?: Pick>, 'attrs' | 'emit' | 'slots'>, _expose?: NonNullable>['expose'], _setup?: Promise<{ - props: { foo: T } & { [K in keyof JSX.ElementChildrenAttribute]?: { default?(data: T): any } }, + props: { foo: T; } & { [K in keyof JSX.ElementChildrenAttribute]?: Readonly<{ default?(data: T): any; }> }, attrs: any, - slots: { default?(data: T): any }, - emit: { (e: 'bar', data: T): void }, - expose(_exposed: { baz: T }): void, + slots: Readonly<{ default?(data: T): any; }>, + emit: { (e: 'bar', data: T): void; }, + expose(_exposed: { baz: T; }): void, }> -) => import('vue').VNode & { __ctx?: Awaited }; +) => import('vue').VNode & { __ctx?: Awaited; }; exactType(ScriptSetup, ScriptSetupExact); exactType(ScriptSetupExpose, ScriptSetupExposeExact); diff --git a/packages/vue-tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/vue-tsc/tests/__snapshots__/dts.spec.ts.snap index cdbf19b223..95a6d745ea 100644 --- a/packages/vue-tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/vue-tsc/tests/__snapshots__/dts.spec.ts.snap @@ -64,9 +64,9 @@ exports[`vue-tsc-dts > Input: components/script-setup-generic.vue, Output: compo baz: T; }): void; attrs: any; - slots: { + slots: Readonly<{ default?(data: T): any; - }; + }>; emit: (e: 'bar', data: T) => void; }, \\"slots\\" | \\"attrs\\" | \\"emit\\">, __VLS_expose?: (exposed: { baz: T; @@ -78,9 +78,9 @@ exports[`vue-tsc-dts > Input: components/script-setup-generic.vue, Output: compo baz: T; }): void; attrs: any; - slots: { + slots: Readonly<{ default?(data: T): any; - }; + }>; emit: (e: 'bar', data: T) => void; }>) => import(\\"vue\\").VNode Input: components/script-setup-generic.vue, Output: compo baz: T; }): void; attrs: any; - slots: { + slots: Readonly<{ default?(data: T): any; - }; + }>; emit: (e: 'bar', data: T) => void; }; };