From 97ad9d8249079ea4129aa79ff721a923b7fe7905 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 21 Jan 2025 22:52:07 +0800 Subject: [PATCH 01/18] feat: type support of slot children --- .../language-core/lib/codegen/globalTypes.ts | 41 +++-- .../lib/codegen/template/context.ts | 5 + .../lib/codegen/template/element.ts | 23 +-- .../lib/codegen/template/elementEvents.ts | 8 +- .../lib/codegen/template/elementProps.ts | 5 +- .../lib/codegen/template/vSlot.ts | 162 +++++++++++------- .../tsc/passedFixtures/vue3/#4668/child.vue | 4 +- .../tsc/passedFixtures/vue3/#4668/main.vue | 2 +- .../vue3/slot-children/child.vue | 5 + .../vue3/slot-children/main.vue | 15 ++ .../vue3/slot-children/parent.vue | 10 ++ 11 files changed, 178 insertions(+), 102 deletions(-) create mode 100644 test-workspace/tsc/passedFixtures/vue3/slot-children/child.vue create mode 100644 test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue create mode 100644 test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index 8e7b3c65f6..d6942dc474 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -1,7 +1,7 @@ import { getSlotsPropertyName } from '../utils/shared'; export function generateGlobalTypes(lib: string, target: number, strictTemplates: boolean) { - const fnPropsType = `(K extends { $props: infer Props } ? Props : any)${strictTemplates ? '' : ' & Record'}`; + const fnPropsType = `(T extends { $props: infer Props } ? Props : any)${strictTemplates ? '' : ' & Record'}`; let text = ``; if (target < 3.5) { text += ` @@ -40,7 +40,6 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates type __VLS_GlobalDirectives = import('${lib}').GlobalDirectives; type __VLS_IsAny = 0 extends 1 & T ? true : false; type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; - type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void; type __VLS_WithComponent = N1 extends keyof LocalComponents ? N1 extends N0 ? Pick : { [K in N0]: LocalComponents[N1] } : N2 extends keyof LocalComponents ? N2 extends N0 ? Pick : { [K in N0]: LocalComponents[N2] } : @@ -50,10 +49,14 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } : N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } : ${strictTemplates ? '{}' : '{ [K in N0]: unknown }'}; - type __VLS_FunctionalComponentProps = - '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: { props?: infer P } } ? NonNullable

: never - : T extends (props: infer P, ...args: any) => any ? P : - {}; + type __VLS_FunctionalComponentCtx = __VLS_PickNotAny<'__ctx' extends keyof __VLS_PickNotAny + ? K extends { __ctx?: infer Ctx } ? NonNullable : never : any + , T extends (props: any, ctx: infer Ctx) => any ? Ctx : any + >; + type __VLS_FunctionalComponentProps = '__ctx' extends keyof __VLS_PickNotAny + ? K extends { __ctx?: { props?: infer P } } ? NonNullable

