Repository: vuejs/eslint-plugin-vue
Pull request #513 (2018-07-07 06:15:25)

Fix attribute-hyphenation ignore lists
Commit f9e1eee3fe711b9dfedc037fe25aa5570370296e introduced the "ignore" config option for the attribute-hyphenation rule.  However, that commit has a few problems:

 - The added testcase doesn't actually test the functionality at all
 - The code only works correctly if the ignore list has exactly 1 item in it
 - There are spelling mistakes in the test

See each individual commit message for more details.

michalsnik: Thanks for working on it @LukeShu! I added one comment :)
LukeShu: v2:
 - Make requested changes to the tests

The change from v1 to v2 is as follows:

```patch
diff --git a/tests/lib/rules/attribute-hyphenation.js b/tests/lib/rules/attribute-hyphenation.js
index 70d798f..ce659cc 100644
--- a/tests/lib/rules/attribute-hyphenation.js
+++ b/tests/lib/rules/attribute-hyphenation.js
@@ -45,7 +45,7 @@ ruleTester.run('attribute-hyphenation', rule, {
     },
     {
       filename: 'test.vue',
-      code: '<template><custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo"><a onClick="" my-prop="prop"></a></custom></template>',
+      code: '<template><custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" second-custom="bar"><a onClick="" my-prop="prop"></a></custom></template>',
       options: ['never', { 'ignore': ['custom-hyphen', 'second-custom'] }]
     }
   ],
@@ -128,6 +128,17 @@ ruleTester.run('attribute-hyphenation', rule, {
         line: 1
       }]
     },
+    {
+      filename: 'test.vue',
+      code: '<template><custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" third-custom="bar"><a onClick="" my-prop="prop"></a></custom></template>',
+      output: '<template><custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" thirdCustom="bar"><a onClick="" my-prop="prop"></a></custom></template>',
+      options: ['never', { 'ignore': ['custom-hyphen', 'second-custom'] }],
+      errors: [{
+        message: "Attribute 'third-custom' can't be hyphenated.",
+        type: 'VDirectiveKey',
+        line: 1
+      }]
+    },
     {
       // This is the same code as the `'ignore': ['custom-hyphen']`
       // valid test; to verify that setting ignore actually makes the
```

Patch:
diff --git a/README.md b/README.md
index 0c46adab..9a19b358 100644
--- a/README.md
+++ b/README.md
@@ -151,7 +151,6 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
 |  | [vue/no-template-key](./docs/rules/no-template-key.md) | disallow `key` attribute on `<template>` |
 |  | [vue/no-textarea-mustache](./docs/rules/no-textarea-mustache.md) | disallow mustaches in `<textarea>` |
 |  | [vue/no-unused-vars](./docs/rules/no-unused-vars.md) | disallow unused variable definitions of v-for directives or scope attributes |
-|  | [vue/no-use-v-if-with-v-for](./docs/rules/no-use-v-if-with-v-for.md) | disallow use v-if on the same element as v-for. |
 |  | [vue/require-component-is](./docs/rules/require-component-is.md) | require `v-bind:is` of `<component>` elements |
 |  | [vue/require-render-return](./docs/rules/require-render-return.md) | enforce render function to always return value |
 |  | [vue/require-v-for-key](./docs/rules/require-v-for-key.md) | require `v-bind:key` with `v-for` directives |
@@ -184,7 +183,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
 
 |    | Rule ID | Description |
 |:---|:--------|:------------|
-| :wrench: | [vue/attribute-hyphenation](./docs/rules/attribute-hyphenation.md) | enforce attribute naming style in template |
+| :wrench: | [vue/attribute-hyphenation](./docs/rules/attribute-hyphenation.md) | enforce attribute naming style on custom components in template |
 | :wrench: | [vue/html-end-tags](./docs/rules/html-end-tags.md) | enforce end tag style |
 | :wrench: | [vue/html-indent](./docs/rules/html-indent.md) | enforce consistent indentation in `<template>` |
 | :wrench: | [vue/html-self-closing](./docs/rules/html-self-closing.md) | enforce self-closing style |
