UNPKG

6.32 kBJavaScriptView Raw
1/**
2 * Requires blocks to begin and end with 2 newlines
3 *
4 * Types: `Boolean`, `Integer`, `Object`
5 *
6 * Values:
7 * - `true` validates all non-empty blocks
8 * - `Integer` specifies a minimum number of lines containing elements in the block before validating
9 * - `Object` (at least one of properties must be true):
10 * - `'open'`
11 * - `true` validates that there is a newline after the opening brace in a block
12 * - `false` ignores the newline validation after the opening brace in a block
13 * - `'close'`
14 * - `true` validates that there is a newline before the closing brace in a block
15 * - `false` ignores the newline validation before the closing brace in a block
16 * - `'allExcept'` array of exceptions:
17 * - `'conditionals'` ignores conditional (if, else if, else) blocks
18 * - `'functions'` ignores function blocks
19 *
20 * #### Example
21 *
22 * ```js
23 * "requirePaddingNewlinesInBlocks": true
24 * "requirePaddingNewlinesInBlocks": 1
25 * "requirePaddingNewlinesInBlocks": { "open": true, "close": false }
26 * "requirePaddingNewlinesInBlocks": { "allExcept": [ "conditionals" ] }
27 * "requirePaddingNewlinesInBlocks": { "open": true, "close": false, allExcept: ['conditionals'] }
28 * ```
29 *
30 * ##### Valid for mode `true` or `{ "open": true, "close": true }`
31 *
32 * ```js
33 * if (true) {
34 *
35 * doSomething();
36 *
37 * }
38 * var abc = function() {};
39 * ```
40 *
41 * ##### Invalid
42 *
43 * ```js
44 * if (true) {doSomething();}
45 * if (true) {
46 * doSomething();
47 * }
48 * ```
49 *
50 * ##### Valid for mode `1`
51 *
52 * ```js
53 * if (true) {
54 *
55 * doSomething();
56 * doSomethingElse();
57 *
58 * }
59 * if (true) {
60 * doSomething();
61 * }
62 * if (true) { doSomething(); }
63 * var abc = function() {};
64 * ```
65 *
66 * ##### Invalid
67 *
68 * ```js
69 * if (true) { doSomething(); doSomethingElse(); }
70 * if (true) {
71 * doSomething();
72 * doSomethingElse();
73 * }
74 * ```
75 *
76 * ##### Valid for mode `{ "open": true, "close": false }`
77 *
78 * ```js
79 * if (true) {
80 *
81 * doSomething();
82 * }
83 * var abc = function() {};
84 * ```
85 *
86 * ##### Invalid
87 *
88 * ```js
89 * if (true) {doSomething();}
90 * if (true) {
91 * doSomething();
92 * }
93 * if (true) {
94 * doSomething();
95 *
96 * }
97 * ```
98 *
99 * ##### Valid for `{ allExcept: ['conditionals'] }`
100 *
101 * ```js
102 * if (true) {
103 * doSomething();
104 * }
105 *
106 * function (foo) {
107 *
108 * return bar;
109 *
110 * }
111 * ```
112 *
113 * ##### Invalid
114 *
115 * ```js
116 * function (foo) {
117 * return bar;
118 * }
119 * ```
120 *
121 * ##### Valid for `{ "open": true, "close": false, allExcept: ['conditionals'] }`
122 *
123 * ```js
124 * function (foo) {
125 *
126 * return bar;
127 * }
128 *
129 * if (true) {
130 * doSomething();
131 * }
132 * ```
133 *
134 * ##### Invalid
135 *
136 * ```js
137 * function (foo) {
138 * return bar;
139 *
140 * }
141 * ```
142 */
143
144var assert = require('assert');
145
146module.exports = function() {};
147
148module.exports.prototype = {
149
150 configure: function(options) {
151 var optionName = this.getOptionName();
152
153 assert(
154 options === true || typeof options === 'number' || typeof options === 'object',
155 optionName + ' option requires the value true, an Integer or an object'
156 );
157
158 this._checkOpen = true;
159 this._checkClose = true;
160 this._minLines = 0;
161
162 if (typeof options === 'object') {
163 assert(options.allExcept || options.open || options.close,
164 optionName + 'option requires either "open", "close", "allExcept"');
165
166 if (options.allExcept) {
167 assert(Array.isArray(options.allExcept), optionName + ' option requires "allExcept" to be an array');
168 assert(options.allExcept.length > 0, optionName + ' option requires "allExcept" to have at least one ' +
169 'item or be set to `true`');
170 this._exceptConditionals = options.allExcept.indexOf('conditionals') > -1;
171 this._exceptFunctions = options.allExcept.indexOf('functions') > -1;
172 }
173
174 if (options.open || options.close) {
175 assert(typeof options.open === 'boolean' && typeof options.close === 'boolean',
176 this.getOptionName() + ' option requires the "open" and "close" ' +
177 'properties to be booleans');
178
179 this._checkOpen = options.open;
180 this._checkClose = options.close;
181 }
182 } else if (typeof options === 'number') {
183 this._minLines = options;
184 } else {
185 assert(options === true, this.getOptionName() + ' option requires either a true value, or an object');
186 }
187 },
188
189 getOptionName: function() {
190 return 'requirePaddingNewlinesInBlocks';
191 },
192
193 check: function(file, errors) {
194 var minLines = this._minLines;
195 var exceptConditionals = this._exceptConditionals;
196 var exceptFunctions = this._exceptFunctions;
197 var checkOpen = this._checkOpen;
198 var checkClose = this._checkClose;
199
200 file.iterateNodesByType('BlockStatement', function(node) {
201 var openingBracket;
202 var closingBracket;
203
204 if (node.body.length <= minLines) {
205 return;
206 }
207
208 if (exceptConditionals && node.parentElement.type === 'IfStatement' ||
209 exceptFunctions && (node.parentElement.type === 'FunctionExpression' ||
210 node.parentElement.type === 'FunctionDeclaration')) {
211 return;
212 }
213
214 if (checkOpen === true) {
215 openingBracket = node.getFirstToken();
216
217 errors.assert.linesBetween({
218 token: openingBracket,
219 nextToken: file.getNextToken(openingBracket, {includeComments: true}),
220 atLeast: 2,
221 message: 'Expected a padding newline after opening curly brace'
222 });
223 }
224
225 if (checkClose === true) {
226 closingBracket = file.getLastNodeToken(node);
227
228 errors.assert.linesBetween({
229 token: file.getPrevToken(closingBracket, {includeComments: true}),
230 nextToken: closingBracket,
231 atLeast: 2,
232 message: 'Expected a padding newline before closing curly brace'
233 });
234 }
235 });
236 }
237};