UNPKG

2.81 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag unnecessary double negation in Boolean contexts
3 * @author Brandon Mills
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = {
13 meta: {
14 docs: {
15 description: "disallow unnecessary boolean casts",
16 category: "Possible Errors",
17 recommended: true
18 },
19
20 schema: []
21 },
22
23 create(context) {
24
25 // Node types which have a test which will coerce values to booleans.
26 const BOOLEAN_NODE_TYPES = [
27 "IfStatement",
28 "DoWhileStatement",
29 "WhileStatement",
30 "ConditionalExpression",
31 "ForStatement"
32 ];
33
34 /**
35 * Check if a node is in a context where its value would be coerced to a boolean at runtime.
36 *
37 * @param {Object} node The node
38 * @param {Object} parent Its parent
39 * @returns {boolean} If it is in a boolean context
40 */
41 function isInBooleanContext(node, parent) {
42 return (
43 (BOOLEAN_NODE_TYPES.indexOf(parent.type) !== -1 &&
44 node === parent.test) ||
45
46 // !<bool>
47 (parent.type === "UnaryExpression" &&
48 parent.operator === "!")
49 );
50 }
51
52
53 return {
54 UnaryExpression(node) {
55 const ancestors = context.getAncestors(),
56 parent = ancestors.pop(),
57 grandparent = ancestors.pop();
58
59 // Exit early if it's guaranteed not to match
60 if (node.operator !== "!" ||
61 parent.type !== "UnaryExpression" ||
62 parent.operator !== "!") {
63 return;
64 }
65
66 if (isInBooleanContext(parent, grandparent) ||
67
68 // Boolean(<bool>) and new Boolean(<bool>)
69 ((grandparent.type === "CallExpression" || grandparent.type === "NewExpression") &&
70 grandparent.callee.type === "Identifier" &&
71 grandparent.callee.name === "Boolean")
72 ) {
73 context.report(node, "Redundant double negation.");
74 }
75 },
76 CallExpression(node) {
77 const parent = node.parent;
78
79 if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") {
80 return;
81 }
82
83 if (isInBooleanContext(node, parent)) {
84 context.report(node, "Redundant Boolean call.");
85 }
86 }
87 };
88
89 }
90};