1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | const astUtils = require("../ast-utils.js");
|
12 |
|
13 | module.exports = {
|
14 | meta: {
|
15 | docs: {
|
16 | description: "disallow unnecessary parentheses",
|
17 | category: "Possible Errors",
|
18 | recommended: false,
|
19 | url: "https://eslint.org/docs/rules/no-extra-parens"
|
20 | },
|
21 |
|
22 | fixable: "code",
|
23 |
|
24 | schema: {
|
25 | anyOf: [
|
26 | {
|
27 | type: "array",
|
28 | items: [
|
29 | {
|
30 | enum: ["functions"]
|
31 | }
|
32 | ],
|
33 | minItems: 0,
|
34 | maxItems: 1
|
35 | },
|
36 | {
|
37 | type: "array",
|
38 | items: [
|
39 | {
|
40 | enum: ["all"]
|
41 | },
|
42 | {
|
43 | type: "object",
|
44 | properties: {
|
45 | conditionalAssign: { type: "boolean" },
|
46 | nestedBinaryExpressions: { type: "boolean" },
|
47 | returnAssign: { type: "boolean" },
|
48 | ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] },
|
49 | enforceForArrowConditionals: { type: "boolean" }
|
50 | },
|
51 | additionalProperties: false
|
52 | }
|
53 | ],
|
54 | minItems: 0,
|
55 | maxItems: 2
|
56 | }
|
57 | ]
|
58 | },
|
59 |
|
60 | messages: {
|
61 | unexpected: "Gratuitous parentheses around expression."
|
62 | }
|
63 | },
|
64 |
|
65 | create(context) {
|
66 | const sourceCode = context.getSourceCode();
|
67 |
|
68 | const tokensToIgnore = new WeakSet();
|
69 | const isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode);
|
70 | const precedence = astUtils.getPrecedence;
|
71 | const ALL_NODES = context.options[0] !== "functions";
|
72 | const EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false;
|
73 | const NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false;
|
74 | const EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false;
|
75 | const IGNORE_JSX = ALL_NODES && context.options[1] && context.options[1].ignoreJSX;
|
76 | const IGNORE_ARROW_CONDITIONALS = ALL_NODES && context.options[1] &&
|
77 | context.options[1].enforceForArrowConditionals === false;
|
78 |
|
79 | const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
|
80 | const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
|
81 |
|
82 | |
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | function ruleApplies(node) {
|
89 | if (node.type === "JSXElement") {
|
90 | const isSingleLine = node.loc.start.line === node.loc.end.line;
|
91 |
|
92 | switch (IGNORE_JSX) {
|
93 |
|
94 |
|
95 | case "all":
|
96 | return false;
|
97 |
|
98 |
|
99 | case "multi-line":
|
100 | return isSingleLine;
|
101 |
|
102 |
|
103 | case "single-line":
|
104 | return !isSingleLine;
|
105 |
|
106 |
|
107 | case "none":
|
108 | break;
|
109 |
|
110 |
|
111 | }
|
112 | }
|
113 |
|
114 | return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
115 | }
|
116 |
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | function isParenthesisedTwice(node) {
|
124 | const previousToken = sourceCode.getTokenBefore(node, 1),
|
125 | nextToken = sourceCode.getTokenAfter(node, 1);
|
126 |
|
127 | return isParenthesised(node) && previousToken && nextToken &&
|
128 | astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
|
129 | astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
|
130 | }
|
131 |
|
132 | |
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 | function hasExcessParens(node) {
|
139 | return ruleApplies(node) && isParenthesised(node);
|
140 | }
|
141 |
|
142 | |
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 | function hasDoubleExcessParens(node) {
|
150 | return ruleApplies(node) && isParenthesisedTwice(node);
|
151 | }
|
152 |
|
153 | |
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 | function isCondAssignException(node) {
|
160 | return EXCEPT_COND_ASSIGN && node.test.type === "AssignmentExpression";
|
161 | }
|
162 |
|
163 | |
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | function isInReturnStatement(node) {
|
170 | while (node) {
|
171 | if (node.type === "ReturnStatement" ||
|
172 | (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement")) {
|
173 | return true;
|
174 | }
|
175 | node = node.parent;
|
176 | }
|
177 |
|
178 | return false;
|
179 | }
|
180 |
|
181 | |
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 | function isNewExpressionWithParens(newExpression) {
|
188 | const lastToken = sourceCode.getLastToken(newExpression);
|
189 | const penultimateToken = sourceCode.getTokenBefore(lastToken);
|
190 |
|
191 | return newExpression.arguments.length > 0 || astUtils.isOpeningParenToken(penultimateToken) && astUtils.isClosingParenToken(lastToken);
|
192 | }
|
193 |
|
194 | |
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | function containsAssignment(node) {
|
201 | if (node.type === "AssignmentExpression") {
|
202 | return true;
|
203 | }
|
204 | if (node.type === "ConditionalExpression" &&
|
205 | (node.consequent.type === "AssignmentExpression" || node.alternate.type === "AssignmentExpression")) {
|
206 | return true;
|
207 | }
|
208 | if ((node.left && node.left.type === "AssignmentExpression") ||
|
209 | (node.right && node.right.type === "AssignmentExpression")) {
|
210 | return true;
|
211 | }
|
212 |
|
213 | return false;
|
214 | }
|
215 |
|
216 | |
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 | function isReturnAssignException(node) {
|
223 | if (!EXCEPT_RETURN_ASSIGN || !isInReturnStatement(node)) {
|
224 | return false;
|
225 | }
|
226 |
|
227 | if (node.type === "ReturnStatement") {
|
228 | return node.argument && containsAssignment(node.argument);
|
229 | }
|
230 | if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") {
|
231 | return containsAssignment(node.body);
|
232 | }
|
233 | return containsAssignment(node);
|
234 |
|
235 | }
|
236 |
|
237 | |
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | function hasExcessParensNoLineTerminator(token, node) {
|
246 | if (token.loc.end.line === node.loc.start.line) {
|
247 | return hasExcessParens(node);
|
248 | }
|
249 |
|
250 | return hasDoubleExcessParens(node);
|
251 | }
|
252 |
|
253 | |
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 | function requiresLeadingSpace(node) {
|
260 | const leftParenToken = sourceCode.getTokenBefore(node);
|
261 | const tokenBeforeLeftParen = sourceCode.getTokenBefore(node, 1);
|
262 | const firstToken = sourceCode.getFirstToken(node);
|
263 |
|
264 | return tokenBeforeLeftParen &&
|
265 | tokenBeforeLeftParen.range[1] === leftParenToken.range[0] &&
|
266 | leftParenToken.range[1] === firstToken.range[0] &&
|
267 | !astUtils.canTokensBeAdjacent(tokenBeforeLeftParen, firstToken);
|
268 | }
|
269 |
|
270 | |
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 | function requiresTrailingSpace(node) {
|
277 | const nextTwoTokens = sourceCode.getTokensAfter(node, { count: 2 });
|
278 | const rightParenToken = nextTwoTokens[0];
|
279 | const tokenAfterRightParen = nextTwoTokens[1];
|
280 | const tokenBeforeRightParen = sourceCode.getLastToken(node);
|
281 |
|
282 | return rightParenToken && tokenAfterRightParen &&
|
283 | !sourceCode.isSpaceBetweenTokens(rightParenToken, tokenAfterRightParen) &&
|
284 | !astUtils.canTokensBeAdjacent(tokenBeforeRightParen, tokenAfterRightParen);
|
285 | }
|
286 |
|
287 | |
288 |
|
289 |
|
290 |
|
291 |
|
292 | function isIIFE(node) {
|
293 | return node.type === "CallExpression" && node.callee.type === "FunctionExpression";
|
294 | }
|
295 |
|
296 | |
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | function report(node) {
|
303 | const leftParenToken = sourceCode.getTokenBefore(node);
|
304 | const rightParenToken = sourceCode.getTokenAfter(node);
|
305 |
|
306 | if (!isParenthesisedTwice(node)) {
|
307 | if (tokensToIgnore.has(sourceCode.getFirstToken(node))) {
|
308 | return;
|
309 | }
|
310 |
|
311 | if (isIIFE(node) && !isParenthesised(node.callee)) {
|
312 | return;
|
313 | }
|
314 | }
|
315 |
|
316 | context.report({
|
317 | node,
|
318 | loc: leftParenToken.loc.start,
|
319 | messageId: "unexpected",
|
320 | fix(fixer) {
|
321 | const parenthesizedSource = sourceCode.text.slice(leftParenToken.range[1], rightParenToken.range[0]);
|
322 |
|
323 | return fixer.replaceTextRange([
|
324 | leftParenToken.range[0],
|
325 | rightParenToken.range[1]
|
326 | ], (requiresLeadingSpace(node) ? " " : "") + parenthesizedSource + (requiresTrailingSpace(node) ? " " : ""));
|
327 | }
|
328 | });
|
329 | }
|
330 |
|
331 | |
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 | function checkUnaryUpdate(node) {
|
338 | if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") {
|
339 | return;
|
340 | }
|
341 |
|
342 | if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) {
|
343 | report(node.argument);
|
344 | }
|
345 | }
|
346 |
|
347 | |
348 |
|
349 |
|
350 |
|
351 |
|
352 | function doesMemberExpressionContainCallExpression(node) {
|
353 | let currentNode = node.object;
|
354 | let currentNodeType = node.object.type;
|
355 |
|
356 | while (currentNodeType === "MemberExpression") {
|
357 | currentNode = currentNode.object;
|
358 | currentNodeType = currentNode.type;
|
359 | }
|
360 |
|
361 | return currentNodeType === "CallExpression";
|
362 | }
|
363 |
|
364 | |
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 | function checkCallNew(node) {
|
371 | const callee = node.callee;
|
372 |
|
373 | if (hasExcessParens(callee) && precedence(callee) >= precedence(node)) {
|
374 | const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee);
|
375 |
|
376 | if (
|
377 | hasDoubleExcessParens(callee) ||
|
378 | !isIIFE(node) && !hasNewParensException && !(
|
379 |
|
380 | |
381 |
|
382 |
|
383 |
|
384 | callee.type === "MemberExpression" &&
|
385 | doesMemberExpressionContainCallExpression(callee)
|
386 | )
|
387 | ) {
|
388 | report(node.callee);
|
389 | }
|
390 | }
|
391 | if (node.arguments.length === 1) {
|
392 | if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
|
393 | report(node.arguments[0]);
|
394 | }
|
395 | } else {
|
396 | node.arguments
|
397 | .filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
|
398 | .forEach(report);
|
399 | }
|
400 | }
|
401 |
|
402 | |
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 | function checkBinaryLogical(node) {
|
409 | const prec = precedence(node);
|
410 | const leftPrecedence = precedence(node.left);
|
411 | const rightPrecedence = precedence(node.right);
|
412 | const isExponentiation = node.operator === "**";
|
413 | const shouldSkipLeft = (NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression")) ||
|
414 | node.left.type === "UnaryExpression" && isExponentiation;
|
415 | const shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression");
|
416 |
|
417 | if (!shouldSkipLeft && hasExcessParens(node.left) && (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation))) {
|
418 | report(node.left);
|
419 | }
|
420 | if (!shouldSkipRight && hasExcessParens(node.right) && (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation))) {
|
421 | report(node.right);
|
422 | }
|
423 | }
|
424 |
|
425 | |
426 |
|
427 |
|
428 |
|
429 |
|
430 | function checkClass(node) {
|
431 | if (!node.superClass) {
|
432 | return;
|
433 | }
|
434 |
|
435 | |
436 |
|
437 |
|
438 |
|
439 | const hasExtraParens = precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR
|
440 | ? hasExcessParens(node.superClass)
|
441 | : hasDoubleExcessParens(node.superClass);
|
442 |
|
443 | if (hasExtraParens) {
|
444 | report(node.superClass);
|
445 | }
|
446 | }
|
447 |
|
448 | |
449 |
|
450 |
|
451 |
|
452 |
|
453 | function checkSpreadOperator(node) {
|
454 | const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR
|
455 | ? hasExcessParens(node.argument)
|
456 | : hasDoubleExcessParens(node.argument);
|
457 |
|
458 | if (hasExtraParens) {
|
459 | report(node.argument);
|
460 | }
|
461 | }
|
462 |
|
463 | |
464 |
|
465 |
|
466 |
|
467 |
|
468 | function checkExpressionOrExportStatement(node) {
|
469 | const firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node);
|
470 | const secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken);
|
471 | const thirdToken = secondToken ? sourceCode.getTokenAfter(secondToken) : null;
|
472 |
|
473 | if (
|
474 | astUtils.isOpeningParenToken(firstToken) &&
|
475 | (
|
476 | astUtils.isOpeningBraceToken(secondToken) ||
|
477 | secondToken.type === "Keyword" && (
|
478 | secondToken.value === "function" ||
|
479 | secondToken.value === "class" ||
|
480 | secondToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(secondToken, astUtils.isNotClosingParenToken))
|
481 | ) ||
|
482 | secondToken && secondToken.type === "Identifier" && secondToken.value === "async" && thirdToken && thirdToken.type === "Keyword" && thirdToken.value === "function"
|
483 | )
|
484 | ) {
|
485 | tokensToIgnore.add(secondToken);
|
486 | }
|
487 |
|
488 | if (hasExcessParens(node)) {
|
489 | report(node);
|
490 | }
|
491 | }
|
492 |
|
493 | return {
|
494 | ArrayExpression(node) {
|
495 | node.elements
|
496 | .filter(e => e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
|
497 | .forEach(report);
|
498 | },
|
499 |
|
500 | ArrowFunctionExpression(node) {
|
501 | if (isReturnAssignException(node)) {
|
502 | return;
|
503 | }
|
504 |
|
505 | if (node.body.type === "ConditionalExpression" &&
|
506 | IGNORE_ARROW_CONDITIONALS &&
|
507 | !isParenthesisedTwice(node.body)
|
508 | ) {
|
509 | return;
|
510 | }
|
511 |
|
512 | if (node.body.type !== "BlockStatement") {
|
513 | const firstBodyToken = sourceCode.getFirstToken(node.body, astUtils.isNotOpeningParenToken);
|
514 | const tokenBeforeFirst = sourceCode.getTokenBefore(firstBodyToken);
|
515 |
|
516 | if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) {
|
517 | tokensToIgnore.add(firstBodyToken);
|
518 | }
|
519 | if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
|
520 | report(node.body);
|
521 | }
|
522 | }
|
523 | },
|
524 |
|
525 | AssignmentExpression(node) {
|
526 | if (isReturnAssignException(node)) {
|
527 | return;
|
528 | }
|
529 |
|
530 | if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) {
|
531 | report(node.right);
|
532 | }
|
533 | },
|
534 |
|
535 | BinaryExpression: checkBinaryLogical,
|
536 | CallExpression: checkCallNew,
|
537 |
|
538 | ConditionalExpression(node) {
|
539 | if (isReturnAssignException(node)) {
|
540 | return;
|
541 | }
|
542 |
|
543 | if (hasExcessParens(node.test) && precedence(node.test) >= precedence({ type: "LogicalExpression", operator: "||" })) {
|
544 | report(node.test);
|
545 | }
|
546 |
|
547 | if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
|
548 | report(node.consequent);
|
549 | }
|
550 |
|
551 | if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
|
552 | report(node.alternate);
|
553 | }
|
554 | },
|
555 |
|
556 | DoWhileStatement(node) {
|
557 | if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
|
558 | report(node.test);
|
559 | }
|
560 | },
|
561 |
|
562 | ExportDefaultDeclaration: node => checkExpressionOrExportStatement(node.declaration),
|
563 | ExpressionStatement: node => checkExpressionOrExportStatement(node.expression),
|
564 |
|
565 | "ForInStatement, ForOfStatement"(node) {
|
566 | if (node.left.type !== "VariableDeclarator") {
|
567 | const firstLeftToken = sourceCode.getFirstToken(node.left, astUtils.isNotOpeningParenToken);
|
568 |
|
569 | if (
|
570 | firstLeftToken.value === "let" && (
|
571 |
|
572 | |
573 |
|
574 |
|
575 |
|
576 | firstLeftToken.range[1] === node.left.range[1] ||
|
577 |
|
578 | |
579 |
|
580 |
|
581 |
|
582 | astUtils.isOpeningBracketToken(
|
583 | sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken)
|
584 | )
|
585 | )
|
586 | ) {
|
587 | tokensToIgnore.add(firstLeftToken);
|
588 | }
|
589 | }
|
590 | if (!(node.type === "ForOfStatement" && node.right.type === "SequenceExpression") && hasExcessParens(node.right)) {
|
591 | report(node.right);
|
592 | }
|
593 | if (hasExcessParens(node.left)) {
|
594 | report(node.left);
|
595 | }
|
596 | },
|
597 |
|
598 | ForStatement(node) {
|
599 | if (node.init && hasExcessParens(node.init)) {
|
600 | report(node.init);
|
601 | }
|
602 |
|
603 | if (node.test && hasExcessParens(node.test) && !isCondAssignException(node)) {
|
604 | report(node.test);
|
605 | }
|
606 |
|
607 | if (node.update && hasExcessParens(node.update)) {
|
608 | report(node.update);
|
609 | }
|
610 | },
|
611 |
|
612 | IfStatement(node) {
|
613 | if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
|
614 | report(node.test);
|
615 | }
|
616 | },
|
617 |
|
618 | LogicalExpression: checkBinaryLogical,
|
619 |
|
620 | MemberExpression(node) {
|
621 | const nodeObjHasExcessParens = hasExcessParens(node.object);
|
622 |
|
623 | if (
|
624 | nodeObjHasExcessParens &&
|
625 | precedence(node.object) >= precedence(node) &&
|
626 | (
|
627 | node.computed ||
|
628 | !(
|
629 | astUtils.isDecimalInteger(node.object) ||
|
630 |
|
631 |
|
632 | (node.object.type === "Literal" && node.object.regex)
|
633 | )
|
634 | )
|
635 | ) {
|
636 | report(node.object);
|
637 | }
|
638 |
|
639 | if (nodeObjHasExcessParens &&
|
640 | node.object.type === "CallExpression" &&
|
641 | node.parent.type !== "NewExpression") {
|
642 | report(node.object);
|
643 | }
|
644 |
|
645 | if (node.computed && hasExcessParens(node.property)) {
|
646 | report(node.property);
|
647 | }
|
648 | },
|
649 |
|
650 | NewExpression: checkCallNew,
|
651 |
|
652 | ObjectExpression(node) {
|
653 | node.properties
|
654 | .filter(property => {
|
655 | const value = property.value;
|
656 |
|
657 | return value && hasExcessParens(value) && precedence(value) >= PRECEDENCE_OF_ASSIGNMENT_EXPR;
|
658 | }).forEach(property => report(property.value));
|
659 | },
|
660 |
|
661 | ReturnStatement(node) {
|
662 | const returnToken = sourceCode.getFirstToken(node);
|
663 |
|
664 | if (isReturnAssignException(node)) {
|
665 | return;
|
666 | }
|
667 |
|
668 | if (node.argument &&
|
669 | hasExcessParensNoLineTerminator(returnToken, node.argument) &&
|
670 |
|
671 |
|
672 | !(node.argument.type === "Literal" && node.argument.regex)) {
|
673 | report(node.argument);
|
674 | }
|
675 | },
|
676 |
|
677 | SequenceExpression(node) {
|
678 | node.expressions
|
679 | .filter(e => hasExcessParens(e) && precedence(e) >= precedence(node))
|
680 | .forEach(report);
|
681 | },
|
682 |
|
683 | SwitchCase(node) {
|
684 | if (node.test && hasExcessParens(node.test)) {
|
685 | report(node.test);
|
686 | }
|
687 | },
|
688 |
|
689 | SwitchStatement(node) {
|
690 | if (hasDoubleExcessParens(node.discriminant)) {
|
691 | report(node.discriminant);
|
692 | }
|
693 | },
|
694 |
|
695 | ThrowStatement(node) {
|
696 | const throwToken = sourceCode.getFirstToken(node);
|
697 |
|
698 | if (hasExcessParensNoLineTerminator(throwToken, node.argument)) {
|
699 | report(node.argument);
|
700 | }
|
701 | },
|
702 |
|
703 | UnaryExpression: checkUnaryUpdate,
|
704 | UpdateExpression: checkUnaryUpdate,
|
705 | AwaitExpression: checkUnaryUpdate,
|
706 |
|
707 | VariableDeclarator(node) {
|
708 | if (node.init && hasExcessParens(node.init) &&
|
709 | precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR &&
|
710 |
|
711 |
|
712 | !(node.init.type === "Literal" && node.init.regex)) {
|
713 | report(node.init);
|
714 | }
|
715 | },
|
716 |
|
717 | WhileStatement(node) {
|
718 | if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
|
719 | report(node.test);
|
720 | }
|
721 | },
|
722 |
|
723 | WithStatement(node) {
|
724 | if (hasDoubleExcessParens(node.object)) {
|
725 | report(node.object);
|
726 | }
|
727 | },
|
728 |
|
729 | YieldExpression(node) {
|
730 | if (node.argument) {
|
731 | const yieldToken = sourceCode.getFirstToken(node);
|
732 |
|
733 | if ((precedence(node.argument) >= precedence(node) &&
|
734 | hasExcessParensNoLineTerminator(yieldToken, node.argument)) ||
|
735 | hasDoubleExcessParens(node.argument)) {
|
736 | report(node.argument);
|
737 | }
|
738 | }
|
739 | },
|
740 |
|
741 | ClassDeclaration: checkClass,
|
742 | ClassExpression: checkClass,
|
743 |
|
744 | SpreadElement: checkSpreadOperator,
|
745 | SpreadProperty: checkSpreadOperator,
|
746 | ExperimentalSpreadProperty: checkSpreadOperator
|
747 | };
|
748 |
|
749 | }
|
750 | };
|