: never + : T extends (props: infer P, ...args: any) => any ? P + : {}; type __VLS_IsFunction = K extends keyof T ? __VLS_IsAny extends false ? unknown extends T[K] @@ -94,12 +97,21 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates > >; type __VLS_PrettifyGlobal = { [K in keyof T]: T[K]; } & {}; - type __VLS_PickFunctionalComponentCtx = 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 - >>; type __VLS_UseTemplateRef = Readonly>; + type __VLS_FunctionalGeneralComponent = (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { + __ctx?: { + attrs?: any, + slots?: T extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any, + emit?: T extends { $emit: infer Emit } ? Emit : any, + props?: ${fnPropsType}, + expose?(exposed: T): void, + } + }; + type __VLS_NormalizeSlotReturns>> = R extends any[] ? { + [K in keyof R]: R[K] extends { __ctx?: any } ? R[K] : ReturnType<__VLS_FunctionalGeneralComponent> + } : R; + function __VLS_getVForSourceType(source: number): [number, number, number][]; function __VLS_getVForSourceType(source: string): [string, number, number][]; function __VLS_getVForSourceType(source: T): [ @@ -131,16 +143,11 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates ? NonNullable : T extends (...args: any) => any ? T - : __VLS_unknownDirective; + : (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void; function __VLS_withScope(ctx: T, scope: K): ctx is T & K; function __VLS_makeOptional(t: T): { [K in keyof T]?: T[K] }; function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): - T extends new (...args: any) => any - ? (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { __ctx?: { - attrs?: any, - slots?: K extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any, - emit?: K extends { $emit: infer Emit } ? Emit : any - } & { props?: ${fnPropsType}; expose?(exposed: K): void; } } + T extends new (...args: any) => any ? __VLS_FunctionalGeneralComponent : T extends () => any ? (props: {}, ctx?: any) => ReturnType : T extends (...args: any) => any ? T : (_: {}${strictTemplates ? '' : ' & Record'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${strictTemplates ? '' : ' & Record'} } }; diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index c435b70f44..1675681cf1 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -145,6 +145,11 @@ export function createTemplateCodegenContext(options: Pick options.scriptSetupImportComponentNames.has(name)); const var_originalComponent = matchImportName ?? ctx.getInternalVariable(); const var_functionalComponent = ctx.getInternalVariable(); - const var_componentInstance = ctx.getInternalVariable(); + const var_componentVnode = ctx.getInternalVariable(); const var_componentEmit = ctx.getInternalVariable(); const var_componentEvents = ctx.getInternalVariable(); const var_defineComponentCtx = ctx.getInternalVariable(); const isComponentTag = node.tag.toLowerCase() === 'component'; + ctx.currentComponent?.childNodes.push({ + name: var_componentVnode, + start: node.loc.start.offset, + end: node.loc.end.offset + }); ctx.currentComponent = { ctxVar: var_defineComponentCtx, - used: false + used: false, + childNodes: [] }; let props = node.props; @@ -227,7 +233,7 @@ export function* generateComponent( }, } }, - var_componentInstance + var_componentVnode ); yield ` = ${var_functionalComponent}`; yield* generateComponentGeneric(ctx); @@ -268,7 +274,7 @@ export function* generateComponent( } } - const usedComponentEventsVar = yield* generateElementEvents(options, ctx, node, var_functionalComponent, var_componentInstance, var_componentEvents); + const usedComponentEventsVar = yield* generateElementEvents(options, ctx, node, var_functionalComponent, var_componentVnode, var_componentEvents); if (usedComponentEventsVar) { ctx.currentComponent.used = true; yield `let ${var_componentEmit}!: typeof ${var_defineComponentCtx}.emit${endOfLine}`; @@ -282,15 +288,10 @@ export function* generateComponent( } const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode; - if (slotDir) { - yield* generateVSlot(options, ctx, node, slotDir); - } - else { - yield* generateElementChildren(options, ctx, node, true); - } + yield* generateVSlot(options, ctx, node, slotDir); if (ctx.currentComponent.used) { - yield `var ${var_defineComponentCtx}!: __VLS_PickFunctionalComponentCtx${endOfLine}`; + yield `var ${var_defineComponentCtx}!: __VLS_FunctionalComponentCtx${endOfLine}`; } } diff --git a/packages/language-core/lib/codegen/template/elementEvents.ts b/packages/language-core/lib/codegen/template/elementEvents.ts index e6ec49a56a..601f4b88f1 100644 --- a/packages/language-core/lib/codegen/template/elementEvents.ts +++ b/packages/language-core/lib/codegen/template/elementEvents.ts @@ -13,7 +13,7 @@ export function* generateElementEvents( ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, componentVar: string, - componentInstanceVar: string, + componentVnodeVar: string, eventsVar: string ): Generator { let usedComponentEventsVar = false; @@ -29,7 +29,7 @@ export function* generateElementEvents( usedComponentEventsVar = true; if (!propsVar) { propsVar = ctx.getInternalVariable(); - yield `let ${propsVar}!: __VLS_FunctionalComponentProps${endOfLine}`; + yield `let ${propsVar}!: __VLS_FunctionalComponentProps${endOfLine}`; } let source = prop.arg.loc.source; let start = prop.arg.loc.start.offset; @@ -41,11 +41,11 @@ export function* generateElementEvents( propPrefix = 'onVnode'; emitPrefix = 'vnode-'; } - yield `const ${ctx.getInternalVariable()}: __VLS_NormalizeComponentEvent = {${newLine}`; + yield `(): __VLS_NormalizeComponentEvent => ({${newLine}`; yield* generateEventArg(ctx, source, start, propPrefix); yield `: `; yield* generateEventExpression(options, ctx, prop); - yield `}${endOfLine}`; + yield `})${endOfLine}`; } } return usedComponentEventsVar; diff --git a/packages/language-core/lib/codegen/template/elementProps.ts b/packages/language-core/lib/codegen/template/elementProps.ts index fa536bbfc9..031453719a 100644 --- a/packages/language-core/lib/codegen/template/elementProps.ts +++ b/packages/language-core/lib/codegen/template/elementProps.ts @@ -138,7 +138,7 @@ export function* generateElementProps( propName ) ), - `: (`, + `: `, ...generatePropExp( options, ctx, @@ -146,8 +146,7 @@ export function* generateElementProps( prop.exp, ctx.codeFeatures.all, enableCodeFeatures - ), - `)` + ) ); if (enableCodeFeatures) { yield* codes; diff --git a/packages/language-core/lib/codegen/template/vSlot.ts b/packages/language-core/lib/codegen/template/vSlot.ts index 8be7bb9c66..27b2a1f586 100644 --- a/packages/language-core/lib/codegen/template/vSlot.ts +++ b/packages/language-core/lib/codegen/template/vSlot.ts @@ -10,60 +10,71 @@ export function* generateVSlot( options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, - slotDir: CompilerDOM.DirectiveNode + slotDir: CompilerDOM.DirectiveNode | undefined ): Generator { if (!ctx.currentComponent) { return; } ctx.currentComponent.used = true; - const slotBlockVars: string[] = []; - yield `{${newLine}`; - yield `const { `; - if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && slotDir.arg.content) { - yield* generateObjectProperty( - options, - ctx, - slotDir.arg.loc.source, - slotDir.arg.loc.start.offset, - slotDir.arg.isStatic ? ctx.codeFeatures.withoutHighlight : ctx.codeFeatures.all, - slotDir.arg.loc, - false, - true - ); - } - else { - yield* wrapWith( - slotDir.loc.start.offset, - slotDir.loc.start.offset + (slotDir.rawName?.length ?? 0), - ctx.codeFeatures.withoutHighlightAndCompletion, - `default` - ); - } - yield `: __VLS_thisSlot } = ${ctx.currentComponent.ctxVar}.slots!${endOfLine}`; + const slotBlockVars: string[] = []; + const var_slot = ctx.getInternalVariable(); - if (slotDir.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { - const slotAst = createTsAst(options.ts, slotDir, `(${slotDir.exp.content}) => {}`); - collectVars(options.ts, slotAst, slotAst, slotBlockVars); - if (!slotDir.exp.content.includes(':')) { - yield `const [`; - yield [ - slotDir.exp.content, - 'template', - slotDir.exp.loc.start.offset, - ctx.codeFeatures.all, - ]; - yield `] = __VLS_getSlotParams(__VLS_thisSlot)${endOfLine}`; + if (slotDir || node.children.length) { + yield `const { `; + if (slotDir) { + if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && slotDir.arg.content) { + yield* generateObjectProperty( + options, + ctx, + slotDir.arg.loc.source, + slotDir.arg.loc.start.offset, + slotDir.arg.isStatic ? ctx.codeFeatures.withoutHighlight : ctx.codeFeatures.all, + slotDir.arg.loc, + false, + true + ); + } + else { + yield* wrapWith( + slotDir.loc.start.offset, + slotDir.loc.start.offset + (slotDir.rawName?.length ?? 0), + ctx.codeFeatures.withoutHighlightAndCompletion, + `default` + ); + } } else { - yield `const `; - yield [ - slotDir.exp.content, - 'template', - slotDir.exp.loc.start.offset, - ctx.codeFeatures.all, - ]; - yield ` = __VLS_getSlotParam(__VLS_thisSlot)${endOfLine}`; + yield `default`; + } + yield `: ${var_slot} } = ${ctx.currentComponent.ctxVar}.slots!${endOfLine}`; + } + + if (slotDir) { + yield `{${newLine}`; + if (slotDir.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { + const slotAst = createTsAst(options.ts, slotDir, `(${slotDir.exp.content}) => {}`); + collectVars(options.ts, slotAst, slotAst, slotBlockVars); + if (!slotDir.exp.content.includes(':')) { + yield `const [`; + yield [ + slotDir.exp.content, + 'template', + slotDir.exp.loc.start.offset, + ctx.codeFeatures.all, + ]; + yield `] = __VLS_getSlotParams(${var_slot})${endOfLine}`; + } + else { + yield `const `; + yield [ + slotDir.exp.content, + 'template', + slotDir.exp.loc.start.offset, + ctx.codeFeatures.all, + ]; + yield ` = __VLS_getSlotParam(${var_slot})${endOfLine}`; + } } } @@ -83,27 +94,50 @@ export function* generateVSlot( ctx.removeLocalVariable(varName); } - let isStatic = true; - if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { - isStatic = slotDir.arg.isStatic; + if (node.children.length) { + yield `(): __VLS_NormalizeSlotReturns => `; + yield* wrapWith( + node.children[0].loc.start.offset, + node.children.at(-1)!.loc.end.offset, + ctx.codeFeatures.verification, + `[`, + ...ctx.currentComponent.childNodes.flatMap(({ name, start, end }) => [ + ...wrapWith( + start, + end, + ctx.codeFeatures.verification, + name + ), + `, ` + ]), + `]` + ); + yield endOfLine; } - if (isStatic && !slotDir.arg) { - yield `${ctx.currentComponent.ctxVar}.slots!['`; - yield [ - '', - 'template', - slotDir.loc.start.offset + ( - slotDir.loc.source.startsWith('#') - ? '#'.length - : slotDir.loc.source.startsWith('v-slot:') - ? 'v-slot:'.length - : 0 - ), - ctx.codeFeatures.completion, - ]; - yield `'/* empty slot name completion */]${endOfLine}`; + + if (slotDir) { + let isStatic = true; + if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { + isStatic = slotDir.arg.isStatic; + } + if (isStatic && !slotDir.arg) { + yield `${ctx.currentComponent.ctxVar}.slots!['`; + yield [ + '', + 'template', + slotDir.loc.start.offset + ( + slotDir.loc.source.startsWith('#') + ? '#'.length + : slotDir.loc.source.startsWith('v-slot:') + ? 'v-slot:'.length + : 0 + ), + ctx.codeFeatures.completion, + ]; + yield `'/* empty slot name completion */]${endOfLine}`; + } + yield `}${newLine}`; } yield* ctx.generateAutoImportCompletion(); - yield `}${newLine}`; } diff --git a/test-workspace/tsc/passedFixtures/vue3/#4668/child.vue b/test-workspace/tsc/passedFixtures/vue3/#4668/child.vue index 3163f4d0d3..7d5b1bda87 100644 --- a/test-workspace/tsc/passedFixtures/vue3/#4668/child.vue +++ b/test-workspace/tsc/passedFixtures/vue3/#4668/child.vue @@ -2,7 +2,7 @@ diff --git a/test-workspace/tsc/passedFixtures/vue3/#4668/main.vue b/test-workspace/tsc/passedFixtures/vue3/#4668/main.vue index 3984709bd1..74a1a9c989 100644 --- a/test-workspace/tsc/passedFixtures/vue3/#4668/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/#4668/main.vue @@ -12,5 +12,5 @@ import { exactType } from '../../shared'; import Child from './child.vue' -const n = 1 as const +const n = 1 diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/child.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/child.vue new file mode 100644 index 0000000000..12c7c9ff29 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/child.vue @@ -0,0 +1,5 @@ + diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue new file mode 100644 index 0000000000..ced9291a8c --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue @@ -0,0 +1,15 @@ + + + diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue new file mode 100644 index 0000000000..5f97ffb139 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue @@ -0,0 +1,10 @@ + From 6e97d236d3106f192522e622184879957e7460f3 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 21 Jan 2025 23:14:13 +0800 Subject: [PATCH 02/18] fix: #932 fixture --- .../lib/codegen/template/elementChildren.ts | 22 +------------------ .../lib/codegen/template/vSlot.ts | 7 +++++- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/packages/language-core/lib/codegen/template/elementChildren.ts b/packages/language-core/lib/codegen/template/elementChildren.ts index f49265e5c7..65de04b9ce 100644 --- a/packages/language-core/lib/codegen/template/elementChildren.ts +++ b/packages/language-core/lib/codegen/template/elementChildren.ts @@ -1,6 +1,5 @@ import * as CompilerDOM from '@vue/compiler-dom'; import type { Code } from '../../types'; -import { endOfLine, wrapWith } from '../utils'; import type { TemplateCodegenContext } from './context'; import type { TemplateCodegenOptions } from './index'; import { generateTemplateChild } from './templateChild'; @@ -8,8 +7,7 @@ import { generateTemplateChild } from './templateChild'; export function* generateElementChildren( options: TemplateCodegenOptions, ctx: TemplateCodegenContext, - node: CompilerDOM.ElementNode, - isDefaultSlot: boolean = false + node: CompilerDOM.ElementNode ): Generator { yield* ctx.resetDirectiveComments('end of element children start'); let prev: CompilerDOM.TemplateChildNode | undefined; @@ -18,22 +16,4 @@ export function* generateElementChildren( prev = childNode; } yield* ctx.generateAutoImportCompletion(); - - // fix https://github.com/vuejs/language-tools/issues/932 - if ( - ctx.currentComponent - && isDefaultSlot - && node.children.length - && node.tagType === CompilerDOM.ElementTypes.COMPONENT - ) { - ctx.currentComponent.used = true; - yield `${ctx.currentComponent.ctxVar}.slots!.`; - yield* wrapWith( - node.children[0].loc.start.offset, - node.children[node.children.length - 1].loc.end.offset, - ctx.codeFeatures.navigation, - `default` - ); - yield endOfLine; - } } diff --git a/packages/language-core/lib/codegen/template/vSlot.ts b/packages/language-core/lib/codegen/template/vSlot.ts index 27b2a1f586..26f4e1cb94 100644 --- a/packages/language-core/lib/codegen/template/vSlot.ts +++ b/packages/language-core/lib/codegen/template/vSlot.ts @@ -45,7 +45,12 @@ export function* generateVSlot( } } else { - yield `default`; + yield* wrapWith( + node.children[0].loc.start.offset, + node.children.at(-1)!.loc.end.offset, + ctx.codeFeatures.navigation, + `default` + ); } yield `: ${var_slot} } = ${ctx.currentComponent.ctxVar}.slots!${endOfLine}`; } From c0df03ad5671afa01461e9a9b58a7abfd8b14671 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 21 Jan 2025 23:58:08 +0800 Subject: [PATCH 03/18] feat: support native element --- .../language-core/lib/codegen/globalTypes.ts | 29 ++++++++++--------- .../lib/codegen/template/element.ts | 6 ++++ .../vue3/slot-children/main.vue | 4 +++ .../vue3/slot-children/parent.vue | 3 +- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index d6942dc474..13ca1198c4 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -57,6 +57,22 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates ? K extends { __ctx?: { props?: infer P } } ? NonNullable

: never : T extends (props: infer P, ...args: any) => any ? P : {}; + type __VLS_FunctionalGeneralComponent = (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { + __ctx?: { + attrs?: any, + slots?: T extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any, + emit?: T extends { $emit: infer Emit } ? Emit : any, + props?: ${fnPropsType}, + expose?(exposed: T): void, + } + }; + type __VLS_NormalizeSlotReturns>> = R extends any[] ? { + [K in keyof R]: R[K] extends infer V + ? V extends { __ctx?: any } ? V + : V extends import('${lib}').VNode ? E + : ReturnType<__VLS_FunctionalGeneralComponent> + : never + } : R; type __VLS_IsFunction = K extends keyof T ? __VLS_IsAny extends false ? unknown extends T[K] @@ -99,19 +115,6 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates type __VLS_PrettifyGlobal = { [K in keyof T]: T[K]; } & {}; type __VLS_UseTemplateRef = Readonly>; - type __VLS_FunctionalGeneralComponent = (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { - __ctx?: { - attrs?: any, - slots?: T extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any, - emit?: T extends { $emit: infer Emit } ? Emit : any, - props?: ${fnPropsType}, - expose?(exposed: T): void, - } - }; - type __VLS_NormalizeSlotReturns>> = R extends any[] ? { - [K in keyof R]: R[K] extends { __ctx?: any } ? R[K] : ReturnType<__VLS_FunctionalGeneralComponent> - } : R; - function __VLS_getVForSourceType(source: number): [number, number, number][]; function __VLS_getVForSourceType(source: string): [string, number, number][]; function __VLS_getVForSourceType(source: T): [ diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index b81507671d..d7037e9b3e 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -307,6 +307,12 @@ export function* generateElement( : undefined; const failedPropExps: FailedPropExpression[] = []; + ctx.currentComponent?.childNodes.push({ + name: `__VLS_nativeElements.${node.tag}`, + start: node.loc.start.offset, + end: node.loc.end.offset + }); + yield `__VLS_asFunctionalElement(__VLS_intrinsicElements`; yield* generatePropertyAccess( options, diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue index ced9291a8c..f5e3309405 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue @@ -11,5 +11,9 @@ const foo = {} as 'a' | 'b'; + + + + diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue index 5f97ffb139..7b59a13bf9 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue @@ -1,10 +1,11 @@ From ce5bdd8173402d45910cf7b7262b9ef3911658df Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Fri, 14 Mar 2025 02:55:43 +0800 Subject: [PATCH 04/18] fix: type --- packages/language-core/lib/codegen/globalTypes.ts | 8 ++++---- packages/language-core/lib/codegen/template/element.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index d820e7a5fa..7bdc3a8563 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -24,7 +24,7 @@ export function generateGlobalTypes({ checkUnknownEvents, checkUnknownComponents, }: VueCompilerOptions) { - const fnPropsType = `(K extends { $props: infer Props } ? Props : any)${checkUnknownProps ? '' : ' & Record'}`; + const fnPropsType = `(T extends { $props: infer Props } ? Props : any)${checkUnknownProps ? '' : ' & Record'}`; let text = ``; if (target < 3.5) { text += ` @@ -76,7 +76,7 @@ export function generateGlobalTypes({ ? K extends { __ctx?: { props?: infer P } } ? NonNullable

: never : T extends (props: infer P, ...args: any) => any ? P : {}; - type __VLS_FunctionalGeneralComponent = (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { + type __VLS_FunctionalComponent = (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { __ctx?: { attrs?: any, slots?: T extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any, @@ -89,7 +89,7 @@ export function generateGlobalTypes({ [K in keyof R]: R[K] extends infer V ? V extends { __ctx?: any } ? V : V extends import('${lib}').VNode ? E - : ReturnType<__VLS_FunctionalGeneralComponent> + : ReturnType<__VLS_FunctionalComponent> : never } : R; type __VLS_IsFunction = K extends keyof T @@ -158,7 +158,7 @@ export function generateGlobalTypes({ : (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void; function __VLS_makeOptional(t: T): { [K in keyof T]?: T[K] }; function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): - T extends new (...args: any) => any ? __VLS_FunctionalGeneralComponent + T extends new (...args: any) => any ? __VLS_FunctionalComponent : T extends () => any ? (props: {}, ctx?: any) => ReturnType : T extends (...args: any) => any ? T : (_: {}${checkUnknownProps ? '' : ' & Record'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${checkUnknownProps ? '' : ' & Record'} } }; diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index a3db57a122..fea345021c 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -296,7 +296,7 @@ export function* generateComponent( } if (ctx.currentComponent.used) { - yield `var ${componentCtxVar}!: __VLS_PickFunctionalComponentCtx${endOfLine}`; + yield `var ${componentCtxVar}!: __VLS_FunctionalComponentCtx${endOfLine}`; } } From 9ad5b60df63dde662c210a545b2c5c571bddfbe3 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 16 Mar 2025 05:23:54 +0800 Subject: [PATCH 05/18] fix: update --- .../lib/codegen/template/element.ts | 13 +++------- .../lib/codegen/template/vSlot.ts | 24 ++++--------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index fbe6223856..1954b72a60 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -16,7 +16,7 @@ import type { TemplateCodegenOptions } from './index'; import { generateInterpolation } from './interpolation'; import { generatePropertyAccess } from './propertyAccess'; import { collectStyleScopedClassReferences } from './styleScopedClasses'; -import { generateImplicitDefaultSlot, generateVSlot } from './vSlot'; +import { generateVSlot } from './vSlot'; const colonReg = /:/g; @@ -286,14 +286,7 @@ export function* generateComponent( collectStyleScopedClassReferences(options, ctx, node); const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode; - if (slotDir) { - yield* generateVSlot(options, ctx, node, slotDir); - } - else { - // #932: reference for default slot - yield* generateImplicitDefaultSlot(ctx, node); - yield* generateElementChildren(options, ctx, node); - } + yield* generateVSlot(options, ctx, node, slotDir); if (ctx.currentComponent.used) { yield `var ${componentCtxVar}!: __VLS_FunctionalComponentCtx${endOfLine}`; @@ -313,7 +306,7 @@ export function* generateElement( const failedPropExps: FailedPropExpression[] = []; ctx.currentComponent?.childNodes.push({ - name: `__VLS_nativeElements.${node.tag}`, + name: `{} as __VLS_NativeElements['${node.tag}']`, start: node.loc.start.offset, end: node.loc.end.offset, }); diff --git a/packages/language-core/lib/codegen/template/vSlot.ts b/packages/language-core/lib/codegen/template/vSlot.ts index bf6079f327..157ad2722e 100644 --- a/packages/language-core/lib/codegen/template/vSlot.ts +++ b/packages/language-core/lib/codegen/template/vSlot.ts @@ -22,6 +22,10 @@ export function* generateVSlot( const slotBlockVars: string[] = []; const var_slot = ctx.getInternalVariable(); + if (slotDir) { + yield `{${newLine}`; + } + if (slotDir || node.children.length) { yield `const { `; if (slotDir) { @@ -187,23 +191,3 @@ function* generateSlotParameters( ]; } } - -export function* generateImplicitDefaultSlot( - ctx: TemplateCodegenContext, - node: CompilerDOM.ElementNode -) { - if (!ctx.currentComponent) { - return; - } - if (node.children.length) { - ctx.currentComponent.used = true; - yield `${ctx.currentComponent.ctxVar}.slots!.`; - yield* wrapWith( - node.children[0].loc.start.offset, - node.children[node.children.length - 1].loc.end.offset, - ctx.codeFeatures.navigation, - `default` - ); - yield endOfLine; - } -} From f0088245cd4413e0302d19a538dbdb67d90f213c Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 16 Mar 2025 15:57:23 +0800 Subject: [PATCH 06/18] fix: map error to entire inner content of parent node --- .../language-core/lib/codegen/globalTypes.ts | 2 +- .../lib/codegen/template/context.ts | 6 +----- .../lib/codegen/template/element.ts | 14 +++----------- .../lib/codegen/template/vSlot.ts | 19 ++++++------------- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index 6fe06862ca..592e1b03fd 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -85,7 +85,7 @@ export function generateGlobalTypes({ expose?: (exposed: T) => void, } }; - type __VLS_NormalizeSlotReturns>> = R extends any[] ? { + type __VLS_NormalizeSlotReturns extends (...args: any) => infer K ? K : any> = R extends any[] ? { [K in keyof R]: R[K] extends infer V ? V extends { __ctx?: any } ? V : V extends import('${lib}').VNode ? E diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 57a7a3d287..606a7ae0fc 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -207,11 +207,7 @@ export function createTemplateCodegenContext(options: Pick => `; + yield `(): __VLS_NormalizeSlotReturns => (`; yield* wrapWith( node.children[0].loc.start.offset, node.children.at(-1)!.loc.end.offset, ctx.codeFeatures.verification, - `[`, - ...ctx.currentComponent.childNodes.flatMap(({ name, start, end }) => [ - ...wrapWith( - start, - end, - ctx.codeFeatures.verification, - name - ), - `, ` - ]), + `{} as [`, + ...ctx.currentComponent.childTypes.map((name) => `${name}, `), `]` ); - yield endOfLine; + yield `)${endOfLine}`; } if (slotDir) { From 63ba3f930db5801ba542e2b79e927082bc30462c Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 16 Mar 2025 16:06:13 +0800 Subject: [PATCH 07/18] test: update case --- .../tsc/passedFixtures/vue2/tsconfig.json | 1 + .../passedFixtures/vue3/slot-children/main.vue | 17 +++++++++++++---- .../vue3/slot-children/parent.vue | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/test-workspace/tsc/passedFixtures/vue2/tsconfig.json b/test-workspace/tsc/passedFixtures/vue2/tsconfig.json index e364652d93..8deef3dc20 100644 --- a/test-workspace/tsc/passedFixtures/vue2/tsconfig.json +++ b/test-workspace/tsc/passedFixtures/vue2/tsconfig.json @@ -39,6 +39,7 @@ "../vue3/events", "../vue3/no-script-block", "../vue3/rootEl", + "../vue3/slot-children", "../vue3/slots", "../vue3/templateRef", "../vue3/templateRef_native", diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue index f5e3309405..d1bba0a23a 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue @@ -6,14 +6,23 @@ const foo = {} as 'a' | 'b'; diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue index 7b59a13bf9..959e3fc55b 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/parent.vue @@ -6,6 +6,6 @@ defineProps<{ foo: T; }>(); defineSlots<{ - default?(): (ReturnType> | VNode)[]; + default?: () => (ReturnType> | VNode)[]; }>(); From 9ac4af840e06c4fff49d485bbb9f99aad38e55e0 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 16 Mar 2025 16:09:39 +0800 Subject: [PATCH 08/18] chore: lint --- test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue index d1bba0a23a..7f0143cce5 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slot-children/main.vue @@ -6,7 +6,7 @@ const foo = {} as 'a' | 'b';