Skip to content

Commit

Permalink
feat(language-core): introduce options to control type inference of `…
Browse files Browse the repository at this point in the history
…$attrs`, `$el`, `$refs` and `$slots` (#5135)

Co-authored-by: Johnson Chu <johnsoncodehk@gmail.com>
  • Loading branch information
KazariEX and johnsoncodehk authored Feb 19, 2025
1 parent 408e97a commit b411d53
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 41 deletions.
12 changes: 10 additions & 2 deletions packages/language-core/lib/codegen/script/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,18 @@ export function* generateComponent(
}
yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, !!emitOptionCodes.length, true);
}
if (options.vueCompilerOptions.target >= 3.5 && options.templateCodegen?.templateRefs.size) {
if (
options.vueCompilerOptions.target >= 3.5
&& options.vueCompilerOptions.inferComponentDollarRefs
&& options.templateCodegen?.templateRefs.size
) {
yield `__typeRefs: {} as __VLS_TemplateRefs,${newLine}`;
}
if (options.vueCompilerOptions.target >= 3.5 && options.templateCodegen?.singleRootElType) {
if (
options.vueCompilerOptions.target >= 3.5
&& options.vueCompilerOptions.inferComponentDollarEl
&& options.templateCodegen?.singleRootElType
) {
yield `__typeEl: {} as __VLS_RootEl,${newLine}`;
}
if (options.sfc.script && options.scriptRanges?.exportDefault?.args) {
Expand Down
44 changes: 24 additions & 20 deletions packages/language-core/lib/codegen/script/scriptSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,18 @@ function* generateSetupFunction(
]);
}
}
for (const { callExp } of scriptSetupRanges.useAttrs) {
setupCodeModifies.push([
[`(`],
callExp.start,
callExp.start
], [
[` as typeof __VLS_special.$attrs)`],
callExp.end,
callExp.end
]);
if (options.vueCompilerOptions.inferTemplateDollarAttrs) {
for (const { callExp } of scriptSetupRanges.useAttrs) {
setupCodeModifies.push([
[`(`],
callExp.start,
callExp.start
], [
[` as typeof __VLS_dollars.$attrs)`],
callExp.end,
callExp.end
]);
}
}
for (const { callExp, exp, arg } of scriptSetupRanges.useCssModule) {
setupCodeModifies.push([
Expand Down Expand Up @@ -210,16 +212,18 @@ function* generateSetupFunction(
]);
}
}
for (const { callExp } of scriptSetupRanges.useSlots) {
setupCodeModifies.push([
[`(`],
callExp.start,
callExp.start
], [
[` as typeof __VLS_special.$slots)`],
callExp.end,
callExp.end
]);
if (options.vueCompilerOptions.inferTemplateDollarSlots) {
for (const { callExp } of scriptSetupRanges.useSlots) {
setupCodeModifies.push([
[`(`],
callExp.start,
callExp.start
], [
[` as typeof __VLS_dollars.$slots)`],
callExp.end,
callExp.end
]);
}
}
const isTs = options.lang !== 'js' && options.lang !== 'jsx';
for (const { callExp, exp, arg } of scriptSetupRanges.useTemplateRef) {
Expand Down
4 changes: 2 additions & 2 deletions packages/language-core/lib/codegen/template/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption

const hoistVars = new Map<string, string>();
const localVars = new Map<string, number>();
const specialVars = new Set<string>();
const dollarVars = new Set<string>();
const accessExternalVariables = new Map<string, Set<number>>();
const slots: {
name: string;
Expand Down Expand Up @@ -83,7 +83,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
resolveCodeFeatures,
slots,
dynamicSlots,
specialVars,
dollarVars,
accessExternalVariables,
lastGenericComment,
blockConditions,
Expand Down
21 changes: 15 additions & 6 deletions packages/language-core/lib/codegen/template/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,20 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
if (options.propsAssignName) {
ctx.addLocalVariable(options.propsAssignName);
}

const slotsPropertyName = getSlotsPropertyName(options.vueCompilerOptions.target);
ctx.specialVars.add(slotsPropertyName);
ctx.specialVars.add('$attrs');
ctx.specialVars.add('$refs');
ctx.specialVars.add('$el');
if (options.vueCompilerOptions.inferTemplateDollarSlots) {
ctx.dollarVars.add(slotsPropertyName);
}
if (options.vueCompilerOptions.inferTemplateDollarAttrs) {
ctx.dollarVars.add('$attrs');
}
if (options.vueCompilerOptions.inferTemplateDollarRefs) {
ctx.dollarVars.add('$refs');
}
if (options.vueCompilerOptions.inferTemplateDollarEl) {
ctx.dollarVars.add('$el');
}

if (options.template.ast) {
yield* generateTemplateChild(options, ctx, options.template.ast, undefined);
Expand All @@ -55,7 +64,7 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
['$el', yield* generateRootEl(ctx)]
];

yield `var __VLS_special!: {${newLine}`;
yield `var __VLS_dollars!: {${newLine}`;
for (const [name, type] of speicalTypes) {
yield `${name}: ${type}${endOfLine}`;
}
Expand Down Expand Up @@ -114,7 +123,7 @@ function* generateInheritedAttrs(
if (ctx.bindingAttrLocs.length) {
yield `[`;
for (const loc of ctx.bindingAttrLocs) {
yield `__VLS_special.`;
yield `__VLS_dollars.`;
yield [
loc.source,
'template',
Expand Down
10 changes: 5 additions & 5 deletions packages/language-core/lib/codegen/template/interpolation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function* forEachInterpolationSegment(
const curVar = ctxVars[i];
const nextVar = ctxVars[i + 1];

yield* generateVar(code, ctx.specialVars, destructuredPropNames, templateRefNames, curVar);
yield* generateVar(code, ctx.dollarVars, destructuredPropNames, templateRefNames, curVar);

if (nextVar.isShorthand) {
yield [code.slice(curVar.offset + curVar.text.length, nextVar.offset + nextVar.text.length), curVar.offset + curVar.text.length];
Expand All @@ -146,7 +146,7 @@ function* forEachInterpolationSegment(
}

const lastVar = ctxVars.at(-1)!;
yield* generateVar(code, ctx.specialVars, destructuredPropNames, templateRefNames, lastVar);
yield* generateVar(code, ctx.dollarVars, 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'];
}
Expand All @@ -158,7 +158,7 @@ function* forEachInterpolationSegment(

function* generateVar(
code: string,
specialVars: Set<string>,
dollarVars: Set<string>,
destructuredPropNames: Set<string> | undefined,
templateRefNames: Set<string> | undefined,
curVar: CtxVar
Expand All @@ -175,8 +175,8 @@ function* generateVar(
yield [`)`, undefined];
}
else {
if (specialVars.has(curVar.text)) {
yield [`__VLS_special.`, undefined];
if (dollarVars.has(curVar.text)) {
yield [`__VLS_dollars.`, undefined];
}
else if (!isDestructuredProp) {
yield [`__VLS_ctx.`, undefined];
Expand Down
6 changes: 6 additions & 0 deletions packages/language-core/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export interface VueCompilerOptions {
checkUnknownEvents: boolean;
checkUnknownDirectives: boolean;
checkUnknownComponents: boolean;
inferComponentDollarEl: boolean;
inferComponentDollarRefs: boolean;
inferTemplateDollarAttrs: boolean;
inferTemplateDollarEl: boolean;
inferTemplateDollarRefs: boolean;
inferTemplateDollarSlots: boolean;
skipTemplateCodegen: boolean;
fallthroughAttributes: boolean;
dataAttributes: string[];
Expand Down
6 changes: 6 additions & 0 deletions packages/language-core/lib/utils/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,12 @@ export function getDefaultCompilerOptions(target = 99, lib = 'vue', strictTempla
checkUnknownEvents: strictTemplates,
checkUnknownDirectives: strictTemplates,
checkUnknownComponents: strictTemplates,
inferComponentDollarEl: false,
inferComponentDollarRefs: false,
inferTemplateDollarAttrs: false,
inferTemplateDollarEl: false,
inferTemplateDollarRefs: false,
inferTemplateDollarSlots: false,
skipTemplateCodegen: false,
fallthroughAttributes: false,
dataAttributes: [],
Expand Down
40 changes: 35 additions & 5 deletions packages/language-core/schemas/vue-tsconfig.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,36 @@
"default": false,
"markdownDescription": "Check unknown components. If not set, uses the 'strictTemplates' value."
},
"inferComponentDollarEl": {
"type": "boolean",
"default": false,
"markdownDescription": "Infer `$el` type on the component instance."
},
"inferComponentDollarRefs": {
"type": "boolean",
"default": false,
"markdownDescription": "Infer `$refs` type on the component instance."
},
"inferTemplateDollarAttrs": {
"type": "boolean",
"default": false,
"markdownDescription": "Infer `$attrs` type in the template and the return type of `useAttrs`."
},
"inferTemplateDollarEl": {
"type": "boolean",
"default": false,
"markdownDescription": "Infer `$el` type in the template."
},
"inferTemplateDollarRefs": {
"type": "boolean",
"default": false,
"markdownDescription": "Infer `$refs` type in the template."
},
"inferTemplateDollarSlots": {
"type": "boolean",
"default": false,
"markdownDescription": "Infer `$slots` type in the template and the return type of `useSlots`."
},
"skipTemplateCodegen": {
"type": "boolean",
"default": false,
Expand All @@ -85,11 +115,6 @@
"default": [ "aria-*" ],
"markdownDescription": "A glob matcher array that should always be recognizing as HTML Attributes rather than Component props. Attribute name will never convert to camelize case."
},
"plugins": {
"type": "array",
"default": [ ],
"markdownDescription": "Plugins to be used in the SFC compiler."
},
"optionsWrapper": {
"type": "array",
"default": [
Expand Down Expand Up @@ -119,6 +144,11 @@
"useTemplateRef": [ "useTemplateRef", "templateRef" ]
}
},
"plugins": {
"type": "array",
"default": [ ],
"markdownDescription": "Plugins to be used in the SFC compiler."
},
"experimentalResolveStyleCssClasses": {
"enum": [
"scoped",
Expand Down
2 changes: 1 addition & 1 deletion packages/tsc/tests/__snapshots__/dts.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ exports[`vue-tsc-dts > Input: reference-type-props/component-destructure.vue, Ou
"type __VLS_Props = {
text: string;
};
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, HTMLDivElement>;
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
export default _default;
"
`;
Expand Down
3 changes: 3 additions & 0 deletions test-workspace/tsc/passedFixtures/vue3/rootEl/base.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<!-- @inferComponentDollarEl true -->
<!-- @inferTemplateDollarEl true -->

<script setup lang="ts">
import { exactType } from '../../shared';
</script>
Expand Down
3 changes: 3 additions & 0 deletions test-workspace/tsc/passedFixtures/vue3/rootEl/child.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<!-- @inferComponentDollarEl true -->
<!-- @inferTemplateDollarEl true -->

<script setup lang="ts">
import { exactType } from '../../shared';
import Base from './base.vue';
Expand Down
2 changes: 2 additions & 0 deletions test-workspace/tsc/passedFixtures/vue3/rootEl/main.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- @inferTemplateDollarEl true -->

<script setup lang="ts">
import { exactType } from '../../shared';
import Child from './child.vue';
Expand Down
2 changes: 2 additions & 0 deletions test-workspace/tsc/passedFixtures/vue3/slots/main.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- @inferTemplateDollarSlots true -->

<template>
<!-- component slots type -->
<Comp value="1">
Expand Down
2 changes: 2 additions & 0 deletions test-workspace/tsc/passedFixtures/vue3/templateRef/main.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- @inferTemplateDollarRefs true -->

<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { exactType } from '../../shared';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- @inferComponentDollarRefs true -->

<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { exactType } from '../../shared';
Expand Down

0 comments on commit b411d53

Please sign in to comment.