eslint 0.22.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +111 -95
  3. package/bin/eslint.js +41 -41
  4. package/conf/environments.js +87 -81
  5. package/conf/eslint.json +186 -179
  6. package/lib/api.js +13 -12
  7. package/lib/cli-engine.js +441 -451
  8. package/lib/cli.js +196 -196
  9. package/lib/config-initializer.js +145 -145
  10. package/lib/config-validator.js +110 -110
  11. package/lib/config.js +428 -416
  12. package/lib/eslint.js +1072 -1073
  13. package/lib/file-finder.js +167 -167
  14. package/lib/formatters/checkstyle.js +68 -68
  15. package/lib/formatters/compact.js +53 -53
  16. package/lib/formatters/jslint-xml.js +40 -40
  17. package/lib/formatters/junit.js +63 -63
  18. package/lib/formatters/stylish.js +90 -90
  19. package/lib/formatters/tap.js +86 -86
  20. package/lib/ignored-paths.js +137 -137
  21. package/lib/load-rules.js +39 -39
  22. package/lib/options.js +132 -126
  23. package/lib/rule-context.js +107 -107
  24. package/lib/rules/accessor-pairs.js +65 -65
  25. package/lib/rules/array-bracket-spacing.js +180 -0
  26. package/lib/rules/block-scoped-var.js +339 -320
  27. package/lib/rules/brace-style.js +228 -228
  28. package/lib/rules/camelcase.js +111 -111
  29. package/lib/rules/comma-dangle.js +67 -64
  30. package/lib/rules/comma-spacing.js +191 -191
  31. package/lib/rules/comma-style.js +195 -195
  32. package/lib/rules/complexity.js +94 -94
  33. package/lib/rules/computed-property-spacing.js +144 -0
  34. package/lib/rules/consistent-return.js +75 -75
  35. package/lib/rules/consistent-this.js +119 -119
  36. package/lib/rules/constructor-super.js +108 -0
  37. package/lib/rules/curly.js +109 -109
  38. package/lib/rules/default-case.js +66 -66
  39. package/lib/rules/dot-location.js +63 -63
  40. package/lib/rules/dot-notation.js +119 -119
  41. package/lib/rules/eol-last.js +38 -38
  42. package/lib/rules/eqeqeq.js +96 -96
  43. package/lib/rules/func-names.js +45 -45
  44. package/lib/rules/func-style.js +49 -49
  45. package/lib/rules/generator-star-spacing.js +104 -87
  46. package/lib/rules/generator-star.js +76 -76
  47. package/lib/rules/global-strict.js +49 -49
  48. package/lib/rules/guard-for-in.js +32 -32
  49. package/lib/rules/handle-callback-err.js +81 -124
  50. package/lib/rules/indent.js +486 -486
  51. package/lib/rules/key-spacing.js +325 -325
  52. package/lib/rules/linebreak-style.js +44 -44
  53. package/lib/rules/lines-around-comment.js +228 -160
  54. package/lib/rules/max-depth.js +89 -89
  55. package/lib/rules/max-len.js +76 -76
  56. package/lib/rules/max-nested-callbacks.js +73 -73
  57. package/lib/rules/max-params.js +45 -45
  58. package/lib/rules/max-statements.js +61 -61
  59. package/lib/rules/new-cap.js +224 -224
  60. package/lib/rules/new-parens.js +29 -29
  61. package/lib/rules/newline-after-var.js +127 -127
  62. package/lib/rules/no-alert.js +153 -153
  63. package/lib/rules/no-array-constructor.js +31 -31
  64. package/lib/rules/no-bitwise.js +57 -57
  65. package/lib/rules/no-caller.js +29 -29
  66. package/lib/rules/no-catch-shadow.js +52 -52
  67. package/lib/rules/no-comma-dangle.js +45 -45
  68. package/lib/rules/no-cond-assign.js +123 -123
  69. package/lib/rules/no-console.js +27 -27
  70. package/lib/rules/no-constant-condition.js +73 -73
  71. package/lib/rules/no-continue.js +23 -23
  72. package/lib/rules/no-control-regex.js +58 -58
  73. package/lib/rules/no-debugger.js +22 -22
  74. package/lib/rules/no-delete-var.js +25 -25
  75. package/lib/rules/no-div-regex.js +27 -27
  76. package/lib/rules/no-dupe-args.js +89 -85
  77. package/lib/rules/no-dupe-keys.js +43 -43
  78. package/lib/rules/no-duplicate-case.js +67 -67
  79. package/lib/rules/no-else-return.js +125 -125
  80. package/lib/rules/no-empty-character-class.js +43 -43
  81. package/lib/rules/no-empty-class.js +45 -45
  82. package/lib/rules/no-empty-label.js +27 -27
  83. package/lib/rules/no-empty.js +49 -49
  84. package/lib/rules/no-eq-null.js +29 -29
  85. package/lib/rules/no-eval.js +26 -26
  86. package/lib/rules/no-ex-assign.js +42 -42
  87. package/lib/rules/no-extend-native.js +103 -103
  88. package/lib/rules/no-extra-bind.js +81 -81
  89. package/lib/rules/no-extra-boolean-cast.js +71 -71
  90. package/lib/rules/no-extra-parens.js +368 -355
  91. package/lib/rules/no-extra-semi.js +70 -23
  92. package/lib/rules/no-extra-strict.js +86 -86
  93. package/lib/rules/no-fallthrough.js +97 -97
  94. package/lib/rules/no-floating-decimal.js +30 -30
  95. package/lib/rules/no-func-assign.js +83 -83
  96. package/lib/rules/no-implied-eval.js +76 -76
  97. package/lib/rules/no-inline-comments.js +49 -49
  98. package/lib/rules/no-inner-declarations.js +78 -78
  99. package/lib/rules/no-invalid-regexp.js +53 -53
  100. package/lib/rules/no-irregular-whitespace.js +135 -135
  101. package/lib/rules/no-iterator.js +28 -28
  102. package/lib/rules/no-label-var.js +64 -64
  103. package/lib/rules/no-labels.js +44 -44
  104. package/lib/rules/no-lone-blocks.js +106 -27
  105. package/lib/rules/no-lonely-if.js +30 -30
  106. package/lib/rules/no-loop-func.js +58 -58
  107. package/lib/rules/no-mixed-requires.js +165 -165
  108. package/lib/rules/no-mixed-spaces-and-tabs.js +74 -74
  109. package/lib/rules/no-multi-spaces.js +119 -119
  110. package/lib/rules/no-multi-str.js +43 -43
  111. package/lib/rules/no-multiple-empty-lines.js +98 -98
  112. package/lib/rules/no-native-reassign.js +62 -62
  113. package/lib/rules/no-negated-in-lhs.js +25 -25
  114. package/lib/rules/no-nested-ternary.js +24 -24
  115. package/lib/rules/no-new-func.js +25 -25
  116. package/lib/rules/no-new-object.js +25 -25
  117. package/lib/rules/no-new-require.js +25 -25
  118. package/lib/rules/no-new-wrappers.js +26 -26
  119. package/lib/rules/no-new.js +27 -27
  120. package/lib/rules/no-obj-calls.js +28 -28
  121. package/lib/rules/no-octal-escape.js +39 -39
  122. package/lib/rules/no-octal.js +25 -25
  123. package/lib/rules/no-param-reassign.js +87 -87
  124. package/lib/rules/no-path-concat.js +39 -39
  125. package/lib/rules/no-plusplus.js +24 -24
  126. package/lib/rules/no-process-env.js +30 -30
  127. package/lib/rules/no-process-exit.js +33 -33
  128. package/lib/rules/no-proto.js +28 -28
  129. package/lib/rules/no-redeclare.js +68 -68
  130. package/lib/rules/no-regex-spaces.js +35 -35
  131. package/lib/rules/no-reserved-keys.js +56 -56
  132. package/lib/rules/no-restricted-modules.js +85 -85
  133. package/lib/rules/no-return-assign.js +53 -24
  134. package/lib/rules/no-script-url.js +34 -34
  135. package/lib/rules/no-self-compare.js +29 -29
  136. package/lib/rules/no-sequences.js +94 -94
  137. package/lib/rules/no-shadow-restricted-names.js +51 -51
  138. package/lib/rules/no-shadow.js +181 -136
  139. package/lib/rules/no-space-before-semi.js +98 -98
  140. package/lib/rules/no-spaced-func.js +37 -37
  141. package/lib/rules/no-sparse-arrays.js +33 -33
  142. package/lib/rules/no-sync.js +30 -30
  143. package/lib/rules/no-ternary.js +24 -24
  144. package/lib/rules/no-this-before-super.js +144 -0
  145. package/lib/rules/no-throw-literal.js +33 -33
  146. package/lib/rules/no-trailing-spaces.js +74 -63
  147. package/lib/rules/no-undef-init.js +28 -28
  148. package/lib/rules/no-undef.js +92 -92
  149. package/lib/rules/no-undefined.js +27 -27
  150. package/lib/rules/no-underscore-dangle.js +73 -73
  151. package/lib/rules/no-unexpected-multiline.js +58 -0
  152. package/lib/rules/no-unneeded-ternary.js +48 -48
  153. package/lib/rules/no-unreachable.js +98 -98
  154. package/lib/rules/no-unused-expressions.js +76 -76
  155. package/lib/rules/no-unused-vars.js +252 -250
  156. package/lib/rules/no-use-before-define.js +105 -105
  157. package/lib/rules/no-var.js +26 -26
  158. package/lib/rules/no-void.js +28 -28
  159. package/lib/rules/no-warning-comments.js +102 -102
  160. package/lib/rules/no-with.js +22 -22
  161. package/lib/rules/no-wrap-func.js +65 -65
  162. package/lib/rules/object-curly-spacing.js +231 -206
  163. package/lib/rules/object-shorthand.js +74 -73
  164. package/lib/rules/one-var.js +311 -304
  165. package/lib/rules/operator-assignment.js +118 -118
  166. package/lib/rules/operator-linebreak.js +114 -114
  167. package/lib/rules/padded-blocks.js +98 -98
  168. package/lib/rules/prefer-const.js +91 -0
  169. package/lib/rules/quote-props.js +72 -72
  170. package/lib/rules/quotes.js +92 -92
  171. package/lib/rules/radix.js +41 -41
  172. package/lib/rules/semi-spacing.js +167 -167
  173. package/lib/rules/semi.js +136 -136
  174. package/lib/rules/sort-vars.js +49 -49
  175. package/lib/rules/space-after-function-name.js +49 -49
  176. package/lib/rules/space-after-keywords.js +82 -82
  177. package/lib/rules/space-before-blocks.js +91 -91
  178. package/lib/rules/space-before-function-paren.js +139 -139
  179. package/lib/rules/space-before-function-parentheses.js +139 -139
  180. package/lib/rules/space-in-brackets.js +305 -305
  181. package/lib/rules/space-in-parens.js +281 -281
  182. package/lib/rules/space-infix-ops.js +106 -106
  183. package/lib/rules/space-return-throw-case.js +38 -38
  184. package/lib/rules/space-unary-ops.js +124 -133
  185. package/lib/rules/spaced-comment.js +143 -0
  186. package/lib/rules/spaced-line-comment.js +89 -89
  187. package/lib/rules/strict.js +242 -242
  188. package/lib/rules/use-isnan.js +26 -26
  189. package/lib/rules/valid-jsdoc.js +215 -215
  190. package/lib/rules/valid-typeof.js +42 -42
  191. package/lib/rules/vars-on-top.js +115 -115
  192. package/lib/rules/wrap-iife.js +48 -48
  193. package/lib/rules/wrap-regex.js +38 -38
  194. package/lib/rules/yoda.js +242 -225
  195. package/lib/rules.js +88 -88
  196. package/lib/timing.js +109 -109
  197. package/lib/token-store.js +201 -201
  198. package/lib/util/traverse.js +105 -105
  199. package/lib/util.js +125 -85
  200. package/package.json +6 -6
  201. package/CHANGELOG.md +0 -1638
