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

Issue:
Add `allow` rule option to `vue/no-template-shadow`
<!--
  Before proposing rule changes, please make sure it hasn't been posted already.
  You can see all open propositions here:
  https://github.com/vuejs/eslint-plugin-vue/issues?q=is%3Aopen+is%3Aissue+label%3A%22new+rule+proposition%22
-->

**What rule do you want to change?**
`vue/no-template-shadow`

**Does this change cause the rule to produce more or fewer warnings?**
Slightly few warnings, in selected occurrences 

**How will the change be implemented? (New option, new default behavior, etc.)?**
Probably the best way is to set a new option to the existing rule, something like this:

```js
"vue/no-template-shadow": ['error', {
    whitelist: ['allowed', 'variable', 'names'],
}],
```

---

I think it can be useful to have the ability to set a whitelist for well known variable names that are allowed to be shadowed, while still being able to throw errors or warnings in all other cases.

It could be possible to have certain selected variable names that have to remain the same (maybe for third party libraries constraints, or for some coding convention), while also wanting to prevent this behavior globally.



Discussion:
To match the `no-shadow` core ESLint rule, we should call that rule option `allow`: https://eslint.org/docs/latest/rules/no-shadow#allow

A PR to implement this is welcome :slightly_smiling_face: 
Thanks for your reply, I did not even notice that he core rule already had this feature :D

I'm not so sure if I am able to contribute with a PR, but maybe I can try to have a look in the next few days if I can free some time and maybe share some insights (not sure if I can properly contribute with code)
@stefanobartoletti @FloEdelmann Hello! I had some free time today and took a stab at it, I hope it's ok 🙏 https://github.com/vuejs/eslint-plugin-vue/pull/2323
@mussinbenarbia thanks for taking care of this!



Patch:
diff --git a/docs/rules/no-template-shadow.md b/docs/rules/no-template-shadow.md
index 5bddba45c..0dcfb2171 100644
--- a/docs/rules/no-template-shadow.md
+++ b/docs/rules/no-template-shadow.md
@@ -36,13 +36,13 @@ This rule aims to eliminate shadowed variable declarations of v-for directives o
 </template>
 
 <script>
-  export default {
-    data () {
-      return {
-        l: false
-      }
+export default {
+  data() {
+    return {
+      l: false
     }
   }
+}
 </script>
 ```
 
@@ -50,7 +50,37 @@ This rule aims to eliminate shadowed variable declarations of v-for directives o
 
 ## :wrench: Options
 
-Nothing.
+This rule takes one optional object option, with the property `"allow"`.
+
+```json
+{
+  "no-template-shadow": ["error", { "allow": [] }]
+}
+```
+
+- `"allow"` (`[string]`) Array of identifier names for which shadowing is allowed.
+
+Examples of correct code for the `{ "allow": ["i"] }` option:
+
+<eslint-code-block :rules="{'vue/no-template-shadow': ['error', { allow: ['i'] }]}">
+
+```vue
+<template>
+  <div v-for="i in 5"></div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      i: 'some value'
+    }
+  }
+}
+</script>
+```
+
+</eslint-code-block>
 
 ## :rocket: Version
 
diff --git a/lib/rules/no-template-shadow.js b/lib/rules/no-template-shadow.js
index 4b7528a0b..8be04b9cc 100644
--- a/lib/rules/no-template-shadow.js
+++ b/lib/rules/no-template-shadow.js
@@ -20,6 +20,13 @@ const GROUP_NAMES = [
   'setup'
 ]
 
+function isAllowedVarName(context, variableName) {
+  if (context.options[0] && context.options[0].allow) {
+    return context.options[0].allow.includes(variableName)
+  }
+  return false
+}
+
 module.exports = {
   meta: {
     type: 'suggestion',
@@ -30,7 +37,21 @@ module.exports = {
       url: 'https://eslint.vuejs.org/rules/no-template-shadow.html'
     },
     fixable: null,
-    schema: [],
+    schema: [
+      {
+        type: 'object',
+        properties: {
+          allow: {
+            type: 'array',
+            items: {
+              type: 'string'
+            },
+            uniqueItems: true
+          }
+        },
+        additionalProperties: false
+      }
+    ],
     messages: {
       alreadyDeclaredInUpperScope:
         "Variable '{{name}}' is already declared in the upper scope."
@@ -102,6 +123,11 @@ module.exports = {
           for (const variable of node.variables) {
             const varNode = variable.id
             const name = varNode.name
+
+            if (isAllowedVarName(context, name)) {
+              continue
+            }
+
             if (
               scopeStack.nodes.some((node) => node.name === name) ||
               jsVars.has(name)


Test patch:
diff --git a/tests/lib/rules/no-template-shadow.js b/tests/lib/rules/no-template-shadow.js
index e2ea096b7..6844b5f9f 100644
--- a/tests/lib/rules/no-template-shadow.js
+++ b/tests/lib/rules/no-template-shadow.js
@@ -155,6 +155,21 @@ ruleTester.run('no-template-shadow', rule, {
       defineProps({k:Number})
       </script>
       `
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div v-for="i in 5">
+          <div v-for="i in 5">
+          </div>
+        </div>
+      </template>
+      <script setup>
+      defineProps({i:Number})
+      </script>
+      `,
+      options: [{ allow: ['i'] }]
     }
   ],