Skip to content
This repository was archived by the owner on Mar 23, 2024. It is now read-only.

Commit 1788d59

Browse files
hzoomarkelog
authored andcommitted
Update: requireCurlyBraces: make rule more flexible
Allow exceptions for return, break, continue, etc statements - "requireCurlyBraces": { "allExcept": ["return", "continue", "break", ...], "keywords": ["if", "else", "for", "while", ... ] } Fixes #244 Closes gh-1938
1 parent 9469688 commit 1788d59

2 files changed

Lines changed: 98 additions & 13 deletions

File tree

lib/rules/require-curly-braces.js

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
/**
22
* Requires curly braces after statements.
33
*
4-
* Types: `Array` or `Boolean`
4+
* Types: `Array` or `Boolean` or `Object`
55
*
6-
* Values: Array of quoted keywords or `true` to require curly braces after the following keywords:
6+
* Values:
7+
* - Array of quoted keywords
8+
* - `true` to require curly braces after the following keywords
9+
* - `Object`
10+
* - `'keywords'`
11+
* - Array of quoted keywords
12+
* - `'allExcept'`
13+
* - Array of keywords inside of the block that would allow curly braces
14+
* - Ex: ["return" , "continue", "break"]
715
*
816
* JSHint: [`curly`](http://jshint.com/docs/options/#curly)
917
*
@@ -45,19 +53,47 @@ module.exports = function() {};
4553

4654
module.exports.prototype = {
4755

48-
configure: function(statementTypes) {
56+
configure: function(options) {
4957
assert(
50-
Array.isArray(statementTypes) || statementTypes === true,
51-
this.getOptionName() + ' option requires array or true value'
58+
Array.isArray(options) || options === true || typeof options === 'object',
59+
this.getOptionName() + ' option requires array, true value, or object'
5260
);
5361

54-
if (statementTypes === true) {
55-
statementTypes = defaultKeywords;
62+
var keywordMap = {
63+
'return': 'ReturnStatement',
64+
'break': 'BreakStatement',
65+
'continue': 'ContinueStatement'
66+
};
67+
68+
if (options === true) {
69+
options = defaultKeywords;
70+
}
71+
72+
if (!Array.isArray(options)) {
73+
assert(
74+
Array.isArray(options.allExcept),
75+
this.getOptionName() + '.allExcept ' +
76+
'property requires an array value'
77+
);
78+
assert(
79+
Array.isArray(options.keywords) || options.keywords === true,
80+
this.getOptionName() + '.keywords ' +
81+
'property requires an array value or a value of true'
82+
);
83+
84+
if (options.keywords === true) {
85+
options.keywords = defaultKeywords;
86+
}
87+
88+
this._exceptions = options.allExcept.map(function(statementType) {
89+
return keywordMap[statementType];
90+
});
91+
options = options.keywords;
5692
}
5793

5894
this._typeIndex = {};
59-
for (var i = 0, l = statementTypes.length; i < l; i++) {
60-
this._typeIndex[statementTypes[i]] = true;
95+
for (var i = 0, l = options.length; i < l; i++) {
96+
this._typeIndex[options[i]] = true;
6197
}
6298
},
6399

@@ -66,6 +102,8 @@ module.exports.prototype = {
66102
},
67103

68104
check: function(file, errors) {
105+
var typeIndex = this._typeIndex;
106+
var exceptions = this._exceptions;
69107

70108
function isNotABlockStatement(node) {
71109
return node && node.type !== 'BlockStatement';
@@ -87,15 +125,17 @@ module.exports.prototype = {
87125
});
88126
}
89127

90-
var typeIndex = this._typeIndex;
91-
92128
if (typeIndex.if || typeIndex.else) {
93129
file.iterateNodesByType('IfStatement', function(node) {
94-
if (typeIndex.if && isNotABlockStatement(node.consequent)) {
130+
if (typeIndex.if && isNotABlockStatement(node.consequent) &&
131+
// check exceptions for if and else
132+
!(exceptions && exceptions.indexOf(node.consequent.type) !== -1)) {
95133
addError('If', node);
96134
}
97135
if (typeIndex.else && isNotABlockStatement(node.alternate) &&
98-
node.alternate.type !== 'IfStatement') {
136+
node.alternate.type !== 'IfStatement' &&
137+
// check exceptions for if and else
138+
!(exceptions && exceptions.indexOf(node.consequent.type) !== -1)) {
99139
addError('Else', file.getPrevToken(file.getFirstNodeToken(node.alternate)));
100140
}
101141
});

test/specs/rules/require-curly-braces.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,49 @@ describe('rules/require-curly-braces', function() {
170170
checker.configure({ requireCurlyBraces: ['else'] });
171171
expect(checker.checkString('if (x) { x++; } else if (x) { x++; }')).to.have.no.errors();
172172
});
173+
174+
describe('option with exceptions', function() {
175+
it('should report on if and else', function() {
176+
checker.configure({
177+
requireCurlyBraces: {
178+
allExcept: ['return', 'break', 'continue'],
179+
keywords: true
180+
}
181+
});
182+
183+
expect(checker.checkString('if (x) x++;')).to.have.errors();
184+
expect(checker.checkString('if (x) {x++} else x--;')).to.have.errors();
185+
expect(checker.checkString('for (x = 0; x < 10; x++) x++;')).to.have.errors();
186+
expect(checker.checkString('while (x) x++;')).to.have.errors();
187+
expect(checker.checkString('do x++; while(x < 5);')).to.have.errors();
188+
expect(checker.checkString('try {x++;} catch(e) throw e;')).to.have.errors();
189+
expect(checker.checkString('switch(\'4\'){ case \'4\': break; }')).to.have.errors();
190+
expect(checker.checkString('switch(\'4\'){ case \'4\': {break;} default: 1; }')).to.have.errors();
191+
expect(checker.checkString('with(x) console.log(toString());')).to.have.errors();
192+
});
193+
194+
it('should report on if and else', function() {
195+
checker.configure({
196+
requireCurlyBraces: {
197+
allExcept: ['return', 'break', 'continue'],
198+
keywords: ['if', 'else']
199+
}
200+
});
201+
202+
expect(checker.checkString('if (x) x++;')).to.have.errors();
203+
expect(checker.checkString('if (x) {x++} else x--;')).to.have.errors();
204+
});
205+
206+
it('should not report on if and else with exceptions', function() {
207+
checker.configure({
208+
requireCurlyBraces: {
209+
allExcept: ['return', 'break', 'continue'],
210+
keywords: ['if', 'else']
211+
}
212+
});
213+
214+
expect(checker.checkString('if (x) return;')).to.have.no.errors();
215+
expect(checker.checkString('if (x) return; else return;')).to.have.no.errors();
216+
});
217+
});
173218
});

0 commit comments

Comments
 (0)