@@ -1,486 +1,486 @@
1
- /**
2
- * @fileoverview This option sets a specific tab width for your code
3
- * This rule has been ported and modified from JSCS.
4
- * @author Dmitriy Shekhovtsov
5
- * @copyright 2015 Dmitriy Shekhovtsov. All rights reserved.
6
- * @copyright 2013 Dulin Marat and other contributors.
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining
9
- * a copy of this software and associated documentation files (the
10
- * "Software"), to deal in the Software without restriction, including
11
- * without limitation the rights to use, copy, modify, merge, publish,
12
- * distribute, sublicense, and/or sell copies of the Software, and to
13
- * permit persons to whom the Software is furnished to do so, subject to
14
- * the following conditions:
15
- *
16
- * The above copyright notice and this permission notice shall be
17
- * included in all copies or substantial portions of the Software.
18
- *
19
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
- */
27
- /*eslint no-use-before-define:[2, "nofunc"]*/
28
- "use strict";
29
-
30
- //------------------------------------------------------------------------------
31
- // Rule Definition
32
- //------------------------------------------------------------------------------
33
-
34
- module.exports = function (context) {
35
- // indentation defaults: 4 spaces
36
- var indentChar = " ";
37
- var indentSize = 4;
38
- var options = {indentSwitchCase: false};
39
-
40
- var lines = null;
41
- var indentStack = [0];
42
- var linesToCheck = null;
43
- var breakIndents = null;
44
-
45
- if (context.options.length) {
46
- if (context.options[0] === "tab") {
47
- indentChar = "\t";
48
- indentSize = 1;
49
- } else /* istanbul ignore else : this will be caught by options validation */ if (typeof context.options[0] === "number") {
50
- indentSize = context.options[0];
51
- }
52
-
53
- if (context.options[1]) {
54
- var opts = context.options[1];
55
- options.indentSwitchCase = opts.indentSwitchCase === true;
56
- }
57
- }
58
-
59
- var blockParents = [
60
- "IfStatement",
61
- "WhileStatement",
62
- "DoWhileStatement",
63
- "ForStatement",
64
- "ForInStatement",
65
- "ForOfStatement",
66
- "FunctionDeclaration",
67
- "FunctionExpression",
68
- "ArrowExpression",
69
- "CatchClause",
70
- "WithStatement"
71
- ];
72
-
73
- var indentableNodes = {
74
- BlockStatement: "body",
75
- Program: "body",
76
- ObjectExpression: "properties",
77
- ArrayExpression: "elements",
78
- SwitchStatement: "cases"
79
- };
80
-
81
- if (options.indentSwitchCase) {
82
- indentableNodes.SwitchCase = "consequent";
83
- }
84
-
85
- //--------------------------------------------------------------------------
86
- // Helpers
87
- //--------------------------------------------------------------------------
88
-
89
- /**
90
- * Mark line to be checked
91
- * @param {Number} line - line number
92
- * @returns {void}
93
- */
94
- function markCheckLine(line) {
95
- linesToCheck[line].check = true;
96
- }
97
-
98
- /**
99
- * Mark line with targeted node to be checked
100
- * @param {ASTNode} checkNode - targeted node
101
- * @returns {void}
102
- */
103
- function markCheck(checkNode) {
104
- markCheckLine(checkNode.loc.start.line - 1);
105
- }
106
-
107
- /**
108
- * Sets pushing indent of current node
109
- * @param {ASTNode} node - targeted node
110
- * @param {Number} indents - indents count to push
111
- * @returns {void}
112
- */
113
- function markPush(node, indents) {
114
- linesToCheck[node.loc.start.line - 1].push.push(indents);
115
- }
116
-
117
- /**
118
- * Marks line as outdent, end of block statement for example
119
- * @param {ASTNode} node - targeted node
120
- * @param {Number} outdents - count of outedents in targeted line
121
- * @returns {void}
122
- */
123
- function markPop(node, outdents) {
124
- linesToCheck[node.loc.end.line - 1].pop.push(outdents);
125
- }
126
-
127
- /**
128
- * Set alt push for current node
129
- * @param {ASTNode} node - targeted node
130
- * @returns {void}
131
- */
132
- function markPushAlt(node) {
133
- linesToCheck[node.loc.start.line - 1].pushAltLine.push(node.loc.end.line - 1);
134
- }
135
-
136
- /**
137
- * Marks end of node block to be checked
138
- * and marks targeted node as indent pushing
139
- * @param {ASTNode} pushNode - targeted node
140
- * @param {Number} indents - indent count to push
141
- * @returns {void}
142
- */
143
- function markPushAndEndCheck(pushNode, indents) {
144
- markPush(pushNode, indents);
145
- markCheckLine(pushNode.loc.end.line - 1);
146
- }
147
-
148
- /**
149
- * Mark node as switch case statement
150
- * and set push\pop indentation changes
151
- * @param {ASTNode} caseNode - targeted node
152
- * @param {ASTNode[]} children - consequent child nodes of case node
153
- * @returns {void}
154
- */
155
- function markCase(caseNode, children) {
156
- var outdentNode = getCaseOutdent(children);
157
-
158
- if (outdentNode) {
159
- // If a case statement has a `break` as a direct child and it is the
160
- // first one encountered, use it as the example for all future case indentation
161
- if (breakIndents === null) {
162
- breakIndents = (caseNode.loc.start.column === outdentNode.loc.start.column) ? 1 : 0;
163
- }
164
- markPop(outdentNode, breakIndents);
165
- } else {
166
- markPop(caseNode, 0);
167
- }
168
- }
169
-
170
- /**
171
- * Mark child nodes to be checked later of targeted node,
172
- * only if child node not in same line as targeted one
173
- * (if child and parent nodes wrote in single line)
174
- * @param {ASTNode} node - targeted node
175
- * @returns {void}
176
- */
177
- function markChildren(node) {
178
- getChildren(node).forEach(function(childNode) {
179
- if (childNode.loc.start.line !== node.loc.start.line || node.type === "Program") {
180
- markCheck(childNode);
181
- }
182
- });
183
- }
184
-
185
- /**
186
- * Mark child block as scope pushing and mark to check
187
- * @param {ASTNode} node - target node
188
- * @param {String} property - target node property containing child
189
- * @returns {void}
190
- */
191
- function markAlternateBlockStatement(node, property) {
192
- var child = node[property];
193
- if (child && child.type === "BlockStatement") {
194
- markCheck(child);
195
- }
196
- }
197
-
198
- /**
199
- * Checks whether node is multiline or single line
200
- * @param {ASTNode} node - target node
201
- * @returns {boolean} - is multiline node
202
- */
203
- function isMultiline(node) {
204
- return node.loc.start.line !== node.loc.end.line;
205
- }
206
-
207
- /**
208
- * Get switch case statement outdent node if any
209
- * @param {ASTNode[]} caseChildren - case statement childs
210
- * @returns {ASTNode} - outdent node
211
- */
212
- function getCaseOutdent(caseChildren) {
213
- var outdentNode;
214
- caseChildren.some(function(node) {
215
- if (node.type === "BreakStatement") {
216
- outdentNode = node;
217
- return true;
218
- }
219
- });
220
-
221
- return outdentNode;
222
- }
223
-
224
- /**
225
- * Returns block containing node
226
- * @param {ASTNode} node - targeted node
227
- * @returns {ASTNode} - block node
228
- */
229
- function getBlockNodeToMark(node) {
230
- var parent = node.parent;
231
-
232
- // The parent of an else is the entire if/else block. To avoid over indenting
233
- // in the case of a non-block if with a block else, mark push where the else starts,
234
- // not where the if starts!
235
- if (parent.type === "IfStatement" && parent.alternate === node) {
236
- return node;
237
- }
238
-
239
- // The end line to check of a do while statement needs to be the location of the
240
- // closing curly brace, not the while statement, to avoid marking the last line of
241
- // a multiline while as a line to check.
242
- if (parent.type === "DoWhileStatement") {
243
- return node;
244
- }
245
-
246
- // Detect bare blocks: a block whose parent doesn"t expect blocks in its syntax specifically.
247
- if (blockParents.indexOf(parent.type) === -1) {
248
- return node;
249
- }
250
-
251
- return parent;
252
- }
253
-
254
- /**
255
- * Get node's children
256
- * @param {ASTNode} node - current node
257
- * @returns {ASTNode[]} - children
258
- */
259
- function getChildren(node) {
260
- var childrenProperty = indentableNodes[node.type];
261
- return node[childrenProperty];
262
- }
263
-
264
- /**
265
- * Gets indentation in line `i`
266
- * @param {Number} i - number of line to get indentation
267
- * @returns {Number} - count of indentation symbols
268
- */
269
- function getIndentationFromLine(i) {
270
- var rNotIndentChar = new RegExp("[^" + indentChar + "]");
271
- var firstContent = lines[i].search(rNotIndentChar);
272
- if (firstContent === -1) {
273
- firstContent = lines[i].length;
274
- }
275
- return firstContent;
276
- }
277
-
278
- /**
279
- * Compares expected and actual indentation
280
- * and reports any violations
281
- * @param {ASTNode} node - node used only for reporting
282
- * @returns {void}
283
- */
284
- function checkIndentations(node) {
285
- linesToCheck.forEach(function(line, i) {
286
- var actualIndentation = getIndentationFromLine(i);
287
- var expectedIndentation = getExpectedIndentation(line, actualIndentation);
288
-
289
- if (line.check) {
290
-
291
- if (actualIndentation !== expectedIndentation) {
292
- context.report(node,
293
- {line: i + 1, column: expectedIndentation},
294
- "Expected indentation of " + expectedIndentation + " characters.");
295
- // correct the indentation so that future lines
296
- // can be validated appropriately
297
- actualIndentation = expectedIndentation;
298
- }
299
- }
300
-
301
- if (line.push.length) {
302
- pushExpectedIndentations(line, actualIndentation);
303
- }
304
- });
305
- }
306
-
307
- /**
308
- * Counts expected indentation for given line number
309
- * @param {Number} line - line number
310
- * @param {Number} actual - actual indentation
311
- * @returns {number} - expected indentation
312
- */
313
- function getExpectedIndentation(line, actual) {
314
- var outdent = indentSize * Math.max.apply(null, line.pop);
315
-
316
- var idx = indentStack.length - 1;
317
- var expected = indentStack[idx];
318
-
319
- if (!Array.isArray(expected)) {
320
- expected = [expected];
321
- }
322
-
323
- expected = expected.map(function(value) {
324
- if (line.pop.length) {
325
- value -= outdent;
326
- }
327
-
328
- return value;
329
- }).reduce(function(previous, current) {
330
- // when the expected is an array, resolve the value
331
- // back into a Number by checking both values are the actual indentation
332
- return actual === current ? current : previous;
333
- });
334
-
335
- indentStack[idx] = expected;
336
-
337
- line.pop.forEach(function() {
338
- indentStack.pop();
339
- });
340
-
341
- return expected;
342
- }
343
-
344
- /**
345
- * Store in stack expected indentations
346
- * @param {Number} line - current line
347
- * @param {Number} actualIndentation - actual indentation at current line
348
- * @returns {void}
349
- */
350
- function pushExpectedIndentations(line, actualIndentation) {
351
- var indents = Math.max.apply(null, line.push);
352
- var expected = actualIndentation + (indentSize * indents);
353
-
354
- // when a line has alternate indentations, push an array of possible values
355
- // on the stack, to be resolved when checked against an actual indentation
356
- if (line.pushAltLine.length) {
357
- expected = [expected];
358
- line.pushAltLine.forEach(function(altLine) {
359
- expected.push(getIndentationFromLine(altLine) + (indentSize * indents));
360
- });
361
- }
362
-
363
- line.push.forEach(function() {
364
- indentStack.push(expected);
365
- });
366
- }
367
-
368
- //--------------------------------------------------------------------------
369
- // Public
370
- //--------------------------------------------------------------------------
371
-
372
- return {
373
- "Program": function (node) {
374
- lines = context.getSourceLines();
375
- linesToCheck = lines.map(function () {
376
- return {
377
- push: [],
378
- pushAltLine: [],
379
- pop: [],
380
- check: false
381
- };
382
- });
383
-
384
- if (!isMultiline(node)) {
385
- return;
386
- }
387
-
388
- markChildren(node);
389
- },
390
- "Program:exit": function (node) {
391
- checkIndentations(node);
392
- },
393
-
394
- "BlockStatement": function (node) {
395
- if (!isMultiline(node)) {
396
- return;
397
- }
398
-
399
- markChildren(node);
400
- markPop(node, 1);
401
-
402
- markPushAndEndCheck(getBlockNodeToMark(node), 1);
403
- },
404
-
405
- "IfStatement": function (node) {
406
- markAlternateBlockStatement(node, "alternate");
407
- },
408
-
409
- "TryStatement": function (node) {
410
- markAlternateBlockStatement(node, "handler");
411
- markAlternateBlockStatement(node, "finalizer");
412
- },
413
-
414
- "SwitchStatement": function (node) {
415
- if (!isMultiline(node)) {
416
- return;
417
- }
418
-
419
- var indents = 1;
420
- var children = getChildren(node);
421
-
422
- if (children.length && node.loc.start.column === children[0].loc.start.column) {
423
- indents = 0;
424
- }
425
-
426
- markChildren(node);
427
- markPop(node, indents);
428
- markPushAndEndCheck(node, indents);
429
- },
430
-
431
- "SwitchCase": function (node) {
432
- if (!options.indentSwitchCase) {
433
- return;
434
- }
435
-
436
- if (!isMultiline(node)) {
437
- return;
438
- }
439
-
440
- var children = getChildren(node);
441
-
442
- if (children.length === 1 && children[0].type === "BlockStatement") {
443
- return;
444
- }
445
-
446
- markPush(node, 1);
447
- markCheck(node);
448
- markChildren(node);
449
-
450
- markCase(node, children);
451
- },
452
-
453
- // indentations inside of function expressions can be offset from
454
- // either the start of the function or the end of the function, therefore
455
- // mark all starting lines of functions as potential indentations
456
- "FunctionDeclaration": function (node) {
457
- markPushAlt(node);
458
- },
459
- "FunctionExpression": function (node) {
460
- markPushAlt(node);
461
- }
462
- };
463
-
464
- };
465
-
466
- module.exports.schema = [
467
- {
468
- "oneOf": [
469
- {
470
- "enum": ["tab"]
471
- },
472
- {
473
- "type": "integer"
474
- }
475
- ]
476
- },
477
- {
478
- "type": "object",
479
- "properties": {
480
- "indentSwitchCase": {
481
- "type": "boolean"
482
- }
483
- },
484
- "additionalProperties": false
485
- }
486
- ];
1
+ /**
2
+ * @fileoverview This option sets a specific tab width for your code
3
+ * This rule has been ported and modified from JSCS.
4
+ * @author Dmitriy Shekhovtsov
5
+ * @copyright 2015 Dmitriy Shekhovtsov. All rights reserved.
6
+ * @copyright 2013 Dulin Marat and other contributors.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining
9
+ * a copy of this software and associated documentation files (the
10
+ * "Software"), to deal in the Software without restriction, including
11
+ * without limitation the rights to use, copy, modify, merge, publish,
12
+ * distribute, sublicense, and/or sell copies of the Software, and to
13
+ * permit persons to whom the Software is furnished to do so, subject to
14
+ * the following conditions:
15
+ *
16
+ * The above copyright notice and this permission notice shall be
17
+ * included in all copies or substantial portions of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ */
27
+ /*eslint no-use-before-define:[2, "nofunc"]*/
28
+ "use strict";
29
+
30
+ //------------------------------------------------------------------------------
31
+ // Rule Definition
32
+ //------------------------------------------------------------------------------
33
+
34
+ module.exports = function (context) {
35
+ // indentation defaults: 4 spaces
36
+ var indentChar = " ";
37
+ var indentSize = 4;
38
+ var options = {indentSwitchCase: false};
39
+
40
+ var lines = null;
41
+ var indentStack = [0];
42
+ var linesToCheck = null;
43
+ var breakIndents = null;
44
+
45
+ if (context.options.length) {
46
+ if (context.options[0] === "tab") {
47
+ indentChar = "\t";
48
+ indentSize = 1;
49
+ } else /* istanbul ignore else : this will be caught by options validation */ if (typeof context.options[0] === "number") {
50
+ indentSize = context.options[0];
51
+ }
52
+
53
+ if (context.options[1]) {
54
+ var opts = context.options[1];
55
+ options.indentSwitchCase = opts.indentSwitchCase === true;
56
+ }
57
+ }
58
+
59
+ var blockParents = [
60
+ "IfStatement",
61
+ "WhileStatement",
62
+ "DoWhileStatement",
63
+ "ForStatement",
64
+ "ForInStatement",
65
+ "ForOfStatement",
66
+ "FunctionDeclaration",
67
+ "FunctionExpression",
68
+ "ArrowExpression",
69
+ "CatchClause",
70
+ "WithStatement"
71
+ ];
72
+
73
+ var indentableNodes = {
74
+ BlockStatement: "body",
75
+ Program: "body",
76
+ ObjectExpression: "properties",
77
+ ArrayExpression: "elements",
78
+ SwitchStatement: "cases"
79
+ };
80
+
81
+ if (options.indentSwitchCase) {
82
+ indentableNodes.SwitchCase = "consequent";
83
+ }
84
+
85
+ //--------------------------------------------------------------------------
86
+ // Helpers
87
+ //--------------------------------------------------------------------------
88
+
89
+ /**
90
+ * Mark line to be checked
91
+ * @param {Number} line - line number
92
+ * @returns {void}
93
+ */
94
+ function markCheckLine(line) {
95
+ linesToCheck[line].check = true;
96
+ }
97
+
98
+ /**
99
+ * Mark line with targeted node to be checked
100
+ * @param {ASTNode} checkNode - targeted node
101
+ * @returns {void}
102
+ */
103
+ function markCheck(checkNode) {
104
+ markCheckLine(checkNode.loc.start.line - 1);
105
+ }
106
+
107
+ /**
108
+ * Sets pushing indent of current node
109
+ * @param {ASTNode} node - targeted node
110
+ * @param {Number} indents - indents count to push
111
+ * @returns {void}
112
+ */
113
+ function markPush(node, indents) {
114
+ linesToCheck[node.loc.start.line - 1].push.push(indents);
115
+ }
116
+
117
+ /**
118
+ * Marks line as outdent, end of block statement for example
119
+ * @param {ASTNode} node - targeted node
120
+ * @param {Number} outdents - count of outedents in targeted line
121
+ * @returns {void}
122
+ */
123
+ function markPop(node, outdents) {
124
+ linesToCheck[node.loc.end.line - 1].pop.push(outdents);
125
+ }
126
+
127
+ /**
128
+ * Set alt push for current node
129
+ * @param {ASTNode} node - targeted node
130
+ * @returns {void}
131
+ */
132
+ function markPushAlt(node) {
133
+ linesToCheck[node.loc.start.line - 1].pushAltLine.push(node.loc.end.line - 1);
134
+ }
135
+
136
+ /**
137
+ * Marks end of node block to be checked
138
+ * and marks targeted node as indent pushing
139
+ * @param {ASTNode} pushNode - targeted node
140
+ * @param {Number} indents - indent count to push
141
+ * @returns {void}
142
+ */
143
+ function markPushAndEndCheck(pushNode, indents) {
144
+ markPush(pushNode, indents);
145
+ markCheckLine(pushNode.loc.end.line - 1);
146
+ }
147
+
148
+ /**
149
+ * Mark node as switch case statement
150
+ * and set push\pop indentation changes
151
+ * @param {ASTNode} caseNode - targeted node
152
+ * @param {ASTNode[]} children - consequent child nodes of case node
153
+ * @returns {void}
154
+ */
155
+ function markCase(caseNode, children) {
156
+ var outdentNode = getCaseOutdent(children);
157
+
158
+ if (outdentNode) {
159
+ // If a case statement has a `break` as a direct child and it is the
160
+ // first one encountered, use it as the example for all future case indentation
161
+ if (breakIndents === null) {
162
+ breakIndents = (caseNode.loc.start.column === outdentNode.loc.start.column) ? 1 : 0;
163
+ }
164
+ markPop(outdentNode, breakIndents);
165
+ } else {
166
+ markPop(caseNode, 0);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Mark child nodes to be checked later of targeted node,
172
+ * only if child node not in same line as targeted one
173
+ * (if child and parent nodes wrote in single line)
174
+ * @param {ASTNode} node - targeted node
175
+ * @returns {void}
176
+ */
177
+ function markChildren(node) {
178
+ getChildren(node).forEach(function(childNode) {
179
+ if (childNode.loc.start.line !== node.loc.start.line || node.type === "Program") {
180
+ markCheck(childNode);
181
+ }
182
+ });
183
+ }
184
+
185
+ /**
186
+ * Mark child block as scope pushing and mark to check
187
+ * @param {ASTNode} node - target node
188
+ * @param {String} property - target node property containing child
189
+ * @returns {void}
190
+ */
191
+ function markAlternateBlockStatement(node, property) {
192
+ var child = node[property];
193
+ if (child && child.type === "BlockStatement") {
194
+ markCheck(child);
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Checks whether node is multiline or single line
200
+ * @param {ASTNode} node - target node
201
+ * @returns {boolean} - is multiline node
202
+ */
203
+ function isMultiline(node) {
204
+ return node.loc.start.line !== node.loc.end.line;
205
+ }
206
+
207
+ /**
208
+ * Get switch case statement outdent node if any
209
+ * @param {ASTNode[]} caseChildren - case statement childs
210
+ * @returns {ASTNode} - outdent node
211
+ */
212
+ function getCaseOutdent(caseChildren) {
213
+ var outdentNode;
214
+ caseChildren.some(function(node) {
215
+ if (node.type === "BreakStatement") {
216
+ outdentNode = node;
217
+ return true;
218
+ }
219
+ });
220
+
221
+ return outdentNode;
222
+ }
223
+
224
+ /**
225
+ * Returns block containing node
226
+ * @param {ASTNode} node - targeted node
227
+ * @returns {ASTNode} - block node
228
+ */
229
+ function getBlockNodeToMark(node) {
230
+ var parent = node.parent;
231
+
232
+ // The parent of an else is the entire if/else block. To avoid over indenting
233
+ // in the case of a non-block if with a block else, mark push where the else starts,
234
+ // not where the if starts!
235
+ if (parent.type === "IfStatement" && parent.alternate === node) {
236
+ return node;
237
+ }
238
+
239
+ // The end line to check of a do while statement needs to be the location of the
240
+ // closing curly brace, not the while statement, to avoid marking the last line of
241
+ // a multiline while as a line to check.
242
+ if (parent.type === "DoWhileStatement") {
243
+ return node;
244
+ }
245
+
246
+ // Detect bare blocks: a block whose parent doesn"t expect blocks in its syntax specifically.
247
+ if (blockParents.indexOf(parent.type) === -1) {
248
+ return node;
249
+ }
250
+
251
+ return parent;
252
+ }
253
+
254
+ /**
255
+ * Get node's children
256
+ * @param {ASTNode} node - current node
257
+ * @returns {ASTNode[]} - children
258
+ */
259
+ function getChildren(node) {
260
+ var childrenProperty = indentableNodes[node.type];
261
+ return node[childrenProperty];
262
+ }
263
+
264
+ /**
265
+ * Gets indentation in line `i`
266
+ * @param {Number} i - number of line to get indentation
267
+ * @returns {Number} - count of indentation symbols
268
+ */
269
+ function getIndentationFromLine(i) {
270
+ var rNotIndentChar = new RegExp("[^" + indentChar + "]");
271
+ var firstContent = lines[i].search(rNotIndentChar);
272
+ if (firstContent === -1) {
273
+ firstContent = lines[i].length;
274
+ }
275
+ return firstContent;
276
+ }
277
+
278
+ /**
279
+ * Compares expected and actual indentation
280
+ * and reports any violations
281
+ * @param {ASTNode} node - node used only for reporting
282
+ * @returns {void}
283
+ */
284
+ function checkIndentations(node) {
285
+ linesToCheck.forEach(function(line, i) {
286
+ var actualIndentation = getIndentationFromLine(i);
287
+ var expectedIndentation = getExpectedIndentation(line, actualIndentation);
288
+
289
+ if (line.check) {
290
+
291
+ if (actualIndentation !== expectedIndentation) {
292
+ context.report(node,
293
+ {line: i + 1, column: expectedIndentation},
294
+ "Expected indentation of " + expectedIndentation + " characters.");
295
+ // correct the indentation so that future lines
296
+ // can be validated appropriately
297
+ actualIndentation = expectedIndentation;
298
+ }
299
+ }
300
+
301
+ if (line.push.length) {
302
+ pushExpectedIndentations(line, actualIndentation);
303
+ }
304
+ });
305
+ }
306
+
307
+ /**
308
+ * Counts expected indentation for given line number
309
+ * @param {Number} line - line number
310
+ * @param {Number} actual - actual indentation
311
+ * @returns {number} - expected indentation
312
+ */
313
+ function getExpectedIndentation(line, actual) {
314
+ var outdent = indentSize * Math.max.apply(null, line.pop);
315
+
316
+ var idx = indentStack.length - 1;
317
+ var expected = indentStack[idx];
318
+
319
+ if (!Array.isArray(expected)) {
320
+ expected = [expected];
321
+ }
322
+
323
+ expected = expected.map(function(value) {
324
+ if (line.pop.length) {
325
+ value -= outdent;
326
+ }
327
+
328
+ return value;
329
+ }).reduce(function(previous, current) {
330
+ // when the expected is an array, resolve the value
331
+ // back into a Number by checking both values are the actual indentation
332
+ return actual === current ? current : previous;
333
+ });
334
+
335
+ indentStack[idx] = expected;
336
+
337
+ line.pop.forEach(function() {
338
+ indentStack.pop();
339
+ });
340
+
341
+ return expected;
342
+ }
343
+
344
+ /**
345
+ * Store in stack expected indentations
346
+ * @param {Number} line - current line
347
+ * @param {Number} actualIndentation - actual indentation at current line
348
+ * @returns {void}
349
+ */
350
+ function pushExpectedIndentations(line, actualIndentation) {
351
+ var indents = Math.max.apply(null, line.push);
352
+ var expected = actualIndentation + (indentSize * indents);
353
+
354
+ // when a line has alternate indentations, push an array of possible values
355
+ // on the stack, to be resolved when checked against an actual indentation
356
+ if (line.pushAltLine.length) {
357
+ expected = [expected];
358
+ line.pushAltLine.forEach(function(altLine) {
359
+ expected.push(getIndentationFromLine(altLine) + (indentSize * indents));
360
+ });
361
+ }
362
+
363
+ line.push.forEach(function() {
364
+ indentStack.push(expected);
365
+ });
366
+ }
367
+
368
+ //--------------------------------------------------------------------------
369
+ // Public
370
+ //--------------------------------------------------------------------------
371
+
372
+ return {
373
+ "Program": function (node) {
374
+ lines = context.getSourceLines();
375
+ linesToCheck = lines.map(function () {
376
+ return {
377
+ push: [],
378
+ pushAltLine: [],
379
+ pop: [],
380
+ check: false
381
+ };
382
+ });
383
+
384
+ if (!isMultiline(node)) {
385
+ return;
386
+ }
387
+
388
+ markChildren(node);
389
+ },
390
+ "Program:exit": function (node) {
391
+ checkIndentations(node);
392
+ },
393
+
394
+ "BlockStatement": function (node) {
395
+ if (!isMultiline(node)) {
396
+ return;
397
+ }
398
+
399
+ markChildren(node);
400
+ markPop(node, 1);
401
+
402
+ markPushAndEndCheck(getBlockNodeToMark(node), 1);
403
+ },
404
+
405
+ "IfStatement": function (node) {
406
+ markAlternateBlockStatement(node, "alternate");
407
+ },
408
+
409
+ "TryStatement": function (node) {
410
+ markAlternateBlockStatement(node, "handler");
411
+ markAlternateBlockStatement(node, "finalizer");
412
+ },
413
+
414
+ "SwitchStatement": function (node) {
415
+ if (!isMultiline(node)) {
416
+ return;
417
+ }
418
+
419
+ var indents = 1;
420
+ var children = getChildren(node);
421
+
422
+ if (children.length && node.loc.start.column === children[0].loc.start.column) {
423
+ indents = 0;
424
+ }
425
+
426
+ markChildren(node);
427
+ markPop(node, indents);
428
+ markPushAndEndCheck(node, indents);
429
+ },
430
+
431
+ "SwitchCase": function (node) {
432
+ if (!options.indentSwitchCase) {
433
+ return;
434
+ }
435
+
436
+ if (!isMultiline(node)) {
437
+ return;
438
+ }
439
+
440
+ var children = getChildren(node);
441
+
442
+ if (children.length === 1 && children[0].type === "BlockStatement") {
443
+ return;
444
+ }
445
+
446
+ markPush(node, 1);
447
+ markCheck(node);
448
+ markChildren(node);
449
+
450
+ markCase(node, children);
451
+ },
452
+
453
+ // indentations inside of function expressions can be offset from
454
+ // either the start of the function or the end of the function, therefore
455
+ // mark all starting lines of functions as potential indentations
456
+ "FunctionDeclaration": function (node) {
457
+ markPushAlt(node);
458
+ },
459
+ "FunctionExpression": function (node) {
460
+ markPushAlt(node);
461
+ }
462
+ };
463
+
464
+ };
465
+
466
+ module.exports.schema = [
467
+ {
468
+ "oneOf": [
469
+ {
470
+ "enum": ["tab"]
471
+ },
472
+ {
473
+ "type": "integer"
474
+ }
475
+ ]
476
+ },
477
+ {
478
+ "type": "object",
479
+ "properties": {
480
+ "indentSwitchCase": {
481
+ "type": "boolean"
482
+ }
483
+ },
484
+ "additionalProperties": false
485
+ }
486
+ ];