UNPKG

6.67 kBJavaScriptView Raw
1/**
2 * Requires newline after blocks
3 *
4 * Type: `Boolean` or `Object`
5 *
6 * Values:
7 * - `true`: always require a newline after blocks
8 * - `Object`:
9 * - `"allExcept"`: `Array`
10 * - `"inCallExpressions"` Blocks don't need a line of padding in function argument lists
11 * - `"inNewExpressions"` Blocks don't need a line of padding in constructor argument lists
12 * - `"inArrayExpressions"` Blocks don't need a line of padding in arrays
13 * - `"inProperties"` Blocks don't need a line of padding as object properties
14 * - `"singleLine"` Blocks don't need a line of padding if they are on a single line
15 *
16 * #### Example
17 *
18 * ```js
19 * "requirePaddingNewLinesAfterBlocks": true
20 * "requirePaddingNewLinesAfterBlocks": {
21 * "allExcept": ["inCallExpressions", "inNewExpressions", "inArrayExpressions", "inProperties", "singleLine"]
22 * }
23 * ```
24 *
25 * ##### Valid
26 *
27 * ```js
28 * function () {
29 * for (var i = 0; i < 2; i++) {
30 * if (true) {
31 * return false;
32 * }
33 *
34 * continue;
35 * }
36 *
37 * var obj = {
38 * foo: function() {
39 * return 1;
40 * },
41 *
42 * bar: function() {
43 * return 2;
44 * }
45 * };
46 *
47 * func(
48 * function() {
49 * }
50 * );
51 *
52 * var a = [
53 * function() {
54 * },
55 *
56 * function() {
57 * }
58 * ]
59 *
60 * }
61 * ```
62 *
63 * ##### Valid for `{ "allExcept": ["inCallExpressions"] }`
64 *
65 * ```js
66 * func(
67 * 2,
68 * 3,
69 * function() {
70 * }
71 * );
72 * ```
73 *
74 * ##### Valid for `{ "allExcept": ["inNewExpressions"] }`
75 *
76 * ```js
77 * new SomeClass(
78 * 2,
79 * 3,
80 * function() {
81 * }
82 * );
83 * ```
84 *
85 * ##### Valid for `{ "allExcept": ["inArrayExpressions"] }`
86 *
87 * ```js
88 * var foo = [
89 * 2,
90 * 3,
91 * function() {
92 * }
93 * ];
94 * ```
95 * ##### Valid for `{ "allExcept": ["inProperties"] }`
96 *
97 * ```js
98 * var foo = {
99 * a: 2,
100 * b: function() {
101 * },
102 * c: 3
103 * ];
104 * ```
105 * ##### Valid for `{ "allExcept": ["singleLine"] }`
106 * ```js
107 * for (var i = 0; i < 10; ++i) {
108 * if (i % 2 === 0) { continue; }
109 * console.log('Its getting odd in here...');
110 * }
111 * ```
112 *
113 * ##### Invalid
114 *
115 * ```js
116 * function () {
117 * for (var i = 0; i < 2; i++) {
118 * if (true) {
119 * return false;
120 * }
121 * continue;
122 * }
123 * }
124 * ```
125 */
126
127var assert = require('assert');
128
129var excludes = {
130 'IfStatement': ['else'],
131 'DoWhileStatement': ['while'],
132 'TryStatement': ['catch', 'finally'],
133 'CatchClause': ['finally'],
134 'FunctionExpression': ['.'],
135 'ArrowFunctionExpression': [')']
136};
137
138module.exports = function() {};
139
140module.exports.prototype = {
141
142 configure: function(value) {
143 this.exceptions = {
144 'CallExpression': false,
145 'NewExpression': false,
146 'ArrayExpression': false,
147 'ObjectProperty': false,
148 'SingleLine': false
149 };
150
151 var optionName = this.getOptionName();
152
153 if (typeof value === 'object') {
154 assert(Array.isArray(value.allExcept), optionName + ' option requires "allExcept" ' +
155 'to be an array');
156 assert(value.allExcept.length > 0, optionName + ' option requires "allExcept" ' +
157 'to have at least one item or be set to `true`');
158
159 value.allExcept.forEach(function(except) {
160 if (except === 'inCallExpressions') {
161 this.exceptions.CallExpression = true;
162 } else if (except === 'inNewExpressions') {
163 this.exceptions.NewExpression = true;
164 } else if (except === 'inArrayExpressions') {
165 this.exceptions.ArrayExpression = true;
166 } else if (except === 'inProperties') {
167 this.exceptions.ObjectProperty = true;
168 } else if (except === 'singleLine') {
169 this.exceptions.SingleLine = true;
170 } else {
171 assert(false, optionName + ' option requires "allExcept" to only have ' +
172 'one of "inCallExpressions", "inNewExpressions",' +
173 '"inArrayExpressions", "inProperties" or "singleLine"');
174 }
175 }, this);
176 } else {
177 assert(value === true,
178 optionName + ' option requires true value or object'
179 );
180 }
181 },
182
183 getOptionName: function() {
184 return 'requirePaddingNewLinesAfterBlocks';
185 },
186
187 check: function(file, errors) {
188 function isException(node, parent, exceptions) {
189 var grandpa = parent.parentElement;
190
191 // Check if this block is used in call or array expression
192 if (grandpa && exceptions[grandpa.type]) {
193 return true;
194 }
195
196 var first = node.getFirstToken();
197 var last = node.getLastToken();
198
199 if (exceptions.SingleLine && file.isOnTheSameLine(first, last)) {
200 return true;
201 }
202
203 return false;
204 }
205
206 file.iterateNodesByType('BlockStatement', (function(node) {
207
208 var endToken = file.getLastNodeToken(node);
209 var parentElement = node.parentElement;
210 var tokens = {
211 next: endToken.getNextCodeToken(),
212 token: endToken
213 };
214
215 if (isException(node, parentElement, this.exceptions)) {
216 return;
217 }
218
219 while (tokens.next.type !== 'EOF') {
220 var excludeValues = excludes[parentElement.type];
221 if (excludeValues && excludeValues.indexOf(tokens.next.value) !== -1) {
222 return;
223 }
224
225 if (file.isOnTheSameLine(tokens.token, tokens.next)) {
226 endToken = tokens.next;
227 tokens.next = tokens.next.getNextCodeToken();
228 continue;
229 }
230
231 if (tokens.next.type === 'Punctuator' && (
232 tokens.next.value === '}' ||
233 tokens.next.value === ']' ||
234 tokens.next.value === '>' ||
235 tokens.next.value === ')')
236 ) {
237 return;
238 }
239
240 errors.assert.linesBetween({
241 token: tokens.token,
242 nextToken: tokens.next,
243 atLeast: 2,
244 message: 'Missing newline after block'
245 });
246
247 return;
248 }
249 }).bind(this));
250 }
251};