Skip to content

Commit a081e07

Browse files
authored
fix(language-core): prevent circular reference of templateRef (#4768)
1 parent af7fc39 commit a081e07

File tree

5 files changed

+48
-19
lines changed

5 files changed

+48
-19
lines changed

packages/language-core/lib/codegen/script/template.ts

+37-10
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,55 @@ export function* generateTemplateCtx(
1313
options: ScriptCodegenOptions,
1414
isClassComponent: boolean
1515
): Generator<Code> {
16-
const exps = [];
16+
const baseExps = [];
17+
const extraExps = [];
18+
1719
if (isClassComponent) {
18-
exps.push(`this`);
20+
baseExps.push(`this`);
1921
}
2022
else {
21-
exps.push(`{} as InstanceType<__VLS_PickNotAny<typeof __VLS_internalComponent, new () => {}>>`);
23+
baseExps.push(`{} as InstanceType<__VLS_PickNotAny<typeof __VLS_internalComponent, new () => {}>>`);
2224
}
2325
if (options.vueCompilerOptions.petiteVueExtensions.some(ext => options.fileBaseName.endsWith(ext))) {
24-
exps.push(`globalThis`);
26+
extraExps.push(`globalThis`);
2527
}
2628
if (options.sfc.styles.some(style => style.module)) {
27-
exps.push(`{} as __VLS_StyleModules`);
29+
extraExps.push(`{} as __VLS_StyleModules`);
30+
}
31+
if (options.scriptSetupRanges?.templateRefs.length) {
32+
let exp = `{} as import('${options.vueCompilerOptions.lib}').UnwrapRef<{${newLine}`;
33+
for (const { name } of options.scriptSetupRanges.templateRefs) {
34+
if (name) {
35+
exp += `${name}: typeof ${name}${newLine}`;
36+
}
37+
}
38+
exp += `}>${newLine}`;
39+
extraExps.push(exp);
2840
}
2941

30-
yield `const __VLS_ctx = `;
31-
if (exps.length === 1) {
32-
yield exps[0];
42+
yield `const __VLS_ctxBase = `;
43+
if (baseExps.length === 1) {
44+
yield baseExps[0];
3345
yield endOfLine;
3446
}
3547
else {
3648
yield `{${newLine}`;
37-
for (const exp of exps) {
49+
for (const exp of baseExps) {
50+
yield `...`;
51+
yield exp;
52+
yield `,${newLine}`;
53+
}
54+
yield `}${endOfLine}`;
55+
}
56+
57+
yield `const __VLS_ctx = `;
58+
if (extraExps.length === 0) {
59+
yield `__VLS_ctxBase${endOfLine}`;
60+
}
61+
else {
62+
yield `{${newLine}`;
63+
yield `...__VLS_ctxBase,${newLine}`;
64+
for (const exp of extraExps) {
3865
yield `...`;
3966
yield exp;
4067
yield `,${newLine}`;
@@ -76,7 +103,7 @@ export function* generateTemplateComponents(options: ScriptCodegenOptions): Gene
76103

77104
exps.push(`{} as NonNullable<typeof __VLS_internalComponent extends { components: infer C } ? C : {}>`);
78105
exps.push(`{} as __VLS_GlobalComponents`);
79-
exps.push(`{} as typeof __VLS_ctx`);
106+
exps.push(`__VLS_ctxBase`);
80107

81108
yield `const __VLS_components = {${newLine}`;
82109
for (const type of exps) {

packages/language-core/lib/codegen/template/element.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -229,15 +229,14 @@ export function* generateComponent(
229229
options.templateRefNames.set(refName, [varName, offset!]);
230230
ctx.usedComponentCtxVars.add(var_defineComponentCtx);
231231

232-
yield `// @ts-ignore${newLine}`;
232+
yield `var ${varName} = {} as (Parameters<typeof ${var_defineComponentCtx}['expose']>[0] | null)`;
233233
if (node.codegenNode?.type === CompilerDOM.NodeTypes.VNODE_CALL
234234
&& node.codegenNode.props?.type === CompilerDOM.NodeTypes.JS_OBJECT_EXPRESSION
235-
&& node.codegenNode.props.properties.find(({ key }) => key.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && key.content === 'ref_for')
235+
&& node.codegenNode.props.properties.some(({ key }) => key.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && key.content === 'ref_for')
236236
) {
237-
yield `var ${varName} = [{} as Parameters<typeof ${var_defineComponentCtx}['expose']>[0]]${endOfLine}`;
238-
} else {
239-
yield `var ${varName} = {} as Parameters<typeof ${var_defineComponentCtx}['expose']>[0]${endOfLine}`;
237+
yield `[]`;
240238
}
239+
yield `${endOfLine}`;
241240
}
242241

243242
const usedComponentEventsVar = yield* generateElementEvents(options, ctx, node, var_functionalComponent, var_componentInstance, var_componentEmit, var_componentEvents);

packages/language-core/lib/codegen/template/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
6565
offset,
6666
ctx.codeFeatures.navigationAndCompletion
6767
)
68-
yield `: ${varName}!,${newLine}`;
68+
yield `: ${varName},${newLine}`;
6969
}
7070
yield `}${endOfLine}`;
7171
yield `declare var $refs: typeof __VLS_refs${endOfLine}`;

test-workspace/tsc/passedFixtures/vue3.5/templateRef/main.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ import { exactType } from '../../shared';
66
<template>
77
<TemplateRef ref="templateRef" />
88

9-
{{ exactType($refs.templateRef.$refs.generic.foo, {} as 1) }}
9+
{{ exactType($refs.templateRef?.$refs.generic?.foo, {} as (1 | undefined)) }}
1010
</template>

test-workspace/tsc/passedFixtures/vue3.5/templateRef/template-ref.vue

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { exactType } from '../../shared';
44
55
const comp1 = useTemplateRef('generic');
66
if (comp1.value) {
7-
exactType(comp1.value.foo, 1)
7+
exactType(comp1.value.foo, 1);
88
}
99
1010
const comp2 = useTemplateRef('v-for');
@@ -20,8 +20,11 @@ if (comp3.value) {
2020

2121
<template>
2222
<Generic ref="generic" :foo="1"></Generic>
23-
23+
{{ exactType(comp1?.foo, {} as 1 | undefined) }}
24+
2425
<Generic v-for="i in 4" ref="v-for" :foo="i"></Generic>
26+
{{ exactType(comp2?.[0]?.foo, {} as number | undefined) }}
2527

2628
<a ref="a"></a>
29+
{{ exactType(comp3?.href, {} as string | undefined) }}
2730
</template>

0 commit comments

Comments
 (0)