Skip to content

Commit

Permalink
feat(volar/export-expose): support generic component (#676)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiyuanzmj committed May 17, 2024
1 parent c4468c5 commit 505e801
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-dancers-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@vue-macros/volar": patch
---

support generic component for export-expose
7 changes: 7 additions & 0 deletions packages/volar/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
26 changes: 17 additions & 9 deletions packages/volar/src/export-expose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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 = ({
Expand Down
17 changes: 6 additions & 11 deletions packages/volar/src/jsx-directive/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getText, isJsxExpression } from '../common'
import { addCode, getText, isJsxExpression } from '../common'
import {
type JsxDirective,
type TransformOptions,
Expand All @@ -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 ''
Expand Down Expand Up @@ -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
}
10 changes: 10 additions & 0 deletions playground/vue3/src/examples/export-expose/child-generic.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script setup lang="ts" generic="T">
import { ref } from 'vue'
import { Ok } from '../../assert'
export const foo = ref('foo')
export const bar = 'bar'
</script>

<template>
<Ok />
</template>
5 changes: 4 additions & 1 deletion playground/vue3/src/examples/export-expose/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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<InstanceType<typeof Child>>()
const childGeneric = ref<ComponentExposed<typeof Child>>()
</script>

<template>
<Child ref="child" />
<ChildGeneric ref="childGeneric" />
<Assert :l="child?.foo" r="new" />
<Assert :l="child?.bar" r="bar" />
<Assert :l="childGeneric?.bar" r="bar" />
</template>
11 changes: 11 additions & 0 deletions playground/vue3/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
/// <reference types="vite/client" />
/// <reference types="unplugin-vue-macros/macros-global" />

declare type ComponentExposed<T> = T extends new (...args: any) => infer E
? E
: T extends (
props: any,
ctx: any,
expose: (exposed: infer E) => any,
...args: any
) => any
? NonNullable<E>
: any

0 comments on commit 505e801

Please sign in to comment.