Repository: vuejs/eslint-plugin-vue
Pull request #218 (2017-10-20 13:08:36)

Fix typos: it's -> its


Patch:
diff --git a/README.md b/README.md
index 8382a664..62121c2e 100644
--- a/README.md
+++ b/README.md
@@ -97,6 +97,7 @@ The `--fix` option on the command line automatically fixes problems reported by
 |  | [no-reserved-keys](./docs/rules/no-reserved-keys.md) | disallow overwriting reserved keys |
 |  | [no-shared-component-data](./docs/rules/no-shared-component-data.md) | enforce component's data property to be a function |
 |  | [no-template-key](./docs/rules/no-template-key.md) | disallow `key` attribute on `<template>` |
+|  | [no-unused-vars](./docs/rules/no-unused-vars.md) | disallow unused variable definitions of v-for directives or scope attributes |
 |  | [require-render-return](./docs/rules/require-render-return.md) | enforce render function to always return value |
 |  | [require-valid-default-prop](./docs/rules/require-valid-default-prop.md) | enforce props default values to be valid |
 |  | [return-in-computed-property](./docs/rules/return-in-computed-property.md) | enforce that a return statement is present in computed property |
diff --git a/docs/rules/html-end-tags.md b/docs/rules/html-end-tags.md
index 059fc3fe..51acebed 100644
--- a/docs/rules/html-end-tags.md
+++ b/docs/rules/html-end-tags.md
@@ -36,6 +36,7 @@ This rule reports the following elements:
         <div></div>
         <p></p>
         <p></p>
+        <div />
         <input>
         <br>
     </div>
