From c5cf643a37174a7c0ac0cc9e1aadafdcfce5e73a Mon Sep 17 00:00:00 2001 From: Niklas Higi Date: Sun, 27 May 2018 11:17:52 +0200 Subject: [PATCH 1/7] Implement rule --- README.md | 1 + docs/rules/v-on-parens.md | 66 ++++++++++++++++++++++++++++++++++ lib/configs/recommended.js | 3 +- lib/index.js | 1 + lib/rules/v-on-parens.js | 60 +++++++++++++++++++++++++++++++ tests/lib/rules/v-on-parens.js | 63 ++++++++++++++++++++++++++++++++ 6 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 docs/rules/v-on-parens.md create mode 100644 lib/rules/v-on-parens.js create mode 100644 tests/lib/rules/v-on-parens.js diff --git a/README.md b/README.md index 015e2922b..aa470d45b 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | | [vue/no-confusing-v-for-v-if](./docs/rules/no-confusing-v-for-v-if.md) | disallow confusing `v-for` and `v-if` on the same element | | :wrench: | [vue/order-in-components](./docs/rules/order-in-components.md) | enforce order of properties in components | | | [vue/this-in-template](./docs/rules/this-in-template.md) | enforce usage of `this` in template | +| :wrench: | [vue/v-on-parens](./docs/rules/v-on-parens.md) | enforce or forbid parentheses after method calls without arguments in `v-on` directives | ### Uncategorized diff --git a/docs/rules/v-on-parens.md b/docs/rules/v-on-parens.md new file mode 100644 index 000000000..11bb3f889 --- /dev/null +++ b/docs/rules/v-on-parens.md @@ -0,0 +1,66 @@ +# enforce or forbid parentheses after method calls without arguments in `v-on` directives (vue/v-on-parens) + +- :gear: This rule is included in `"plugin:vue/recommended"`. +- :wrench: The `--fix` option on the [command line](http://eslint.org/docs/user-guide/command-line-interface#fix) can automatically fix some of the problems reported by this rule. + +## :book: Rule Details + +:-1: Example of **incorrect** code for this rule: + +```html + +``` + +:+1: Example of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Default is set to `never`. + +``` +'vue/v-on-parens': [2, 'always'|'never'] +``` + +### `"always"` - Always use parentheses in `v-on` directives + +:-1: Example of **incorrect** code: + +```html + +``` + +:+1: Example of **correct** code: + +```html + +``` + +### `"never"` - Never use parentheses in `v-on` directives for method calls without arguments + +:-1: Example of **incorrect** code: + +```html + +``` + +:+1: Example of **correct** code: + +```html + +``` diff --git a/lib/configs/recommended.js b/lib/configs/recommended.js index aad9a5405..9301320fd 100644 --- a/lib/configs/recommended.js +++ b/lib/configs/recommended.js @@ -10,6 +10,7 @@ module.exports = { 'vue/html-quotes': 'error', 'vue/no-confusing-v-for-v-if': 'error', 'vue/order-in-components': 'error', - 'vue/this-in-template': 'error' + 'vue/this-in-template': 'error', + 'vue/v-on-parens': 'error' } } diff --git a/lib/index.js b/lib/index.js index d96fd38e0..efc6e44ad 100644 --- a/lib/index.js +++ b/lib/index.js @@ -44,6 +44,7 @@ module.exports = { 'script-indent': require('./rules/script-indent'), 'this-in-template': require('./rules/this-in-template'), 'v-bind-style': require('./rules/v-bind-style'), + 'v-on-parens': require('./rules/v-on-parens'), 'v-on-style': require('./rules/v-on-style'), 'valid-template-root': require('./rules/valid-template-root'), 'valid-v-bind': require('./rules/valid-v-bind'), diff --git a/lib/rules/v-on-parens.js b/lib/rules/v-on-parens.js new file mode 100644 index 000000000..ce72ca047 --- /dev/null +++ b/lib/rules/v-on-parens.js @@ -0,0 +1,60 @@ +/** + * @author Niklas Higi + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: 'enforce or forbid parentheses after method calls without arguments in `v-on` directives', + category: 'recommended', + url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/v-on-parens.md' + }, + fixable: 'code', + schema: [ + { enum: ['always', 'never'] } + ] + }, + + create (context) { + const always = context.options[0] === 'always' + + return utils.defineTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='on'][key.argument!=null] VOnExpression > ExpressionStatement > *" (node) { + const hasParens = node.type === 'CallExpression' + if (hasParens && node.arguments.length > 0) return + + if (always && !hasParens) { + context.report({ + node, + loc: node.loc, + message: "Method calls inside of 'v-on' directives must have parentheses.", + fix: fixer => fixer.insertTextAfter(node, '()') + }) + } else if (!always && hasParens) { + context.report({ + node, + loc: node.loc, + message: "Method calls without arguments inside of 'v-on' directives must not have parentheses.", + fix: fixer => { + const nodeString = context.getSourceCode().getText().substring(...node.range) + // This ensures that parens are also removed if they contain whitespace + const parensLength = nodeString.match(/\(\s*\)\s*$/)[0].length + return fixer.removeRange([node.end - parensLength, node.end]) + } + }) + } + } + }) + } +} diff --git a/tests/lib/rules/v-on-parens.js b/tests/lib/rules/v-on-parens.js new file mode 100644 index 000000000..23fb98000 --- /dev/null +++ b/tests/lib/rules/v-on-parens.js @@ -0,0 +1,63 @@ +/** + * @author Niklas Higi + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/v-on-parens') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('v-on-parens', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '', + options: ['always'] + }, + { + filename: 'test.vue', + code: '', + options: ['never'] + }, + { + filename: 'test.vue', + code: '', + options: ['always'] + }, + { + filename: 'test.vue', + code: '', + options: ['never'] + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["Method calls inside of 'v-on' directives always require parentheses."], + options: ['always'] + }, + { + filename: 'test.vue', + code: '', + errors: ["Method calls without arguments inside of 'v-on' directives must not have parentheses."], + options: ['never'] + } + ] +}) From 6b3448424aa768dd522827d0c130341ae81ab3f8 Mon Sep 17 00:00:00 2001 From: Niklas Higi Date: Sun, 27 May 2018 11:46:35 +0200 Subject: [PATCH 2/7] Get rid of spread operator, update error message in test --- lib/rules/v-on-parens.js | 2 +- tests/lib/rules/v-on-parens.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rules/v-on-parens.js b/lib/rules/v-on-parens.js index ce72ca047..4940da938 100644 --- a/lib/rules/v-on-parens.js +++ b/lib/rules/v-on-parens.js @@ -47,7 +47,7 @@ module.exports = { loc: node.loc, message: "Method calls without arguments inside of 'v-on' directives must not have parentheses.", fix: fixer => { - const nodeString = context.getSourceCode().getText().substring(...node.range) + const nodeString = context.getSourceCode().getText().substring(node.range[0], node.range[1]) // This ensures that parens are also removed if they contain whitespace const parensLength = nodeString.match(/\(\s*\)\s*$/)[0].length return fixer.removeRange([node.end - parensLength, node.end]) diff --git a/tests/lib/rules/v-on-parens.js b/tests/lib/rules/v-on-parens.js index 23fb98000..f2b693f3b 100644 --- a/tests/lib/rules/v-on-parens.js +++ b/tests/lib/rules/v-on-parens.js @@ -50,7 +50,7 @@ tester.run('v-on-parens', rule, { { filename: 'test.vue', code: '', - errors: ["Method calls inside of 'v-on' directives always require parentheses."], + errors: ["Method calls inside of 'v-on' directives must have parentheses."], options: ['always'] }, { From b5325451cba819f58d191aa68b74d13e2bc3ec32 Mon Sep 17 00:00:00 2001 From: michalsnik Date: Mon, 7 Jan 2019 14:35:08 +0100 Subject: [PATCH 3/7] Update meta --- docs/rules/README.md | 2 +- docs/rules/v-on-parens.md | 1 - lib/configs/recommended.js | 3 +-- lib/rules/v-on-parens.js | 5 +++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 6335adee7..a2134a864 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -121,7 +121,6 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | [vue/no-v-html](./no-v-html.md) | disallow use of v-html to prevent XSS attack | | | [vue/order-in-components](./order-in-components.md) | enforce order of properties in components | :wrench: | | [vue/this-in-template](./this-in-template.md) | disallow usage of `this` in template | | -| [vue/v-on-parens](./v-on-parens.md) | enforce or forbid parentheses after method calls without arguments in `v-on` directives | :wrench: | ## Uncategorized @@ -149,6 +148,7 @@ For example: | [vue/script-indent](./script-indent.md) | enforce consistent indentation in `