diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index 19689701d5..2a733c60af 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -114,7 +114,7 @@ declare function __VLS_asFunctionalComponent any ? T : (_: {}${strictTemplates ? '' : ' & Record'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${strictTemplates ? '' : ' & Record'} } }; declare function __VLS_elementAsFunction(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record'}) => void; -declare function __VLS_functionalComponentArgsRest any>(t: T): Parameters['length'] extends 2 ? [any] : []; +declare function __VLS_functionalComponentArgsRest any>(t: T): 2 extends Parameters['length'] ? [any] : []; declare function __VLS_pickFunctionalComponentCtx(comp: T, compInstance: K): NonNullable<__VLS_PickNotAny< '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } ? Ctx : never : any , T extends (props: any, ctx: infer Ctx) => any ? Ctx : any diff --git a/packages/language-core/lib/codegen/localTypes.ts b/packages/language-core/lib/codegen/localTypes.ts index e244f16f0f..d4939c3bf6 100644 --- a/packages/language-core/lib/codegen/localTypes.ts +++ b/packages/language-core/lib/codegen/localTypes.ts @@ -80,19 +80,6 @@ type __VLS_TypePropsToOption = { `__VLS_OmitIndexSignature`, () => `type __VLS_OmitIndexSignature = { [K in keyof T as {} extends Record ? never : K]: T[K]; }${endOfLine}` ); - const PickRefsExpose = defineHelper( - `__VLS_PickRefsExpose`, - () => ` -type __VLS_PickRefsExpose = T extends object - ? { [K in keyof T]: (T[K] extends any[] - ? Parameters[0][] - : T[K] extends { expose?: (exposed: infer E) => void } - ? E - : T[K]) | null } - : never; -`.trimStart() - ); - const helpers = { [PrettifyLocal.name]: PrettifyLocal, [OmitKeepDiscriminatedUnion.name]: OmitKeepDiscriminatedUnion, @@ -101,7 +88,6 @@ type __VLS_PickRefsExpose = T extends object [PropsChildren.name]: PropsChildren, [TypePropsToOption.name]: TypePropsToOption, [OmitIndexSignature.name]: OmitIndexSignature, - [PickRefsExpose.name]: PickRefsExpose, }; used.clear(); @@ -117,7 +103,6 @@ type __VLS_PickRefsExpose = T extends object get PropsChildren() { return PropsChildren.name; }, get TypePropsToOption() { return TypePropsToOption.name; }, get OmitIndexSignature() { return OmitIndexSignature.name; }, - get PickRefsExpose() { return PickRefsExpose.name; }, }; function* generate(names: string[]) { diff --git a/packages/language-core/lib/codegen/script/internalComponent.ts b/packages/language-core/lib/codegen/script/internalComponent.ts index 137a15997a..bfa36b65a8 100644 --- a/packages/language-core/lib/codegen/script/internalComponent.ts +++ b/packages/language-core/lib/codegen/script/internalComponent.ts @@ -47,9 +47,6 @@ export function* generateInternalComponent( } yield `}${endOfLine}`; // return { yield `},${newLine}`; // setup() { - if (options.vueCompilerOptions.target >= 3.5) { - yield `__typeRefs: {} as __VLS_Refs,${newLine}`; - } if (options.sfc.scriptSetup && options.scriptSetupRanges && !ctx.bypassDefineComponent) { const emitOptionCodes = [...generateEmitsOption(options, options.sfc.scriptSetup, options.scriptSetupRanges)]; for (const code of emitOptionCodes) { diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index 695d0ace06..7c5d85d6ec 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -13,20 +13,34 @@ export function* generateTemplateCtx( options: ScriptCodegenOptions, isClassComponent: boolean ): Generator { - const types = []; + const exps = []; if (isClassComponent) { - types.push(`typeof this`); + exps.push(`this`); } else { - types.push(`InstanceType<__VLS_PickNotAny {}>>`); + exps.push(`{} as InstanceType<__VLS_PickNotAny {}>>`); } if (options.vueCompilerOptions.petiteVueExtensions.some(ext => options.fileBaseName.endsWith(ext))) { - types.push(`typeof globalThis`); + exps.push(`globalThis`); } if (options.sfc.styles.some(style => style.module)) { - types.push(`__VLS_StyleModules`); + exps.push(`{} as __VLS_StyleModules`); + } + + yield `const __VLS_ctx = `; + if (exps.length === 1) { + yield exps[0]; + yield endOfLine; + } + else { + yield `{${newLine}`; + for (const exp of exps) { + yield `...`; + yield exp; + yield `,${newLine}`; + } + yield `}${endOfLine}`; } - yield `let __VLS_ctx!: ${types.join(' & ')}${endOfLine}`; } export function* generateTemplateComponents(options: ScriptCodegenOptions): Generator { @@ -87,7 +101,7 @@ export function* generateTemplate( }); yield* generateTemplateCtx(options, isClassComponent); yield* generateTemplateComponents(options); - yield* generateTemplateBody(options, ctx, templateCodegenCtx); + yield* generateTemplateBody(options, templateCodegenCtx); yield* generateInternalComponent(options, ctx, templateCodegenCtx); } else { @@ -100,7 +114,6 @@ export function* generateTemplate( function* generateTemplateBody( options: ScriptCodegenOptions, - ctx: ScriptCodegenContext, templateCodegenCtx: TemplateCodegenContext ): Generator { const firstClasses = new Set(); @@ -142,14 +155,14 @@ function* generateTemplateBody( yield `// no template${newLine}`; if (!options.scriptSetupRanges?.slots.define) { yield `const __VLS_slots = {}${endOfLine}`; - yield `const __VLS_refs = {}${endOfLine}`; + yield `const $refs = {}${endOfLine}`; yield `const __VLS_inheritedAttrs = {}${endOfLine}`; } } yield `const __VLS_templateResult = {`; yield `slots: ${options.scriptSetupRanges?.slots.name ?? '__VLS_slots'},${newLine}`; - yield `refs: __VLS_refs as ${ctx.localTypes.PickRefsExpose},${newLine}`; + yield `refs: $refs,${newLine}`; yield `attrs: {} as Partial,${newLine}`; yield `}${endOfLine}`; } diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index 2a3edac1da..9670cbf4c6 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -225,7 +225,19 @@ export function* generateComponent( const refName = yield* generateVScope(options, ctx, node, props); if (refName) { + const varName = ctx.getInternalVariable(); + options.templateRefNames.set(refName, varName); ctx.usedComponentCtxVars.add(var_defineComponentCtx); + + yield `// @ts-ignore${newLine}`; + if (node.codegenNode?.type === CompilerDOM.NodeTypes.VNODE_CALL + && node.codegenNode.props?.type === CompilerDOM.NodeTypes.JS_OBJECT_EXPRESSION + && node.codegenNode.props.properties.find(({ key }) => key.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && key.content === 'ref_for') + ) { + yield `var ${varName} = [{} as Parameters[0]]${endOfLine}`; + } else { + yield `var ${varName} = {} as Parameters[0]${endOfLine}`; + } } const usedComponentEventsVar = yield* generateElementEvents(options, ctx, node, var_functionalComponent, var_componentInstance, var_componentEmit, var_componentEvents); @@ -257,19 +269,6 @@ export function* generateComponent( if (ctx.usedComponentCtxVars.has(var_defineComponentCtx)) { yield `const ${var_defineComponentCtx} = __VLS_pickFunctionalComponentCtx(${var_originalComponent}, ${var_componentInstance})${endOfLine}`; - if (refName) { - yield `// @ts-ignore${newLine}`; - if (node.codegenNode?.type === CompilerDOM.NodeTypes.VNODE_CALL - && node.codegenNode.props?.type === CompilerDOM.NodeTypes.JS_OBJECT_EXPRESSION - && node.codegenNode.props.properties.find(({ key }) => key.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && key.content === 'ref_for') - ) { - yield `(${refName} ??= []).push(${var_defineComponentCtx})`; - } else { - yield `${refName} = ${var_defineComponentCtx}`; - } - - yield endOfLine; - } } } @@ -335,14 +334,7 @@ export function* generateElement( const refName = yield* generateVScope(options, ctx, node, node.props); if (refName) { - yield `// @ts-ignore${newLine}`; - yield `${refName} = __VLS_intrinsicElements`; - yield* generatePropertyAccess( - options, - ctx, - node.tag - ); - yield endOfLine; + options.templateRefNames.set(refName, `__VLS_intrinsicElements['${node.tag}']`); } const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode; @@ -574,9 +566,7 @@ function* generateReferencesForElements( ctx.accessExternalVariable(content, startOffset); } - const refName = CompilerDOM.toValidAssetId(prop.value.content, '_VLS_refs' as any); - options.templateRefNames.set(prop.value.content, refName); - return refName; + return prop.value.content; } } } diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index c68a820da3..643136d385 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -32,6 +32,7 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator { - for (const [, validId] of options.templateRefNames) { - yield `let ${validId}${newLine}`; - } yield `const __VLS_refs = {${newLine}`; - for (const [name, validId] of options.templateRefNames) { - yield `'${name}': ${validId}!,${newLine}`; + for (const [name, varName] of options.templateRefNames) { + yield `'${name}': ${varName}!,${newLine}`; } yield `}${endOfLine}`; + yield `declare var $refs: typeof __VLS_refs${endOfLine}`; } function* generateSlotsType(): Generator { diff --git a/packages/language-core/lib/parsers/scriptSetupRanges.ts b/packages/language-core/lib/parsers/scriptSetupRanges.ts index 0a53528a1c..59de404b3e 100644 --- a/packages/language-core/lib/parsers/scriptSetupRanges.ts +++ b/packages/language-core/lib/parsers/scriptSetupRanges.ts @@ -50,7 +50,6 @@ export function parseScriptSetupRanges( name?: string; define?: ReturnType; }[] = []; - const definePropProposalA = vueCompilerOptions.experimentalDefinePropProposal === 'kevinEdition' || ast.text.trimStart().startsWith('// @experimentalDefinePropProposal=kevinEdition'); const definePropProposalB = vueCompilerOptions.experimentalDefinePropProposal === 'johnsonEdition' || ast.text.trimStart().startsWith('// @experimentalDefinePropProposal=johnsonEdition'); const defineProp: { @@ -63,11 +62,12 @@ export function parseScriptSetupRanges( required: boolean; isModel?: boolean; }[] = []; - const bindings = parseBindingRanges(ts, ast); const text = ast.text; const leadingCommentEndOffset = ts.getLeadingCommentRanges(text, 0)?.reverse()[0].end ?? 0; const importComponentNames = new Set(); + let bindings = parseBindingRanges(ts, ast); + ts.forEachChild(ast, node => { const isTypeExport = (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) && node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword); if ( @@ -102,6 +102,12 @@ export function parseScriptSetupRanges( }); ts.forEachChild(ast, child => visitNode(child, [ast])); + const templateRefNames = new Set(templateRefs.map(ref => ref.name)); + bindings = bindings.filter(range => { + const name = text.substring(range.start, range.end); + return !templateRefNames.has(name); + }); + return { leadingCommentEndOffset, importSectionEndOffset, diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap index a134e8d034..0b12b2b53a 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -645,7 +645,6 @@ declare var __VLS_3: { str: string; }; declare var __VLS_inheritedAttrs: {}; -declare const __VLS_refs: {}; declare const __VLS_templateResult: { slots: { "no-bind"?(_: typeof __VLS_0): any; @@ -653,18 +652,13 @@ declare const __VLS_templateResult: { "named-slot"?(_: typeof __VLS_2): any; vbind?(_: typeof __VLS_3): any; }; - refs: __VLS_PickRefsExpose; + refs: {}; attrs: Partial; }; type __VLS_Slots = typeof __VLS_templateResult['slots']; declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly>, {}, {}>; declare const _default: __VLS_WithTemplateSlots; export default _default; -type __VLS_PickRefsExpose = T extends object ? { - [K in keyof T]: (T[K] extends any[] ? Parameters[0][] : T[K] extends { - expose?: (exposed: infer E) => void; - } ? E : T[K]) | null; -} : never; type __VLS_WithTemplateSlots = T & { new (): { $slots: S; @@ -676,7 +670,6 @@ type __VLS_WithTemplateSlots = T & { exports[`vue-tsc-dts > Input: template-slots/component-define-slots.vue, Output: template-slots/component-define-slots.vue.d.ts 1`] = ` "import { VNode } from 'vue'; declare var __VLS_inheritedAttrs: {}; -declare const __VLS_refs: {}; declare const __VLS_templateResult: { slots: Readonly<{ default: (props: { @@ -703,18 +696,13 @@ declare const __VLS_templateResult: { }) => VNode[]; 'no-bind': () => VNode[]; }; - refs: __VLS_PickRefsExpose; + refs: {}; attrs: Partial; }; type __VLS_Slots = typeof __VLS_templateResult['slots']; declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly>, {}, {}>; declare const _default: __VLS_WithTemplateSlots; export default _default; -type __VLS_PickRefsExpose = T extends object ? { - [K in keyof T]: (T[K] extends any[] ? Parameters[0][] : T[K] extends { - expose?: (exposed: infer E) => void; - } ? E : T[K]) | null; -} : never; type __VLS_WithTemplateSlots = T & { new (): { $slots: S; @@ -725,7 +713,6 @@ type __VLS_WithTemplateSlots = T & { exports[`vue-tsc-dts > Input: template-slots/component-destructuring.vue, Output: template-slots/component-destructuring.vue.d.ts 1`] = ` "declare var __VLS_inheritedAttrs: {}; -declare const __VLS_refs: {}; declare const __VLS_templateResult: { slots: Readonly<{ bottom: (props: { @@ -736,18 +723,13 @@ declare const __VLS_templateResult: { num: number; }) => any[]; }; - refs: __VLS_PickRefsExpose; + refs: {}; attrs: Partial; }; type __VLS_Slots = typeof __VLS_templateResult['slots']; declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly>, {}, {}>; declare const _default: __VLS_WithTemplateSlots; export default _default; -type __VLS_PickRefsExpose = T extends object ? { - [K in keyof T]: (T[K] extends any[] ? Parameters[0][] : T[K] extends { - expose?: (exposed: infer E) => void; - } ? E : T[K]) | null; -} : never; type __VLS_WithTemplateSlots = T & { new (): { $slots: S; @@ -769,7 +751,6 @@ declare var __VLS_3: { str: string; }; declare var __VLS_inheritedAttrs: {}; -declare const __VLS_refs: {}; declare const __VLS_templateResult: { slots: { "no-bind"?(_: typeof __VLS_0): any; @@ -777,18 +758,13 @@ declare const __VLS_templateResult: { "named-slot"?(_: typeof __VLS_2): any; vbind?(_: typeof __VLS_3): any; }; - refs: __VLS_PickRefsExpose; + refs: {}; attrs: Partial; }; type __VLS_Slots = typeof __VLS_templateResult['slots']; declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly>, {}, {}>; declare const _default: __VLS_WithTemplateSlots; export default _default; -type __VLS_PickRefsExpose = T extends object ? { - [K in keyof T]: (T[K] extends any[] ? Parameters[0][] : T[K] extends { - expose?: (exposed: infer E) => void; - } ? E : T[K]) | null; -} : never; type __VLS_WithTemplateSlots = T & { new (): { $slots: S; diff --git a/test-workspace/tsc/passedFixtures/vue3.5/templateRef/components.d.ts b/test-workspace/tsc/passedFixtures/vue3.5/templateRef/components.d.ts new file mode 100644 index 0000000000..3a355c3137 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3.5/templateRef/components.d.ts @@ -0,0 +1,7 @@ +declare module 'vue3.5' { + export interface GlobalComponents { + Generic: typeof import('./generic.vue')['default']; + } +} + +export { }; diff --git a/test-workspace/tsc/passedFixtures/vue3.5/templateRef/main.vue b/test-workspace/tsc/passedFixtures/vue3.5/templateRef/main.vue index 7f871fac60..0eb980af65 100644 --- a/test-workspace/tsc/passedFixtures/vue3.5/templateRef/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3.5/templateRef/main.vue @@ -6,5 +6,5 @@ import { exactType } from '../../shared'; diff --git a/test-workspace/tsc/passedFixtures/vue3.5/templateRef/template-ref.vue b/test-workspace/tsc/passedFixtures/vue3.5/templateRef/template-ref.vue index 2a08b3ce79..6547d70c37 100644 --- a/test-workspace/tsc/passedFixtures/vue3.5/templateRef/template-ref.vue +++ b/test-workspace/tsc/passedFixtures/vue3.5/templateRef/template-ref.vue @@ -1,21 +1,26 @@