From 49848b4149f244e37129edea634b3920599f8680 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 19 Jan 2025 01:29:53 +0800 Subject: [PATCH 1/4] feat: introduce options to control types of `$attrs`, `$el`, `$refs` and `$slots` --- .../lib/codegen/script/component.ts | 12 ++++- .../lib/codegen/script/scriptSetup.ts | 44 ++++++++++--------- .../lib/codegen/template/context.ts | 4 +- .../lib/codegen/template/index.ts | 21 ++++++--- .../lib/codegen/template/interpolation.ts | 10 ++--- packages/language-core/lib/types.ts | 14 ++++++ packages/language-core/lib/utils/ts.ts | 43 ++++++++++++++++++ .../schemas/vue-tsconfig.schema.json | 38 +++++++++++++--- .../tsc/passedFixtures/vue3/rootEl/base.vue | 2 + .../tsc/passedFixtures/vue3/rootEl/child.vue | 2 + .../vue3/templateRef/template-ref.vue | 2 + 11 files changed, 152 insertions(+), 40 deletions(-) diff --git a/packages/language-core/lib/codegen/script/component.ts b/packages/language-core/lib/codegen/script/component.ts index d4552a8466..bfca43e122 100644 --- a/packages/language-core/lib/codegen/script/component.ts +++ b/packages/language-core/lib/codegen/script/component.ts @@ -40,10 +40,18 @@ export function* generateComponent( const { args } = options.scriptRanges.exportDefault; yield generateSfcBlockSection(options.sfc.script, args.start + 1, args.end - 1, codeFeatures.all); } - if (options.vueCompilerOptions.target >= 3.5 && options.templateCodegen?.templateRefs.size) { + if ( + options.vueCompilerOptions.target >= 3.5 + && options.vueCompilerOptions.typedDollarRefs.expose + && 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.typedDollarEl.expose + && options.templateCodegen?.singleRootElType + ) { yield `__typeEl: {} as __VLS_TemplateEl,${newLine}`; } yield `})`; diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index 81eac14a19..d62c6480fd 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -170,16 +170,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.typedDollarAttrs.self) { + 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([ @@ -209,16 +211,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.typedDollarSlots.self) { + 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) { diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index c435b70f44..7e2da5556b 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -103,7 +103,7 @@ export function createTemplateCodegenContext(options: Pick(); - const specialVars = new Set(); + const dollarVars = new Set(); const accessExternalVariables = new Map>(); const slots: { name: string; @@ -132,7 +132,7 @@ export function createTemplateCodegenContext(options: Pick, + dollarVars: Set, destructuredPropNames: Set | undefined, templateRefNames: Set | undefined, curVar: CtxVar, @@ -176,8 +176,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]; diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 6d1e05cac5..78529544d9 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -49,6 +49,20 @@ export interface VueCompilerOptions { useSlots: string[]; useTemplateRef: string[]; }; + typedDollarAttrs: { + self: boolean; + }, + typedDollarEl: { + self: boolean; + expose: boolean; + }, + typedDollarRefs: { + self: boolean; + expose: boolean; + }, + typedDollarSlots: { + self: boolean; + }, plugins: VueLanguagePlugin[]; // experimental diff --git a/packages/language-core/lib/utils/ts.ts b/packages/language-core/lib/utils/ts.ts index ff9e3471a1..ebdd68808d 100644 --- a/packages/language-core/lib/utils/ts.ts +++ b/packages/language-core/lib/utils/ts.ts @@ -253,6 +253,20 @@ function getDefaultOptions(options: Partial): VueCompilerOpt useSlots: ['useSlots'], useTemplateRef: ['useTemplateRef', 'templateRef'], }, + typedDollarAttrs: { + self: true + }, + typedDollarEl: { + self: true, + expose: false + }, + typedDollarRefs: { + self: true, + expose: false + }, + typedDollarSlots: { + self: true + }, plugins: [], experimentalDefinePropProposal: false, experimentalResolveStyleCssClasses: 'scoped', @@ -275,6 +289,22 @@ export function resolveVueCompilerOptions( ...defaults.composables, ...options.composables, }, + typedDollarAttrs: mergeTypedDollar( + options.typedDollarAttrs, + defaults.typedDollarAttrs + ), + typedDollarEl: mergeTypedDollar( + options.typedDollarEl, + defaults.typedDollarEl + ), + typedDollarRefs: mergeTypedDollar( + options.typedDollarRefs, + defaults.typedDollarRefs + ), + typedDollarSlots: mergeTypedDollar( + options.typedDollarSlots, + defaults.typedDollarSlots + ), // https://github.com/vuejs/vue-next/blob/master/packages/compiler-dom/src/transforms/vModel.ts#L49-L51 // https://vuejs.org/guide/essentials/forms.html#form-input-bindings @@ -315,3 +345,16 @@ export function setupGlobalTypes(rootDir: string, vueOptions: VueCompilerOptions return { absolutePath: globalTypesPath }; } catch { } } + +function mergeTypedDollar( + value: T | undefined, + defaults: { self: boolean; expose?: boolean; } +) { + return (typeof value === "boolean" ? { + self: value, + expose: value + } : { + ...defaults, + ...value + }) as T; +} diff --git a/packages/language-core/schemas/vue-tsconfig.schema.json b/packages/language-core/schemas/vue-tsconfig.schema.json index 5c6f33426f..f9ab6458dd 100644 --- a/packages/language-core/schemas/vue-tsconfig.schema.json +++ b/packages/language-core/schemas/vue-tsconfig.schema.json @@ -65,11 +65,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": [ @@ -99,6 +94,39 @@ "useTemplateRef": [ "useTemplateRef", "templateRef" ] } }, + "typedDollarAttrs": { + "type": ["boolean", "object"], + "default": { + "self": true, + "expose": false + } + }, + "typedDollarEl": { + "type": ["boolean", "object"], + "default": { + "self": true, + "expose": false + } + }, + "typedDollarRefs": { + "type": ["boolean", "object"], + "default": { + "self": true, + "expose": false + } + }, + "typedDollarSlots": { + "type": ["boolean", "object"], + "default": { + "self": false, + "expose": true + } + }, + "plugins": { + "type": "array", + "default": [ ], + "markdownDescription": "Plugins to be used in the SFC compiler." + }, "experimentalResolveStyleCssClasses": { "enum": [ "scoped", diff --git a/test-workspace/tsc/passedFixtures/vue3/rootEl/base.vue b/test-workspace/tsc/passedFixtures/vue3/rootEl/base.vue index dee0efe5f9..d137fd9a3b 100644 --- a/test-workspace/tsc/passedFixtures/vue3/rootEl/base.vue +++ b/test-workspace/tsc/passedFixtures/vue3/rootEl/base.vue @@ -1,3 +1,5 @@ + + diff --git a/test-workspace/tsc/passedFixtures/vue3/rootEl/child.vue b/test-workspace/tsc/passedFixtures/vue3/rootEl/child.vue index ba23fc8016..23589a430d 100644 --- a/test-workspace/tsc/passedFixtures/vue3/rootEl/child.vue +++ b/test-workspace/tsc/passedFixtures/vue3/rootEl/child.vue @@ -1,3 +1,5 @@ + +