From 5ed9a1790265d98ae42fc92a8a560ddb1d73effa Mon Sep 17 00:00:00 2001 From: Armano Date: Sun, 11 Nov 2018 23:23:57 +0100 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8FNew:=20Add=20`component-defin?= =?UTF-8?q?ition-name-casing`=20rule.=20#256?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this rule replaces `name-property-casing` fix issue: #251 --- .../rules/component-definition-name-casing.md | 47 +++ docs/rules/name-property-casing.md | 1 + lib/rules/component-definition-name-casing.js | 72 +++++ lib/rules/name-property-casing.js | 2 + .../rules/component-definition-name-casing.js | 270 ++++++++++++++++++ 5 files changed, 392 insertions(+) create mode 100644 docs/rules/component-definition-name-casing.md create mode 100644 lib/rules/component-definition-name-casing.js create mode 100644 tests/lib/rules/component-definition-name-casing.js diff --git a/docs/rules/component-definition-name-casing.md b/docs/rules/component-definition-name-casing.md new file mode 100644 index 000000000..8bc3f7305 --- /dev/null +++ b/docs/rules/component-definition-name-casing.md @@ -0,0 +1,47 @@ +# enforce specific casing for component definition name (vue/component-definition-name-casing) + +- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. + +Define a style for component definition name casing for consistency purposes. + +## :book: Rule Details + +:+1: Examples of **correct** code for `PascalCase`: + +```js +export default { + name: 'MyComponent' +} +``` +```js +Vue.component('MyComponent', { + +}) +``` + +:+1: Examples of **correct** code for `kebab-case`: + +```js +export default { + name: 'my-component' +} +``` +```js +Vue.component('my-component', { + +}) +``` + +## :wrench: Options + +Default casing is set to `PascalCase`. + +```json +{ + "vue/component-definition-name-casing": ["error", "PascalCase|kebab-case"] +} +``` + +## Related links + +- [Style guide - Component name casing in JS/JSX](https://vuejs.org/v2/style-guide/#Component-name-casing-in-JS-JSX-strongly-recommended) diff --git a/docs/rules/name-property-casing.md b/docs/rules/name-property-casing.md index c8457af82..e8e4b9747 100644 --- a/docs/rules/name-property-casing.md +++ b/docs/rules/name-property-casing.md @@ -2,6 +2,7 @@ - :gear: This rule is included in `"plugin:vue/strongly-recommended"` and `"plugin:vue/recommended"`. - :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. +- :warning: This rule was **deprecated** and replaced by [vue/component-definition-name-casing](component-definition-name-casing.md) rule. Define a style for the `name` property casing for consistency purposes. diff --git a/lib/rules/component-definition-name-casing.js b/lib/rules/component-definition-name-casing.js new file mode 100644 index 000000000..d7d0ffa09 --- /dev/null +++ b/lib/rules/component-definition-name-casing.js @@ -0,0 +1,72 @@ +/** + * @fileoverview enforce specific casing for component definition name + * @author Armano + */ +'use strict' + +const utils = require('../utils') +const casing = require('../utils/casing') +const allowedCaseOptions = ['PascalCase', 'kebab-case'] + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: 'enforce specific casing for component definition name', + category: undefined, + url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v5.0.0-beta.3/docs/rules/component-definition-name-casing.md' + }, + fixable: 'code', // or "code" or "whitespace" + schema: [ + { + enum: allowedCaseOptions + } + ] + }, + + create (context) { + const options = context.options[0] + const caseType = allowedCaseOptions.indexOf(options) !== -1 ? options : 'PascalCase' + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + function convertName (node) { + const value = casing.getConverter(caseType)(node.value) + if (value !== node.value) { + context.report({ + node: node, + message: 'Property name "{{value}}" is not {{caseType}}.', + data: { + value: node.value, + caseType: caseType + }, + fix: fixer => fixer.replaceText(node, node.raw.replace(node.value, value)) + }) + } + } + + return utils.executeOnVue(context, (obj) => { + if (obj.parent && obj.parent.type === 'CallExpression' && obj.parent.arguments && obj.parent.arguments.length === 2) { + const argument = obj.parent.arguments[0] + if (argument.type === 'Literal') { + convertName(argument) + } + } + + const node = obj.properties + .find(item => ( + item.type === 'Property' && + item.key.name === 'name' && + item.value.type === 'Literal' + )) + + if (!node) return + convertName(node.value) + }) + } +} diff --git a/lib/rules/name-property-casing.js b/lib/rules/name-property-casing.js index 4244494ef..8639c75db 100644 --- a/lib/rules/name-property-casing.js +++ b/lib/rules/name-property-casing.js @@ -19,6 +19,8 @@ module.exports = { category: 'strongly-recommended', url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v5.0.0-beta.3/docs/rules/name-property-casing.md' }, + deprecated: true, + replacedBy: ['component-definition-name-casing'], fixable: 'code', // or "code" or "whitespace" schema: [ { diff --git a/tests/lib/rules/component-definition-name-casing.js b/tests/lib/rules/component-definition-name-casing.js new file mode 100644 index 000000000..26b40e160 --- /dev/null +++ b/tests/lib/rules/component-definition-name-casing.js @@ -0,0 +1,270 @@ +/** + * @fileoverview enforce specific casing for component definition name + * @author Armano + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/component-definition-name-casing') +const RuleTester = require('eslint').RuleTester + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const parserOptions = { + ecmaVersion: 2018, + sourceType: 'module' +} + +const ruleTester = new RuleTester() +ruleTester.run('component-definition-name-casing', rule, { + + valid: [ + { + filename: 'test.vue', + code: ` + export default { + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + ...name + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'FooBar' + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'FooBar' + } + `, + options: ['PascalCase'], + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'foo-bar' + } + `, + options: ['kebab-case'], + parserOptions + }, + { + filename: 'test.vue', + code: `Vue.component('FooBar', {})`, + parserOptions + }, + { + filename: 'test.vue', + code: `Vue.component('FooBar', {})`, + options: ['PascalCase'], + parserOptions + }, + { + filename: 'test.vue', + code: `Vue.component('foo-bar', {})`, + options: ['kebab-case'], + parserOptions + }, + { + filename: 'test.vue', + code: `Vue.component(fooBar, {})`, + options: ['kebab-case'], + parserOptions + } + ], + + invalid: [ + { + filename: 'test.vue', + code: ` + export default { + name: 'foo-bar' + } + `, + output: ` + export default { + name: 'FooBar' + } + `, + parserOptions, + errors: [{ + message: 'Property name "foo-bar" is not PascalCase.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'foo bar' + } + `, + output: ` + export default { + name: 'FooBar' + } + `, + parserOptions, + errors: [{ + message: 'Property name "foo bar" is not PascalCase.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'foo!bar' + } + `, + output: ` + export default { + name: 'FooBar' + } + `, + parserOptions, + errors: [{ + message: 'Property name "foo!bar" is not PascalCase.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.js', + code: ` + new Vue({ + name: 'foo!bar' + }) + `, + output: ` + new Vue({ + name: 'FooBar' + }) + `, + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: 'Property name "foo!bar" is not PascalCase.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'foo_bar' + } + `, + output: ` + export default { + name: 'FooBar' + } + `, + parserOptions, + errors: [{ + message: 'Property name "foo_bar" is not PascalCase.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'foo_bar' + } + `, + output: ` + export default { + name: 'FooBar' + } + `, + options: ['PascalCase'], + parserOptions, + errors: [{ + message: 'Property name "foo_bar" is not PascalCase.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'foo_bar' + } + `, + output: ` + export default { + name: 'foo-bar' + } + `, + options: ['kebab-case'], + parserOptions, + errors: [{ + message: 'Property name "foo_bar" is not kebab-case.', + type: 'Literal', + line: 3 + }] + }, + { + filename: 'test.vue', + code: `Vue.component('foo-bar', {})`, + output: `Vue.component('FooBar', {})`, + parserOptions, + errors: [{ + message: 'Property name "foo-bar" is not PascalCase.', + type: 'Literal', + line: 1 + }] + }, + { + filename: 'test.js', + code: `Vue.component('foo_bar', {})`, + output: `Vue.component('FooBar', {})`, + options: ['PascalCase'], + parserOptions, + errors: [{ + message: 'Property name "foo_bar" is not PascalCase.', + type: 'Literal', + line: 1 + }] + }, + { + filename: 'test.vue', + code: `Vue.component('foo_bar', {})`, + output: `Vue.component('foo-bar', {})`, + options: ['kebab-case'], + parserOptions, + errors: [{ + message: 'Property name "foo_bar" is not kebab-case.', + type: 'Literal', + line: 1 + }] + } + ] +})