fix(compiler-sfc): fix usage detection for types in v-for/v-slot expressions

fix #5959
This commit is contained in:
Evan You 2022-05-21 00:09:15 +08:00
parent 8ba0bb8ec3
commit 583b625987
3 changed files with 20 additions and 6 deletions

View File

@ -722,7 +722,7 @@ return { props, a, emit }
exports[`SFC compile <script setup> dev mode import usage check TS annotations 1`] = ` exports[`SFC compile <script setup> dev mode import usage check TS annotations 1`] = `
"import { defineComponent as _defineComponent } from 'vue' "import { defineComponent as _defineComponent } from 'vue'
import { Foo, Bar, Baz } from './x' import { Foo, Bar, Baz, Qux, Fred } from './x'
export default /*#__PURE__*/_defineComponent({ export default /*#__PURE__*/_defineComponent({
setup(__props, { expose }) { setup(__props, { expose }) {

View File

@ -446,7 +446,7 @@ defineExpose({ foo: 123 })
test('TS annotations', () => { test('TS annotations', () => {
const { content } = compile(` const { content } = compile(`
<script setup lang="ts"> <script setup lang="ts">
import { Foo, Bar, Baz } from './x' import { Foo, Bar, Baz, Qux, Fred } from './x'
const a = 1 const a = 1
function b() {} function b() {}
</script> </script>
@ -454,6 +454,8 @@ defineExpose({ foo: 123 })
{{ a as Foo }} {{ a as Foo }}
{{ b<Bar>() }} {{ b<Bar>() }}
{{ Baz }} {{ Baz }}
<Comp v-slot="{ data }: Qux">{{ data }}</Comp>
<div v-for="{ z = x as Qux } in list as Fred"/>
</template> </template>
`) `)
expect(content).toMatch(`return { a, b, Baz }`) expect(content).toMatch(`return { a, b, Baz }`)

View File

@ -65,7 +65,7 @@ const WITH_DEFAULTS = 'withDefaults'
const DEFAULT_VAR = `__default__` const DEFAULT_VAR = `__default__`
const isBuiltInDir = makeMap( const isBuiltInDir = makeMap(
`once,memo,if,else,else-if,slot,text,html,on,bind,model,show,cloak,is` `once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
) )
export interface SFCScriptCompileOptions { export interface SFCScriptCompileOptions {
@ -2103,7 +2103,8 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
} }
if (prop.exp) { if (prop.exp) {
code += `,${processExp( code += `,${processExp(
(prop.exp as SimpleExpressionNode).content (prop.exp as SimpleExpressionNode).content,
prop.name
)}` )}`
} }
} }
@ -2122,8 +2123,19 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
return code return code
} }
function processExp(exp: string) { const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/
if (/ as \w|<.*>/.test(exp)) {
function processExp(exp: string, dir?: string): string {
if (/ as\s+\w|<.*>|:/.test(exp)) {
if (dir === 'slot') {
exp = `(${exp})=>{}`
} else if (dir === 'for') {
const inMatch = exp.match(forAliasRE)
if (inMatch) {
const [, LHS, RHS] = inMatch
return processExp(`(${LHS})=>{}`) + processExp(RHS)
}
}
let ret = '' let ret = ''
// has potential type cast or generic arguments that uses types // has potential type cast or generic arguments that uses types
const ast = parseExpression(exp, { plugins: ['typescript'] }) const ast = parseExpression(exp, { plugins: ['typescript'] })