Skip to content

Commit

Permalink
fix(language-core): correct codegen of native element refs
Browse files Browse the repository at this point in the history
  • Loading branch information
KazariEX committed Feb 18, 2025
1 parent 72c7059 commit 32e455f
Show file tree
Hide file tree
Showing 11 changed files with 36 additions and 99 deletions.
10 changes: 3 additions & 7 deletions packages/language-core/lib/codegen/globalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@ export function generateGlobalTypes({
const __VLS_unref: typeof import('${lib}').unref;
const __VLS_placeholder: any;
const __VLS_nativeElements = {
...{} as SVGElementTagNameMap,
...{} as HTMLElementTagNameMap,
};
type __VLS_NativeElements = __VLS_SpreadMerge<SVGElementTagNameMap, HTMLElementTagNameMap>;
type __VLS_IntrinsicElements = ${(
target >= 3.3
? `import('${lib}/jsx-runtime').JSX.IntrinsicElements;`
Expand All @@ -68,7 +64,7 @@ export function generateGlobalTypes({
type __VLS_GlobalDirectives = import('${lib}').GlobalDirectives;
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
type __VLS_SpreadMerge<A, B> = Omit<A, keyof B> & B;
type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
Expand Down Expand Up @@ -152,7 +148,7 @@ export function generateGlobalTypes({
? NonNullable<T['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>
: T extends (...args: any) => any
? T
: __VLS_unknownDirective;
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any
Expand Down
2 changes: 1 addition & 1 deletion packages/language-core/lib/codegen/template/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
const bindingAttrLocs: CompilerDOM.SourceLocation[] = [];
const inheritedAttrVars = new Set<string>();
const templateRefs = new Map<string, {
varName: string;
typeExp: string;
offset: number;
}>();

Expand Down
38 changes: 18 additions & 20 deletions packages/language-core/lib/codegen/template/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ const colonReg = /:/g;
export function* generateComponent(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
node: CompilerDOM.ElementNode
node: CompilerDOM.ElementNode,
isVForChild: boolean
): Generator<Code> {
const tagOffsets = [node.loc.start.offset + options.template.content.slice(node.loc.start.offset).indexOf(node.tag)];
if (!node.isSelfClosing && options.template.lang === 'html') {
Expand Down Expand Up @@ -255,12 +256,6 @@ export function* generateComponent(
yield* generateElementEvents(options, ctx, node, componentFunctionalVar, componentVNodeVar, componentCtxVar);
yield* generateElementDirectives(options, ctx, node);

if (hasVBindAttrs(options, ctx, node)) {
const attrsVar = ctx.getInternalVariable();
ctx.inheritedAttrVars.add(attrsVar);
yield `let ${attrsVar}!: Parameters<typeof ${componentFunctionalVar}>[0];\n`;
}

const [refName, offset] = yield* generateElementReference(options, ctx, node);
const isRootNode = node === ctx.singleRootNode;

Expand All @@ -269,25 +264,28 @@ export function* generateComponent(
ctx.currentComponent.used = true;

yield `var ${componentInstanceVar} = {} as (Parameters<NonNullable<typeof ${componentCtxVar}['expose']>>[0] | null)`;
if (node.codegenNode?.type === CompilerDOM.NodeTypes.VNODE_CALL
&& node.codegenNode.props?.type === CompilerDOM.NodeTypes.JS_OBJECT_EXPRESSION
&& node.codegenNode.props.properties.some(({ key }) => key.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && key.content === 'ref_for')
) {
if (isVForChild) {
yield `[]`;
}
yield `${endOfLine}`;

if (refName) {
if (refName && offset) {
ctx.templateRefs.set(refName, {
varName: ctx.getHoistVariable(componentInstanceVar),
offset: offset!
typeExp: `typeof ${ctx.getHoistVariable(componentInstanceVar)}`,
offset
});
}
if (isRootNode) {
ctx.singleRootElType = `NonNullable<typeof ${componentInstanceVar}>['$el']`;
}
}

if (hasVBindAttrs(options, ctx, node)) {
const attrsVar = ctx.getInternalVariable();
ctx.inheritedAttrVars.add(attrsVar);
yield `let ${attrsVar}!: Parameters<typeof ${componentFunctionalVar}>[0]${endOfLine}`;
}

collectStyleScopedClassReferences(options, ctx, node);

const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode;
Expand Down Expand Up @@ -358,18 +356,18 @@ export function* generateElement(
yield* generateElementDirectives(options, ctx, node);

const [refName, offset] = yield* generateElementReference(options, ctx, node);
if (refName) {
let element = `__VLS_nativeElements['${node.tag}']`;
if (refName && offset) {
let typeExp = `__VLS_NativeElements['${node.tag}']`;
if (isVForChild) {
element = `[${element}]`;
typeExp += `[]`;
}
ctx.templateRefs.set(refName, {
varName: element,
offset: offset!
typeExp,
offset
});
}
if (ctx.singleRootNode === node) {
ctx.singleRootElType = `typeof __VLS_nativeElements['${node.tag}']`;
ctx.singleRootElType = `__VLS_NativeElements['${node.tag}']`;
}

if (hasVBindAttrs(options, ctx, node)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/language-core/lib/codegen/template/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,15 @@ function* generateTemplateRefs(
ctx: TemplateCodegenContext
): Generator<Code> {
yield `type __VLS_TemplateRefs = {${newLine}`;
for (const [name, { varName, offset }] of ctx.templateRefs) {
for (const [name, { typeExp, offset }] of ctx.templateRefs) {
yield* generateObjectProperty(
options,
ctx,
name,
offset,
ctx.codeFeatures.navigationAndCompletion
);
yield `: typeof ${varName},${newLine}`;
yield `: ${typeExp},${newLine}`;
}
yield `}${endOfLine}`;
return `__VLS_TemplateRefs`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export function* generateTemplateChild(
}
else {
const { currentComponent } = ctx;
yield* generateComponent(options, ctx, node);
yield* generateComponent(options, ctx, node, isVForChild);
ctx.currentComponent = currentComponent;
}
}
Expand Down
16 changes: 0 additions & 16 deletions test-workspace/tsc/passedFixtures/vue3/#4777/template-ref.vue

This file was deleted.

This file was deleted.

6 changes: 3 additions & 3 deletions test-workspace/tsc/passedFixtures/vue3/templateRef/main.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { exactType } from '../../shared';
import TemplateRef from './template-ref.vue';
import TemplateRefs from './template-refs.vue';
function Comp() {
const foo = useTemplateRef('templateRef');
Expand All @@ -11,9 +11,9 @@ function Comp() {
</script>

<template>
<TemplateRef ref="templateRef" />
<TemplateRefs ref="templateRefs" />

{{ exactType($refs.templateRef?.$refs.generic?.foo, {} as (1 | undefined)) }}
{{ exactType($refs.templateRefs?.$refs.generic?.foo, {} as (1 | undefined)) }}

<Comp />
</template>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { exactType } from '../../shared';
import Generic from './generic.vue';
const comp1 = useTemplateRef('generic');
if (comp1.value) {
Expand All @@ -14,20 +15,23 @@ if (comp2.value) {
const comp3 = useTemplateRef('native');
if (comp3.value) {
exactType(comp3.value.href, {} as string);
exactType(comp3.value, {} as HTMLAnchorElement);
}
const comp4 = useTemplateRef('v-for-native');
if (comp4.value) {
exactType(comp4.value[0]?.href, {} as string | undefined);
exactType(comp4.value, {} as HTMLAnchorElement[]);
}
// @ts-expect-error
useTemplateRef('unknown');
</script>

<template>
<GenericGlobal ref="generic" :foo="1"/>
<Generic ref="generic" :foo="1"/>
{{ exactType(comp1?.foo, {} as 1 | undefined) }}

<GenericGlobal v-for="i in 4" ref="v-for-generic" :foo="i"/>
<Generic v-for="i in 4" ref="v-for-generic" :foo="i"/>
{{ exactType(comp2?.[0]?.foo, {} as number | undefined) }}

<a ref="native"></a>
Expand Down
38 changes: 0 additions & 38 deletions test-workspace/tsc/passedFixtures/vue3/templateRef_native/main.vue

This file was deleted.

0 comments on commit 32e455f

Please sign in to comment.