From 1ed81132de22ab635fb8910cac27777c508a7e60 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Wed, 9 Feb 2022 17:54:00 +0800 Subject: [PATCH 1/7] Add `prefer-true-attribute-shorthand` rule --- docs/rules/README.md | 1 + docs/rules/prefer-true-attribute-shorthand.md | 68 +++++++++ lib/index.js | 1 + lib/rules/prefer-true-attribute-shorthand.js | 69 +++++++++ .../rules/prefer-true-attribute-shorthand.js | 133 ++++++++++++++++++ 5 files changed, 272 insertions(+) create mode 100644 docs/rules/prefer-true-attribute-shorthand.md create mode 100644 lib/rules/prefer-true-attribute-shorthand.js create mode 100644 tests/lib/rules/prefer-true-attribute-shorthand.js diff --git a/docs/rules/README.md b/docs/rules/README.md index b74075445..a612dca83 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -353,6 +353,7 @@ For example: | [vue/no-v-text](./no-v-text.md) | disallow use of v-text | | | [vue/padding-line-between-blocks](./padding-line-between-blocks.md) | require or disallow padding lines between blocks | :wrench: | | [vue/prefer-separate-static-class](./prefer-separate-static-class.md) | require static class names in template to be in a separate `class` attribute | :wrench: | +| [vue/prefer-true-attribute-shorthand](./prefer-true-attribute-shorthand.md) | require shorthand form attribute when `v-bind` value is `true`. | :bulb: | | [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | | [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: | | [vue/require-expose](./require-expose.md) | require declare public properties using `expose` | :bulb: | diff --git a/docs/rules/prefer-true-attribute-shorthand.md b/docs/rules/prefer-true-attribute-shorthand.md new file mode 100644 index 000000000..130df55b5 --- /dev/null +++ b/docs/rules/prefer-true-attribute-shorthand.md @@ -0,0 +1,68 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/prefer-true-attribute-shorthand +description: require shorthand form attribute when `v-bind` value is `true`. +--- +# vue/prefer-true-attribute-shorthand + +> require shorthand form attribute when `v-bind` value is `true`. + +- :exclamation: ***This rule has not been released yet.*** +- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). + +## :book: Rule Details + +`v-bind` attribute with `true` value usually can be written in shorthand form. This can reduce verbosity. + + + +```vue + +``` + + + +However, those two representations are not always equivalent. +This case will be occurred if the definition of a prop include `String`: + +```vue + + + +``` + +```vue + +``` + +Those two calls will introduce different render result. See [this demo](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCBNeUNvbXBvbmVudCBmcm9tICcuL015Q29tcG9uZW50LnZ1ZSdcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxNeUNvbXBvbmVudCBhIGIvPlxuICA8TXlDb21wb25lbnQgOmE9XCJ0cnVlXCIgOmI9XCJ0cnVlXCIvPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59IiwiTXlDb21wb25lbnQudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgcHJvcHM6IHtcbiAgICBhOiBCb29sZWFuLFxuICAgIGI6IFtTdHJpbmcsIEJvb2xlYW5dXG4gIH1cbn1cbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxwcmU+XG5hOiB7e2F9fVxuYjoge3tifX1cbiAgPC9wcmU+XG48L3RlbXBsYXRlPiJ9). + +## :wrench: Options + +Nothing. + +## :mag: Implementation + +- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/prefer-true-attribute-shorthand.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/prefer-true-attribute-shorthand.js) diff --git a/lib/index.js b/lib/index.js index 5d770e8b2..941de0b56 100644 --- a/lib/index.js +++ b/lib/index.js @@ -159,6 +159,7 @@ module.exports = { 'padding-line-between-blocks': require('./rules/padding-line-between-blocks'), 'prefer-separate-static-class': require('./rules/prefer-separate-static-class'), 'prefer-template': require('./rules/prefer-template'), + 'prefer-true-attribute-shorthand': require('./rules/prefer-true-attribute-shorthand'), 'prop-name-casing': require('./rules/prop-name-casing'), 'quote-props': require('./rules/quote-props'), 'require-component-is': require('./rules/require-component-is'), diff --git a/lib/rules/prefer-true-attribute-shorthand.js b/lib/rules/prefer-true-attribute-shorthand.js new file mode 100644 index 000000000..69d1797ae --- /dev/null +++ b/lib/rules/prefer-true-attribute-shorthand.js @@ -0,0 +1,69 @@ +/** + * @author Pig Fang + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: 'problem', + docs: { + description: + 'require shorthand form attribute when `v-bind` value is `true`.', + categories: undefined, + url: 'https://eslint.vuejs.org/rules/prefer-true-attribute-shorthand.html' + }, + fixable: null, + hasSuggestions: true, + schema: [], + messages: { + report: + "Boolean prop with 'true' value can be written in shorthand form.", + fix: 'Rewrite this prop into shorthand form.' + } + }, + /** @param {RuleContext} context */ + create(context) { + // ... + + return utils.defineTemplateBodyVisitor(context, { + /** @param {VDirective} node */ + "VAttribute[directive=true][key.name.name='bind']"(node) { + const { argument } = node.key + if ( + !argument || + !node.value || + !node.value.expression || + node.value.expression.type !== 'Literal' || + node.value.expression.value !== true + ) { + return + } + + context.report({ + node, + messageId: 'report', + suggest: [ + { + messageId: 'fix', + fix: (fixer) => { + const sourceCode = context.getSourceCode() + return fixer.replaceText(node, sourceCode.getText(argument)) + } + } + ] + }) + } + }) + } +} diff --git a/tests/lib/rules/prefer-true-attribute-shorthand.js b/tests/lib/rules/prefer-true-attribute-shorthand.js new file mode 100644 index 000000000..002b0d004 --- /dev/null +++ b/tests/lib/rules/prefer-true-attribute-shorthand.js @@ -0,0 +1,133 @@ +/** + * @author Pig Fang + * See LICENSE file in root directory for full license. + */ +'use strict' + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/prefer-true-attribute-shorthand') + +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + ecmaVersion: 2020, + sourceType: 'module' + } +}) + +tester.run('prefer-true-attribute-shorthand', rule, { + valid: [ + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + } + ], + invalid: [ + { + filename: 'test.vue', + code: ` + `, + errors: [ + { + messageId: 'report', + line: 3, + column: 17, + suggestions: [ + { + messageId: 'fix', + output: ` + ` + } + ] + } + ] + }, + { + filename: 'test.vue', + code: ` + `, + errors: [ + { + messageId: 'report', + line: 3, + column: 17, + suggestions: [ + { + messageId: 'fix', + output: ` + ` + } + ] + } + ] + } + ] +}) From 62119d57154019b00d0a6fc2d77f1a587fb64487 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Wed, 9 Feb 2022 18:08:26 +0800 Subject: [PATCH 2/7] fix typo --- docs/rules/prefer-true-attribute-shorthand.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/prefer-true-attribute-shorthand.md b/docs/rules/prefer-true-attribute-shorthand.md index 130df55b5..f67a3beee 100644 --- a/docs/rules/prefer-true-attribute-shorthand.md +++ b/docs/rules/prefer-true-attribute-shorthand.md @@ -32,7 +32,7 @@ description: require shorthand form attribute when `v-bind` value is `true`. However, those two representations are not always equivalent. -This case will be occurred if the definition of a prop include `String`: +This case will be occurred if the definition of a prop includes `String`: ```vue `, errors: [ { - messageId: 'report', + messageId: 'expectShort', line: 3, column: 17, suggestions: [ { - messageId: 'fix', + messageId: 'suggestion', output: ` `, errors: [ { - messageId: 'report', + messageId: 'expectShort', line: 3, column: 17, suggestions: [ { - messageId: 'fix', + messageId: 'suggestion', output: ` `, options: ['never'] + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + `, + options: ['never'] } ], invalid: [ From 2188af9edd3159d81c1da72b3f61894089bbd86d Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Fri, 11 Feb 2022 15:43:37 +0800 Subject: [PATCH 6/7] provide suggestions instead of auto fix --- lib/rules/prefer-true-attribute-shorthand.js | 25 ++++++++++++++--- .../rules/prefer-true-attribute-shorthand.js | 27 +++++++++++++------ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/lib/rules/prefer-true-attribute-shorthand.js b/lib/rules/prefer-true-attribute-shorthand.js index cb2ed9645..19a98a351 100644 --- a/lib/rules/prefer-true-attribute-shorthand.js +++ b/lib/rules/prefer-true-attribute-shorthand.js @@ -31,7 +31,11 @@ module.exports = { "Boolean prop with 'true' value should be written in shorthand form.", expectLong: "Boolean prop with 'true' value should be written in long form.", - suggestion: 'Rewrite this prop into shorthand form.' + rewriteIntoShort: 'Rewrite this prop into shorthand form.', + rewriteIntoLongVueProp: + 'Rewrite this prop into long-form Vue component prop.', + rewriteIntoLongHtmlAttr: + 'Rewrite this prop into long-form HTML attribute.' } }, /** @param {RuleContext} context */ @@ -49,8 +53,21 @@ module.exports = { context.report({ node, messageId: 'expectLong', - fix: (fixer) => - fixer.replaceText(node, `:${node.key.rawName}="true"`) + suggest: [ + { + messageId: 'rewriteIntoLongVueProp', + fix: (fixer) => + fixer.replaceText(node, `:${node.key.rawName}="true"`) + }, + { + messageId: 'rewriteIntoLongHtmlAttr', + fix: (fixer) => + fixer.replaceText( + node, + `${node.key.rawName}="${node.key.rawName}"` + ) + } + ] }) return } @@ -79,7 +96,7 @@ module.exports = { messageId: 'expectShort', suggest: [ { - messageId: 'suggestion', + messageId: 'rewriteIntoShort', fix: (fixer) => { const sourceCode = context.getSourceCode() return fixer.replaceText(node, sourceCode.getText(argument)) diff --git a/tests/lib/rules/prefer-true-attribute-shorthand.js b/tests/lib/rules/prefer-true-attribute-shorthand.js index fcf801935..e7d52ef7f 100644 --- a/tests/lib/rules/prefer-true-attribute-shorthand.js +++ b/tests/lib/rules/prefer-true-attribute-shorthand.js @@ -164,7 +164,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { column: 17, suggestions: [ { - messageId: 'suggestion', + messageId: 'rewriteIntoShort', output: `