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 |
|
127 | var assert = require('assert');
|
128 |
|
129 | var excludes = {
|
130 | 'IfStatement': ['else'],
|
131 | 'DoWhileStatement': ['while'],
|
132 | 'TryStatement': ['catch', 'finally'],
|
133 | 'CatchClause': ['finally'],
|
134 | 'FunctionExpression': ['.'],
|
135 | 'ArrowFunctionExpression': [')']
|
136 | };
|
137 |
|
138 | module.exports = function() {};
|
139 |
|
140 | module.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 | };
|