Skip to content

Commit 435e9d0

Browse files
committed
Add rule curly-bracket-spacing.
fixes #150
1 parent 164b2ae commit 435e9d0

File tree

4 files changed

+326
-1
lines changed

4 files changed

+326
-1
lines changed

docs/rules/curly-bracket-spacing.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Enforce spacing on the style of curly brackets. (curly-bracket-spacing)
2+
3+
- :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.
4+
5+
## :book: Rule Details
6+
7+
This rule aims to enforce unified spacing of curly brackets.
8+
9+
:-1: Examples of **incorrect** code for this rule:
10+
11+
```html
12+
<template>
13+
<div>{{ text }}</div>
14+
</template>
15+
```
16+
17+
:+1: Examples of **correct** code for this rule:
18+
19+
```html
20+
<template>
21+
<div>{{ text }}</div>
22+
</template>
23+
```
24+
25+
## :wrench: Options
26+
27+
Default spacing is set to `always`
28+
29+
```
30+
'vue/curly-bracket-spacing': [2, 'always'|'never']
31+
```
32+
33+
### `"always"` - Expect one space between expression and curly brackets.
34+
35+
:+1: Examples of **correct** code`:
36+
37+
```html
38+
<template>
39+
<div>{{ text }}</div>
40+
</template>
41+
```
42+
43+
:-1: Examples of **incorrect** code`:
44+
45+
```html
46+
<template>
47+
<div>{{text}}</div>
48+
</template>
49+
```
50+
51+
### `"never"` - Expect no spaces between expression and curly brackets.
52+
53+
:+1: Examples of **correct** code`:
54+
55+
```html
56+
<template>
57+
<div>{{text}}</div>
58+
</template>
59+
```
60+
61+
:-1: Examples of **incorrect** code`:
62+
63+
```html
64+
<template>
65+
<div>{{ text }}</div>
66+
</template>
67+
```

