diff --git a/.changeset/modern-dancers-explode.md b/.changeset/modern-dancers-explode.md new file mode 100644 index 000000000..dc9e0e0c4 --- /dev/null +++ b/.changeset/modern-dancers-explode.md @@ -0,0 +1,5 @@ +--- +"@vue-macros/volar": patch +--- + +support generic component for export-expose diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index d8d7b3f64..674558625 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -34,6 +34,13 @@ export function addEmits(content: Code[], decl: Code[]) { return true } +export function addCode(codes: Code[], ...args: Code[]) { + const index = codes.findIndex((code) => + code.includes('__VLS_setup = (async () => {'), + ) + codes.splice(index > -1 ? index + 1 : codes.length, 0, ...args) +} + export function getVolarOptions( vueCompilerOptions: VueCompilerOptions, ): VolarOptions | undefined { diff --git a/packages/volar/src/export-expose.ts b/packages/volar/src/export-expose.ts index 77fdc2f7c..f29c047d1 100644 --- a/packages/volar/src/export-expose.ts +++ b/packages/volar/src/export-expose.ts @@ -3,11 +3,11 @@ import { type Sfc, type VueLanguagePlugin, allCodeFeatures, - replaceAll, + replace, replaceSourceRange, } from '@vue/language-core' import { createFilter } from '@rollup/pluginutils' -import { getStart, getVolarOptions } from './common' +import { addCode, getStart, getVolarOptions } from './common' import type { VolarOptions } from '..' function transform(options: { @@ -142,13 +142,21 @@ function transform(options: { ',\n', ]) - replaceAll( - codes, - /return {\n/g, - 'return {\n...{ ', - ...exposedStrings, - ' },\n', - ) + if (sfc.scriptSetup?.generic) { + addCode(codes, `const __VLS_exportExposed = {\n`, ...exposedStrings, `};\n`) + + replace( + codes, + /(?<=expose\(exposed: import\(\S+\)\.ShallowUnwrapRef<)/, + 'typeof __VLS_exportExposed & ', + ) + } else { + replace( + codes, + /(?<=export\sdefault \(await import\(\S+\)\)\.defineComponent\({[\S\s]*setup\(\) {\nreturn {\n)/, + ...exposedStrings, + ) + } } const plugin: VueLanguagePlugin = ({ diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index f5c949c1f..ba776e5a0 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -1,4 +1,4 @@ -import { getText, isJsxExpression } from '../common' +import { addCode, getText, isJsxExpression } from '../common' import { type JsxDirective, type TransformOptions, @@ -11,7 +11,7 @@ export function transformCtx( index: number, options: TransformOptions, ) { - const { ts, codes, sfc } = options + const { ts, codes } = options const openingElement = getOpeningElement(node, options) if (!openingElement) return '' @@ -39,15 +39,10 @@ export function transformCtx( ) } - const code = `const ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}));\n` - if (sfc.scriptSetup?.generic) { - const index = codes.findIndex((code) => - code.includes('__VLS_setup = (async () => {'), - ) - codes.splice(index + 1, 0, code) - } else { - codes.push(code) - } + addCode( + codes, + `const ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}));\n`, + ) return ctxName } diff --git a/playground/vue3/src/examples/export-expose/child-generic.vue b/playground/vue3/src/examples/export-expose/child-generic.vue new file mode 100644 index 000000000..63271c8bc --- /dev/null +++ b/playground/vue3/src/examples/export-expose/child-generic.vue @@ -0,0 +1,10 @@ + + + diff --git a/playground/vue3/src/examples/export-expose/index.vue b/playground/vue3/src/examples/export-expose/index.vue index caec61fd5..3feb9bed1 100644 --- a/playground/vue3/src/examples/export-expose/index.vue +++ b/playground/vue3/src/examples/export-expose/index.vue @@ -2,12 +2,15 @@ import { ref } from 'vue' import { Assert } from '../../assert' import Child from './child.vue' +import ChildGeneric from './child-generic.vue' const child = ref>() +const childGeneric = ref>() diff --git a/playground/vue3/src/vite-env.d.ts b/playground/vue3/src/vite-env.d.ts index f96dbf9bf..f5fe0eb78 100644 --- a/playground/vue3/src/vite-env.d.ts +++ b/playground/vue3/src/vite-env.d.ts @@ -1,2 +1,13 @@ /// /// + +declare type ComponentExposed = T extends new (...args: any) => infer E + ? E + : T extends ( + props: any, + ctx: any, + expose: (exposed: infer E) => any, + ...args: any + ) => any + ? NonNullable + : any