]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): fix import usage check for lowercase imported components
authorEvan You <yyx990803@gmail.com>
Tue, 17 Aug 2021 14:10:26 +0000 (10:10 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 17 Aug 2021 14:10:26 +0000 (10:10 -0400)
fix #4358

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

index 3ab28dceb2d8443cb2eda08acd974f1ce729f211..c282b7eb4d6725aa49ec508d52fc3fb3410b9232 100644 (file)
@@ -126,6 +126,82 @@ return { props, a, emit }
 }"
 `;
 
+exports[`SFC compile <script setup> dev mode import usage check components 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+import { FooBar, FooBaz, FooQux, foo } from './x'
+        
+export default _defineComponent({
+  setup(__props, { expose }) {
+  expose()
+
+        const fooBar: FooBar = 1
+        
+return { fooBar, FooBaz, FooQux, foo }
+}
+
+})"
+`;
+
+exports[`SFC compile <script setup> dev mode import usage check directive 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+import { vMyDir } from './x'
+        
+export default _defineComponent({
+  setup(__props, { expose }) {
+  expose()
+
+        
+return { vMyDir }
+}
+
+})"
+`;
+
+exports[`SFC compile <script setup> dev mode import usage check js template string interpolations 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+import { VAR, VAR2, VAR3 } from './x'
+        
+export default _defineComponent({
+  setup(__props, { expose }) {
+  expose()
+
+        
+return { VAR, VAR3 }
+}
+
+})"
+`;
+
+exports[`SFC compile <script setup> dev mode import usage check last tag 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+import { FooBaz, Last } from './x'
+        
+export default _defineComponent({
+  setup(__props, { expose }) {
+  expose()
+
+        
+return { FooBaz, Last }
+}
+
+})"
+`;
+
+exports[`SFC compile <script setup> dev mode import usage check vue interpolations 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+import { x, y, z, x$y } from './x'
+      
+export default _defineComponent({
+  setup(__props, { expose }) {
+  expose()
+
+      
+return { x, z, x$y }
+}
+
+})"
+`;
+
 exports[`SFC compile <script setup> errors should allow defineProps/Emit() referencing imported binding 1`] = `
 "import { bar } from './bar'
         
@@ -204,22 +280,6 @@ return { x }
 }"
 `;
 
-exports[`SFC compile <script setup> imports imports not used in <template> should not be exposed 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-import { FooBar, FooBaz, FooQux, vMyDir, x, y, z, x$y, VAR, VAR2, VAR3, Last } from './x'
-        
-export default _defineComponent({
-  setup(__props, { expose }) {
-  expose()
-
-        const fooBar: FooBar = 1
-        
-return { fooBar, FooBaz, FooQux, vMyDir, x, z, x$y, VAR, VAR3, Last }
-}
-
-})"
-`;
-
 exports[`SFC compile <script setup> imports should allow defineProps/Emit at the start of imports 1`] = `
 "import { ref } from 'vue'
       
index ce8816910dfefb9a3689e5a13c1ad02d2c14acc6..2bf7f1fd2e320189823b3e2d46de2fe4a2a63e13 100644 (file)
@@ -209,32 +209,90 @@ defineExpose({ foo: 123 })
         content.lastIndexOf(`import { x }`)
       )
     })
+  })
 
-    test('imports not used in <template> should not be exposed', () => {
+  // in dev mode, declared bindings are returned as an object from setup()
+  // when using TS, users may import types which should not be returned as
+  // values, so we need to check import usage in the template to determine
+  // what to be returned.
+  describe('dev mode import usage check', () => {
+    test('components', () => {
       const { content } = compile(`
         <script setup lang="ts">
-        import { FooBar, FooBaz, FooQux, vMyDir, x, y, z, x$y, VAR, VAR2, VAR3, Last } from './x'
+        import { FooBar, FooBaz, FooQux, foo } from './x'
         const fooBar: FooBar = 1
         </script>
         <template>
-          <FooBaz v-my-dir>{{ x }} {{ yy }} {{ x$y }}</FooBaz>
+          <FooBaz></FooBaz>
           <foo-qux/>
-          <div :id="z + 'y'">FooBar</div>
-          {{ \`\${VAR}VAR2\${VAR3}\` }}
-          <Last/>
+          <foo/>
+          FooBar
         </template>
         `)
-      // FooBar: should not be matched by plain text
+      // FooBar: should not be matched by plain text or incorrect case
       // FooBaz: used as PascalCase component
       // FooQux: used as kebab-case component
-      // vMyDir: used as directive v-my-dir
+      // foo: lowercase component
+      expect(content).toMatch(`return { fooBar, FooBaz, FooQux, foo }`)
+      assertCode(content)
+    })
+
+    test('directive', () => {
+      const { content } = compile(`
+        <script setup lang="ts">
+        import { vMyDir } from './x'
+        </script>
+        <template>
+          <div v-my-dir></div>
+        </template>
+        `)
+      expect(content).toMatch(`return { vMyDir }`)
+      assertCode(content)
+    })
+
+    test('vue interpolations', () => {
+      const { content } = compile(`
+      <script setup lang="ts">
+      import { x, y, z, x$y } from './x'
+      </script>
+      <template>
+        <div :id="z + 'y'">{{ x }} {{ yy }} {{ x$y }}</div>
+      </template>
+      `)
       // x: used in interpolation
       // y: should not be matched by {{ yy }} or 'y' in binding exps
       // x$y: #4274 should escape special chars when creating Regex
-      // VAR & VAR3: #4340 interpolations in tempalte strings
-      expect(content).toMatch(
-        `return { fooBar, FooBaz, FooQux, vMyDir, x, z, x$y, VAR, VAR3, Last }`
-      )
+      expect(content).toMatch(`return { x, z, x$y }`)
+      assertCode(content)
+    })
+
+    // #4340 interpolations in tempalte strings
+    test('js template string interpolations', () => {
+      const { content } = compile(`
+        <script setup lang="ts">
+        import { VAR, VAR2, VAR3 } from './x'
+        </script>
+        <template>
+          {{ \`\${VAR}VAR2\${VAR3}\` }}
+        </template>
+        `)
+      // VAR2 should not be matched
+      expect(content).toMatch(`return { VAR, VAR3 }`)
+      assertCode(content)
+    })
+
+    // edge case: last tag in template
+    test('last tag', () => {
+      const { content } = compile(`
+        <script setup lang="ts">
+        import { FooBaz, Last } from './x'
+        </script>
+        <template>
+          <FooBaz></FooBaz>
+          <Last/>
+        </template>
+        `)
+      expect(content).toMatch(`return { FooBaz, Last }`)
       assertCode(content)
     })
   })
index 031d20634cf2f8acc495da51d4d94323cd4fcf1a..5289d110462580f2b7063037e6dfec45d1d9ea3b 100644 (file)
@@ -2212,7 +2212,7 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
             !parserOptions.isNativeTag!(node.tag) &&
             !parserOptions.isBuiltInComponent!(node.tag)
           ) {
-            code += `,${capitalize(camelize(node.tag))}`
+            code += `,${camelize(node.tag)},${capitalize(camelize(node.tag))}`
           }
           for (let i = 0; i < node.props.length; i++) {
             const prop = node.props[i]