.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / tslint / lib / rules / strictComparisonsRule.js
1 "use strict";
2 /**
3  * @license
4  * Copyright 2019 Palantir Technologies, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 Object.defineProperty(exports, "__esModule", { value: true });
19 var tslib_1 = require("tslib");
20 var _a, _b, _c;
21 var tsutils_1 = require("tsutils");
22 var ts = require("typescript");
23 var Lint = require("../index");
24 var strictComparisons_examples_1 = require("./code-examples/strictComparisons.examples");
25 var OPTION_ALLOW_OBJECT_EQUAL_COMPARISON = "allow-object-equal-comparison";
26 var OPTION_ALLOW_STRING_ORDER_COMPARISON = "allow-string-order-comparison";
27 var typeNames = (_a = {},
28     _a[0 /* Any */] = "any",
29     _a[1 /* Number */] = "number",
30     _a[2 /* Enum */] = "enum",
31     _a[3 /* String */] = "string",
32     _a[4 /* Boolean */] = "boolean",
33     _a[5 /* Null */] = "null",
34     _a[6 /* Undefined */] = "undefined",
35     _a[7 /* Object */] = "object",
36     _a);
37 var Rule = /** @class */ (function (_super) {
38     tslib_1.__extends(Rule, _super);
39     function Rule() {
40         return _super !== null && _super.apply(this, arguments) || this;
41     }
42     /* tslint:enable:object-literal-sort-keys */
43     Rule.INVALID_TYPES = function (types1, types2) {
44         var types1String = types1.map(function (type) { return typeNames[type]; }).join(" | ");
45         var types2String = types2.map(function (type) { return typeNames[type]; }).join(" | ");
46         return "Cannot compare type '" + types1String + "' to type '" + types2String + "'.";
47     };
48     Rule.INVALID_TYPE_FOR_OPERATOR = function (type, comparator) {
49         return "Cannot use '" + comparator + "' comparator for type '" + typeNames[type] + "'.";
50     };
51     Rule.prototype.applyWithProgram = function (sourceFile, program) {
52         return this.applyWithFunction(sourceFile, walk, this.getRuleOptions(), program);
53     };
54     Rule.prototype.getRuleOptions = function () {
55         if (this.ruleArguments[0] === undefined) {
56             return {};
57         }
58         else {
59             return this.ruleArguments[0];
60         }
61     };
62     /* tslint:disable:object-literal-sort-keys */
63     Rule.metadata = {
64         ruleName: "strict-comparisons",
65         description: "Only allow comparisons between primitives.",
66         optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n                One of the following arguments may be optionally provided:\n                * `", "` allows `!=` `==` `!==` `===` comparison between any types.\n                * `", "` allows `>` `<` `>=` `<=` comparison between strings."], ["\n                One of the following arguments may be optionally provided:\n                * \\`", "\\` allows \\`!=\\` \\`==\\` \\`!==\\` \\`===\\` comparison between any types.\n                * \\`", "\\` allows \\`>\\` \\`<\\` \\`>=\\` \\`<=\\` comparison between strings."])), OPTION_ALLOW_OBJECT_EQUAL_COMPARISON, OPTION_ALLOW_STRING_ORDER_COMPARISON),
67         options: {
68             type: "object",
69             properties: (_b = {},
70                 _b[OPTION_ALLOW_OBJECT_EQUAL_COMPARISON] = {
71                     type: "boolean",
72                 },
73                 _b[OPTION_ALLOW_STRING_ORDER_COMPARISON] = {
74                     type: "boolean",
75                 },
76                 _b),
77         },
78         optionExamples: [
79             true,
80             [
81                 true,
82                 (_c = {},
83                     _c[OPTION_ALLOW_OBJECT_EQUAL_COMPARISON] = false,
84                     _c[OPTION_ALLOW_STRING_ORDER_COMPARISON] = false,
85                     _c),
86             ],
87         ],
88         rationale: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n                When using comparison operators to compare objects, they compare references and not values.\n                This is often done accidentally.\n                With this rule, `>`, `>=`, `<`, `<=` operators are only allowed when comparing `numbers`.\n                `===`, `!==` are allowed for `number` `string` and `boolean` types and if one of the\n                operands is `null` or `undefined`.\n            "], ["\n                When using comparison operators to compare objects, they compare references and not values.\n                This is often done accidentally.\n                With this rule, \\`>\\`, \\`>=\\`, \\`<\\`, \\`<=\\` operators are only allowed when comparing \\`numbers\\`.\n                \\`===\\`, \\`!==\\` are allowed for \\`number\\` \\`string\\` and \\`boolean\\` types and if one of the\n                operands is \\`null\\` or \\`undefined\\`.\n            "]))),
89         type: "functionality",
90         typescriptOnly: false,
91         requiresTypeInfo: true,
92         codeExamples: strictComparisons_examples_1.codeExamples,
93     };
94     return Rule;
95 }(Lint.Rules.TypedRule));
96 exports.Rule = Rule;
97 function walk(ctx, program) {
98     var sourceFile = ctx.sourceFile, options = ctx.options;
99     var checker = program.getTypeChecker();
100     return ts.forEachChild(sourceFile, function cb(node) {
101         if (tsutils_1.isBinaryExpression(node) && isComparisonOperator(node)) {
102             var isEquality = isEqualityOperator(node);
103             var leftType = checker.getTypeAtLocation(node.left);
104             var rightType = checker.getTypeAtLocation(node.right);
105             if ((containsNullOrUndefined(leftType) || containsNullOrUndefined(rightType)) &&
106                 isEquality) {
107                 return;
108             }
109             var leftKinds = getTypes(leftType);
110             var rightKinds = getTypes(rightType);
111             var operandKind = getStrictestComparableType(leftKinds, rightKinds);
112             if (operandKind === undefined) {
113                 var failureString = Rule.INVALID_TYPES(leftKinds, rightKinds);
114                 ctx.addFailureAtNode(node, failureString);
115             }
116             else {
117                 var failureString = Rule.INVALID_TYPE_FOR_OPERATOR(operandKind, node.operatorToken.getText());
118                 if (isEquality) {
119                     // Check !=, ==, !==, ===
120                     switch (operandKind) {
121                         case 0 /* Any */:
122                         case 1 /* Number */:
123                         case 2 /* Enum */:
124                         case 3 /* String */:
125                         case 4 /* Boolean */:
126                             break;
127                         case 5 /* Null */:
128                         case 6 /* Undefined */:
129                         case 7 /* Object */:
130                             if (options[OPTION_ALLOW_OBJECT_EQUAL_COMPARISON]) {
131                                 break;
132                             }
133                             ctx.addFailureAtNode(node, failureString);
134                             break;
135                         default:
136                             ctx.addFailureAtNode(node, failureString);
137                     }
138                 }
139                 else {
140                     // Check >, <, >=, <=
141                     switch (operandKind) {
142                         case 0 /* Any */:
143                         case 1 /* Number */:
144                             break;
145                         case 3 /* String */:
146                             if (options[OPTION_ALLOW_STRING_ORDER_COMPARISON]) {
147                                 break;
148                             }
149                             ctx.addFailureAtNode(node, failureString);
150                             break;
151                         default:
152                             ctx.addFailureAtNode(node, failureString);
153                     }
154                 }
155             }
156         }
157         return ts.forEachChild(node, cb);
158     });
159 }
160 function containsNullOrUndefined(type) {
161     return (type.intrinsicName === "null" ||
162         type.intrinsicName === "undefined");
163 }
164 function getTypes(types) {
165     // Compatibility for TypeScript pre-2.4, which used EnumLiteralType instead of LiteralType
166     var baseType = types.baseType;
167     return tsutils_1.isUnionType(types)
168         ? Array.from(new Set(types.types.map(getKind)))
169         : tsutils_1.isTypeFlagSet(types, ts.TypeFlags.EnumLiteral) && typeof baseType !== "undefined"
170             ? [getKind(baseType)]
171             : [getKind(types)];
172 }
173 function getStrictestComparableType(typesLeft, typesRight) {
174     var overlappingTypes = typesLeft.filter(function (type) { return typesRight.indexOf(type) >= 0; });
175     if (overlappingTypes.length > 0) {
176         return getStrictestKind(overlappingTypes);
177     }
178     else {
179         // In case one of the types is "any", get the strictest type of the other array
180         if (arrayContainsKind(typesLeft, [0 /* Any */])) {
181             return getStrictestKind(typesRight);
182         }
183         if (arrayContainsKind(typesRight, [0 /* Any */])) {
184             return getStrictestKind(typesLeft);
185         }
186         // In case one array contains NullOrUndefined and the other an Object, return Object
187         if ((arrayContainsKind(typesLeft, [5 /* Null */, 6 /* Undefined */]) &&
188             arrayContainsKind(typesRight, [7 /* Object */])) ||
189             (arrayContainsKind(typesRight, [5 /* Null */, 6 /* Undefined */]) &&
190                 arrayContainsKind(typesLeft, [7 /* Object */]))) {
191             return 7 /* Object */;
192         }
193         return undefined;
194     }
195 }
196 function arrayContainsKind(types, typeToCheck) {
197     return types.some(function (type) { return typeToCheck.indexOf(type) >= 0; });
198 }
199 function getStrictestKind(types) {
200     // tslint:disable-next-line:no-unsafe-any
201     return Math.max.apply(Math, types);
202 }
203 function isComparisonOperator(node) {
204     switch (node.operatorToken.kind) {
205         case ts.SyntaxKind.LessThanToken:
206         case ts.SyntaxKind.GreaterThanToken:
207         case ts.SyntaxKind.LessThanEqualsToken:
208         case ts.SyntaxKind.GreaterThanEqualsToken:
209         case ts.SyntaxKind.EqualsEqualsToken:
210         case ts.SyntaxKind.ExclamationEqualsToken:
211         case ts.SyntaxKind.EqualsEqualsEqualsToken:
212         case ts.SyntaxKind.ExclamationEqualsEqualsToken:
213             return true;
214         default:
215             return false;
216     }
217 }
218 function isEqualityOperator(node) {
219     switch (node.operatorToken.kind) {
220         case ts.SyntaxKind.EqualsEqualsToken:
221         case ts.SyntaxKind.ExclamationEqualsToken:
222         case ts.SyntaxKind.EqualsEqualsEqualsToken:
223         case ts.SyntaxKind.ExclamationEqualsEqualsToken:
224             return true;
225         default:
226             return false;
227     }
228 }
229 function getKind(type) {
230     // tslint:disable:no-bitwise
231     if (is(ts.TypeFlags.String | ts.TypeFlags.StringLiteral)) {
232         return 3 /* String */;
233     }
234     else if (is(ts.TypeFlags.Number | ts.TypeFlags.NumberLiteral)) {
235         return 1 /* Number */;
236     }
237     else if (is(ts.TypeFlags.BooleanLike)) {
238         return 4 /* Boolean */;
239     }
240     else if (is(ts.TypeFlags.Null)) {
241         return 5 /* Null */;
242     }
243     else if (is(ts.TypeFlags.Undefined)) {
244         return 6 /* Undefined */;
245     }
246     else if (is(ts.TypeFlags.Any)) {
247         return 0 /* Any */;
248     }
249     else {
250         return 7 /* Object */;
251     }
252     // tslint:enable:no-bitwise
253     function is(flags) {
254         return tsutils_1.isTypeFlagSet(type, flags);
255     }
256 }
257 var templateObject_1, templateObject_2;