@@ -221,6 +220,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
 |:---|:--------|:------------|
 | :wrench: | [vue/html-closing-bracket-newline](./docs/rules/html-closing-bracket-newline.md) | require or disallow a line break before tag's closing brackets |
 | :wrench: | [vue/html-closing-bracket-spacing](./docs/rules/html-closing-bracket-spacing.md) | require or disallow a space before tag's closing brackets |
+|  | [vue/no-use-v-if-with-v-for](./docs/rules/no-use-v-if-with-v-for.md) | disallow use v-if on the same element as v-for |
 | :wrench: | [vue/prop-name-casing](./docs/rules/prop-name-casing.md) | enforce specific casing for the Prop name in Vue components |
 | :wrench: | [vue/script-indent](./docs/rules/script-indent.md) | enforce consistent indentation in `<script>` |
 
diff --git a/docs/rules/no-use-v-if-with-v-for.md b/docs/rules/no-use-v-if-with-v-for.md
index cbe33005..4da80935 100644
--- a/docs/rules/no-use-v-if-with-v-for.md
+++ b/docs/rules/no-use-v-if-with-v-for.md
@@ -1,4 +1,4 @@
-# disallow use v-if on the same element as v-for. (vue/no-use-v-if-with-v-for)
+# disallow use v-if on the same element as v-for (vue/no-use-v-if-with-v-for)
 
 > Never use `v-if` on the same element as `v-for`.
 >
