Skip to content

Commit ce8f6d1

Browse files
committed
Add no-multi-spaces rule.
fixes #133
1 parent 3db7b13 commit ce8f6d1

File tree

4 files changed

+244
-0
lines changed

4 files changed

+244
-0
lines changed

docs/rules/no-multi-spaces.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This rule warns about the usage of extra whitespaces between attributes (no-multi-spaces)
2+
3+
The `--fix` option on the command line can automatically fix some of the problems reported by this rule.
4+
5+
This rule aims to remove multiple spaces in a row between attributes witch are not used for indentation.
6+
7+
## Rule Details
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```html
12+
<template>
13+
<div class="foo" :style="foo"\t
14+
:foo="bar" >
15+
</div>
16+
</template>
17+
```
18+
19+
Examples of **correct** code for this rule:
20+
21+
```html
22+
<template>
23+
<div class="foo"
24+
:style="foo">
25+
</div>
26+
</template>
27+
```
28+
29+
### Options
30+
31+
Nothing

lib/rules/html-no-self-closing.js

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ function create (context) {
2828
return
2929
}
3030

31+
// TODO: Check `context.parserServices.getTemplateBodyTokenStore` exists or not.
3132
const sourceCode = context.parserServices.getTemplateBodyTokenStore(context)
3233
const lastToken = sourceCode.getLastToken(node.startTag)
3334
if (lastToken.type !== 'HTMLSelfClosingTagClose') {

lib/rules/no-multi-spaces.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* @fileoverview This rule warns about the usage of extra whitespaces between attributes
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Rule Definition
9+
// ------------------------------------------------------------------------------
10+
11+
module.exports = {
12+
meta: {
13+
docs: {
14+
description: 'This rule warns about the usage of extra whitespaces between attributes',
15+
category: 'Stylistic Issues',
16+
recommended: false
17+
},
18+
fixable: 'whitespace', // or "code" or "whitespace"
19+
schema: []
20+
},
21+
22+
/**
23+
* @param {RuleContext} context - The rule context.
24+
* @returns {Object} AST event handlers.
25+
*/
26+
create (context) {
27+
const sourceCode = context.getSourceCode()
28+
29+
// ----------------------------------------------------------------------
30+
// Public
31+
// ----------------------------------------------------------------------
32+
33+
return {
34+
Program (node) {
35+
// TODO: Check `context.parserServices.getTemplateBodyTokenStore` exists or not.
36+
const tokenStore = context.parserServices.getTemplateBodyTokenStore()
37+
const tokens = tokenStore.getTokens(node.templateBody, { includeComments: true })
38+
39+
let prevToken = tokens.shift()
40+
for (const token of tokens) {
41+
if (sourceCode.isSpaceBetweenTokens(prevToken, token)) {
42+
const text = sourceCode.getText(token, (token.range[0] - prevToken.range[1] + 1), 0)
43+
44+
const match = text.match(/([^\r\n\t\s])([ \t]+)([>]?)([\n\r]?)/)
45+
if (!match) {
46+
prevToken = token
47+
continue // there is no errors
48+
}
49+
50+
const spaces = match[2].length
51+
const requiredSpaces = match[3] === '>' || match[4] !== '' ? 0 : 1
52+
53+
if (spaces > requiredSpaces) {
54+
context.report({
55+
node: token,
56+
loc: {
57+
start: {
58+
line: prevToken.loc.end.line,
59+
column: prevToken.loc.end.column + requiredSpaces
60+
},
61+
end: {
62+
line: prevToken.loc.end.line,
63+
column: prevToken.loc.end.column + spaces
64+
}
65+
},
66+
message: 'Extra whitespace detected.',
67+
fix: (fixer) => fixer.removeRange([prevToken.range[1] + requiredSpaces, prevToken.range[1] + spaces])
68+
})
69+
}
70+
}
71+
prevToken = token
72+
}
73+
}
74+
}
75+
}
76+
}

tests/lib/rules/no-multi-spaces.js

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* @fileoverview This rule warns about the usage of extra whitespaces between attributes
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/no-multi-spaces')
12+
const RuleTester = require('eslint').RuleTester
13+
14+
// ------------------------------------------------------------------------------
15+
// Tests
16+
// ------------------------------------------------------------------------------
17+
18+
const ruleTester = new RuleTester({
19+
parser: 'vue-eslint-parser',
20+
parserOptions: { ecmaVersion: 2015 }
21+
})
22+
23+
ruleTester.run('no-multi-spaces', rule, {
24+
valid: [
25+
'',
26+
'<template></template>',
27+
'<template><div /></template>',
28+
'<template><div class="foo"></div></template>',
29+
'<template><div class="foo" @click="bar"></div></template>',
30+
'<template><div class="foo"\n :style="foo"></div></template>',
31+
'<template><div class="foo"\n\t\t\t:style="foo"></div></template>',
32+
'<template><div class="foo"\n :style="foo"\n ></div></template>',
33+
'<template><div class="foo"\n :style="foo" /></template>',
34+
'<template><div class="foo"\n :style="foo"\n /></template>'
35+
],
36+
invalid: [
37+
{
38+
code: '<template><div /></template>',
39+
output: '<template><div /></template>',
40+
errors: [{
41+
message: 'Extra whitespace detected.',
42+
type: 'HTMLSelfClosingTagClose'
43+
}]
44+
},
45+
{
46+
code: '<template><div class="foo" /></template>',
47+
output: '<template><div class="foo" /></template>',
48+
errors: [
49+
{
50+
message: 'Extra whitespace detected.',
51+
type: 'HTMLIdentifier'
52+
},
53+
{
54+
message: 'Extra whitespace detected.',
55+
type: 'HTMLSelfClosingTagClose'
56+
}
57+
]
58+
},
59+
{
60+
code: '<template><div\t\tclass="foo"\t\t/></template>',
61+
output: '<template><div\tclass="foo"\t/></template>',
62+
errors: [
63+
{
64+
message: 'Extra whitespace detected.',
65+
type: 'HTMLIdentifier'
66+
},
67+
{
68+
message: 'Extra whitespace detected.',
69+
type: 'HTMLSelfClosingTagClose'
70+
}
71+
]
72+
},
73+
{
74+
code: '<template><div :class="foo" /></template>',
75+
output: '<template><div :class="foo" /></template>',
76+
errors: [
77+
{
78+
message: 'Extra whitespace detected.',
79+
type: 'HTMLIdentifier'
80+
},
81+
{
82+
message: 'Extra whitespace detected.',
83+
type: 'HTMLSelfClosingTagClose'
84+
}
85+
]
86+
},
87+
{
88+
code: '<template><div :foo="" class="foo" /></template>',
89+
output: '<template><div :foo="" class="foo" /></template>',
90+
errors: [{
91+
message: 'Extra whitespace detected.',
92+
type: 'HTMLSelfClosingTagClose'
93+
}]
94+
},
95+
{
96+
code: '<template><div foo="" class="foo" /></template>',
97+
output: '<template><div foo="" class="foo" /></template>',
98+
errors: [{
99+
message: 'Extra whitespace detected.',
100+
type: 'HTMLSelfClosingTagClose'
101+
}]
102+
},
103+
{
104+
code: '<template><foo v-foo="" class="foo" /></template>',
105+
output: '<template><foo v-foo="" class="foo" /></template>',
106+
errors: [{
107+
message: 'Extra whitespace detected.',
108+
type: 'HTMLSelfClosingTagClose'
109+
}]
110+
},
111+
{
112+
code: '<template><foo v-foo="" \n class="foo" /></template>',
113+
output: '<template><foo v-foo=""\n class="foo" /></template>',
114+
errors: [
115+
{
116+
message: 'Extra whitespace detected.',
117+
type: 'HTMLIdentifier'
118+
},
119+
{
120+
message: 'Extra whitespace detected.',
121+
type: 'HTMLSelfClosingTagClose'
122+
}
123+
]
124+
},
125+
{
126+
code: '<template><div class="foo " class=" foo " /></template>',
127+
output: '<template><div class="foo " class=" foo " /></template>',
128+
errors: [
129+
{
130+
message: 'Extra whitespace detected.',
131+
type: 'HTMLIdentifier'
132+
}
133+
]
134+
}
135+
]
136+
})

0 commit comments

Comments
 (0)