11/**
22 * Disallows newline before opening curly brace of all block statements.
33 *
4- * Type: `Boolean` or `Array`
4+ * Type: `Boolean` or `Array` or `Object`
55 *
66 * Values:
77 *
88 * - `true` always disallows newline before curly brace of block statements
99 * - `Array` specifies block-type keywords after which newlines are disallowed before curly brace
1010 * - Valid types include: `['if', 'else', 'try', 'catch', 'finally', 'do', 'while', 'for', 'function', 'class']`
11+ * - `Object`:
12+ * - `value`: `true` or an Array
13+ * - `allExcept`: Array of exceptions
14+ * - `"multiLine"`: if the conditions span on multiple lines, require a new line before the curly brace
1115 *
1216 * #### Example
1317 *
162166 * return x - 1;
163167 * }
164168 * ```
169+ *
170+ * #### Example
171+ *
172+ * ```js
173+ * "disallowNewlineBeforeBlockStatements": {
174+ * "value": true,
175+ * "allExcept": ["multiLine"]
176+ * }
177+ * ```
178+ *
179+ * ##### Valid
180+ *
181+ * ```js
182+ * function myFunc(x,
183+ * y)
184+ * {
185+ * return x + y;
186+ * }
187+ *
188+ * function foo() {
189+ * if (bar && baz &&
190+ * bat)
191+ * {
192+ * return true;
193+ * }
194+ * }
195+ * ```
196+ *
197+ * ##### Invalid
198+ *
199+ * ```js
200+ * function myFunc(x,
201+ * y) {
202+ * return x + y;
203+ * }
204+ *
205+ * function foo() {
206+ * if (bar && baz &&
207+ * bat) {
208+ * return true;
209+ * }
210+ * }
211+ * ```
165212 */
166213
167214var assert = require ( 'assert' ) ;
168215
169216module . exports = function ( ) { } ;
170217
171218module . exports . prototype = {
172- configure : function ( settingValue ) {
219+ configure : function ( options ) {
220+ var settingValue ;
221+ this . _hasMultiLineEx = false ;
222+ if ( options . constructor === Object ) {
223+ settingValue = options . value ;
224+ if ( options . allExcept ) {
225+ assert (
226+ Array . isArray ( options . allExcept ) && options . allExcept . length === 1 &&
227+ options . allExcept [ 0 ] === 'multiLine' ,
228+ 'allExcept option must be an array whose values can be only `multiLine`'
229+ ) ;
230+ this . _hasMultiLineEx = true ;
231+ }
232+ } else {
233+ settingValue = options ;
234+ }
173235 assert (
174236 Array . isArray ( settingValue ) && settingValue . length || settingValue === true ,
175237 'disallowNewlineBeforeBlockStatements option requires non-empty array value or true value'
@@ -184,6 +246,23 @@ module.exports.prototype = {
184246
185247 check : function ( file , errors ) {
186248 var setting = this . _setting ;
249+ var hasMultiLineEx = this . _hasMultiLineEx ;
250+
251+ function assertSameLine ( token , nextToken ) {
252+ errors . assert . sameLine ( {
253+ token : token ,
254+ nextToken : nextToken ,
255+ message : 'Newline before curly brace for block statement is disallowed'
256+ } ) ;
257+ }
258+ function assertDifferentLine ( token , nextToken ) {
259+ errors . assert . differentLine ( {
260+ token : token ,
261+ nextToken : nextToken ,
262+ message : 'Newline before curly brace for block statement is required'
263+ } ) ;
264+ }
265+
187266 file . iterateNodesByType ( [ 'BlockStatement' , 'ClassBody' ] , function ( node ) {
188267 if ( isBareBlock ( node ) ) {
189268 return ;
@@ -193,11 +272,40 @@ module.exports.prototype = {
193272 var openingBrace = file . getFirstNodeToken ( node ) ;
194273 var prevToken = file . getPrevToken ( openingBrace ) ;
195274
196- errors . assert . sameLine ( {
197- token : prevToken ,
198- nextToken : openingBrace ,
199- message : 'Newline before curly brace for block statement is disallowed'
200- } ) ;
275+ if ( hasMultiLineEx !== true ) {
276+ assertSameLine ( prevToken , openingBrace ) ;
277+ return ;
278+ }
279+
280+ // Check if the 'conditions' span on multiple lines.
281+ // The simplest way is to check if the round braces are on different lines.
282+ //
283+ // For example:
284+ // // same line
285+ // for (var i = 0; i < length; i++) {
286+ // }
287+ //
288+ // // different lines:
289+ // for (var i = 0;
290+ // i < length;
291+ // i++)
292+ // {
293+ // }
294+ var parentNode = node . parentNode ;
295+ var parentNextToken = file . getFirstNodeToken ( parentNode ) ;
296+ var openingRoundBrace = file . findNextToken ( parentNextToken , 'Punctuator' , '(' ) ;
297+ var closingRoundBrace = file . findPrevToken ( openingBrace , 'Punctuator' , ')' ) ;
298+
299+ // Not always the conditions are there: to check look for the presence of round braces.
300+ // For example:
301+ // try {
302+ // } ...
303+ if ( openingRoundBrace && closingRoundBrace &&
304+ openingRoundBrace . loc . start . line !== closingRoundBrace . loc . end . line ) {
305+ assertDifferentLine ( prevToken , openingBrace ) ;
306+ } else {
307+ assertSameLine ( prevToken , openingBrace ) ;
308+ }
201309 }
202310 } ) ;
203311 }
0 commit comments