.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / eqeqeq.js
1 /**
2  * @fileoverview Rule to flag statements that use != and == instead of !== and ===
3  * @author Nicholas C. Zakas
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 module.exports = {
19     meta: {
20         type: "suggestion",
21
22         docs: {
23             description: "require the use of `===` and `!==`",
24             category: "Best Practices",
25             recommended: false,
26             url: "https://eslint.org/docs/rules/eqeqeq"
27         },
28
29         schema: {
30             anyOf: [
31                 {
32                     type: "array",
33                     items: [
34                         {
35                             enum: ["always"]
36                         },
37                         {
38                             type: "object",
39                             properties: {
40                                 null: {
41                                     enum: ["always", "never", "ignore"]
42                                 }
43                             },
44                             additionalProperties: false
45                         }
46                     ],
47                     additionalItems: false
48                 },
49                 {
50                     type: "array",
51                     items: [
52                         {
53                             enum: ["smart", "allow-null"]
54                         }
55                     ],
56                     additionalItems: false
57                 }
58             ]
59         },
60
61         fixable: "code",
62
63         messages: {
64             unexpected: "Expected '{{expectedOperator}}' and instead saw '{{actualOperator}}'."
65         }
66     },
67
68     create(context) {
69         const config = context.options[0] || "always";
70         const options = context.options[1] || {};
71         const sourceCode = context.getSourceCode();
72
73         const nullOption = (config === "always")
74             ? options.null || "always"
75             : "ignore";
76         const enforceRuleForNull = (nullOption === "always");
77         const enforceInverseRuleForNull = (nullOption === "never");
78
79         /**
80          * Checks if an expression is a typeof expression
81          * @param  {ASTNode} node The node to check
82          * @returns {boolean} if the node is a typeof expression
83          */
84         function isTypeOf(node) {
85             return node.type === "UnaryExpression" && node.operator === "typeof";
86         }
87
88         /**
89          * Checks if either operand of a binary expression is a typeof operation
90          * @param {ASTNode} node The node to check
91          * @returns {boolean} if one of the operands is typeof
92          * @private
93          */
94         function isTypeOfBinary(node) {
95             return isTypeOf(node.left) || isTypeOf(node.right);
96         }
97
98         /**
99          * Checks if operands are literals of the same type (via typeof)
100          * @param {ASTNode} node The node to check
101          * @returns {boolean} if operands are of same type
102          * @private
103          */
104         function areLiteralsAndSameType(node) {
105             return node.left.type === "Literal" && node.right.type === "Literal" &&
106                     typeof node.left.value === typeof node.right.value;
107         }
108
109         /**
110          * Checks if one of the operands is a literal null
111          * @param {ASTNode} node The node to check
112          * @returns {boolean} if operands are null
113          * @private
114          */
115         function isNullCheck(node) {
116             return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
117         }
118
119         /**
120          * Reports a message for this rule.
121          * @param {ASTNode} node The binary expression node that was checked
122          * @param {string} expectedOperator The operator that was expected (either '==', '!=', '===', or '!==')
123          * @returns {void}
124          * @private
125          */
126         function report(node, expectedOperator) {
127             const operatorToken = sourceCode.getFirstTokenBetween(
128                 node.left,
129                 node.right,
130                 token => token.value === node.operator
131             );
132
133             context.report({
134                 node,
135                 loc: operatorToken.loc,
136                 messageId: "unexpected",
137                 data: { expectedOperator, actualOperator: node.operator },
138                 fix(fixer) {
139
140                     // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
141                     if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
142                         return fixer.replaceText(operatorToken, expectedOperator);
143                     }
144                     return null;
145                 }
146             });
147         }
148
149         return {
150             BinaryExpression(node) {
151                 const isNull = isNullCheck(node);
152
153                 if (node.operator !== "==" && node.operator !== "!=") {
154                     if (enforceInverseRuleForNull && isNull) {
155                         report(node, node.operator.slice(0, -1));
156                     }
157                     return;
158                 }
159
160                 if (config === "smart" && (isTypeOfBinary(node) ||
161                         areLiteralsAndSameType(node) || isNull)) {
162                     return;
163                 }
164
165                 if (!enforceRuleForNull && isNull) {
166                     return;
167                 }
168
169                 report(node, `${node.operator}=`);
170             }
171         };
172
173     }
174 };