Repository: vuejs/eslint-plugin-vue
Pull request #574 (2018-09-16 05:38:59)

Update no-unused-components.md
typo


Patch:
diff --git a/README.md b/README.md
index 4ad4a204..2cebaac5 100644
--- a/README.md
+++ b/README.md
@@ -284,8 +284,9 @@ The `vue-eslint-parser` uses the parser which is set by `parserOptions.parser` t
   ```
 
 2. Make sure your tool is set to lint `.vue` files.
-  - CLI targets only `.js` files by default. You have to specify additional extensions by `--ext` option or glob patterns. E.g. `eslint "src/**/*.{js,vue}"` or `eslint src --ext .vue`.
+  - CLI targets only `.js` files by default. You have to specify additional extensions by `--ext` option or glob patterns. E.g. `eslint "src/**/*.{js,vue}"` or `eslint src --ext .vue`. If you use `@vue/cli-plugin-eslint` and the `vue-cli-service lint` command - you don't have to worry about it.
   - VSCode targets only JavaScript or HTML files by default. You have to add `"vue"` to the `"eslint.validate"` array in vscode settings. e.g. `"eslint.validate": [ "javascript", "javascriptreact", "vue" ]`
+  - If you use `Vetur` plugin in VSCode - set `"vetur.validation.template": false` to avoid default Vetur template validation. Check out [vetur documentation](https://github.com/vuejs/vetur/blob/master/docs/linting-error.md) for more info.
 
 ## :anchor: Semantic Versioning Policy
 
diff --git a/docs/rules/no-unused-components.md b/docs/rules/no-unused-components.md
index 6375c111..28e6ac32 100644
--- a/docs/rules/no-unused-components.md
+++ b/docs/rules/no-unused-components.md
@@ -72,7 +72,7 @@ Note that components registered under other than `PascalCase` name have to be ca
 }
 ```
 
-- `ignoreWhenBindingPresent` ... surpresses all errors if binding has been detected in the template
+- `ignoreWhenBindingPresent` ... suppresses all errors if binding has been detected in the template
     default `true`
 
 
diff --git a/lib/rules/html-self-closing.js b/lib/rules/html-self-closing.js
index 65aac0a5..de310743 100644
--- a/lib/rules/html-self-closing.js
+++ b/lib/rules/html-self-closing.js
@@ -165,7 +165,11 @@ module.exports = {
               if (elementType === ELEMENT_TYPE.VOID) {
                 return fixer.replaceText(close, '>')
               }
-              return fixer.replaceText(close, `></${node.rawName}>`)
+              // If only `close` is targeted for replacement, it conflicts with `component-name-in-template-casing`,
+              // so replace the entire element.
+              // return fixer.replaceText(close, `></${node.rawName}>`)
+              const elementPart = sourceCode.text.slice(node.range[0], close.range[0])
+              return fixer.replaceText(node, elementPart + `></${node.rawName}>`)
             }
           })
         }
diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js
index ffd103eb..c9529495 100644
--- a/lib/rules/order-in-components.js
+++ b/lib/rules/order-in-components.js
@@ -193,22 +193,22 @@ module.exports = {
               if (hasSideEffectsPossibility) {
                 return undefined
               }
-              const comma = sourceCode.getTokenAfter(propertyNode)
-              const hasAfterComma = isComma(comma)
+              const afterComma = sourceCode.getTokenAfter(propertyNode)
+              const hasAfterComma = isComma(afterComma)
 
-              const codeStart = sourceCode.getTokenBefore(propertyNode).range[1] // to include comments
-              const codeEnd = hasAfterComma ? comma.range[1] : propertyNode.range[1]
+              const beforeComma = sourceCode.getTokenBefore(propertyNode)
+              const codeStart = beforeComma.range[1] // to include comments
+              const codeEnd = hasAfterComma ? afterComma.range[1] : propertyNode.range[1]
 
               const propertyCode = sourceCode.text.slice(codeStart, codeEnd) + (hasAfterComma ? '' : ',')
               const insertTarget = sourceCode.getTokenBefore(firstUnorderedPropertyNode)
-              // If we can upgrade requirements to `eslint@>4.1.0`, this code can be replaced by:
-              // return [
-              //   fixer.removeRange([codeStart, codeEnd]),
-              //   fixer.insertTextAfter(insertTarget, propertyCode)
-              // ]
-              const insertStart = insertTarget.range[1]
-              const newCode = propertyCode + sourceCode.text.slice(insertStart, codeStart)
-              return fixer.replaceTextRange([insertStart, codeEnd], newCode)
+
+              const removeStart = hasAfterComma ? codeStart : beforeComma.range[0]
+
+              return [
+                fixer.removeRange([removeStart, codeEnd]),
+                fixer.insertTextAfter(insertTarget, propertyCode)
+              ]
             }
           })
         }


