.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / tslint / lib / rules / strictTypePredicatesRule.js
1 "use strict";
2 /**
3  * @license
4  * Copyright 2017 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 tsutils_1 = require("tsutils");
21 var ts = require("typescript");
22 var error_1 = require("../error");
23 var Lint = require("../index");
24 // tslint:disable:no-bitwise
25 var Rule = /** @class */ (function (_super) {
26     tslib_1.__extends(Rule, _super);
27     function Rule() {
28         return _super !== null && _super.apply(this, arguments) || this;
29     }
30     Rule.FAILURE_STRING = function (value) {
31         return "Expression is always " + value + ".";
32     };
33     Rule.FAILURE_STRICT_PREFER_STRICT_EQUALS = function (value, isPositive) {
34         return "Use '" + (isPositive ? "===" : "!==") + " " + value + "' instead.";
35     };
36     Rule.prototype.applyWithProgram = function (sourceFile, program) {
37         if (!Lint.isStrictNullChecksEnabled(program.getCompilerOptions())) {
38             error_1.showWarningOnce("strict-type-predicates does not work without --strictNullChecks");
39             return [];
40         }
41         return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
42     };
43     /* tslint:disable:object-literal-sort-keys */
44     Rule.metadata = {
45         ruleName: "strict-type-predicates",
46         description: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n            Warns for type predicates that are always true or always false.\n            Works for 'typeof' comparisons to constants (e.g. 'typeof foo === \"string\"'), and equality comparison to 'null'/'undefined'.\n            (TypeScript won't let you compare '1 === 2', but it has an exception for '1 === undefined'.)\n            Does not yet work for 'instanceof'.\n            Does *not* warn for 'if (x.y)' where 'x.y' is always truthy. For that, see strict-boolean-expressions.\n\n            This rule requires `strictNullChecks` to work properly."], ["\n            Warns for type predicates that are always true or always false.\n            Works for 'typeof' comparisons to constants (e.g. 'typeof foo === \"string\"'), and equality comparison to 'null'/'undefined'.\n            (TypeScript won't let you compare '1 === 2', but it has an exception for '1 === undefined'.)\n            Does not yet work for 'instanceof'.\n            Does *not* warn for 'if (x.y)' where 'x.y' is always truthy. For that, see strict-boolean-expressions.\n\n            This rule requires \\`strictNullChecks\\` to work properly."]))),
47         optionsDescription: "Not configurable.",
48         options: null,
49         optionExamples: [true],
50         type: "functionality",
51         typescriptOnly: true,
52         requiresTypeInfo: true,
53     };
54     /* tslint:enable:object-literal-sort-keys */
55     Rule.FAILURE_STRING_BAD_TYPEOF = "Bad comparison for 'typeof'.";
56     return Rule;
57 }(Lint.Rules.TypedRule));
58 exports.Rule = Rule;
59 function walk(ctx, checker) {
60     return ts.forEachChild(ctx.sourceFile, function cb(node) {
61         if (tsutils_1.isBinaryExpression(node)) {
62             var equals = Lint.getEqualsKind(node.operatorToken);
63             if (equals !== undefined) {
64                 checkEquals(node, equals);
65             }
66         }
67         return ts.forEachChild(node, cb);
68     });
69     function checkEquals(node, _a) {
70         var isStrict = _a.isStrict, isPositive = _a.isPositive;
71         var exprPred = getTypePredicate(node, isStrict);
72         if (exprPred === undefined) {
73             return;
74         }
75         if (exprPred.kind === 2 /* TypeofTypo */) {
76             fail(Rule.FAILURE_STRING_BAD_TYPEOF);
77             return;
78         }
79         var exprType = checker.getTypeAtLocation(exprPred.expression);
80         // TODO: could use checker.getBaseConstraintOfType to help with type parameters, but it's not publicly exposed.
81         if (tsutils_1.isTypeFlagSet(exprType, ts.TypeFlags.Any | ts.TypeFlags.TypeParameter | ts.TypeFlags.Unknown)) {
82             return;
83         }
84         switch (exprPred.kind) {
85             case 0 /* Plain */: {
86                 var predicate = exprPred.predicate, isNullOrUndefined = exprPred.isNullOrUndefined;
87                 var value = getConstantBoolean(exprType, predicate);
88                 // 'null'/'undefined' are the only two values *not* assignable to '{}'.
89                 if (value !== undefined && (isNullOrUndefined || !isEmptyType(checker, exprType))) {
90                     fail(Rule.FAILURE_STRING(value === isPositive));
91                 }
92                 break;
93             }
94             case 1 /* NonStructNullUndefined */: {
95                 var result = testNonStrictNullUndefined(exprType);
96                 if (result !== undefined) {
97                     fail(typeof result === "boolean"
98                         ? Rule.FAILURE_STRING(result === isPositive)
99                         : Rule.FAILURE_STRICT_PREFER_STRICT_EQUALS(result, isPositive));
100                 }
101             }
102         }
103         function fail(failure) {
104             ctx.addFailureAtNode(node, failure);
105         }
106     }
107 }
108 /** Detects a type predicate given `left === right`. */
109 function getTypePredicate(node, isStrictEquals) {
110     var left = node.left, right = node.right;
111     var lr = getTypePredicateOneWay(left, right, isStrictEquals);
112     return lr !== undefined ? lr : getTypePredicateOneWay(right, left, isStrictEquals);
113 }
114 /** Only gets the type predicate if the expression is on the left. */
115 function getTypePredicateOneWay(left, right, isStrictEquals) {
116     switch (right.kind) {
117         case ts.SyntaxKind.TypeOfExpression:
118             var expression = right.expression;
119             if (!tsutils_1.isLiteralExpression(left)) {
120                 if ((tsutils_1.isIdentifier(left) && left.text === "undefined") ||
121                     left.kind === ts.SyntaxKind.NullKeyword ||
122                     left.kind === ts.SyntaxKind.TrueKeyword ||
123                     left.kind === ts.SyntaxKind.FalseKeyword) {
124                     return { kind: 2 /* TypeofTypo */ };
125                 }
126                 return undefined;
127             }
128             var predicate = getTypePredicateForKind(left.text);
129             return predicate === undefined
130                 ? { kind: 2 /* TypeofTypo */ }
131                 : {
132                     expression: expression,
133                     isNullOrUndefined: left.text === "undefined",
134                     kind: 0 /* Plain */,
135                     predicate: predicate,
136                 };
137         case ts.SyntaxKind.NullKeyword:
138             return nullOrUndefined(ts.TypeFlags.Null);
139         case ts.SyntaxKind.Identifier:
140             if (right.originalKeywordKind === ts.SyntaxKind.UndefinedKeyword) {
141                 return nullOrUndefined(undefinedFlags);
142             }
143             return undefined;
144         default:
145             return undefined;
146     }
147     function nullOrUndefined(flags) {
148         return isStrictEquals
149             ? {
150                 expression: left,
151                 isNullOrUndefined: true,
152                 kind: 0 /* Plain */,
153                 predicate: flagPredicate(flags),
154             }
155             : { kind: 1 /* NonStructNullUndefined */, expression: left };
156     }
157 }
158 function isEmptyType(checker, type) {
159     return checker.typeToString(type) === "{}";
160 }
161 var undefinedFlags = ts.TypeFlags.Undefined | ts.TypeFlags.Void;
162 function getTypePredicateForKind(kind) {
163     switch (kind) {
164         case "undefined":
165             return flagPredicate(undefinedFlags);
166         case "boolean":
167             return flagPredicate(ts.TypeFlags.BooleanLike);
168         case "number":
169             return flagPredicate(ts.TypeFlags.NumberLike);
170         case "string":
171             return flagPredicate(ts.TypeFlags.StringLike);
172         case "symbol":
173             return flagPredicate(ts.TypeFlags.ESSymbol);
174         case "function":
175             return isFunction;
176         case "object":
177             // It's an object if it's not any of the above.
178             var allFlags_1 = ts.TypeFlags.Undefined |
179                 ts.TypeFlags.Void |
180                 ts.TypeFlags.BooleanLike |
181                 ts.TypeFlags.NumberLike |
182                 ts.TypeFlags.StringLike |
183                 ts.TypeFlags.ESSymbol;
184             return function (type) { return !tsutils_1.isTypeFlagSet(type, allFlags_1) && !isFunction(type); };
185         default:
186             return undefined;
187     }
188 }
189 function flagPredicate(testedFlag) {
190     return function (type) { return tsutils_1.isTypeFlagSet(type, testedFlag); };
191 }
192 function isFunction(t) {
193     if (t.getConstructSignatures().length !== 0 || t.getCallSignatures().length !== 0) {
194         return true;
195     }
196     var symbol = t.getSymbol();
197     return symbol !== undefined && symbol.getName() === "Function";
198 }
199 /** Returns a boolean value if that should always be the result of a type predicate. */
200 function getConstantBoolean(type, predicate) {
201     var anyTrue = false;
202     var anyFalse = false;
203     for (var _i = 0, _a = unionParts(type); _i < _a.length; _i++) {
204         var ty = _a[_i];
205         if (predicate(ty)) {
206             anyTrue = true;
207         }
208         else {
209             anyFalse = true;
210         }
211         if (anyTrue && anyFalse) {
212             return undefined;
213         }
214     }
215     return anyTrue;
216 }
217 /** Returns bool for always/never true, or a string to recommend strict equality. */
218 function testNonStrictNullUndefined(type) {
219     var anyNull = false;
220     var anyUndefined = false;
221     var anyOther = false;
222     for (var _i = 0, _a = unionParts(type); _i < _a.length; _i++) {
223         var ty = _a[_i];
224         if (tsutils_1.isTypeFlagSet(ty, ts.TypeFlags.Null)) {
225             anyNull = true;
226         }
227         else if (tsutils_1.isTypeFlagSet(ty, undefinedFlags)) {
228             anyUndefined = true;
229         }
230         else {
231             anyOther = true;
232         }
233     }
234     return !anyOther
235         ? true
236         : anyNull && anyUndefined
237             ? undefined
238             : anyNull
239                 ? "null"
240                 : anyUndefined
241                     ? "undefined"
242                     : false;
243 }
244 function unionParts(type) {
245     return tsutils_1.isUnionType(type) ? type.types : [type];
246 }
247 var templateObject_1;