diff --git a/docs/rules/no-unused-vars.md b/docs/rules/no-unused-vars.md
new file mode 100644
index 00000000..bd71a3c0
--- /dev/null
+++ b/docs/rules/no-unused-vars.md
@@ -0,0 +1,29 @@
+# disallow unused variable definitions of v-for directives or scope attributes (no-unused-vars)
+
+This rule report variable definitions of v-for directives or scope attributes if those are not used.
+
+## :book: Rule Details
+
+:-1: Examples of **incorrect** code for this rule:
+
+```html
+<template>
+    <ol v-for="i in 5"><!-- "i" is defined but never used. -->
+        <li>item</li>
+    </ol>
+</template>
+```
+
+:+1: Examples of **correct** code for this rule:
+
+```html
+<template>
+    <ol v-for="i in 5">
+        <li>{{i}}</li><!-- "i" is defined and used. -->
+    </ol>
+</template>
+```
+
+## :wrench: Options
+
+Nothing.
diff --git a/lib/recommended-rules.js b/lib/recommended-rules.js
index d332ae56..64b59f93 100644
--- a/lib/recommended-rules.js
+++ b/lib/recommended-rules.js
@@ -1,7 +1,7 @@
 /*
  * IMPORTANT!
  * This file has been automatically generated,
- * in order to update it's content execute "npm run update"
+ * in order to update its content execute "npm run update"
  */
 module.exports = {
   "vue/attribute-hyphenation": "off",
@@ -40,6 +40,7 @@ module.exports = {
   "vue/no-side-effects-in-computed-properties": "off",
   "vue/no-template-key": "off",
   "vue/no-textarea-mustache": "error",
+  "vue/no-unused-vars": "off",
   "vue/order-in-components": "off",
   "vue/require-component-is": "error",
   "vue/require-default-prop": "off",
diff --git a/lib/rules/html-end-tags.js b/lib/rules/html-end-tags.js
index 9a0f5bc2..05ba6464 100644
--- a/lib/rules/html-end-tags.js
+++ b/lib/rules/html-end-tags.js
@@ -27,6 +27,7 @@ function create (context) {
       const name = node.name
       const isVoid = utils.isHtmlVoidElementName(name)
       const hasEndTag = node.endTag != null
+      const isSelfClosing = node.startTag.selfClosing
 
       if (isVoid && hasEndTag) {
         context.report({
@@ -37,7 +38,7 @@ function create (context) {
           fix: (fixer) => fixer.remove(node.endTag)
         })
       }
-      if (!isVoid && !hasEndTag) {
+      if (!isVoid && !(hasEndTag || isSelfClosing)) {
         context.report({
           node: node.startTag,
           loc: node.startTag.loc,
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
new file mode 100644
index 00000000..8aadc0a2
--- /dev/null
+++ b/lib/rules/no-unused-vars.js
@@ -0,0 +1,47 @@
+/**
+ * @fileoverview disallow unused variable definitions of v-for directives or scope attributes.
+ * @author 薛定谔的猫<hh_2013@foxmail.com>
+ */
+'use strict'
+
+const utils = require('../utils')
+
+/**
+ * Creates AST event handlers for require-v-for-key.
+ *
+ * @param {RuleContext} context - The rule context.
+ * @returns {Object} AST event handlers.
+ */
+function create (context) {
+  return utils.defineTemplateBodyVisitor(context, {
+    VElement (node) {
+      for (const variable of node.variables) {
+        if (variable.references.length === 0) {
+          context.report({
+            node: variable.id,
+            loc: variable.id.loc,
+            message: `'{{name}}' is defined but never used.`,
+            data: variable.id
+          })
+        }
+      }
+    }
+  })
+}
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = {
+  create,
+  meta: {
+    docs: {
+      description: 'disallow unused variable definitions of v-for directives or scope attributes',
+      category: 'Possible Errors',
+      recommended: false
+    },
+    fixable: null,
+    schema: []
+  }
+}
diff --git a/lib/rules/require-prop-types.js b/lib/rules/require-prop-types.js
index 514bec50..16382aa6 100644
--- a/lib/rules/require-prop-types.js
+++ b/lib/rules/require-prop-types.js
@@ -39,7 +39,7 @@ function create (context) {
       if (!hasType) {
         context.report({
           node: cp,
-          message: 'Prop "{{name}}" should define at least it\'s type.',
+          message: 'Prop "{{name}}" should define at least its type.',
           data: {
             name: cp.key.name
           }
diff --git a/lib/rules/require-v-for-key.js b/lib/rules/require-v-for-key.js
index 448cd535..d0bf59a9 100644
--- a/lib/rules/require-v-for-key.js
+++ b/lib/rules/require-v-for-key.js
@@ -21,7 +21,7 @@ const utils = require('../utils')
  * @param {ASTNode} element The element node to check.
  */
 function checkKey (context, element) {
-  if (element.name === 'template') {
+  if (element.name === 'template' || element.name === 'slot') {
     for (const child of element.children) {
       if (child.type === 'VElement') {
         checkKey(context, child)
diff --git a/lib/utils/index.js b/lib/utils/index.js
index 957a9d6c..635707b6 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -247,7 +247,7 @@ module.exports = {
   },
 
   /**
-   * Parse member expression node to get array with all of it's parts
+   * Parse member expression node to get array with all of its parts
    * @param {ASTNode} MemberExpression
    * @returns {Array}
    */
diff --git a/tools/update-rules.js b/tools/update-rules.js
index c1f50884..4980d6c0 100644
--- a/tools/update-rules.js
+++ b/tools/update-rules.js
@@ -94,7 +94,7 @@ const recommendedRules = rules.reduce((obj, entry) => {
 const recommendedRulesContent = `/*
  * IMPORTANT!
  * This file has been automatically generated,
- * in order to update it's content execute "npm run update"
+ * in order to update its content execute "npm run update"
  */
 module.exports = ${JSON.stringify(recommendedRules, null, 2)}`
 


Test patch:
diff --git a/tests/lib/rules/html-end-tags.js b/tests/lib/rules/html-end-tags.js
index b4d648d5..3884290d 100644
--- a/tests/lib/rules/html-end-tags.js
+++ b/tests/lib/rules/html-end-tags.js
@@ -46,6 +46,10 @@ tester.run('html-end-tags', rule, {
     {
       filename: 'test.vue',
       code: '<template><div><img></div></template>'
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><div /></div></template>'
     }
   ],
   invalid: [
diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js
new file mode 100644
index 00000000..92812ebc
--- /dev/null
+++ b/tests/lib/rules/no-unused-vars.js
@@ -0,0 +1,67 @@
+/**
+ * @author 薛定谔的猫<hh_2013@foxmail.com>
+ * @copyright 2017 薛定谔的猫. All rights reserved.
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const RuleTester = require('eslint').RuleTester
+const rule = require('../../../lib/rules/no-unused-vars')
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+const tester = new RuleTester({
+  parser: 'vue-eslint-parser',
+  parserOptions: { ecmaVersion: 2015 }
+})
+
+tester.run('no-unused-vars', rule, {
+  valid: [
+    {
+      code: '<template><ol v-for="i in 5"><li>{{i}}</li></ol></template>'
+    },
+    {
+      code: '<template><ol v-for="i in 5"><li :prop="i"></li></ol></template>'
+    },
+    {
+      code: '<template v-for="i in 5"><comp v-for="j in 10">{{i}}{{j}}</comp></template>'
+    },
+    {
+      code: '<template><ol v-for="i in data"><li v-for="f in i">{{ f.bar.baz }}</li></ol></template>'
+    },
+    {
+      code: '<template scope="props">{{props}}</template>'
+    },
+    {
+      code: '<template scope="props"><span v-if="props"></span></template>'
+    }
+  ],
+  invalid: [
+    {
+      code: '<template><ol v-for="i in 5"><li></li></ol></template>',
+      errors: ['\'i\' is defined but never used.']
+    },
+    {
+      code: '<template scope="props"></template>',
+      errors: ['\'props\' is defined but never used.']
+    },
+    {
+      code: '<template v-for="i in 5"><comp v-for="j in 10">{{i}}{{i}}</comp></template>',
+      errors: ['\'j\' is defined but never used.']
+    },
+    {
+      code: '<template><ol v-for="i in data"><li v-for="f in i"></li></ol></template>',
+      errors: ['\'f\' is defined but never used.']
+    },
+    {
+      code: '<template><div v-for="(v, i, c) in foo"></div></template>',
+      errors: ['\'v\' is defined but never used.', '\'i\' is defined but never used.', '\'c\' is defined but never used.']
+    }
+  ]
+})
diff --git a/tests/lib/rules/require-prop-types.js b/tests/lib/rules/require-prop-types.js
index f630354c..1c6944e0 100644
--- a/tests/lib/rules/require-prop-types.js
+++ b/tests/lib/rules/require-prop-types.js
@@ -111,7 +111,7 @@ ruleTester.run('require-prop-types', rule, {
       `,
       parserOptions: { ecmaVersion: 6, sourceType: 'module' },
       errors: [{
-        message: 'Prop "foo" should define at least it\'s type.',
+        message: 'Prop "foo" should define at least its type.',
         line: 4
       }]
     },
@@ -128,7 +128,7 @@ ruleTester.run('require-prop-types', rule, {
       `,
       parserOptions: { ecmaVersion: 6, sourceType: 'module' },
       errors: [{
-        message: 'Prop "foo" should define at least it\'s type.',
+        message: 'Prop "foo" should define at least its type.',
         line: 4
       }]
     },
@@ -143,7 +143,7 @@ ruleTester.run('require-prop-types', rule, {
       `,
       parserOptions: { ecmaVersion: 6, sourceType: 'module' },
       errors: [{
-        message: 'Prop "foo" should define at least it\'s type.',
+        message: 'Prop "foo" should define at least its type.',
         line: 4
       }]
     }
diff --git a/tests/lib/rules/require-v-for-key.js b/tests/lib/rules/require-v-for-key.js
index 5d4a1837..ab026ed4 100644
--- a/tests/lib/rules/require-v-for-key.js
+++ b/tests/lib/rules/require-v-for-key.js
@@ -42,6 +42,14 @@ tester.run('require-v-for-key', rule, {
     {
       filename: 'test.vue',
       code: '<template><div><template v-for="x in list"><div :key="x"></div></template></div></template>'
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><slot v-for="x in list" :name="x"></slot></div></template>'
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><slot v-for="x in list" :name="x"><div :key="x"></div></slot></div></template>'
     }
   ],
   invalid: [
@@ -59,6 +67,11 @@ tester.run('require-v-for-key', rule, {
       filename: 'test.vue',
       code: '<template><div><template v-for="x in list"><div></div></template></div></template>',
       errors: ["Elements in iteration expect to have 'v-bind:key' directives."]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><slot v-for="x in list" :name="x"><div></div></slot></div></template>',
+      errors: ["Elements in iteration expect to have 'v-bind:key' directives."]
     }
   ]
 })