.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / tslint / lib / rules / noUnsafeAnyRule.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 Lint = require("../index");
23 var utils_1 = require("../utils");
24 var Rule = /** @class */ (function (_super) {
25     tslib_1.__extends(Rule, _super);
26     function Rule() {
27         return _super !== null && _super.apply(this, arguments) || this;
28     }
29     Rule.prototype.applyWithProgram = function (sourceFile, program) {
30         return this.applyWithWalker(new NoUnsafeAnyWalker(sourceFile, this.ruleName, program.getTypeChecker()));
31     };
32     /* tslint:disable:object-literal-sort-keys */
33     Rule.metadata = {
34         ruleName: "no-unsafe-any",
35         description: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n            Warns when using an expression of type 'any' in a dynamic way.\n            Uses are only allowed if they would work for `{} | null | undefined`.\n            Downcasting to unknown is always safe.\n            Type casts and tests are allowed.\n            Expressions that work on all values (such as `\"\" + x`) are allowed."], ["\n            Warns when using an expression of type 'any' in a dynamic way.\n            Uses are only allowed if they would work for \\`{} | null | undefined\\`.\n            Downcasting to unknown is always safe.\n            Type casts and tests are allowed.\n            Expressions that work on all values (such as \\`\"\" + x\\`) are allowed."]))),
36         optionsDescription: "Not configurable.",
37         options: null,
38         optionExamples: [true],
39         rationale: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n            If you're dealing with data of unknown or \"any\" types, you shouldn't be accessing members of it.\n            Either add type annotations for properties that may exist or change the data type to the empty object type `{}`.\n\n            Alternately, if you're creating storage or handling for consistent but unknown types, such as in data structures\n            or serialization, use `<T>` template types for generic type handling.\n\n            Also see the `no-any` rule.\n        "], ["\n            If you're dealing with data of unknown or \"any\" types, you shouldn't be accessing members of it.\n            Either add type annotations for properties that may exist or change the data type to the empty object type \\`{}\\`.\n\n            Alternately, if you're creating storage or handling for consistent but unknown types, such as in data structures\n            or serialization, use \\`<T>\\` template types for generic type handling.\n\n            Also see the \\`no-any\\` rule.\n        "]))),
40         type: "functionality",
41         typescriptOnly: true,
42         requiresTypeInfo: true,
43     };
44     /* tslint:enable:object-literal-sort-keys */
45     Rule.FAILURE_STRING = "Unsafe use of expression of type 'any'.";
46     return Rule;
47 }(Lint.Rules.TypedRule));
48 exports.Rule = Rule;
49 var NoUnsafeAnyWalker = /** @class */ (function (_super) {
50     tslib_1.__extends(NoUnsafeAnyWalker, _super);
51     function NoUnsafeAnyWalker(sourceFile, ruleName, checker) {
52         var _this = _super.call(this, sourceFile, ruleName, undefined) || this;
53         _this.checker = checker;
54         /** Wraps `visitNode` with the correct `this` binding and discards the return value to prevent `forEachChild` from returning early */
55         _this.visitNodeCallback = function (node) { return void _this.visitNode(node); };
56         return _this;
57     }
58     NoUnsafeAnyWalker.prototype.walk = function (sourceFile) {
59         if (sourceFile.isDeclarationFile) {
60             return; // Not possible in a declaration file.
61         }
62         sourceFile.statements.forEach(this.visitNodeCallback);
63     };
64     NoUnsafeAnyWalker.prototype.visitNode = function (node, anyOk) {
65         switch (node.kind) {
66             case ts.SyntaxKind.ParenthesizedExpression:
67                 // Don't warn on a parenthesized expression, warn on its contents.
68                 return this.visitNode(node.expression, anyOk);
69             case ts.SyntaxKind.LabeledStatement:
70                 // Ignore label
71                 return this.visitNode(node.statement);
72             // ignore labels
73             case ts.SyntaxKind.BreakStatement:
74             case ts.SyntaxKind.ContinueStatement:
75             // Ignore types
76             case ts.SyntaxKind.InterfaceDeclaration:
77             case ts.SyntaxKind.TypeAliasDeclaration:
78             case ts.SyntaxKind.TypeParameter:
79             case ts.SyntaxKind.IndexSignature:
80             // Ignore imports
81             case ts.SyntaxKind.ImportEqualsDeclaration:
82             case ts.SyntaxKind.ImportDeclaration:
83             case ts.SyntaxKind.ExportDeclaration:
84             case ts.SyntaxKind.ExportAssignment:
85                 return false;
86             case ts.SyntaxKind.ThisKeyword:
87             case ts.SyntaxKind.Identifier:
88                 return anyOk ? false : this.check(node);
89             // Recurse through these, but ignore the immediate child because it is allowed to be 'any'.
90             case ts.SyntaxKind.DeleteExpression:
91             case ts.SyntaxKind.ExpressionStatement:
92             case ts.SyntaxKind.TypeAssertionExpression:
93             case ts.SyntaxKind.AsExpression:
94             case ts.SyntaxKind.TemplateSpan: // Allow stringification (works on all values). Note: tagged templates handled differently.
95             case ts.SyntaxKind.TypeOfExpression:
96             case ts.SyntaxKind.VoidExpression:
97                 return this.visitNode(node.expression, true);
98             case ts.SyntaxKind.ThrowStatement: {
99                 var expression = node.expression;
100                 return expression !== undefined ? this.visitNode(expression, true) : false;
101             }
102             case ts.SyntaxKind.PropertyAssignment: {
103                 var _a = node, name = _a.name, initializer = _a.initializer;
104                 this.visitNode(name, /*anyOk*/ true);
105                 if (tsutils_1.isReassignmentTarget(node.parent)) {
106                     return this.visitNode(initializer, true);
107                 }
108                 return this.checkContextualType(initializer, true);
109             }
110             case ts.SyntaxKind.ShorthandPropertyAssignment: {
111                 var _b = node, name = _b.name, objectAssignmentInitializer = _b.objectAssignmentInitializer;
112                 if (objectAssignmentInitializer !== undefined) {
113                     return this.checkContextualType(objectAssignmentInitializer);
114                 }
115                 return this.checkContextualType(name, true);
116             }
117             case ts.SyntaxKind.PropertyDeclaration: {
118                 var _c = node, name = _c.name, initializer = _c.initializer;
119                 this.visitNode(name, true);
120                 return (initializer !== undefined &&
121                     this.visitNode(initializer, isPropertyAnyOrUnknown(node, this.checker)));
122             }
123             case ts.SyntaxKind.SpreadAssignment:
124                 return this.visitNode(node.expression, 
125                 // allow any in object spread, but not in object rest
126                 !tsutils_1.isReassignmentTarget(node.parent));
127             case ts.SyntaxKind.ComputedPropertyName:
128                 return this.visitNode(node.expression, true);
129             case ts.SyntaxKind.TaggedTemplateExpression: {
130                 var _d = node, tag = _d.tag, template = _d.template;
131                 if (template.kind === ts.SyntaxKind.TemplateExpression) {
132                     for (var _i = 0, _e = template.templateSpans; _i < _e.length; _i++) {
133                         var expression = _e[_i].expression;
134                         this.checkContextualType(expression);
135                     }
136                 }
137                 // Also check the template expression itself
138                 if (this.visitNode(tag)) {
139                     return true;
140                 }
141                 return anyOk ? false : this.check(node);
142             }
143             case ts.SyntaxKind.CallExpression:
144             case ts.SyntaxKind.NewExpression: {
145                 var _f = node, expression = _f.expression, args = _f.arguments;
146                 if (args !== undefined) {
147                     for (var _g = 0, args_1 = args; _g < args_1.length; _g++) {
148                         var arg = args_1[_g];
149                         this.checkContextualType(arg);
150                     }
151                 }
152                 if (this.visitNode(expression)) {
153                     return true;
154                 }
155                 // Also check the call expression itself
156                 return anyOk ? false : this.check(node);
157             }
158             case ts.SyntaxKind.PropertyAccessExpression:
159                 // Don't warn for right hand side; this is redundant if we warn for the access itself.
160                 if (this.visitNode(node.expression)) {
161                     return true;
162                 }
163                 return anyOk ? false : this.check(node);
164             case ts.SyntaxKind.ElementAccessExpression: {
165                 var _h = node, expression = _h.expression, argumentExpression = _h.argumentExpression;
166                 if (argumentExpression !== undefined) {
167                     this.visitNode(argumentExpression, true);
168                 }
169                 if (this.visitNode(expression)) {
170                     return true;
171                 }
172                 return anyOk ? false : this.check(node);
173             }
174             case ts.SyntaxKind.ReturnStatement: {
175                 var expression = node.expression;
176                 return expression !== undefined && this.checkContextualType(expression, true);
177             }
178             case ts.SyntaxKind.SwitchStatement: {
179                 var _j = node, expression = _j.expression, clauses = _j.caseBlock.clauses;
180                 // Allow `switch (x) {}` where `x` is any
181                 this.visitNode(expression, /*anyOk*/ true);
182                 for (var _k = 0, clauses_1 = clauses; _k < clauses_1.length; _k++) {
183                     var clause = clauses_1[_k];
184                     if (clause.kind === ts.SyntaxKind.CaseClause) {
185                         // Allow `case x:` where `x` is any
186                         this.visitNode(clause.expression, /*anyOk*/ true);
187                     }
188                     for (var _l = 0, _m = clause.statements; _l < _m.length; _l++) {
189                         var statement = _m[_l];
190                         this.visitNode(statement);
191                     }
192                 }
193                 return false;
194             }
195             case ts.SyntaxKind.ModuleDeclaration: {
196                 // In `declare global { ... }`, don't mark `global` as unsafe any.
197                 var body = node.body;
198                 return body !== undefined && this.visitNode(body);
199             }
200             case ts.SyntaxKind.IfStatement: {
201                 var _o = node, expression = _o.expression, thenStatement = _o.thenStatement, elseStatement = _o.elseStatement;
202                 this.visitNode(expression, true); // allow truthyness check
203                 this.visitNode(thenStatement);
204                 return elseStatement !== undefined && this.visitNode(elseStatement);
205             }
206             case ts.SyntaxKind.PrefixUnaryExpression: {
207                 var _p = node, operator = _p.operator, operand = _p.operand;
208                 this.visitNode(operand, operator === ts.SyntaxKind.ExclamationToken); // allow falsyness check
209                 return false;
210             }
211             case ts.SyntaxKind.ForStatement: {
212                 var _q = node, initializer = _q.initializer, condition = _q.condition, incrementor = _q.incrementor, statement = _q.statement;
213                 if (initializer !== undefined) {
214                     this.visitNode(initializer, true);
215                 }
216                 if (condition !== undefined) {
217                     this.visitNode(condition, true);
218                 } // allow truthyness check
219                 if (incrementor !== undefined) {
220                     this.visitNode(incrementor, true);
221                 }
222                 return this.visitNode(statement);
223             }
224             case ts.SyntaxKind.DoStatement:
225             case ts.SyntaxKind.WhileStatement:
226                 this.visitNode(node.expression, true);
227                 return this.visitNode(node.statement);
228             case ts.SyntaxKind.ConditionalExpression: {
229                 var _r = node, condition = _r.condition, whenTrue = _r.whenTrue, whenFalse = _r.whenFalse;
230                 this.visitNode(condition, true);
231                 var left = this.visitNode(whenTrue, anyOk);
232                 return this.visitNode(whenFalse, anyOk) || left;
233             }
234             case ts.SyntaxKind.VariableDeclaration:
235             case ts.SyntaxKind.Parameter:
236                 return this.checkVariableOrParameterDeclaration(node);
237             case ts.SyntaxKind.BinaryExpression:
238                 return this.checkBinaryExpression(node, anyOk);
239             case ts.SyntaxKind.AwaitExpression:
240                 this.visitNode(node.expression);
241                 return anyOk ? false : this.check(node);
242             case ts.SyntaxKind.YieldExpression:
243                 return this.checkYieldExpression(node, anyOk);
244             case ts.SyntaxKind.ClassExpression:
245             case ts.SyntaxKind.ClassDeclaration:
246                 this.checkClassLikeDeclaration(node);
247                 return false;
248             case ts.SyntaxKind.ArrayLiteralExpression: {
249                 for (var _s = 0, _t = node.elements; _s < _t.length; _s++) {
250                     var element = _t[_s];
251                     this.checkContextualType(element, true);
252                 }
253                 return false;
254             }
255             case ts.SyntaxKind.JsxExpression:
256                 return (node.expression !== undefined &&
257                     this.checkContextualType(node.expression));
258         }
259         if (tsutils_1.isTypeNodeKind(node.kind) || tsutils_1.isTokenKind(node.kind)) {
260             return false;
261         }
262         return ts.forEachChild(node, this.visitNodeCallback);
263     };
264     NoUnsafeAnyWalker.prototype.check = function (node) {
265         if (!isNodeAny(node, this.checker)) {
266             return false;
267         }
268         this.addFailureAtNode(node, Rule.FAILURE_STRING);
269         return true;
270     };
271     NoUnsafeAnyWalker.prototype.checkContextualType = function (node, allowIfNoContextualType) {
272         var type = this.checker.getContextualType(node);
273         var anyOk = (type === undefined && allowIfNoContextualType) || isAny(type, true);
274         return this.visitNode(node, anyOk);
275     };
276     // Allow `const x = foo;` and `const x: any = foo`, but not `const x: Foo = foo;`.
277     NoUnsafeAnyWalker.prototype.checkVariableOrParameterDeclaration = function (_a) {
278         var name = _a.name, type = _a.type, initializer = _a.initializer;
279         this.checkBindingName(name);
280         // Always allow the LHS to be `any`. Just don't allow RHS to be `any` when LHS isn't `any` or `unknown`.
281         var anyOk = (name.kind === ts.SyntaxKind.Identifier &&
282             (type === undefined ||
283                 type.kind === ts.SyntaxKind.AnyKeyword ||
284                 type.kind === ts.SyntaxKind.UnknownKeyword)) ||
285             (type !== undefined && type.kind === ts.SyntaxKind.AnyKeyword) ||
286             (type !== undefined && type.kind === ts.SyntaxKind.UnknownKeyword);
287         return initializer !== undefined && this.visitNode(initializer, anyOk);
288     };
289     NoUnsafeAnyWalker.prototype.checkBinaryExpression = function (node, anyOk) {
290         var allowAnyLeft = false;
291         var allowAnyRight = false;
292         switch (node.operatorToken.kind) {
293             case ts.SyntaxKind.ExclamationEqualsEqualsToken:
294             case ts.SyntaxKind.ExclamationEqualsToken:
295             case ts.SyntaxKind.EqualsEqualsEqualsToken:
296             case ts.SyntaxKind.EqualsEqualsToken:
297             case ts.SyntaxKind.CommaToken: // Allow `any, any`
298             case ts.SyntaxKind.BarBarToken: // Allow `any || any`
299             case ts.SyntaxKind.AmpersandAmpersandToken: // Allow `any && any`
300                 allowAnyLeft = allowAnyRight = true;
301                 break;
302             case ts.SyntaxKind.InstanceOfKeyword: // Allow test
303                 allowAnyLeft = true;
304                 break;
305             case ts.SyntaxKind.EqualsToken:
306                 // Allow assignment if the lhs is also *any*.
307                 allowAnyLeft = true;
308                 allowAnyRight = isNodeAny(node.left, this.checker, true);
309                 break;
310             case ts.SyntaxKind.PlusToken: // Allow implicit stringification
311             case ts.SyntaxKind.PlusEqualsToken:
312                 allowAnyLeft = allowAnyRight =
313                     isStringLike(node.left, this.checker) ||
314                         (isStringLike(node.right, this.checker) &&
315                             node.operatorToken.kind === ts.SyntaxKind.PlusToken);
316         }
317         this.visitNode(node.left, allowAnyLeft);
318         this.visitNode(node.right, allowAnyRight);
319         return anyOk ? false : this.check(node);
320     };
321     NoUnsafeAnyWalker.prototype.checkYieldExpression = function (node, anyOk) {
322         if (node.expression !== undefined) {
323             this.checkContextualType(node.expression, true);
324         }
325         if (anyOk) {
326             return false;
327         }
328         this.addFailureAtNode(node, Rule.FAILURE_STRING);
329         return true;
330     };
331     NoUnsafeAnyWalker.prototype.checkClassLikeDeclaration = function (node) {
332         if (node.decorators !== undefined) {
333             node.decorators.forEach(this.visitNodeCallback);
334         }
335         if (node.heritageClauses !== undefined) {
336             node.heritageClauses.forEach(this.visitNodeCallback);
337         }
338         return node.members.forEach(this.visitNodeCallback);
339     };
340     NoUnsafeAnyWalker.prototype.checkBindingName = function (node) {
341         if (node.kind !== ts.SyntaxKind.Identifier) {
342             if (isNodeAny(node, this.checker)) {
343                 this.addFailureAtNode(node, Rule.FAILURE_STRING);
344             }
345             for (var _i = 0, _a = node.elements; _i < _a.length; _i++) {
346                 var element = _a[_i];
347                 if (element.kind !== ts.SyntaxKind.OmittedExpression) {
348                     if (element.propertyName !== undefined &&
349                         element.propertyName.kind === ts.SyntaxKind.ComputedPropertyName) {
350                         this.visitNode(element.propertyName.expression);
351                     }
352                     this.checkBindingName(element.name);
353                     if (element.initializer !== undefined) {
354                         this.checkContextualType(element.initializer);
355                     }
356                 }
357             }
358         }
359     };
360     return NoUnsafeAnyWalker;
361 }(Lint.AbstractWalker));
362 /** Check if property has no type annotation in this class and the base class */
363 function isPropertyAnyOrUnknown(node, checker) {
364     if (!isNodeAny(node.name, checker, true) ||
365         node.name.kind === ts.SyntaxKind.ComputedPropertyName) {
366         return false;
367     }
368     for (var _i = 0, _a = checker.getBaseTypes(checker.getTypeAtLocation(node.parent)); _i < _a.length; _i++) {
369         var base = _a[_i];
370         var prop = base.getProperty(node.name.text);
371         if (prop !== undefined && prop.declarations !== undefined) {
372             return isAny(checker.getTypeOfSymbolAtLocation(prop, prop.declarations[0]), true);
373         }
374     }
375     return true;
376 }
377 /**
378  * @param orUnknown If true, this function will also return true when the node is unknown.
379  */
380 function isNodeAny(node, checker, orUnknown) {
381     if (orUnknown === void 0) { orUnknown = false; }
382     var symbol = checker.getSymbolAtLocation(node);
383     if (symbol !== undefined && tsutils_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)) {
384         symbol = checker.getAliasedSymbol(symbol);
385     }
386     if (symbol !== undefined) {
387         // NamespaceModule is a type-only namespace without runtime value, its type is 'any' when used as 'ns.Type' -> avoid error
388         if (tsutils_1.isSymbolFlagSet(symbol, ts.SymbolFlags.NamespaceModule)) {
389             return false;
390         }
391         if (tsutils_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Type)) {
392             return isAny(checker.getDeclaredTypeOfSymbol(symbol), orUnknown);
393         }
394     }
395     // Lowercase JSX elements are assumed to be allowed by design
396     if (isJsxNativeElement(node)) {
397         return false;
398     }
399     return isAny(checker.getTypeAtLocation(node), orUnknown);
400 }
401 var jsxElementTypes = new Set([
402     ts.SyntaxKind.JsxClosingElement,
403     ts.SyntaxKind.JsxOpeningElement,
404     ts.SyntaxKind.JsxSelfClosingElement,
405 ]);
406 function isJsxNativeElement(node) {
407     if (!tsutils_1.isIdentifier(node) || node.parent === undefined) {
408         return false;
409     }
410     // TypeScript <=2.1 incorrectly parses JSX fragments
411     if (node.text === "") {
412         return true;
413     }
414     return jsxElementTypes.has(node.parent.kind) && utils_1.isLowerCase(node.text[0]);
415 }
416 function isStringLike(expr, checker) {
417     return tsutils_1.isTypeFlagSet(checker.getTypeAtLocation(expr), ts.TypeFlags.StringLike);
418 }
419 function isAny(type, orUnknown) {
420     if (orUnknown === void 0) { orUnknown = false; }
421     return (type !== undefined &&
422         (tsutils_1.isTypeFlagSet(type, ts.TypeFlags.Any) ||
423             (orUnknown && tsutils_1.isTypeFlagSet(type, ts.TypeFlags.Unknown))));
424 }
425 var templateObject_1, templateObject_2;