diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index 433bb591e4..92a49bf7ac 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -127,15 +127,15 @@ function* generateTemplateBody( yield `const __VLS_slots = {}${endOfLine}`; } yield `const __VLS_inheritedAttrs = {}${endOfLine}`; - yield `const $refs = {}${endOfLine}`; - yield `const $el = {} as any${endOfLine}`; + yield `const __VLS_refs = {}${endOfLine}`; + yield `const __VLS_rootEl = {} as any${endOfLine}`; } yield `return {${newLine}`; yield ` attrs: {} as Partial,${newLine}`; yield ` slots: ${options.scriptSetupRanges?.defineSlots?.name ?? '__VLS_slots'},${newLine}`; - yield ` refs: $refs,${newLine}`; - yield ` rootEl: $el,${newLine}`; + yield ` refs: __VLS_refs,${newLine}`; + yield ` rootEl: __VLS_rootEl,${newLine}`; yield `}${endOfLine}`; } diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 662ee6cff2..6996375ee6 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -103,6 +103,7 @@ export function createTemplateCodegenContext(options: Pick(); + const specialVars = new Set(); const accessExternalVariables = new Map>(); const slots: { name: string; @@ -132,6 +133,7 @@ export function createTemplateCodegenContext(options: Pick${endOfLine}`; } - if ( - options.vueCompilerOptions.fallthroughAttributes - && ( - node.props.some(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE && prop.name === 'bind' && prop.exp?.loc.source === '$attrs') - || node === ctx.singleRootNode - ) - ) { - const varAttrs = ctx.getInternalVariable(); - ctx.inheritedAttrVars.add(varAttrs); - yield `var ${varAttrs}!: Parameters[0];\n`; + if (hasVBindAttrs(options, ctx, node)) { + const attrsVar = ctx.getInternalVariable(); + ctx.inheritedAttrVars.add(attrsVar); + yield `let ${attrsVar}!: Parameters[0];\n`; } const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode; @@ -365,13 +359,7 @@ export function* generateElement( yield* generateElementChildren(options, ctx, node); } - if ( - options.vueCompilerOptions.fallthroughAttributes - && ( - node.props.some(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE && prop.name === 'bind' && prop.exp?.loc.source === '$attrs') - || node === ctx.singleRootNode - ) - ) { + if (hasVBindAttrs(options, ctx, node)) { ctx.inheritedAttrVars.add(`__VLS_intrinsicElements.${node.tag}`); } } @@ -625,6 +613,21 @@ function* generateReferencesForElements( return []; } +function hasVBindAttrs( + options: TemplateCodegenOptions, + ctx: TemplateCodegenContext, + node: CompilerDOM.ElementNode +) { + return options.vueCompilerOptions.fallthroughAttributes && ( + node === ctx.singleRootNode || + node.props.some(prop => + prop.type === CompilerDOM.NodeTypes.DIRECTIVE + && prop.name === 'bind' + && prop.exp?.loc.source === '$attrs' + ) + ); +} + function camelizeComponentName(newName: string) { return camelize('-' + newName); } diff --git a/packages/language-core/lib/codegen/template/elementProps.ts b/packages/language-core/lib/codegen/template/elementProps.ts index c55084e82b..95a1b64ecb 100644 --- a/packages/language-core/lib/codegen/template/elementProps.ts +++ b/packages/language-core/lib/codegen/template/elementProps.ts @@ -145,7 +145,6 @@ export function* generateElementProps( prop, prop.exp, ctx.codeFeatures.all, - prop.arg?.loc.start.offset === prop.exp?.loc.start.offset, enableCodeFeatures ), `)` @@ -257,7 +256,6 @@ export function* generateElementProps( prop, prop.exp, ctx.codeFeatures.all, - false, enableCodeFeatures ) ); @@ -279,9 +277,10 @@ function* generatePropExp( prop: CompilerDOM.DirectiveNode, exp: CompilerDOM.SimpleExpressionNode | undefined, features: VueCodeInformation, - isShorthand: boolean, enableCodeFeatures: boolean ): Generator { + const isShorthand = prop.arg?.loc.start.offset === prop.exp?.loc.start.offset; + if (isShorthand && features.completion) { features = { ...features, diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index b19c0d461d..565cb4f87a 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -35,26 +35,38 @@ 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) { @@ -86,21 +98,22 @@ function* generateSlots(options: TemplateCodegenOptions, ctx: TemplateCodegenCon } yield `}${endOfLine}`; } - const name = getSlotsPropertyName(options.vueCompilerOptions.target); - yield `var ${name}!: typeof ${options.slotsAssignName ?? '__VLS_slots'}${endOfLine}`; + return `typeof ${options.slotsAssignName ?? `__VLS_slots`}`; } -function* generateInheritedAttrs(ctx: TemplateCodegenContext): Generator { +function* generateInheritedAttrs( + ctx: TemplateCodegenContext +): Generator { yield 'let __VLS_inheritedAttrs!: {}'; for (const varName of ctx.inheritedAttrVars) { yield ` & typeof ${varName}`; } yield endOfLine; - yield `var $attrs!: Partial & Record${endOfLine}`; if (ctx.bindingAttrLocs.length) { yield `[`; for (const loc of ctx.bindingAttrLocs) { + yield `__VLS_special.`; yield [ loc.source, 'template', @@ -111,9 +124,12 @@ function* generateInheritedAttrs(ctx: TemplateCodegenContext): Generator { } yield `]${endOfLine}`; } + return `Partial & Record`; } -function* generateRefs(ctx: TemplateCodegenContext): Generator { +function* generateRefs( + ctx: TemplateCodegenContext +): Generator { yield `const __VLS_refs = {${newLine}`; for (const [name, [varName, offset]] of ctx.templateRefs) { yield* generateStringLiteralKey( @@ -124,16 +140,16 @@ function* generateRefs(ctx: TemplateCodegenContext): Generator { yield `: ${varName},${newLine}`; } yield `}${endOfLine}`; - yield `var $refs!: typeof __VLS_refs${endOfLine}`; + return `typeof __VLS_refs`; } -function* generateRootEl(ctx: TemplateCodegenContext): Generator { - if (ctx.singleRootElType) { - yield `var $el!: ${ctx.singleRootElType}${endOfLine}`; - } - else { - yield `var $el!: any${endOfLine}`; - } +function* generateRootEl( + ctx: TemplateCodegenContext +): Generator { + yield `let __VLS_rootEl!: `; + yield ctx.singleRootElType ?? `any`; + yield endOfLine; + return `typeof __VLS_rootEl`; } export function* forEachElementNode(node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode): Generator { diff --git a/packages/language-core/lib/codegen/template/interpolation.ts b/packages/language-core/lib/codegen/template/interpolation.ts index f66fb18eea..366b606971 100644 --- a/packages/language-core/lib/codegen/template/interpolation.ts +++ b/packages/language-core/lib/codegen/template/interpolation.ts @@ -71,6 +71,12 @@ export function* generateInterpolation( } } +interface CtxVar { + text: string; + isShorthand: boolean; + offset: number; +}; + function* forEachInterpolationSegment( ts: typeof import('typescript'), destructuredPropNames: Set | undefined, @@ -80,20 +86,16 @@ function* forEachInterpolationSegment( offset: number | undefined, ast: ts.SourceFile ): Generator<[fragment: string, offset: number | undefined, type?: 'errorMappingOnly' | 'startText' | 'endText']> { - let ctxVars: { - text: string, - isShorthand: boolean, - offset: number, - }[] = []; + let ctxVars: CtxVar[] = []; const varCb = (id: ts.Identifier, isShorthand: boolean) => { const text = getNodeText(ts, id, ast); if ( - ctx.hasLocalVariable(text) || + ctx.hasLocalVariable(text) // https://github.com/vuejs/core/blob/245230e135152900189f13a4281302de45fdcfaa/packages/compiler-core/src/transforms/transformExpression.ts#L342-L352 - isGloballyAllowed(text) || - text === 'require' || - text.startsWith('__VLS_') + || isGloballyAllowed(text) + || text === 'require' + || text.startsWith('__VLS_') ) { // localVarOffsets.push(localVar.getStart(ast)); } @@ -132,7 +134,7 @@ function* forEachInterpolationSegment( const curVar = ctxVars[i]; const nextVar = ctxVars[i + 1]; - yield* generateVar(code, destructuredPropNames, templateRefNames, curVar, nextVar); + yield* generateVar(code, ctx.specialVars, destructuredPropNames, templateRefNames, curVar, nextVar); if (nextVar.isShorthand) { yield [code.slice(curVar.offset + curVar.text.length, nextVar.offset + nextVar.text.length), curVar.offset + curVar.text.length]; @@ -144,7 +146,7 @@ function* forEachInterpolationSegment( } const lastVar = ctxVars.at(-1)!; - yield* generateVar(code, destructuredPropNames, templateRefNames, lastVar); + yield* generateVar(code, ctx.specialVars, destructuredPropNames, templateRefNames, lastVar); if (lastVar.offset + lastVar.text.length < code.length) { yield [code.slice(lastVar.offset + lastVar.text.length), lastVar.offset + lastVar.text.length, 'endText']; } @@ -156,18 +158,11 @@ function* forEachInterpolationSegment( function* generateVar( code: string, + specialVars: Set, destructuredPropNames: Set | undefined, templateRefNames: Set | undefined, - curVar: { - text: string, - isShorthand: boolean, - offset: number, - }, - nextVar: { - text: string, - isShorthand: boolean, - offset: number, - } = curVar + curVar: CtxVar, + nextVar: CtxVar = curVar ): Generator<[fragment: string, offset: number | undefined, type?: 'errorMappingOnly']> { // fix https://github.com/vuejs/language-tools/issues/1205 // fix https://github.com/vuejs/language-tools/issues/1264 @@ -181,7 +176,10 @@ function* generateVar( yield [`)`, undefined]; } else { - if (!isDestructuredProp) { + if (specialVars.has(curVar.text)) { + yield [`__VLS_special.`, undefined]; + } + else if (!isDestructuredProp) { yield [`__VLS_ctx.`, undefined]; } yield [code.slice(curVar.offset, curVar.offset + curVar.text.length), curVar.offset]; diff --git a/packages/language-core/lib/plugins/vue-tsx.ts b/packages/language-core/lib/plugins/vue-tsx.ts index 42e6015679..48d33f31b6 100644 --- a/packages/language-core/lib/plugins/vue-tsx.ts +++ b/packages/language-core/lib/plugins/vue-tsx.ts @@ -189,7 +189,7 @@ function createTsx( slotsAssignName: slotsAssignName.get(), propsAssignName: propsAssignName.get(), inheritAttrs: inheritAttrs.get(), - selfComponentName: selfComponentName.get() + selfComponentName: selfComponentName.get(), }); let current = codegen.next(); @@ -202,7 +202,7 @@ function createTsx( return { ...current.value, - codes: codes, + codes, }; }); const generatedScript = computed(() => {