Skip to content

Commit

Permalink
fix(language-core): hoist the variables that may cause TS4081 (#5192)
Browse files Browse the repository at this point in the history
  • Loading branch information
KazariEX authored Feb 17, 2025
1 parent 50d3a8e commit b9ae179
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 37 deletions.
19 changes: 18 additions & 1 deletion packages/language-core/lib/codegen/template/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
return features;
}

const hoistVars = new Map<string, string>();
const localVars = new Map<string, number>();
const specialVars = new Set<string>();
const accessExternalVariables = new Map<string, Set<number>>();
Expand All @@ -67,7 +68,10 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
const inlayHints: InlayHintInfo[] = [];
const bindingAttrLocs: CompilerDOM.SourceLocation[] = [];
const inheritedAttrVars = new Set<string>();
const templateRefs = new Map<string, [varName: string, offset: number]>();
const templateRefs = new Map<string, {
varName: string;
offset: number;
}>();

return {
codeFeatures: new Proxy(codeFeatures, {
Expand Down Expand Up @@ -116,6 +120,19 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
getInternalVariable: () => {
return `__VLS_${variableId++}`;
},
getHoistVariable: (originalVar: string) => {
let name = hoistVars.get(originalVar);
if (name === undefined) {
hoistVars.set(originalVar, name = `__VLS_${variableId++}`);
}
return name;
},
generateHoistVariables: function* () {
// trick to avoid TS 4081 (#5186)
for (const [originalVar, hoistVar] of hoistVars) {
yield `var ${hoistVar} = ${originalVar}${endOfLine}`;
}
},
ignoreError: function* (): Generator<Code> {
if (!ignoredError) {
ignoredError = true;
Expand Down
14 changes: 10 additions & 4 deletions packages/language-core/lib/codegen/template/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,10 @@ export function* generateComponent(
yield `${endOfLine}`;

if (refName) {
ctx.templateRefs.set(refName, [varName, offset!]);
ctx.templateRefs.set(refName, {
varName: ctx.getHoistVariable(varName),
offset: offset!
});
}
if (isRootNode) {
ctx.singleRootElType = `NonNullable<typeof ${varName}>['$el']`;
Expand Down Expand Up @@ -358,11 +361,14 @@ export function* generateElement(

const [refName, offset] = yield* generateVScope(options, ctx, node, node.props);
if (refName) {
let refValue = `__VLS_nativeElements['${node.tag}']`;
let element = `__VLS_nativeElements['${node.tag}']`;
if (isVForChild) {
refValue = `[${refValue}]`;
element = `[${element}]`;
}
ctx.templateRefs.set(refName, [refValue, offset!]);
ctx.templateRefs.set(refName, {
varName: element,
offset: offset!
});
}
if (ctx.singleRootNode === node) {
ctx.singleRootElType = `typeof __VLS_nativeElements['${node.tag}']`;
Expand Down
20 changes: 4 additions & 16 deletions packages/language-core/lib/codegen/template/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
}

yield* generateStyleScopedClassReferences(ctx);
yield* ctx.generateAutoImportCompletion();
yield* ctx.generateHoistVariables();

const speicalTypes = [
[slotsPropertyName, yield* generateSlots(options, ctx)],
['$attrs', yield* generateInheritedAttrs(options, ctx)],
Expand All @@ -58,7 +61,6 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
}
yield `} & { [K in keyof import('${options.vueCompilerOptions.lib}').ComponentPublicInstance]: unknown }${endOfLine}`;

yield* ctx.generateAutoImportCompletion();
return ctx;
}

Expand All @@ -67,20 +69,6 @@ function* generateSlots(
ctx: TemplateCodegenContext
): Generator<Code> {
if (!options.hasDefineSlots) {
const hoistVars = new Map<string, string>();

// trick to avoid TS 4081 (#5186)
for (const slot of ctx.dynamicSlots) {
hoistVars.set(slot.expVar, slot.expVar = ctx.getInternalVariable());
hoistVars.set(slot.propsVar, slot.propsVar = ctx.getInternalVariable());
}
for (const slot of ctx.slots) {
hoistVars.set(slot.propsVar, slot.propsVar = ctx.getInternalVariable());
}
for (const [originalVar, hoistVar] of hoistVars) {
yield `var ${hoistVar} = ${originalVar}${endOfLine}`;
}

const name = getSlotsPropertyName(options.vueCompilerOptions.target);
yield `type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.${name}>`;
for (const { expVar, propsVar } of ctx.dynamicSlots) {
Expand Down Expand Up @@ -145,7 +133,7 @@ function* generateTemplateRefs(
ctx: TemplateCodegenContext
): Generator<Code> {
yield `type __VLS_TemplateRefs = {${newLine}`;
for (const [name, [varName, offset]] of ctx.templateRefs) {
for (const [name, { varName, offset }] of ctx.templateRefs) {
yield* generateObjectProperty(
options,
ctx,
Expand Down
8 changes: 4 additions & 4 deletions packages/language-core/lib/codegen/template/slotOutlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export function* generateSlotOutlet(
offset: nameProp.loc.start.offset + nameProp.loc.source.indexOf(nameProp.value.content, nameProp.name.length),
tagRange: [startTagOffset, startTagOffset + node.tag.length],
nodeLoc: node.loc,
propsVar,
propsVar: ctx.getHoistVariable(propsVar),
});
}
else if (
Expand All @@ -155,16 +155,16 @@ export function* generateSlotOutlet(
);
yield `)${endOfLine}`;
ctx.dynamicSlots.push({
expVar,
propsVar,
expVar: ctx.getHoistVariable(expVar),
propsVar: ctx.getHoistVariable(propsVar),
});
}
else {
ctx.slots.push({
name: 'default',
tagRange: [startTagOffset, startTagEndOffset],
nodeLoc: node.loc,
propsVar,
propsVar: ctx.getHoistVariable(propsVar),
});
}
}
Expand Down
24 changes: 12 additions & 12 deletions packages/tsc/tests/__snapshots__/dts.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -587,23 +587,23 @@ export {};
exports[`vue-tsc-dts > Input: template-slots/component.vue, Output: template-slots/component.vue.d.ts 1`] = `
"declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
declare var __VLS_4: {};
declare var __VLS_5: {
declare var __VLS_1: {};
declare var __VLS_3: {
num: number;
};
declare var __VLS_6: {
declare var __VLS_5: {
str: string;
};
declare var __VLS_7: {
num: number;
str: string;
};
type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$slots> & {
'no-bind'?: (props: typeof __VLS_4) => any;
'no-bind'?: (props: typeof __VLS_1) => any;
} & {
default?: (props: typeof __VLS_5) => any;
default?: (props: typeof __VLS_3) => any;
} & {
'named-slot'?: (props: typeof __VLS_6) => any;
'named-slot'?: (props: typeof __VLS_5) => any;
} & {
vbind?: (props: typeof __VLS_7) => any;
}>;
Expand Down Expand Up @@ -664,23 +664,23 @@ type __VLS_WithSlots<T, S> = T & {
exports[`vue-tsc-dts > Input: template-slots/component-no-script.vue, Output: template-slots/component-no-script.vue.d.ts 1`] = `
"declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
declare var __VLS_4: {};
declare var __VLS_5: {
declare var __VLS_1: {};
declare var __VLS_3: {
num: number;
};
declare var __VLS_6: {
declare var __VLS_5: {
str: string;
};
declare var __VLS_7: {
num: number;
str: string;
};
type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$slots> & {
'no-bind'?: (props: typeof __VLS_4) => any;
'no-bind'?: (props: typeof __VLS_1) => any;
} & {
default?: (props: typeof __VLS_5) => any;
default?: (props: typeof __VLS_3) => any;
} & {
'named-slot'?: (props: typeof __VLS_6) => any;
'named-slot'?: (props: typeof __VLS_5) => any;
} & {
vbind?: (props: typeof __VLS_7) => any;
}>;
Expand Down

0 comments on commit b9ae179

Please sign in to comment.