diff --git a/lib/rules/attribute-hyphenation.js b/lib/rules/attribute-hyphenation.js
index ef8ea031..5514ac2d 100644
--- a/lib/rules/attribute-hyphenation.js
+++ b/lib/rules/attribute-hyphenation.js
@@ -16,7 +16,7 @@ module.exports = {
     docs: {
       description: 'enforce attribute naming style on custom components in template',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/attribute-hyphenation.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/attribute-hyphenation.md'
     },
     fixable: 'code',
     schema: [
@@ -49,10 +49,10 @@ module.exports = {
     const option = context.options[0]
     const optionsPayload = context.options[1]
     const useHyphenated = option !== 'never'
-    const ignoredAttributes = ['data-', 'aria-', 'slot-scope']
+    let ignoredAttributes = ['data-', 'aria-', 'slot-scope']
 
     if (optionsPayload && optionsPayload.ignore) {
-      ignoredAttributes.push(optionsPayload.ignore)
+      ignoredAttributes = ignoredAttributes.concat(optionsPayload.ignore)
     }
 
     const caseConverter = casing.getConverter(useHyphenated ? 'kebab-case' : 'camelCase')
@@ -63,7 +63,7 @@ module.exports = {
       context.report({
         node: node.key,
         loc: node.loc,
-        message: useHyphenated ? "Attribute '{{text}}' must be hyphenated." : "Attribute '{{text}}' cann't be hyphenated.",
+        message: useHyphenated ? "Attribute '{{text}}' must be hyphenated." : "Attribute '{{text}}' can't be hyphenated.",
         data: {
           text
         },
diff --git a/lib/rules/comment-directive.js b/lib/rules/comment-directive.js
index 9faffa60..73d88eeb 100644
--- a/lib/rules/comment-directive.js
+++ b/lib/rules/comment-directive.js
@@ -109,7 +109,7 @@ module.exports = {
     docs: {
       description: 'support comment-directives in `<template>`',
       category: 'base',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/comment-directive.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/comment-directive.md'
     },
     schema: []
   },
diff --git a/lib/rules/html-closing-bracket-newline.js b/lib/rules/html-closing-bracket-newline.js
index f55485ba..b3850a4a 100644
--- a/lib/rules/html-closing-bracket-newline.js
+++ b/lib/rules/html-closing-bracket-newline.js
@@ -32,7 +32,7 @@ module.exports = {
     docs: {
       description: "require or disallow a line break before tag's closing brackets",
       category: undefined,
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-closing-bracket-newline.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/html-closing-bracket-newline.md'
     },
     fixable: 'whitespace',
     schema: [{
diff --git a/lib/rules/html-closing-bracket-spacing.js b/lib/rules/html-closing-bracket-spacing.js
index 212cada9..9ee1e390 100644
--- a/lib/rules/html-closing-bracket-spacing.js
+++ b/lib/rules/html-closing-bracket-spacing.js
@@ -53,7 +53,7 @@ module.exports = {
     docs: {
       description: 'require or disallow a space before tag\'s closing brackets',
       category: undefined,
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-closing-bracket-spacing.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/html-closing-bracket-spacing.md'
     },
     schema: [{
       type: 'object',
diff --git a/lib/rules/html-end-tags.js b/lib/rules/html-end-tags.js
index 6ee1919c..836a756b 100644
--- a/lib/rules/html-end-tags.js
+++ b/lib/rules/html-end-tags.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce end tag style',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-end-tags.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/html-end-tags.md'
     },
     fixable: 'code',
     schema: []
diff --git a/lib/rules/html-indent.js b/lib/rules/html-indent.js
index 12f439cd..abee5103 100644
--- a/lib/rules/html-indent.js
+++ b/lib/rules/html-indent.js
@@ -29,7 +29,7 @@ module.exports = {
     docs: {
       description: 'enforce consistent indentation in `<template>`',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-indent.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/html-indent.md'
     },
     fixable: 'whitespace',
     schema: [
diff --git a/lib/rules/html-quotes.js b/lib/rules/html-quotes.js
index 3a987606..e5d0db43 100644
--- a/lib/rules/html-quotes.js
+++ b/lib/rules/html-quotes.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce quotes style of HTML attributes',
       category: 'recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-quotes.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/html-quotes.md'
     },
     fixable: 'code',
     schema: [
diff --git a/lib/rules/html-self-closing.js b/lib/rules/html-self-closing.js
index d0e5011d..7333c23d 100644
--- a/lib/rules/html-self-closing.js
+++ b/lib/rules/html-self-closing.js
@@ -88,7 +88,7 @@ module.exports = {
     docs: {
       description: 'enforce self-closing style',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-self-closing.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/html-self-closing.md'
     },
     fixable: 'code',
     schema: {
diff --git a/lib/rules/jsx-uses-vars.js b/lib/rules/jsx-uses-vars.js
index 067eb915..99c5f715 100644
--- a/lib/rules/jsx-uses-vars.js
+++ b/lib/rules/jsx-uses-vars.js
@@ -39,7 +39,7 @@ module.exports = {
     docs: {
       description: 'prevent variables used in JSX to be marked as unused', // eslint-disable-line consistent-docs-description
       category: 'base',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/jsx-uses-vars.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/jsx-uses-vars.md'
     },
     schema: []
   },
diff --git a/lib/rules/max-attributes-per-line.js b/lib/rules/max-attributes-per-line.js
index 5e4b92ee..ac630874 100644
--- a/lib/rules/max-attributes-per-line.js
+++ b/lib/rules/max-attributes-per-line.js
@@ -14,7 +14,7 @@ module.exports = {
     docs: {
       description: 'enforce the maximum number of attributes per line',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/max-attributes-per-line.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/max-attributes-per-line.md'
     },
     fixable: 'whitespace', // or "code" or "whitespace"
     schema: [
diff --git a/lib/rules/mustache-interpolation-spacing.js b/lib/rules/mustache-interpolation-spacing.js
index 0b6b69f4..b27432ac 100644
--- a/lib/rules/mustache-interpolation-spacing.js
+++ b/lib/rules/mustache-interpolation-spacing.js
@@ -19,7 +19,7 @@ module.exports = {
     docs: {
       description: 'enforce unified spacing in mustache interpolations',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/mustache-interpolation-spacing.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/mustache-interpolation-spacing.md'
     },
     fixable: 'whitespace',
     schema: [
diff --git a/lib/rules/name-property-casing.js b/lib/rules/name-property-casing.js
index 9fc3eb3c..0ab4c795 100644
--- a/lib/rules/name-property-casing.js
+++ b/lib/rules/name-property-casing.js
@@ -17,7 +17,7 @@ module.exports = {
     docs: {
       description: 'enforce specific casing for the name property in Vue components',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/name-property-casing.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/name-property-casing.md'
     },
     fixable: 'code', // or "code" or "whitespace"
     schema: [
diff --git a/lib/rules/no-async-in-computed-properties.js b/lib/rules/no-async-in-computed-properties.js
index 5b931613..aebe27a0 100644
--- a/lib/rules/no-async-in-computed-properties.js
+++ b/lib/rules/no-async-in-computed-properties.js
@@ -64,7 +64,7 @@ module.exports = {
     docs: {
       description: 'disallow asynchronous actions in computed properties',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-async-in-computed-properties.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-async-in-computed-properties.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/no-confusing-v-for-v-if.js b/lib/rules/no-confusing-v-for-v-if.js
index 32cf1686..13777d1d 100644
--- a/lib/rules/no-confusing-v-for-v-if.js
+++ b/lib/rules/no-confusing-v-for-v-if.js
@@ -39,7 +39,7 @@ module.exports = {
     docs: {
       description: 'disallow confusing `v-for` and `v-if` on the same element',
       category: 'recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-confusing-v-for-v-if.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-confusing-v-for-v-if.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/no-dupe-keys.js b/lib/rules/no-dupe-keys.js
index 841b4c97..13d130b4 100644
--- a/lib/rules/no-dupe-keys.js
+++ b/lib/rules/no-dupe-keys.js
@@ -17,7 +17,7 @@ module.exports = {
     docs: {
       description: 'disallow duplication of field names',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-dupe-keys.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-dupe-keys.md'
     },
     fixable: null, // or "code" or "whitespace"
     schema: [
diff --git a/lib/rules/no-duplicate-attributes.js b/lib/rules/no-duplicate-attributes.js
index 1a68e877..67228909 100644
--- a/lib/rules/no-duplicate-attributes.js
+++ b/lib/rules/no-duplicate-attributes.js
@@ -39,7 +39,7 @@ module.exports = {
     docs: {
       description: 'disallow duplication of attributes',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-duplicate-attributes.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-duplicate-attributes.md'
     },
     fixable: null,
 
diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js
index 956ecff7..73bad5ce 100644
--- a/lib/rules/no-multi-spaces.js
+++ b/lib/rules/no-multi-spaces.js
@@ -13,7 +13,7 @@ module.exports = {
     docs: {
       description: 'disallow multiple spaces',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-multi-spaces.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-multi-spaces.md'
     },
     fixable: 'whitespace', // or "code" or "whitespace"
     schema: []
diff --git a/lib/rules/no-parsing-error.js b/lib/rules/no-parsing-error.js
index 80f5f8c8..1d015cd2 100644
--- a/lib/rules/no-parsing-error.js
+++ b/lib/rules/no-parsing-error.js
@@ -58,7 +58,7 @@ module.exports = {
     docs: {
       description: 'disallow parsing errors in `<template>`',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-parsing-error.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-parsing-error.md'
     },
     fixable: null,
     schema: [
diff --git a/lib/rules/no-reserved-keys.js b/lib/rules/no-reserved-keys.js
index 2d4dafb5..51549637 100644
--- a/lib/rules/no-reserved-keys.js
+++ b/lib/rules/no-reserved-keys.js
@@ -18,7 +18,7 @@ module.exports = {
     docs: {
       description: 'disallow overwriting reserved keys',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-reserved-keys.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-reserved-keys.md'
     },
     fixable: null,
     schema: [
diff --git a/lib/rules/no-shared-component-data.js b/lib/rules/no-shared-component-data.js
index bf5ecf69..c1655fa5 100644
--- a/lib/rules/no-shared-component-data.js
+++ b/lib/rules/no-shared-component-data.js
@@ -40,7 +40,7 @@ module.exports = {
     docs: {
       description: "enforce component's data property to be a function",
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-shared-component-data.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-shared-component-data.md'
     },
     fixable: 'code',
     schema: []
diff --git a/lib/rules/no-side-effects-in-computed-properties.js b/lib/rules/no-side-effects-in-computed-properties.js
index 9ef2d8b7..ee54aa49 100644
--- a/lib/rules/no-side-effects-in-computed-properties.js
+++ b/lib/rules/no-side-effects-in-computed-properties.js
@@ -15,7 +15,7 @@ module.exports = {
     docs: {
       description: 'disallow side effects in computed properties',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-side-effects-in-computed-properties.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-side-effects-in-computed-properties.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/no-template-key.js b/lib/rules/no-template-key.js
index 2a899415..b0c0c5a5 100644
--- a/lib/rules/no-template-key.js
+++ b/lib/rules/no-template-key.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'disallow `key` attribute on `<template>`',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-template-key.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-template-key.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/no-textarea-mustache.js b/lib/rules/no-textarea-mustache.js
index a5af82bf..2d8e6dd6 100644
--- a/lib/rules/no-textarea-mustache.js
+++ b/lib/rules/no-textarea-mustache.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'disallow mustaches in `<textarea>`',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-textarea-mustache.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-textarea-mustache.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index fb5dd3e0..5b9cb2e2 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -15,7 +15,7 @@ module.exports = {
     docs: {
       description: 'disallow unused variable definitions of v-for directives or scope attributes',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/no-unused-vars.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-unused-vars.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/no-use-v-if-with-v-for.js b/lib/rules/no-use-v-if-with-v-for.js
index e76bf824..5a537145 100644
--- a/lib/rules/no-use-v-if-with-v-for.js
+++ b/lib/rules/no-use-v-if-with-v-for.js
@@ -52,7 +52,7 @@ module.exports = {
     docs: {
       description: 'disallow use v-if on the same element as v-for',
       category: undefined,
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.3.0/docs/rules/no-use-v-if-with-v-for.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/no-use-v-if-with-v-for.md'
     },
     fixable: null,
     schema: [{
diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js
index 83967711..dfdeb365 100644
--- a/lib/rules/order-in-components.js
+++ b/lib/rules/order-in-components.js
@@ -135,7 +135,7 @@ module.exports = {
     docs: {
       description: 'enforce order of properties in components',
       category: 'recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/order-in-components.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/order-in-components.md'
     },
     fixable: 'code', // null or "code" or "whitespace"
     schema: [
diff --git a/lib/rules/require-component-is.js b/lib/rules/require-component-is.js
index 23903618..3b8a3760 100644
--- a/lib/rules/require-component-is.js
+++ b/lib/rules/require-component-is.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'require `v-bind:is` of `<component>` elements',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/require-component-is.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/require-component-is.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/require-default-prop.js b/lib/rules/require-default-prop.js
index 339ae08c..ddba4b9d 100644
--- a/lib/rules/require-default-prop.js
+++ b/lib/rules/require-default-prop.js
@@ -15,7 +15,7 @@ module.exports = {
     docs: {
       description: 'require default value for props',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/require-default-prop.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/require-default-prop.md'
     },
     fixable: null, // or "code" or "whitespace"
     schema: []
diff --git a/lib/rules/require-prop-types.js b/lib/rules/require-prop-types.js
index 6bfa2463..2bfdefc0 100644
--- a/lib/rules/require-prop-types.js
+++ b/lib/rules/require-prop-types.js
@@ -15,7 +15,7 @@ module.exports = {
     docs: {
       description: 'require type definitions in props',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/require-prop-types.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/require-prop-types.md'
     },
     fixable: null, // or "code" or "whitespace"
     schema: [
diff --git a/lib/rules/require-render-return.js b/lib/rules/require-render-return.js
index c6fcd2f7..f7773ad0 100644
--- a/lib/rules/require-render-return.js
+++ b/lib/rules/require-render-return.js
@@ -15,7 +15,7 @@ module.exports = {
     docs: {
       description: 'enforce render function to always return value',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/require-render-return.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/require-render-return.md'
     },
     fixable: null, // or "code" or "whitespace"
     schema: []
diff --git a/lib/rules/require-v-for-key.js b/lib/rules/require-v-for-key.js
index 31e1959a..b1ab13c3 100644
--- a/lib/rules/require-v-for-key.js
+++ b/lib/rules/require-v-for-key.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'require `v-bind:key` with `v-for` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/require-v-for-key.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/require-v-for-key.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/require-valid-default-prop.js b/lib/rules/require-valid-default-prop.js
index a0124836..ce663c13 100644
--- a/lib/rules/require-valid-default-prop.js
+++ b/lib/rules/require-valid-default-prop.js
@@ -24,7 +24,7 @@ module.exports = {
     docs: {
       description: 'enforce props default values to be valid',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/require-valid-default-prop.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/require-valid-default-prop.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/return-in-computed-property.js b/lib/rules/return-in-computed-property.js
index f022fd6a..5dfd5423 100644
--- a/lib/rules/return-in-computed-property.js
+++ b/lib/rules/return-in-computed-property.js
@@ -15,7 +15,7 @@ module.exports = {
     docs: {
       description: 'enforce that a return statement is present in computed property',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/return-in-computed-property.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/return-in-computed-property.md'
     },
     fixable: null, // or "code" or "whitespace"
     schema: [
diff --git a/lib/rules/script-indent.js b/lib/rules/script-indent.js
index 58a514d2..46732b8e 100644
--- a/lib/rules/script-indent.js
+++ b/lib/rules/script-indent.js
@@ -19,7 +19,7 @@ module.exports = {
     docs: {
       description: 'enforce consistent indentation in `<script>`',
       category: undefined,
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/script-indent.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/script-indent.md'
     },
     fixable: 'whitespace',
     schema: [
diff --git a/lib/rules/this-in-template.js b/lib/rules/this-in-template.js
index 9128e898..3ca9bb85 100644
--- a/lib/rules/this-in-template.js
+++ b/lib/rules/this-in-template.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce usage of `this` in template',
       category: 'recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/this-in-template.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/this-in-template.md'
     },
     fixable: null,
     schema: [
diff --git a/lib/rules/v-bind-style.js b/lib/rules/v-bind-style.js
index 243a9923..2fd4069e 100644
--- a/lib/rules/v-bind-style.js
+++ b/lib/rules/v-bind-style.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce `v-bind` directive style',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/v-bind-style.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/v-bind-style.md'
     },
     fixable: 'code',
     schema: [
diff --git a/lib/rules/v-on-style.js b/lib/rules/v-on-style.js
index 863aa489..a4b88eed 100644
--- a/lib/rules/v-on-style.js
+++ b/lib/rules/v-on-style.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce `v-on` directive style',
       category: 'strongly-recommended',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/v-on-style.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/v-on-style.md'
     },
     fixable: 'code',
     schema: [
diff --git a/lib/rules/valid-template-root.js b/lib/rules/valid-template-root.js
index cb087485..1217000b 100644
--- a/lib/rules/valid-template-root.js
+++ b/lib/rules/valid-template-root.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid template root',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-template-root.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-template-root.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-bind.js b/lib/rules/valid-v-bind.js
index 1212ae24..053bdbb3 100644
--- a/lib/rules/valid-v-bind.js
+++ b/lib/rules/valid-v-bind.js
@@ -26,7 +26,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-bind` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-bind.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-bind.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-cloak.js b/lib/rules/valid-v-cloak.js
index 1ff1041f..d10397e4 100644
--- a/lib/rules/valid-v-cloak.js
+++ b/lib/rules/valid-v-cloak.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-cloak` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-cloak.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-cloak.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-else-if.js b/lib/rules/valid-v-else-if.js
index d511f634..b13ebf98 100644
--- a/lib/rules/valid-v-else-if.js
+++ b/lib/rules/valid-v-else-if.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-else-if` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-else-if.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-else-if.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-else.js b/lib/rules/valid-v-else.js
index 8da85dae..acab5e07 100644
--- a/lib/rules/valid-v-else.js
+++ b/lib/rules/valid-v-else.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-else` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-else.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-else.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-for.js b/lib/rules/valid-v-for.js
index b84c5cc7..577a1ead 100644
--- a/lib/rules/valid-v-for.js
+++ b/lib/rules/valid-v-for.js
@@ -106,7 +106,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-for` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-for.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-for.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-html.js b/lib/rules/valid-v-html.js
index d51c7e34..1f421279 100644
--- a/lib/rules/valid-v-html.js
+++ b/lib/rules/valid-v-html.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-html` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-html.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-html.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-if.js b/lib/rules/valid-v-if.js
index f0ed67fc..c87dad0b 100644
--- a/lib/rules/valid-v-if.js
+++ b/lib/rules/valid-v-if.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-if` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-if.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-if.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-model.js b/lib/rules/valid-v-model.js
index 6b2bada4..f91487d4 100644
--- a/lib/rules/valid-v-model.js
+++ b/lib/rules/valid-v-model.js
@@ -82,7 +82,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-model` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-model.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-model.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-on.js b/lib/rules/valid-v-on.js
index d295bbae..03b4d3c1 100644
--- a/lib/rules/valid-v-on.js
+++ b/lib/rules/valid-v-on.js
@@ -115,7 +115,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-on` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-on.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-on.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-once.js b/lib/rules/valid-v-once.js
index 1d7000bf..2522a833 100644
--- a/lib/rules/valid-v-once.js
+++ b/lib/rules/valid-v-once.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-once` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-once.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-once.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-pre.js b/lib/rules/valid-v-pre.js
index 864073c3..dff12414 100644
--- a/lib/rules/valid-v-pre.js
+++ b/lib/rules/valid-v-pre.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-pre` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-pre.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-pre.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-show.js b/lib/rules/valid-v-show.js
index 10504c9b..1d13bc45 100644
--- a/lib/rules/valid-v-show.js
+++ b/lib/rules/valid-v-show.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-show` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-show.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-show.md'
     },
     fixable: null,
     schema: []
diff --git a/lib/rules/valid-v-text.js b/lib/rules/valid-v-text.js
index f72ead15..89915390 100644
--- a/lib/rules/valid-v-text.js
+++ b/lib/rules/valid-v-text.js
@@ -20,7 +20,7 @@ module.exports = {
     docs: {
       description: 'enforce valid `v-text` directives',
       category: 'essential',
-      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/valid-v-text.md'
+      url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.6.0/docs/rules/valid-v-text.md'
     },
     fixable: null,
     schema: []
diff --git a/package.json b/package.json
index fc5134c5..3645ab4e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-vue",
-  "version": "4.5.0",
+  "version": "4.6.0",
   "description": "Official ESLint plugin for Vue.js",
   "main": "lib/index.js",
   "scripts": {


Test patch:
diff --git a/tests/lib/rules/attribute-hyphenation.js b/tests/lib/rules/attribute-hyphenation.js
index 340bd32d..c1f9b57b 100644
--- a/tests/lib/rules/attribute-hyphenation.js
+++ b/tests/lib/rules/attribute-hyphenation.js
@@ -45,8 +45,8 @@ ruleTester.run('attribute-hyphenation', rule, {
     },
     {
       filename: 'test.vue',
-      code: '<template><div data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hypen="foo"><a onClick="" my-prop="prop"></a></div></template>',
-      options: ['never', { 'ignore': ['custom-hypen'] }]
+      code: '<template><custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" second-custom="bar"><a onClick="" my-prop="prop"></a></custom></template>',
+      options: ['never', { 'ignore': ['custom-hyphen', 'second-custom'] }]
     }
   ],
 
@@ -57,7 +57,7 @@ ruleTester.run('attribute-hyphenation', rule, {
       output: '<template><div><custom myProp="foo"></custom></div></template>',
       options: ['never'],
       errors: [{
-        message: "Attribute 'my-prop' cann't be hyphenated.",
+        message: "Attribute 'my-prop' can't be hyphenated.",
         type: 'VIdentifier',
         line: 1
       }]
@@ -79,7 +79,7 @@ ruleTester.run('attribute-hyphenation', rule, {
       output: '<template><div><custom :myProp="prop"></custom></div></template>',
       options: ['never'],
       errors: [{
-        message: "Attribute ':my-prop' cann't be hyphenated.",
+        message: "Attribute ':my-prop' can't be hyphenated.",
         type: 'VDirectiveKey',
         line: 1
       }]
@@ -101,7 +101,7 @@ ruleTester.run('attribute-hyphenation', rule, {
       output: '<template><div><custom v-bind:myProp="prop"></custom></div></template>',
       options: ['never'],
       errors: [{
-        message: "Attribute 'v-bind:my-prop' cann't be hyphenated.",
+        message: "Attribute 'v-bind:my-prop' can't be hyphenated.",
         type: 'VDirectiveKey',
         line: 1
       }]
@@ -116,6 +116,89 @@ ruleTester.run('attribute-hyphenation', rule, {
         type: 'VDirectiveKey',
         line: 1
       }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><custom v-bind:MyProp="prop"></custom></div></template>',
+      output: '<template><div><custom v-bind:my-prop="prop"></custom></div></template>',
+      options: ['always', { 'ignore': [] }],
+      errors: [{
+        message: "Attribute 'v-bind:MyProp' must be hyphenated.",
+        type: 'VDirectiveKey',
+        line: 1
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><custom v-bind:my-prop="prop" :second-prop="test"></custom></div></template>',
+      output: '<template><div><custom v-bind:my-prop="prop" :secondProp="test"></custom></div></template>',
+      options: ['never', { ignore: ['my-prop'] }],
+      errors: [{
+        message: "Attribute ':second-prop' can't be hyphenated.",
+        type: 'VDirectiveKey',
+        line: 1
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div><custom v-bind:myProp="prop" :secondProp="test"></custom></div></template>',
+      output: '<template><div><custom v-bind:my-prop="prop" :secondProp="test"></custom></div></template>',
+      options: ['always', { ignore: ['secondProp'] }],
+      errors: [{
+        message: "Attribute 'v-bind:myProp' must be hyphenated.",
+        type: 'VDirectiveKey',
+        line: 1
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" second-custom="baz" third-custom="bar">
+            <a onClick="" my-prop="prop"></a>
+          </custom>
+        </template>
+      `,
+      output: `
+        <template>
+          <custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" second-custom="baz" thirdCustom="bar">
+            <a onClick="" my-prop="prop"></a>
+          </custom>
+        </template>
+      `,
+      options: ['never', { 'ignore': ['custom-hyphen', 'second-custom'] }],
+      errors: [{
+        message: "Attribute 'third-custom' can't be hyphenated.",
+        type: 'VIdentifier',
+        line: 3
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        <template>
+          <custom data-id="foo" aria-test="bar" slot-scope="{ data }" custom-hyphen="foo" second-custom="baz" thirdCustom="bar">
+            <a onClick="" my-prop="prop"></a>
+          </custom>
+        </template>
+      `,
+      output: `
+        <template>
+          <custom data-id="foo" aria-test="bar" slot-scope="{ data }" customHyphen="foo" secondCustom="baz" thirdCustom="bar">
+            <a onClick="" my-prop="prop"></a>
+          </custom>
+        </template>
+      `,
+      options: ['never'],
+      errors: [{
+        message: "Attribute 'custom-hyphen' can't be hyphenated.",
+        type: 'VIdentifier',
+        line: 3
+      }, {
+        message: "Attribute 'second-custom' can't be hyphenated.",
+        type: 'VIdentifier',
+        line: 3
+      }]
     }
   ]
 })