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.
- package/LICENSE +20 -20
- package/README.md +111 -95
- package/bin/eslint.js +41 -41
- package/conf/environments.js +87 -81
- package/conf/eslint.json +186 -179
- package/lib/api.js +13 -12
- package/lib/cli-engine.js +441 -451
- package/lib/cli.js +196 -196
- package/lib/config-initializer.js +145 -145
- package/lib/config-validator.js +110 -110
- package/lib/config.js +428 -416
- package/lib/eslint.js +1072 -1073
- package/lib/file-finder.js +167 -167
- package/lib/formatters/checkstyle.js +68 -68
- package/lib/formatters/compact.js +53 -53
- package/lib/formatters/jslint-xml.js +40 -40
- package/lib/formatters/junit.js +63 -63
- package/lib/formatters/stylish.js +90 -90
- package/lib/formatters/tap.js +86 -86
- package/lib/ignored-paths.js +137 -137
- package/lib/load-rules.js +39 -39
- package/lib/options.js +132 -126
- package/lib/rule-context.js +107 -107
- package/lib/rules/accessor-pairs.js +65 -65
- package/lib/rules/array-bracket-spacing.js +180 -0
- package/lib/rules/block-scoped-var.js +339 -320
- package/lib/rules/brace-style.js +228 -228
- package/lib/rules/camelcase.js +111 -111
- package/lib/rules/comma-dangle.js +67 -64
- package/lib/rules/comma-spacing.js +191 -191
- package/lib/rules/comma-style.js +195 -195
- package/lib/rules/complexity.js +94 -94
- package/lib/rules/computed-property-spacing.js +144 -0
- package/lib/rules/consistent-return.js +75 -75
- package/lib/rules/consistent-this.js +119 -119
- package/lib/rules/constructor-super.js +108 -0
- package/lib/rules/curly.js +109 -109
- package/lib/rules/default-case.js +66 -66
- package/lib/rules/dot-location.js +63 -63
- package/lib/rules/dot-notation.js +119 -119
- package/lib/rules/eol-last.js +38 -38
- package/lib/rules/eqeqeq.js +96 -96
- package/lib/rules/func-names.js +45 -45
- package/lib/rules/func-style.js +49 -49
- package/lib/rules/generator-star-spacing.js +104 -87
- package/lib/rules/generator-star.js +76 -76
- package/lib/rules/global-strict.js +49 -49
- package/lib/rules/guard-for-in.js +32 -32
- package/lib/rules/handle-callback-err.js +81 -124
- package/lib/rules/indent.js +486 -486
- package/lib/rules/key-spacing.js +325 -325
- package/lib/rules/linebreak-style.js +44 -44
- package/lib/rules/lines-around-comment.js +228 -160
- package/lib/rules/max-depth.js +89 -89
- package/lib/rules/max-len.js +76 -76
- package/lib/rules/max-nested-callbacks.js +73 -73
- package/lib/rules/max-params.js +45 -45
- package/lib/rules/max-statements.js +61 -61
- package/lib/rules/new-cap.js +224 -224
- package/lib/rules/new-parens.js +29 -29
- package/lib/rules/newline-after-var.js +127 -127
- package/lib/rules/no-alert.js +153 -153
- package/lib/rules/no-array-constructor.js +31 -31
- package/lib/rules/no-bitwise.js +57 -57
- package/lib/rules/no-caller.js +29 -29
- package/lib/rules/no-catch-shadow.js +52 -52
- package/lib/rules/no-comma-dangle.js +45 -45
- package/lib/rules/no-cond-assign.js +123 -123
- package/lib/rules/no-console.js +27 -27
- package/lib/rules/no-constant-condition.js +73 -73
- package/lib/rules/no-continue.js +23 -23
- package/lib/rules/no-control-regex.js +58 -58
- package/lib/rules/no-debugger.js +22 -22
- package/lib/rules/no-delete-var.js +25 -25
- package/lib/rules/no-div-regex.js +27 -27
- package/lib/rules/no-dupe-args.js +89 -85
- package/lib/rules/no-dupe-keys.js +43 -43
- package/lib/rules/no-duplicate-case.js +67 -67
- package/lib/rules/no-else-return.js +125 -125
- package/lib/rules/no-empty-character-class.js +43 -43
- package/lib/rules/no-empty-class.js +45 -45
- package/lib/rules/no-empty-label.js +27 -27
- package/lib/rules/no-empty.js +49 -49
- package/lib/rules/no-eq-null.js +29 -29
- package/lib/rules/no-eval.js +26 -26
- package/lib/rules/no-ex-assign.js +42 -42
- package/lib/rules/no-extend-native.js +103 -103
- package/lib/rules/no-extra-bind.js +81 -81
- package/lib/rules/no-extra-boolean-cast.js +71 -71
- package/lib/rules/no-extra-parens.js +368 -355
- package/lib/rules/no-extra-semi.js +70 -23
- package/lib/rules/no-extra-strict.js +86 -86
- package/lib/rules/no-fallthrough.js +97 -97
- package/lib/rules/no-floating-decimal.js +30 -30
- package/lib/rules/no-func-assign.js +83 -83
- package/lib/rules/no-implied-eval.js +76 -76
- package/lib/rules/no-inline-comments.js +49 -49
- package/lib/rules/no-inner-declarations.js +78 -78
- package/lib/rules/no-invalid-regexp.js +53 -53
- package/lib/rules/no-irregular-whitespace.js +135 -135
- package/lib/rules/no-iterator.js +28 -28
- package/lib/rules/no-label-var.js +64 -64
- package/lib/rules/no-labels.js +44 -44
- package/lib/rules/no-lone-blocks.js +106 -27
- package/lib/rules/no-lonely-if.js +30 -30
- package/lib/rules/no-loop-func.js +58 -58
- package/lib/rules/no-mixed-requires.js +165 -165
- package/lib/rules/no-mixed-spaces-and-tabs.js +74 -74
- package/lib/rules/no-multi-spaces.js +119 -119
- package/lib/rules/no-multi-str.js +43 -43
- package/lib/rules/no-multiple-empty-lines.js +98 -98
- package/lib/rules/no-native-reassign.js +62 -62
- package/lib/rules/no-negated-in-lhs.js +25 -25
- package/lib/rules/no-nested-ternary.js +24 -24
- package/lib/rules/no-new-func.js +25 -25
- package/lib/rules/no-new-object.js +25 -25
- package/lib/rules/no-new-require.js +25 -25
- package/lib/rules/no-new-wrappers.js +26 -26
- package/lib/rules/no-new.js +27 -27
- package/lib/rules/no-obj-calls.js +28 -28
- package/lib/rules/no-octal-escape.js +39 -39
- package/lib/rules/no-octal.js +25 -25
- package/lib/rules/no-param-reassign.js +87 -87
- package/lib/rules/no-path-concat.js +39 -39
- package/lib/rules/no-plusplus.js +24 -24
- package/lib/rules/no-process-env.js +30 -30
- package/lib/rules/no-process-exit.js +33 -33
- package/lib/rules/no-proto.js +28 -28
- package/lib/rules/no-redeclare.js +68 -68
- package/lib/rules/no-regex-spaces.js +35 -35
- package/lib/rules/no-reserved-keys.js +56 -56
- package/lib/rules/no-restricted-modules.js +85 -85
- package/lib/rules/no-return-assign.js +53 -24
- package/lib/rules/no-script-url.js +34 -34
- package/lib/rules/no-self-compare.js +29 -29
- package/lib/rules/no-sequences.js +94 -94
- package/lib/rules/no-shadow-restricted-names.js +51 -51
- package/lib/rules/no-shadow.js +181 -136
- package/lib/rules/no-space-before-semi.js +98 -98
- package/lib/rules/no-spaced-func.js +37 -37
- package/lib/rules/no-sparse-arrays.js +33 -33
- package/lib/rules/no-sync.js +30 -30
- package/lib/rules/no-ternary.js +24 -24
- package/lib/rules/no-this-before-super.js +144 -0
- package/lib/rules/no-throw-literal.js +33 -33
- package/lib/rules/no-trailing-spaces.js +74 -63
- package/lib/rules/no-undef-init.js +28 -28
- package/lib/rules/no-undef.js +92 -92
- package/lib/rules/no-undefined.js +27 -27
- package/lib/rules/no-underscore-dangle.js +73 -73
- package/lib/rules/no-unexpected-multiline.js +58 -0
- package/lib/rules/no-unneeded-ternary.js +48 -48
- package/lib/rules/no-unreachable.js +98 -98
- package/lib/rules/no-unused-expressions.js +76 -76
- package/lib/rules/no-unused-vars.js +252 -250
- package/lib/rules/no-use-before-define.js +105 -105
- package/lib/rules/no-var.js +26 -26
- package/lib/rules/no-void.js +28 -28
- package/lib/rules/no-warning-comments.js +102 -102
- package/lib/rules/no-with.js +22 -22
- package/lib/rules/no-wrap-func.js +65 -65
- package/lib/rules/object-curly-spacing.js +231 -206
- package/lib/rules/object-shorthand.js +74 -73
- package/lib/rules/one-var.js +311 -304
- package/lib/rules/operator-assignment.js +118 -118
- package/lib/rules/operator-linebreak.js +114 -114
- package/lib/rules/padded-blocks.js +98 -98
- package/lib/rules/prefer-const.js +91 -0
- package/lib/rules/quote-props.js +72 -72
- package/lib/rules/quotes.js +92 -92
- package/lib/rules/radix.js +41 -41
- package/lib/rules/semi-spacing.js +167 -167
- package/lib/rules/semi.js +136 -136
- package/lib/rules/sort-vars.js +49 -49
- package/lib/rules/space-after-function-name.js +49 -49
- package/lib/rules/space-after-keywords.js +82 -82
- package/lib/rules/space-before-blocks.js +91 -91
- package/lib/rules/space-before-function-paren.js +139 -139
- package/lib/rules/space-before-function-parentheses.js +139 -139
- package/lib/rules/space-in-brackets.js +305 -305
- package/lib/rules/space-in-parens.js +281 -281
- package/lib/rules/space-infix-ops.js +106 -106
- package/lib/rules/space-return-throw-case.js +38 -38
- package/lib/rules/space-unary-ops.js +124 -133
- package/lib/rules/spaced-comment.js +143 -0
- package/lib/rules/spaced-line-comment.js +89 -89
- package/lib/rules/strict.js +242 -242
- package/lib/rules/use-isnan.js +26 -26
- package/lib/rules/valid-jsdoc.js +215 -215
- package/lib/rules/valid-typeof.js +42 -42
- package/lib/rules/vars-on-top.js +115 -115
- package/lib/rules/wrap-iife.js +48 -48
- package/lib/rules/wrap-regex.js +38 -38
- package/lib/rules/yoda.js +242 -225
- package/lib/rules.js +88 -88
- package/lib/timing.js +109 -109
- package/lib/token-store.js +201 -201
- package/lib/util/traverse.js +105 -105
- package/lib/util.js +125 -85
- package/package.json +6 -6
- package/CHANGELOG.md +0 -1638
@@ -1,355 +1,368 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Disallow parenthesising higher precedence subexpressions.
|
3
|
-
* @author Michael Ficarra
|
4
|
-
* @copyright 2014 Michael Ficarra. All rights reserved.
|
5
|
-
*/
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Rule Definition
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
module.exports = function(context) {
|
13
|
-
|
14
|
-
var ALL_NODES = context.options[0] !== "functions";
|
15
|
-
|
16
|
-
/**
|
17
|
-
* Determines if this rule should be enforced for a node given the current configuration.
|
18
|
-
* @param {ASTNode} node - The node to be checked.
|
19
|
-
* @returns {boolean} True if the rule should be enforced for this node.
|
20
|
-
* @private
|
21
|
-
*/
|
22
|
-
function ruleApplies(node) {
|
23
|
-
return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
24
|
-
}
|
25
|
-
|
26
|
-
/**
|
27
|
-
* Determines if a node is surrounded by parentheses.
|
28
|
-
* @param {ASTNode} node - The node to be checked.
|
29
|
-
* @returns {boolean} True if the node is parenthesised.
|
30
|
-
* @private
|
31
|
-
*/
|
32
|
-
function isParenthesised(node) {
|
33
|
-
var previousToken = context.getTokenBefore(node),
|
34
|
-
nextToken = context.getTokenAfter(node);
|
35
|
-
|
36
|
-
return previousToken && nextToken &&
|
37
|
-
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
|
38
|
-
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
|
39
|
-
}
|
40
|
-
|
41
|
-
/**
|
42
|
-
* Determines if a node is surrounded by parentheses twice.
|
43
|
-
* @param {ASTNode} node - The node to be checked.
|
44
|
-
* @returns {boolean} True if the node is doubly parenthesised.
|
45
|
-
* @private
|
46
|
-
*/
|
47
|
-
function isParenthesisedTwice(node) {
|
48
|
-
var previousToken = context.getTokenBefore(node, 1),
|
49
|
-
nextToken = context.getTokenAfter(node, 1);
|
50
|
-
|
51
|
-
return isParenthesised(node) && previousToken && nextToken &&
|
52
|
-
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
|
53
|
-
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
|
54
|
-
}
|
55
|
-
|
56
|
-
/**
|
57
|
-
* Determines if a node is surrounded by (potentially) invalid parentheses.
|
58
|
-
* @param {ASTNode} node - The node to be checked.
|
59
|
-
* @returns {boolean} True if the node is incorrectly parenthesised.
|
60
|
-
* @private
|
61
|
-
*/
|
62
|
-
function hasExcessParens(node) {
|
63
|
-
return ruleApplies(node) && isParenthesised(node);
|
64
|
-
}
|
65
|
-
|
66
|
-
/**
|
67
|
-
* Determines if a node that is expected to be parenthesised is surrounded by
|
68
|
-
* (potentially) invalid extra parentheses.
|
69
|
-
* @param {ASTNode} node - The node to be checked.
|
70
|
-
* @returns {boolean} True if the node is has an unexpected extra pair of parentheses.
|
71
|
-
* @private
|
72
|
-
*/
|
73
|
-
function hasDoubleExcessParens(node) {
|
74
|
-
return ruleApplies(node) && isParenthesisedTwice(node);
|
75
|
-
}
|
76
|
-
|
77
|
-
function precedence(node) {
|
78
|
-
|
79
|
-
switch (node.type) {
|
80
|
-
case "SequenceExpression":
|
81
|
-
return 0;
|
82
|
-
|
83
|
-
case "AssignmentExpression":
|
84
|
-
case "ArrowFunctionExpression":
|
85
|
-
case "YieldExpression":
|
86
|
-
return 1;
|
87
|
-
|
88
|
-
case "ConditionalExpression":
|
89
|
-
return 3;
|
90
|
-
|
91
|
-
case "LogicalExpression":
|
92
|
-
switch (node.operator) {
|
93
|
-
case "||":
|
94
|
-
return 4;
|
95
|
-
case "&&":
|
96
|
-
return 5;
|
97
|
-
// no default
|
98
|
-
}
|
99
|
-
|
100
|
-
/* falls through */
|
101
|
-
case "BinaryExpression":
|
102
|
-
switch (node.operator) {
|
103
|
-
case "|":
|
104
|
-
return 6;
|
105
|
-
case "^":
|
106
|
-
return 7;
|
107
|
-
case "&":
|
108
|
-
return 8;
|
109
|
-
case "==":
|
110
|
-
case "!=":
|
111
|
-
case "===":
|
112
|
-
case "!==":
|
113
|
-
return 9;
|
114
|
-
case "<":
|
115
|
-
case "<=":
|
116
|
-
case ">":
|
117
|
-
case ">=":
|
118
|
-
case "in":
|
119
|
-
case "instanceof":
|
120
|
-
return 10;
|
121
|
-
case "<<":
|
122
|
-
case ">>":
|
123
|
-
case ">>>":
|
124
|
-
return 11;
|
125
|
-
case "+":
|
126
|
-
case "-":
|
127
|
-
return 12;
|
128
|
-
case "*":
|
129
|
-
case "/":
|
130
|
-
case "%":
|
131
|
-
return 13;
|
132
|
-
// no default
|
133
|
-
}
|
134
|
-
/* falls through */
|
135
|
-
case "UnaryExpression":
|
136
|
-
return 14;
|
137
|
-
case "UpdateExpression":
|
138
|
-
return 15;
|
139
|
-
case "CallExpression":
|
140
|
-
// IIFE is allowed to have parens in any position (#655)
|
141
|
-
if (node.callee.type === "FunctionExpression") {
|
142
|
-
return -1;
|
143
|
-
}
|
144
|
-
return 16;
|
145
|
-
case "NewExpression":
|
146
|
-
return 17;
|
147
|
-
// no default
|
148
|
-
}
|
149
|
-
return 18;
|
150
|
-
}
|
151
|
-
|
152
|
-
function report(node) {
|
153
|
-
var previousToken = context.getTokenBefore(node);
|
154
|
-
context.report(node, previousToken.loc.start, "Gratuitous parentheses around expression.");
|
155
|
-
}
|
156
|
-
|
157
|
-
function dryUnaryUpdate(node) {
|
158
|
-
if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) {
|
159
|
-
report(node.argument);
|
160
|
-
}
|
161
|
-
}
|
162
|
-
|
163
|
-
function dryCallNew(node) {
|
164
|
-
if (hasExcessParens(node.callee) && precedence(node.callee) >= precedence(node) && !(
|
165
|
-
node.type === "CallExpression" &&
|
166
|
-
node.callee.type === "FunctionExpression" &&
|
167
|
-
// One set of parentheses are allowed for a function expression
|
168
|
-
!hasDoubleExcessParens(node.callee)
|
169
|
-
)) {
|
170
|
-
report(node.callee);
|
171
|
-
}
|
172
|
-
if (node.arguments.length === 1) {
|
173
|
-
if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) {
|
174
|
-
report(node.arguments[0]);
|
175
|
-
}
|
176
|
-
} else {
|
177
|
-
[].forEach.call(node.arguments, function(arg) {
|
178
|
-
if (hasExcessParens(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) {
|
179
|
-
report(arg);
|
180
|
-
}
|
181
|
-
});
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
function dryBinaryLogical(node) {
|
186
|
-
var prec = precedence(node);
|
187
|
-
if (hasExcessParens(node.left) && precedence(node.left) >= prec) {
|
188
|
-
report(node.left);
|
189
|
-
}
|
190
|
-
if (hasExcessParens(node.right) && precedence(node.right) > prec) {
|
191
|
-
report(node.right);
|
192
|
-
}
|
193
|
-
}
|
194
|
-
|
195
|
-
return {
|
196
|
-
"ArrayExpression": function(node) {
|
197
|
-
[].forEach.call(node.elements, function(e) {
|
198
|
-
if (e && hasExcessParens(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) {
|
199
|
-
report(e);
|
200
|
-
}
|
201
|
-
});
|
202
|
-
},
|
203
|
-
"ArrowFunctionExpression": function(node) {
|
204
|
-
if (node.body.type !== "BlockStatement"
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
if (
|
258
|
-
report(node.
|
259
|
-
}
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
if (
|
267
|
-
report(node.test);
|
268
|
-
}
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
}
|
301
|
-
},
|
302
|
-
"
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
"
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
}
|
354
|
-
|
355
|
-
|
1
|
+
/**
|
2
|
+
* @fileoverview Disallow parenthesising higher precedence subexpressions.
|
3
|
+
* @author Michael Ficarra
|
4
|
+
* @copyright 2014 Michael Ficarra. All rights reserved.
|
5
|
+
*/
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Rule Definition
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
module.exports = function(context) {
|
13
|
+
|
14
|
+
var ALL_NODES = context.options[0] !== "functions";
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Determines if this rule should be enforced for a node given the current configuration.
|
18
|
+
* @param {ASTNode} node - The node to be checked.
|
19
|
+
* @returns {boolean} True if the rule should be enforced for this node.
|
20
|
+
* @private
|
21
|
+
*/
|
22
|
+
function ruleApplies(node) {
|
23
|
+
return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
24
|
+
}
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Determines if a node is surrounded by parentheses.
|
28
|
+
* @param {ASTNode} node - The node to be checked.
|
29
|
+
* @returns {boolean} True if the node is parenthesised.
|
30
|
+
* @private
|
31
|
+
*/
|
32
|
+
function isParenthesised(node) {
|
33
|
+
var previousToken = context.getTokenBefore(node),
|
34
|
+
nextToken = context.getTokenAfter(node);
|
35
|
+
|
36
|
+
return previousToken && nextToken &&
|
37
|
+
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
|
38
|
+
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* Determines if a node is surrounded by parentheses twice.
|
43
|
+
* @param {ASTNode} node - The node to be checked.
|
44
|
+
* @returns {boolean} True if the node is doubly parenthesised.
|
45
|
+
* @private
|
46
|
+
*/
|
47
|
+
function isParenthesisedTwice(node) {
|
48
|
+
var previousToken = context.getTokenBefore(node, 1),
|
49
|
+
nextToken = context.getTokenAfter(node, 1);
|
50
|
+
|
51
|
+
return isParenthesised(node) && previousToken && nextToken &&
|
52
|
+
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
|
53
|
+
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Determines if a node is surrounded by (potentially) invalid parentheses.
|
58
|
+
* @param {ASTNode} node - The node to be checked.
|
59
|
+
* @returns {boolean} True if the node is incorrectly parenthesised.
|
60
|
+
* @private
|
61
|
+
*/
|
62
|
+
function hasExcessParens(node) {
|
63
|
+
return ruleApplies(node) && isParenthesised(node);
|
64
|
+
}
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Determines if a node that is expected to be parenthesised is surrounded by
|
68
|
+
* (potentially) invalid extra parentheses.
|
69
|
+
* @param {ASTNode} node - The node to be checked.
|
70
|
+
* @returns {boolean} True if the node is has an unexpected extra pair of parentheses.
|
71
|
+
* @private
|
72
|
+
*/
|
73
|
+
function hasDoubleExcessParens(node) {
|
74
|
+
return ruleApplies(node) && isParenthesisedTwice(node);
|
75
|
+
}
|
76
|
+
|
77
|
+
function precedence(node) {
|
78
|
+
|
79
|
+
switch (node.type) {
|
80
|
+
case "SequenceExpression":
|
81
|
+
return 0;
|
82
|
+
|
83
|
+
case "AssignmentExpression":
|
84
|
+
case "ArrowFunctionExpression":
|
85
|
+
case "YieldExpression":
|
86
|
+
return 1;
|
87
|
+
|
88
|
+
case "ConditionalExpression":
|
89
|
+
return 3;
|
90
|
+
|
91
|
+
case "LogicalExpression":
|
92
|
+
switch (node.operator) {
|
93
|
+
case "||":
|
94
|
+
return 4;
|
95
|
+
case "&&":
|
96
|
+
return 5;
|
97
|
+
// no default
|
98
|
+
}
|
99
|
+
|
100
|
+
/* falls through */
|
101
|
+
case "BinaryExpression":
|
102
|
+
switch (node.operator) {
|
103
|
+
case "|":
|
104
|
+
return 6;
|
105
|
+
case "^":
|
106
|
+
return 7;
|
107
|
+
case "&":
|
108
|
+
return 8;
|
109
|
+
case "==":
|
110
|
+
case "!=":
|
111
|
+
case "===":
|
112
|
+
case "!==":
|
113
|
+
return 9;
|
114
|
+
case "<":
|
115
|
+
case "<=":
|
116
|
+
case ">":
|
117
|
+
case ">=":
|
118
|
+
case "in":
|
119
|
+
case "instanceof":
|
120
|
+
return 10;
|
121
|
+
case "<<":
|
122
|
+
case ">>":
|
123
|
+
case ">>>":
|
124
|
+
return 11;
|
125
|
+
case "+":
|
126
|
+
case "-":
|
127
|
+
return 12;
|
128
|
+
case "*":
|
129
|
+
case "/":
|
130
|
+
case "%":
|
131
|
+
return 13;
|
132
|
+
// no default
|
133
|
+
}
|
134
|
+
/* falls through */
|
135
|
+
case "UnaryExpression":
|
136
|
+
return 14;
|
137
|
+
case "UpdateExpression":
|
138
|
+
return 15;
|
139
|
+
case "CallExpression":
|
140
|
+
// IIFE is allowed to have parens in any position (#655)
|
141
|
+
if (node.callee.type === "FunctionExpression") {
|
142
|
+
return -1;
|
143
|
+
}
|
144
|
+
return 16;
|
145
|
+
case "NewExpression":
|
146
|
+
return 17;
|
147
|
+
// no default
|
148
|
+
}
|
149
|
+
return 18;
|
150
|
+
}
|
151
|
+
|
152
|
+
function report(node) {
|
153
|
+
var previousToken = context.getTokenBefore(node);
|
154
|
+
context.report(node, previousToken.loc.start, "Gratuitous parentheses around expression.");
|
155
|
+
}
|
156
|
+
|
157
|
+
function dryUnaryUpdate(node) {
|
158
|
+
if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) {
|
159
|
+
report(node.argument);
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
function dryCallNew(node) {
|
164
|
+
if (hasExcessParens(node.callee) && precedence(node.callee) >= precedence(node) && !(
|
165
|
+
node.type === "CallExpression" &&
|
166
|
+
node.callee.type === "FunctionExpression" &&
|
167
|
+
// One set of parentheses are allowed for a function expression
|
168
|
+
!hasDoubleExcessParens(node.callee)
|
169
|
+
)) {
|
170
|
+
report(node.callee);
|
171
|
+
}
|
172
|
+
if (node.arguments.length === 1) {
|
173
|
+
if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) {
|
174
|
+
report(node.arguments[0]);
|
175
|
+
}
|
176
|
+
} else {
|
177
|
+
[].forEach.call(node.arguments, function(arg) {
|
178
|
+
if (hasExcessParens(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) {
|
179
|
+
report(arg);
|
180
|
+
}
|
181
|
+
});
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
function dryBinaryLogical(node) {
|
186
|
+
var prec = precedence(node);
|
187
|
+
if (hasExcessParens(node.left) && precedence(node.left) >= prec) {
|
188
|
+
report(node.left);
|
189
|
+
}
|
190
|
+
if (hasExcessParens(node.right) && precedence(node.right) > prec) {
|
191
|
+
report(node.right);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
return {
|
196
|
+
"ArrayExpression": function(node) {
|
197
|
+
[].forEach.call(node.elements, function(e) {
|
198
|
+
if (e && hasExcessParens(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) {
|
199
|
+
report(e);
|
200
|
+
}
|
201
|
+
});
|
202
|
+
},
|
203
|
+
"ArrowFunctionExpression": function(node) {
|
204
|
+
if (node.body.type !== "BlockStatement") {
|
205
|
+
if (node.body.type !== "ObjectExpression" && hasExcessParens(node.body) && precedence(node.body) >= precedence({type: "AssignmentExpression"})) {
|
206
|
+
report(node.body);
|
207
|
+
return;
|
208
|
+
}
|
209
|
+
|
210
|
+
// Object literals *must* be parenthesized
|
211
|
+
if (node.body.type === "ObjectExpression" && hasDoubleExcessParens(node.body)) {
|
212
|
+
report(node.body);
|
213
|
+
return;
|
214
|
+
}
|
215
|
+
}
|
216
|
+
},
|
217
|
+
"AssignmentExpression": function(node) {
|
218
|
+
if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) {
|
219
|
+
report(node.right);
|
220
|
+
}
|
221
|
+
},
|
222
|
+
"BinaryExpression": dryBinaryLogical,
|
223
|
+
"CallExpression": dryCallNew,
|
224
|
+
"ConditionalExpression": function(node) {
|
225
|
+
if (hasExcessParens(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) {
|
226
|
+
report(node.test);
|
227
|
+
}
|
228
|
+
if (hasExcessParens(node.consequent) && precedence(node.consequent) >= precedence({type: "AssignmentExpression"})) {
|
229
|
+
report(node.consequent);
|
230
|
+
}
|
231
|
+
if (hasExcessParens(node.alternate) && precedence(node.alternate) >= precedence({type: "AssignmentExpression"})) {
|
232
|
+
report(node.alternate);
|
233
|
+
}
|
234
|
+
},
|
235
|
+
"DoWhileStatement": function(node) {
|
236
|
+
if (hasDoubleExcessParens(node.test)) {
|
237
|
+
report(node.test);
|
238
|
+
}
|
239
|
+
},
|
240
|
+
"ExpressionStatement": function(node) {
|
241
|
+
var firstToken;
|
242
|
+
if (hasExcessParens(node.expression) && node.expression.type !== "CallExpression") {
|
243
|
+
firstToken = context.getFirstToken(node.expression);
|
244
|
+
// Pure object literals ({}) do not need parentheses but
|
245
|
+
// member expressions do ({}.toString())
|
246
|
+
if (firstToken.value !== "{" || node.expression.type === "ObjectExpression") {
|
247
|
+
report(node.expression);
|
248
|
+
}
|
249
|
+
}
|
250
|
+
},
|
251
|
+
"ForInStatement": function(node) {
|
252
|
+
if (hasExcessParens(node.right)) {
|
253
|
+
report(node.right);
|
254
|
+
}
|
255
|
+
},
|
256
|
+
"ForOfStatement": function(node) {
|
257
|
+
if (hasExcessParens(node.right)) {
|
258
|
+
report(node.right);
|
259
|
+
}
|
260
|
+
},
|
261
|
+
"ForStatement": function(node) {
|
262
|
+
if (node.init && hasExcessParens(node.init)) {
|
263
|
+
report(node.init);
|
264
|
+
}
|
265
|
+
|
266
|
+
if (node.test && hasExcessParens(node.test)) {
|
267
|
+
report(node.test);
|
268
|
+
}
|
269
|
+
|
270
|
+
if (node.update && hasExcessParens(node.update)) {
|
271
|
+
report(node.update);
|
272
|
+
}
|
273
|
+
},
|
274
|
+
"IfStatement": function(node) {
|
275
|
+
if (hasDoubleExcessParens(node.test)) {
|
276
|
+
report(node.test);
|
277
|
+
}
|
278
|
+
},
|
279
|
+
"LogicalExpression": dryBinaryLogical,
|
280
|
+
"MemberExpression": function(node) {
|
281
|
+
if (
|
282
|
+
hasExcessParens(node.object) &&
|
283
|
+
precedence(node.object) >= precedence(node) &&
|
284
|
+
(
|
285
|
+
node.computed ||
|
286
|
+
!(
|
287
|
+
(node.object.type === "Literal" &&
|
288
|
+
typeof node.object.value === "number" &&
|
289
|
+
/^[0-9]+$/.test(context.getFirstToken(node.object).value))
|
290
|
+
||
|
291
|
+
// RegExp literal is allowed to have parens (#1589)
|
292
|
+
(node.object.type === "Literal" && node.object.regex)
|
293
|
+
)
|
294
|
+
)
|
295
|
+
) {
|
296
|
+
report(node.object);
|
297
|
+
}
|
298
|
+
if (node.computed && hasExcessParens(node.property)) {
|
299
|
+
report(node.property);
|
300
|
+
}
|
301
|
+
},
|
302
|
+
"NewExpression": dryCallNew,
|
303
|
+
"ObjectExpression": function(node) {
|
304
|
+
[].forEach.call(node.properties, function(e) {
|
305
|
+
var v = e.value;
|
306
|
+
if (v && hasExcessParens(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) {
|
307
|
+
report(v);
|
308
|
+
}
|
309
|
+
});
|
310
|
+
},
|
311
|
+
"ReturnStatement": function(node) {
|
312
|
+
if (node.argument && hasExcessParens(node.argument) &&
|
313
|
+
// RegExp literal is allowed to have parens (#1589)
|
314
|
+
!(node.argument.type === "Literal" && node.argument.regex)) {
|
315
|
+
report(node.argument);
|
316
|
+
}
|
317
|
+
},
|
318
|
+
"SequenceExpression": function(node) {
|
319
|
+
[].forEach.call(node.expressions, function(e) {
|
320
|
+
if (hasExcessParens(e) && precedence(e) >= precedence(node)) {
|
321
|
+
report(e);
|
322
|
+
}
|
323
|
+
});
|
324
|
+
},
|
325
|
+
"SwitchCase": function(node) {
|
326
|
+
if (node.test && hasExcessParens(node.test)) {
|
327
|
+
report(node.test);
|
328
|
+
}
|
329
|
+
},
|
330
|
+
"SwitchStatement": function(node) {
|
331
|
+
if (hasDoubleExcessParens(node.discriminant)) {
|
332
|
+
report(node.discriminant);
|
333
|
+
}
|
334
|
+
},
|
335
|
+
"ThrowStatement": function(node) {
|
336
|
+
if (hasExcessParens(node.argument)) {
|
337
|
+
report(node.argument);
|
338
|
+
}
|
339
|
+
},
|
340
|
+
"UnaryExpression": dryUnaryUpdate,
|
341
|
+
"UpdateExpression": dryUnaryUpdate,
|
342
|
+
"VariableDeclarator": function(node) {
|
343
|
+
if (node.init && hasExcessParens(node.init) &&
|
344
|
+
precedence(node.init) >= precedence({type: "AssignmentExpression"}) &&
|
345
|
+
// RegExp literal is allowed to have parens (#1589)
|
346
|
+
!(node.init.type === "Literal" && node.init.regex)) {
|
347
|
+
report(node.init);
|
348
|
+
}
|
349
|
+
},
|
350
|
+
"WhileStatement": function(node) {
|
351
|
+
if (hasDoubleExcessParens(node.test)) {
|
352
|
+
report(node.test);
|
353
|
+
}
|
354
|
+
},
|
355
|
+
"WithStatement": function(node) {
|
356
|
+
if (hasDoubleExcessParens(node.object)) {
|
357
|
+
report(node.object);
|
358
|
+
}
|
359
|
+
}
|
360
|
+
};
|
361
|
+
|
362
|
+
};
|
363
|
+
|
364
|
+
module.exports.schema = [
|
365
|
+
{
|
366
|
+
"enum": ["all", "functions"]
|
367
|
+
}
|
368
|
+
];
|