lib/rules/curly-bracket-spacing.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* @fileoverview Enforce spacing on the style of curly brackets.
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
docs: {
20+
description: 'Enforce spacing on the style of curly brackets.',
21+
category: 'Stylistic Issues',
22+
recommended: false
23+
},
24+
fixable: 'whitespace',
25+
schema: [
26+
{
27+
enum: ['always', 'never']
28+
}
29+
]
30+
},
31+
32+
create (context) {
33+
const options = context.options[0]
34+
const optSpaces = options !== 'never' ? 1 : 0
35+
const template = context.parserServices.getTemplateBodyTokenStore && context.parserServices.getTemplateBodyTokenStore()
36+
37+
// ----------------------------------------------------------------------
38+
// Helpers
39+
// ----------------------------------------------------------------------
40+
41+
function checkTokens (leftToken, rightToken) {
42+
if (leftToken.loc.end.line === rightToken.loc.start.line) {
43+
const spaces = rightToken.loc.start.column - leftToken.loc.end.column
44+
if (optSpaces !== spaces) {
45+
context.report({
46+
node: rightToken,
47+
loc: {
48+
start: leftToken.loc.end,
49+
end: rightToken.loc.start
50+
},
51+
message: 'Found {{spaces}} whitespaces, {{type}} expected.',
52+
data: {
53+
spaces: spaces === 0 ? 'none' : spaces,
54+
type: optSpaces ? '1' : 'none'
55+
},
56+
fix: (fixer) => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], optSpaces ? ' ' : '')
57+
})
58+
}
59+
}
60+
}
61+
62+
// ----------------------------------------------------------------------
63+
// Public
64+
// ----------------------------------------------------------------------
65+
66+
utils.registerTemplateBodyVisitor(context, {
67+
VExpressionContainer (node) {
68+
const tokens = template.getTokens(node, {
69+
includeComments: true,
70+
filter: token => token.type !== 'HTMLWhitespace' // When there is only whitespace between ignore it
71+
})
72+
73+
const startToken = tokens.shift()
74+
const endToken = tokens.pop()
75+
if (tokens.length > 0) {
76+
checkTokens(startToken, tokens[0])
77+
checkTokens(tokens[tokens.length - 1], endToken)
78+
} else {
79+
checkTokens(startToken, endToken)
80+
}
81+
}
82+
})
83+
84+
return { }
85+
}
86+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
},
4646
"dependencies": {
4747
"requireindex": "^1.1.0",
48-
"vue-eslint-parser": "2.0.0-beta.6"
48+
"vue-eslint-parser": "2.0.0-beta.7"
4949
},
5050
"devDependencies": {
5151
"@types/node": "^4.2.16",
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/**
2+
* @fileoverview Enforce spacing on the style of curly brackets.
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/curly-bracket-spacing')
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('curly-bracket-spacing', rule, {
24+
25+
valid: [
26+
{
27+
filename: 'test.vue',
28+
code: '<template></template>'
29+
},
30+
{
31+
filename: 'test.vue',
32+
code: '<template><div></div></template>'
33+
},
34+
{
35+
filename: 'test.vue',
36+
code: '<template> <div id=" "></div> </template>'
37+
},
38+
{
39+
filename: 'test.vue',
40+
code: '<template><div>{{ text }}</div></template>'
41+
},
42+
{
43+
filename: 'test.vue',
44+
code: '<template><div>{{ }}</div></template>'
45+
},
46+
{
47+
filename: 'test.vue',
48+
code: '<template><div>{{ }}</div></template>',
49+
options: ['always']
50+
},
51+
{
52+
filename: 'test.vue',
53+
code: '<template><div>{{}}</div></template>',
54+
options: ['never']
55+
},
56+
{
57+
filename: 'test.vue',
58+
code: '<template><div>{{text}}</div></template>',
59+
options: ['never']
60+
},
61+
{
62+
filename: 'test.vue',
63+
code: '<template><div>{{ text }}</div></template>',
64+
options: ['always']
65+
}
66+
],
67+
68+
invalid: [
69+
{
70+
filename: 'test.vue',
71+
code: '<template><div>{{ }}</div></template>',
72+
output: '<template><div>{{ }}</div></template>',
73+
options: ['always'],
74+
errors: [{
75+
message: 'Found 9 whitespaces, 1 expected.',
76+
type: 'VExpressionEnd'
77+
}]
78+
},
79+
{
80+
filename: 'test.vue',
81+
code: '<template><div>{{ text}}</div></template>',
82+
output: '<template><div>{{ text }}</div></template>',
83+
options: ['always'],
84+
errors: [{
85+
message: 'Found none whitespaces, 1 expected.',
86+
type: 'VExpressionEnd'
87+
}]
88+
},
89+
{
90+
filename: 'test.vue',
91+
code: '<template><div>{{text }}</div></template>',
92+
output: '<template><div>{{ text }}</div></template>',
93+
options: ['always'],
94+
errors: [{
95+
message: 'Found none whitespaces, 1 expected.',
96+
type: 'Identifier'
97+
}]
98+
},
99+
{
100+
filename: 'test.vue',
101+
code: '<template><div>{{ text}}</div></template>',
102+
output: '<template><div>{{text}}</div></template>',
103+
options: ['never'],
104+
errors: [{
105+
message: 'Found 1 whitespaces, none expected.',
106+
type: 'Identifier'
107+
}]
108+
},
109+
{
110+
filename: 'test.vue',
111+
code: '<template><div>{{text }}</div></template>',
112+
output: '<template><div>{{text}}</div></template>',
113+
options: ['never'],
114+
errors: [{
115+
message: 'Found 1 whitespaces, none expected.',
116+
type: 'VExpressionEnd'
117+
}]
118+
},
119+
{
120+
filename: 'test.vue',
121+
code: '<template><div>{{text}}</div></template>',
122+
output: '<template><div>{{ text }}</div></template>',
123+
options: ['always'],
124+
errors: [{
125+
message: 'Found none whitespaces, 1 expected.',
126+
type: 'Identifier'
127+
}, {
128+
message: 'Found none whitespaces, 1 expected.',
129+
type: 'VExpressionEnd'
130+
}]
131+
},
132+
{
133+
filename: 'test.vue',
134+
code: '<template><div>{{ text }}</div></template>',
135+
output: '<template><div>{{text}}</div></template>',
136+
options: ['never'],
137+
errors: [{
138+
message: 'Found 1 whitespaces, none expected.',
139+
type: 'Identifier'
140+
}, {
141+
message: 'Found 1 whitespaces, none expected.',
142+
type: 'VExpressionEnd'
143+
}]
144+
},
145+
{
146+
filename: 'test.vue',
147+
code: '<template><div>{{ text }}</div></template>',
148+
output: '<template><div>{{ text }}</div></template>',
149+
options: ['always'],
150+
errors: [{
151+
message: 'Found 3 whitespaces, 1 expected.',
152+
type: 'Identifier'
153+
}, {
154+
message: 'Found 3 whitespaces, 1 expected.',
155+
type: 'VExpressionEnd'
156+
}]
157+
},
158+
{
159+
filename: 'test.vue',
160+
code: '<template><div>{{ text }}</div></template>',
161+
output: '<template><div>{{text}}</div></template>',
162+
options: ['never'],
163+
errors: [{
164+
message: 'Found 3 whitespaces, none expected.',
165+
type: 'Identifier'
166+
}, {
167+
message: 'Found 3 whitespaces, none expected.',
168+
type: 'VExpressionEnd'
169+
}]
170+
}
171+
]
172+
})

0 commit comments

Comments
 (0)