Repository: vuejs/eslint-plugin-vue (JavaScript)

Issue:
vue/component-name-in-template-casing does not work with script setup
**Checklist**

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have read the [FAQ](https://eslint.vuejs.org/user-guide/#faq) and my problem is not listed.

**Tell us about your environment**

- **ESLint version:** 7.32.0
- **eslint-plugin-vue version:** 7.18.0
- **Node version:** 16.6.1
- **Operating System:** Windows 

**Please show your full configuration:**
<!-- Paste content of your .eslintrc file -->
```
{
    root: true,
    env: {
        browser: true,
        es2021: true,
        node: true,
    },
    parser: 'vue-eslint-parser',
    parserOptions: {
        parser: '@typescript-eslint/parser',
        ecmaVersion: 'latest',
        sourceType: 'module',
    },
    extends: [
        'plugin:vue/vue3-recommended',
        'eslint:recommended',
        '@vue/typescript/recommended',
        '@vue/prettier',
        '@vue/prettier/@typescript-eslint',
    ],
    globals: {
        defineProps: 'readonly',
        defineEmits: 'readonly',
        defineExpose: 'readonly',
        withDefaults: 'readonly',
    },
    rules: {
        'vue/component-name-in-template-casing': ['error', 'kebab-case'],
    },
};
```

**What did you do?**
```
<template>
   <HelloWorld />
</template>

<script setup lang="ts">
    import HelloWorld from './HelloWorld.vue';
</script>
```

**What did you expect to happen?**
I expected that the `vue/component-name-in-template-casing` rule would throw an error for the `HelloWorld` tag in the template section of my vue file because it is written in PascalCase and not kebab-case.

**What actually happened?**
No linting error gets thrown when writing my code as above. However when I write my code as follows an error gets thrown stating that my component is not kebab-base:

```
<template>
   <HelloWorld />
</template>

<script lang="ts">
    import HelloWorld from './HelloWorld.vue';

    export default {
        components: { HelloWorld },
    }
</script>
```



Discussion:
Same issue here. Isn't it a bug (not an enhancement)?
Same issue here!

You can work around it by setting `registeredComponentsOnly` to false - although, obviously, that has side effects.



Patch:
diff --git a/lib/rules/component-name-in-template-casing.js b/lib/rules/component-name-in-template-casing.js
index 017e4cb08..772fa83ac 100644
--- a/lib/rules/component-name-in-template-casing.js
+++ b/lib/rules/component-name-in-template-casing.js
@@ -68,9 +68,22 @@ module.exports = {
       context.parserServices.getTemplateBodyTokenStore &&
       context.parserServices.getTemplateBodyTokenStore()
 
-    /** @type { string[] } */
-    const registeredComponents = []
+    /** @type { Set<string> } */
+    const registeredComponents = new Set()
 
+    if (utils.isScriptSetup(context)) {
+      // For <script setup>
+      const globalScope = context.getSourceCode().scopeManager.globalScope
+      if (globalScope) {
+        // Only check find the import module
+        const moduleScope = globalScope.childScopes.find(
+          (scope) => scope.type === 'module'
+        )
+        for (const variable of (moduleScope && moduleScope.variables) || []) {
+          registeredComponents.add(variable.name)
+        }
+      }
+    }
     /**
      * Checks whether the given node is the verification target node.
      * @param {VElement} node element node
@@ -95,7 +108,7 @@ module.exports = {
       }
       // We only verify the components registered in the component.
       if (
-        registeredComponents
+        [...registeredComponents]
           .filter((name) => casing.isPascalCase(name)) // When defining a component with PascalCase, you can use either case
           .some(
             (name) =>
@@ -153,9 +166,9 @@ module.exports = {
         },
         ...(registeredComponentsOnly
           ? utils.executeOnVue(context, (obj) => {
-              registeredComponents.push(
-                ...utils.getRegisteredComponents(obj).map((n) => n.name)
-              )
+              for (const n of utils.getRegisteredComponents(obj)) {
+                registeredComponents.add(n.name)
+              }
             })
           : {})
       }


Test patch:
diff --git a/tests/lib/rules/component-name-in-template-casing.js b/tests/lib/rules/component-name-in-template-casing.js
index 4c4d9f5cb..f0fe5b9f4 100644
--- a/tests/lib/rules/component-name-in-template-casing.js
+++ b/tests/lib/rules/component-name-in-template-casing.js
@@ -814,6 +814,46 @@ tester.run('component-name-in-template-casing', rule, {
         'Component name "client-only" is not PascalCase.',
         'Component name "keep-alive" is not PascalCase.'
       ]
+    },
+    {
+      code: `
+        <template>
+          <the-component />
+        </template>
+        <script setup>
+          import TheComponent from '@/components/theComponent.vue'
+        </script>
+      `,
+      options: ['PascalCase'],
+      output: `
+        <template>
+          <TheComponent />
+        </template>
+        <script setup>
+          import TheComponent from '@/components/theComponent.vue'
+        </script>
+      `,
+      errors: ['Component name "the-component" is not PascalCase.']
+    },
+    {
+      code: `
+        <template>
+          <TheComponent />
+        </template>
+        <script setup>
+          import TheComponent from '@/components/theComponent.vue'
+        </script>
+      `,
+      options: ['kebab-case'],
+      output: `
+        <template>
+          <the-component />
+        </template>
+        <script setup>
+          import TheComponent from '@/components/theComponent.vue'
+        </script>
+      `,
+      errors: ['Component name "TheComponent" is not kebab-case.']
     }
   ]
 })