Test patch:
diff --git a/tests/lib/autofix.js b/tests/lib/autofix.js
new file mode 100644
index 00000000..5a38dd0e
--- /dev/null
+++ b/tests/lib/autofix.js
@@ -0,0 +1,160 @@
+/**
+ * @author Yosuke Ota <https://github.com/ota-meshi>
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const Linter = require('eslint').Linter
+const chai = require('chai')
+
+const rules = require('../..').rules
+
+const assert = chai.assert
+
+const baseConfig = {
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    ecmaVersion: 2018,
+    sourceType: 'module',
+    ecmaFeatures: {
+      jsx: true
+    }
+  }
+}
+
+describe('Complex autofix test cases', () => {
+  const linter = new Linter()
+  for (const key of Object.keys(rules)) {
+    const ruleId = `vue/${key}`
+    linter.defineRule(ruleId, rules[key])
+  }
+
+  // https://github.com/vuejs/eslint-plugin-vue/issues/566
+  describe('Autofix of `vue/order-in-components` and `comma-dangle` should not conflict.', () => {
+    const config = Object.assign({}, baseConfig, { 'rules': {
+      'vue/order-in-components': ['error'],
+      'comma-dangle': ['error', 'always']
+    }})
+
+    it('Even if set comma-dangle:always, the output should be as expected.', () => {
+      const code = `
+      <script>
+        export default {
+          data() {
+          },
+          name: 'burger'
+        };
+      </script>`
+      const output = `
+      <script>
+        export default {
+          name: 'burger',
+          data() {
+          },
+        };
+      </script>`
+      assert.equal(
+        linter.verifyAndFix(code, config, 'test.vue').output,
+        output
+      )
+    })
+
+    it('Even if include comments, the output should be as expected.', () => {
+      const code = `
+      <script>
+        export default {
+          /**data*/
+          data() {
+          }/*after data*/,
+          /**name*/
+          name: 'burger'/*after name*/
+        };
+      </script>`
+      const output = `
+      <script>
+        export default {
+          /**name*/
+          name: 'burger',
+          /**data*/
+          data() {
+          },/*after data*//*after name*/
+        };
+      </script>`
+      assert.equal(
+        linter.verifyAndFix(code, config, 'test.vue').output,
+        output
+      )
+    })
+  })
+
+  // https://github.com/vuejs/eslint-plugin-vue/issues/554
+  describe('Autofix of `html-self-closing` and `component-name-in-template-casing` should not conflict.', () => {
+    const kebabConfig = Object.assign({}, baseConfig, { 'rules': {
+      'vue/html-self-closing': ['error', {
+        'html': {
+          'component': 'never'
+        }
+      }],
+      'vue/component-name-in-template-casing': ['error', 'kebab-case']
+    }})
+
+    const pascalConfig = Object.assign({}, baseConfig, { 'rules': {
+      'vue/html-self-closing': ['error', {
+        'html': {
+          'component': 'never'
+        }
+      }],
+      'vue/component-name-in-template-casing': ['error']
+    }})
+
+    it('Even if set kebab-case, the output should be as expected.', () => {
+      const code = `
+      <template>
+        <VueComponent />
+      </template>`
+      const output = `
+      <template>
+        <vue-component ></vue-component>
+      </template>`
+
+      assert.equal(
+        linter.verifyAndFix(code, kebabConfig, 'test.vue').output,
+        output
+      )
+    })
+
+    it('Even if set PascalCase, the output should be as expected.', () => {
+      const code = `
+      <template>
+        <vue-component />
+      </template>`
+      const output = `
+      <template>
+        <VueComponent ></VueComponent>
+      </template>`
+
+      assert.equal(
+        linter.verifyAndFix(code, pascalConfig, 'test.vue').output,
+        output
+      )
+    })
+
+    it('Even if element have an attributes, the output should be as expected.', () => {
+      const code = `
+      <template>
+        <vue-component attr
+          id="item1" />
+      </template>`
+      const output = `
+      <template>
+        <VueComponent attr
+          id="item1" ></VueComponent>
+      </template>`
+
+      assert.equal(
+        linter.verifyAndFix(code, pascalConfig, 'test.vue').output,
+        output
+      )
+    })
+  })
+})
diff --git a/tests/lib/rules/order-in-components.js b/tests/lib/rules/order-in-components.js
index 236524e8..b022508f 100644
--- a/tests/lib/rules/order-in-components.js
+++ b/tests/lib/rules/order-in-components.js
@@ -374,7 +374,7 @@ ruleTester.run('order-in-components', rule, {
           data() {
           },
           test: 'ok',
-          name: 'burger',
+          name: 'burger'
         };
       `,
       options: [{ order: ['data', 'test', 'name'] }],
@@ -401,7 +401,33 @@ ruleTester.run('order-in-components', rule, {
           name: 'burger',
           /** data provider */
           data() {
-          },
+          }
+        };
+      `,
+      errors: [{
+        message: 'The "name" property should be above the "data" property on line 4.',
+        line: 7
+      }]
+    },
+    {
+      filename: 'example.vue',
+      code: `
+        export default {
+          /** data provider */
+          data() {
+          }/*test*/,
+          /** name of vue component */
+          name: 'burger'
+        };
+      `,
+      parserOptions,
+      output: `
+        export default {
+          /** name of vue component */
+          name: 'burger',
+          /** data provider */
+          data() {
+          }/*test*/
         };
       `,
       errors: [{
@@ -413,7 +439,7 @@ ruleTester.run('order-in-components', rule, {
       filename: 'example.vue',
       code: `export default {data(){},name:'burger'};`,
       parserOptions,
-      output: `export default {name:'burger',data(){},};`,
+      output: `export default {name:'burger',data(){}};`,
       errors: [{
         message: 'The "name" property should be above the "data" property on line 1.',
         line: 1