Преглед изворни кода

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

fix #5959
Evan You пре 4 година
родитељ
комит
583b625987

+ 1 - 1
packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap

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

+ 3 - 1
packages/compiler-sfc/__tests__/compileScript.spec.ts

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

+ 16 - 4
packages/compiler-sfc/src/compileScript.ts

@@ -65,7 +65,7 @@ const WITH_DEFAULTS = 'withDefaults'
 const DEFAULT_VAR = `__default__`
 
 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 {
@@ -2103,7 +2103,8 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
               }
               if (prop.exp) {
                 code += `,${processExp(
-                  (prop.exp as SimpleExpressionNode).content
+                  (prop.exp as SimpleExpressionNode).content,
+                  prop.name
                 )}`
               }
             }
@@ -2122,8 +2123,19 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
   return code
 }
 
-function processExp(exp: string) {
-  if (/ as \w|<.*>/.test(exp)) {
+const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/
+
+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 = ''
     // has potential type cast or generic arguments that uses types
     const ast = parseExpression(exp, { plugins: ['typescript'] })