From 8f82b7382dbecd3632bff0e941b1ad52ef0fa6db Mon Sep 17 00:00:00 2001 From: ota Date: Wed, 20 May 2020 14:14:23 +0900 Subject: [PATCH] Fix false positives for member call and autofix error in `vue/v-on-function-call` rule. --- lib/rules/v-on-function-call.js | 32 ++++++++++++++++++++----- tests/lib/rules/v-on-function-call.js | 34 +++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/lib/rules/v-on-function-call.js b/lib/rules/v-on-function-call.js index 4953049b7..9bf7cd6fc 100644 --- a/lib/rules/v-on-function-call.js +++ b/lib/rules/v-on-function-call.js @@ -9,6 +9,19 @@ const utils = require('../utils') +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Check whether the given token is a left parenthesis. + * @param {Token} token The token to check. + * @returns {boolean} `true` if the token is a left parenthesis. + */ +function isLeftParen (token) { + return token != null && token.type === 'Punctuator' && token.value === '(' +} + // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ @@ -40,17 +53,24 @@ module.exports = { }) }, - "VAttribute[directive=true][key.name.name='on'][key.argument!=null] VOnExpression > ExpressionStatement > *" (node) { - if (!always && node.type === 'CallExpression' && node.arguments.length === 0) { + "VAttribute[directive=true][key.name.name='on'][key.argument!=null] VOnExpression > ExpressionStatement > CallExpression" (node) { + if (!always && node.arguments.length === 0 && node.callee.type === 'Identifier') { 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[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]) + const tokenStore = context.parserServices.getTemplateBodyTokenStore() + const rightToken = tokenStore.getLastToken(node) + const leftToken = tokenStore.getTokenAfter(node.callee, isLeftParen) + const tokens = tokenStore.getTokensBetween(leftToken, rightToken, { includeComments: true }) + + if (tokens.length) { + // The comment is included and cannot be fixed. + return null + } + + return fixer.removeRange([leftToken.range[0], rightToken.range[1]]) } }) } diff --git a/tests/lib/rules/v-on-function-call.js b/tests/lib/rules/v-on-function-call.js index 5a3533f21..b8ddf99b1 100644 --- a/tests/lib/rules/v-on-function-call.js +++ b/tests/lib/rules/v-on-function-call.js @@ -44,6 +44,33 @@ tester.run('v-on-function-call', rule, { filename: 'test.vue', code: '', options: ['never'] + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '', + options: ['always'] + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '', + options: ['always'] + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '', + options: ['always'] } ], invalid: [ @@ -67,6 +94,13 @@ tester.run('v-on-function-call', rule, { output: ``, errors: ["Method calls without arguments inside of 'v-on' directives must not have parentheses."], options: ['never'] + }, + { + filename: 'test.vue', + code: '', + output: null, + errors: ["Method calls without arguments inside of 'v-on' directives must not have parentheses."], + options: ['never'] } ] })