From 014110bf90b10ee35f164921ecdf356a7d396030 Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 9 Aug 2017 00:25:03 +0200 Subject: [PATCH 1/2] Add "no-multi-spaces" rule --- docs/rules/no-multi-spaces.md | 31 +++++ lib/rules/no-multi-spaces.js | 74 ++++++++++++ package.json | 2 +- tests/lib/rules/no-multi-spaces.js | 177 +++++++++++++++++++++++++++++ 4 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 docs/rules/no-multi-spaces.md create mode 100644 lib/rules/no-multi-spaces.js create mode 100644 tests/lib/rules/no-multi-spaces.js diff --git a/docs/rules/no-multi-spaces.md b/docs/rules/no-multi-spaces.md new file mode 100644 index 000000000..b93254dab --- /dev/null +++ b/docs/rules/no-multi-spaces.md @@ -0,0 +1,31 @@ +# This rule warns about the usage of extra whitespaces between attributes (no-multi-spaces) + +The `--fix` option on the command line can automatically fix some of the problems reported by this rule. + +This rule aims to remove multiple spaces in a row between attributes witch are not used for indentation. + +## Rule Details + +Examples of **incorrect** code for this rule: + +```html + +``` + +Examples of **correct** code for this rule: + +```html + +``` + +### Options + +Nothing diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js new file mode 100644 index 000000000..353be895d --- /dev/null +++ b/lib/rules/no-multi-spaces.js @@ -0,0 +1,74 @@ +/** + * @fileoverview This rule warns about the usage of extra whitespaces between attributes + * @author Armano + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: 'This rule warns about the usage of extra whitespaces between attributes', + category: 'Stylistic Issues', + recommended: false + }, + fixable: 'whitespace', // or "code" or "whitespace" + schema: [] + }, + + /** + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ + create (context) { + function formatValue (token) { + switch (token.type) { + case 'HTMLSelfClosingTagClose': return '/>' + case 'HTMLTagClose': return '>' + } + + return token.value + } + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return { + Program (node) { + if (context.parserServices.getTemplateBodyTokenStore == null) { + context.report({ + loc: { line: 1, column: 0 }, + message: 'Use the latest vue-eslint-parser. See also https://github.com/vuejs/eslint-plugin-vue#what-is-the-use-the-latest-vue-eslint-parser-error.' + }) + return + } + const tokenStore = context.parserServices.getTemplateBodyTokenStore() + const tokens = tokenStore.getTokens(node.templateBody, { includeComments: true }) + + let prevToken = tokens.shift() + for (const token of tokens) { + const spaces = token.range[0] - prevToken.range[1] + if (spaces > 1 && token.loc.start.line === prevToken.loc.start.line) { + context.report({ + node: token, + loc: { + start: prevToken.loc.end, + end: token.loc.start + }, + message: "Multiple spaces found before '{{displayValue}}'.", + fix: (fixer) => fixer.replaceTextRange([prevToken.range[1], token.range[0]], ' '), + data: { + displayValue: formatValue(token) + } + }) + } + prevToken = token + } + } + } + } +} diff --git a/package.json b/package.json index 6ebff6e25..e111a90cc 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "dependencies": { "requireindex": "^1.1.0", - "vue-eslint-parser": "2.0.0-beta.6" + "vue-eslint-parser": "2.0.0-beta.7" }, "devDependencies": { "@types/node": "^4.2.16", diff --git a/tests/lib/rules/no-multi-spaces.js b/tests/lib/rules/no-multi-spaces.js new file mode 100644 index 000000000..afb93cf07 --- /dev/null +++ b/tests/lib/rules/no-multi-spaces.js @@ -0,0 +1,177 @@ +/** + * @fileoverview This rule warns about the usage of extra whitespaces between attributes + * @author Armano + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/no-multi-spaces') +const RuleTester = require('eslint').RuleTester + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +ruleTester.run('no-multi-spaces', rule, { + valid: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '' + ], + invalid: [ + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'class'.", + type: 'HTMLIdentifier' + }, + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'class'.", + type: 'HTMLIdentifier' + }, + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before ':class'.", + type: 'HTMLIdentifier' + }, + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'test'.", + type: 'Identifier' + }, + { + message: "Multiple spaces found before '}}'.", + type: 'VExpressionEnd' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before '>'.", + type: 'HTMLTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'i'.", + type: 'Identifier' + }, + { + message: "Multiple spaces found before 'in'.", + type: 'Keyword' + }, + { + message: "Multiple spaces found before 'b'.", + type: 'Identifier' + }, + { + message: "Multiple spaces found before '\"'.", + type: 'Punctuator' + } + ] + } + ] +}) From b0278339ddded62aa54d99834e3d9df0651cd515 Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 9 Aug 2017 12:24:53 +0200 Subject: [PATCH 2/2] -> sourceCode.getText --- lib/rules/no-multi-spaces.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js index 353be895d..c9d6369f4 100644 --- a/lib/rules/no-multi-spaces.js +++ b/lib/rules/no-multi-spaces.js @@ -24,15 +24,6 @@ module.exports = { * @returns {Object} AST event handlers. */ create (context) { - function formatValue (token) { - switch (token.type) { - case 'HTMLSelfClosingTagClose': return '/>' - case 'HTMLTagClose': return '>' - } - - return token.value - } - // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- @@ -46,6 +37,7 @@ module.exports = { }) return } + const sourceCode = context.getSourceCode() const tokenStore = context.parserServices.getTemplateBodyTokenStore() const tokens = tokenStore.getTokens(node.templateBody, { includeComments: true }) @@ -62,7 +54,7 @@ module.exports = { message: "Multiple spaces found before '{{displayValue}}'.", fix: (fixer) => fixer.replaceTextRange([prevToken.range[1], token.range[0]], ' '), data: { - displayValue: formatValue(token) + displayValue: sourceCode.getText(token) } }) }