diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-12-10 21:51:33 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-12-10 21:51:33 +0100 |
commit | 0469abd4a9c9270a1fdc962969e36e63699af8b4 (patch) | |
tree | f9864d4a4148621378958794cbbfdc2393733283 /node_modules/tslint/lib/rules/noUnsafeAnyRule.js | |
parent | 6947e79bbc258f7bc96af424ddb71a511f0c15a3 (diff) |
upgrade dependencies
Diffstat (limited to 'node_modules/tslint/lib/rules/noUnsafeAnyRule.js')
-rw-r--r-- | node_modules/tslint/lib/rules/noUnsafeAnyRule.js | 360 |
1 files changed, 225 insertions, 135 deletions
diff --git a/node_modules/tslint/lib/rules/noUnsafeAnyRule.js b/node_modules/tslint/lib/rules/noUnsafeAnyRule.js index 3ff493ce9..c0a36360a 100644 --- a/node_modules/tslint/lib/rules/noUnsafeAnyRule.js +++ b/node_modules/tslint/lib/rules/noUnsafeAnyRule.js @@ -26,7 +26,7 @@ var Rule = /** @class */ (function (_super) { return _super !== null && _super.apply(this, arguments) || this; } Rule.prototype.applyWithProgram = function (sourceFile, program) { - return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker()); + return this.applyWithWalker(new NoUnsafeAnyWalker(sourceFile, this.ruleName, program.getTypeChecker())); }; /* tslint:disable:object-literal-sort-keys */ Rule.metadata = { @@ -44,229 +44,319 @@ var Rule = /** @class */ (function (_super) { return Rule; }(Lint.Rules.TypedRule)); exports.Rule = Rule; -function walk(ctx, checker) { - if (ctx.sourceFile.isDeclarationFile) { - // Not possible in a declaration file. - return; +var NoUnsafeAnyWalker = /** @class */ (function (_super) { + tslib_1.__extends(NoUnsafeAnyWalker, _super); + function NoUnsafeAnyWalker(sourceFile, ruleName, checker) { + var _this = _super.call(this, sourceFile, ruleName, undefined) || this; + _this.checker = checker; + /** Wraps `visitNode` with the correct `this` binding and discards the return value to prevent `forEachChild` from returning early */ + _this.visitNodeCallback = function (node) { return void _this.visitNode(node); }; + return _this; } - return ts.forEachChild(ctx.sourceFile, cb); - /** @param anyOk If true, this node will be allowed to be of type *any*. (But its children might not.) */ - function cb(node, anyOk) { + NoUnsafeAnyWalker.prototype.walk = function (sourceFile) { + if (sourceFile.isDeclarationFile) { + return; // Not possible in a declaration file. + } + sourceFile.statements.forEach(this.visitNodeCallback); + }; + NoUnsafeAnyWalker.prototype.visitNode = function (node, anyOk) { switch (node.kind) { case ts.SyntaxKind.ParenthesizedExpression: // Don't warn on a parenthesized expression, warn on its contents. - return cb(node.expression, anyOk); - case ts.SyntaxKind.Parameter: { - var _a = node, type = _a.type, initializer = _a.initializer; - // TODO handle destructuring - if (initializer !== undefined) { - return cb(initializer, /*anyOk*/ type !== undefined && type.kind === ts.SyntaxKind.AnyKeyword); - } - return; - } + return this.visitNode(node.expression, anyOk); case ts.SyntaxKind.LabeledStatement: // Ignore label - return cb(node.statement); - case ts.SyntaxKind.BreakStatement: // Ignore label + return this.visitNode(node.statement); + // ignore labels + case ts.SyntaxKind.BreakStatement: case ts.SyntaxKind.ContinueStatement: // Ignore types case ts.SyntaxKind.InterfaceDeclaration: case ts.SyntaxKind.TypeAliasDeclaration: - case ts.SyntaxKind.QualifiedName: - case ts.SyntaxKind.TypePredicate: - case ts.SyntaxKind.TypeOfExpression: + case ts.SyntaxKind.TypeParameter: + case ts.SyntaxKind.IndexSignature: // Ignore imports case ts.SyntaxKind.ImportEqualsDeclaration: case ts.SyntaxKind.ImportDeclaration: case ts.SyntaxKind.ExportDeclaration: - // These show as type "any" if in type position. - case ts.SyntaxKind.NumericLiteral: - case ts.SyntaxKind.StringLiteral: - return; + case ts.SyntaxKind.ExportAssignment: + return false; + case ts.SyntaxKind.ThisKeyword: + case ts.SyntaxKind.Identifier: + return anyOk ? false : this.check(node); // Recurse through these, but ignore the immediate child because it is allowed to be 'any'. case ts.SyntaxKind.DeleteExpression: case ts.SyntaxKind.ExpressionStatement: case ts.SyntaxKind.TypeAssertionExpression: case ts.SyntaxKind.AsExpression: case ts.SyntaxKind.TemplateSpan: // Allow stringification (works on all values). Note: tagged templates handled differently. - case ts.SyntaxKind.ThrowStatement: { - var expression = node.expression; - return cb(expression, /*anyOk*/ true); - } + case ts.SyntaxKind.ThrowStatement: + case ts.SyntaxKind.TypeOfExpression: + case ts.SyntaxKind.VoidExpression: + return this.visitNode(node.expression, true); case ts.SyntaxKind.PropertyAssignment: { - // Only check RHS. - var _b = node, name = _b.name, initializer = _b.initializer; - // The LHS will be 'any' if the RHS is, so just handle the RHS. - // Still need to check the LHS in case it is a computed key. - cb(name, /*anyOk*/ true); - cb(initializer); - return; + var _a = node, name = _a.name, initializer = _a.initializer; + this.visitNode(name, /*anyOk*/ true); + if (tsutils_1.isReassignmentTarget(node.parent)) { + return this.visitNode(initializer, true); + } + return this.checkContextualType(initializer, true); + } + case ts.SyntaxKind.ShorthandPropertyAssignment: { + var _b = node, name = _b.name, objectAssignmentInitializer = _b.objectAssignmentInitializer; + if (objectAssignmentInitializer !== undefined) { + return this.checkContextualType(objectAssignmentInitializer); + } + return this.checkContextualType(name, true); } case ts.SyntaxKind.PropertyDeclaration: { var _c = node, name = _c.name, initializer = _c.initializer; - if (initializer !== undefined) { - return cb(initializer, /*anyOk*/ isNodeAny(name, checker)); - } - return; + this.visitNode(name, true); + return initializer !== undefined && + this.visitNode(initializer, isPropertyAny(node, this.checker)); } + case ts.SyntaxKind.ComputedPropertyName: + return this.visitNode(node.expression, true); case ts.SyntaxKind.TaggedTemplateExpression: { var _d = node, tag = _d.tag, template = _d.template; - cb(tag); if (template.kind === ts.SyntaxKind.TemplateExpression) { for (var _i = 0, _e = template.templateSpans; _i < _e.length; _i++) { var expression = _e[_i].expression; - checkContextual(expression); + this.checkContextualType(expression); } } // Also check the template expression itself - check(); - return; + if (this.visitNode(tag)) { + return true; + } + return anyOk ? false : this.check(node); } case ts.SyntaxKind.CallExpression: case ts.SyntaxKind.NewExpression: { var _f = node, expression = _f.expression, args = _f.arguments; - cb(expression); if (args !== undefined) { for (var _g = 0, args_1 = args; _g < args_1.length; _g++) { var arg = args_1[_g]; - checkContextual(arg); + this.checkContextualType(arg); } } + if (this.visitNode(expression)) { + return true; + } // Also check the call expression itself - check(); - return; + return anyOk ? false : this.check(node); } case ts.SyntaxKind.PropertyAccessExpression: // Don't warn for right hand side; this is redundant if we warn for the access itself. - cb(node.expression); - check(); - return; - case ts.SyntaxKind.VariableDeclaration: - return checkVariableDeclaration(node); - case ts.SyntaxKind.BinaryExpression: - return checkBinaryExpression(node); + if (this.visitNode(node.expression)) { + return true; + } + return anyOk ? false : this.check(node); + case ts.SyntaxKind.ElementAccessExpression: { + var _h = node, expression = _h.expression, argumentExpression = _h.argumentExpression; + if (argumentExpression !== undefined) { + this.visitNode(argumentExpression, true); + } + if (this.visitNode(expression)) { + return true; + } + return anyOk ? false : this.check(node); + } case ts.SyntaxKind.ReturnStatement: { var expression = node.expression; - if (expression !== undefined) { - return checkContextual(expression); - } - return; + return expression !== undefined && this.checkContextualType(expression, true); } case ts.SyntaxKind.SwitchStatement: { - var _h = node, expression = _h.expression, clauses = _h.caseBlock.clauses; + var _j = node, expression = _j.expression, clauses = _j.caseBlock.clauses; // Allow `switch (x) {}` where `x` is any - cb(expression, /*anyOk*/ true); - for (var _j = 0, clauses_1 = clauses; _j < clauses_1.length; _j++) { - var clause = clauses_1[_j]; + this.visitNode(expression, /*anyOk*/ true); + for (var _k = 0, clauses_1 = clauses; _k < clauses_1.length; _k++) { + var clause = clauses_1[_k]; if (clause.kind === ts.SyntaxKind.CaseClause) { // Allow `case x:` where `x` is any - cb(clause.expression, /*anyOk*/ true); + this.visitNode(clause.expression, /*anyOk*/ true); } - for (var _k = 0, _l = clause.statements; _k < _l.length; _k++) { - var statement = _l[_k]; - cb(statement); + for (var _l = 0, _m = clause.statements; _l < _m.length; _l++) { + var statement = _m[_l]; + this.visitNode(statement); } } - break; + return false; } case ts.SyntaxKind.ModuleDeclaration: { // In `declare global { ... }`, don't mark `global` as unsafe any. var body = node.body; - if (body !== undefined) { - cb(body); - } - return; + return body !== undefined && this.visitNode(body); } case ts.SyntaxKind.IfStatement: { - var _m = node, expression = _m.expression, thenStatement = _m.thenStatement, elseStatement = _m.elseStatement; - cb(expression, true); // allow truthyness check - cb(thenStatement); - if (elseStatement !== undefined) { - cb(elseStatement); - } - return; + var _o = node, expression = _o.expression, thenStatement = _o.thenStatement, elseStatement = _o.elseStatement; + this.visitNode(expression, true); // allow truthyness check + this.visitNode(thenStatement); + return elseStatement !== undefined && this.visitNode(elseStatement); } case ts.SyntaxKind.PrefixUnaryExpression: { - var _o = node, operator = _o.operator, operand = _o.operand; - cb(operand, operator === ts.SyntaxKind.ExclamationToken); // allow falsyness check - check(); - return; + var _p = node, operator = _p.operator, operand = _p.operand; + this.visitNode(operand, operator === ts.SyntaxKind.ExclamationToken); // allow falsyness check + return false; } case ts.SyntaxKind.ForStatement: { - var _p = node, initializer = _p.initializer, condition = _p.condition, incrementor = _p.incrementor, statement = _p.statement; + var _q = node, initializer = _q.initializer, condition = _q.condition, incrementor = _q.incrementor, statement = _q.statement; if (initializer !== undefined) { - cb(initializer); + this.visitNode(initializer, true); } if (condition !== undefined) { - cb(condition, true); + this.visitNode(condition, true); } // allow truthyness check if (incrementor !== undefined) { - cb(incrementor); + this.visitNode(incrementor, true); } - return cb(statement); + return this.visitNode(statement); } case ts.SyntaxKind.DoStatement: case ts.SyntaxKind.WhileStatement: - cb(node.statement); - return cb(node.expression, true); - default: - if (!(tsutils_1.isExpression(node) && check())) { - return ts.forEachChild(node, cb); + this.visitNode(node.expression, true); + return this.visitNode(node.statement); + case ts.SyntaxKind.ConditionalExpression: { + var _r = node, condition = _r.condition, whenTrue = _r.whenTrue, whenFalse = _r.whenFalse; + this.visitNode(condition, true); + var left = this.visitNode(whenTrue, anyOk); + return this.visitNode(whenFalse, anyOk) || left; + } + case ts.SyntaxKind.VariableDeclaration: + case ts.SyntaxKind.Parameter: + return this.checkVariableOrParameterDeclaration(node); + case ts.SyntaxKind.BinaryExpression: + return this.checkBinaryExpression(node, anyOk); + case ts.SyntaxKind.AwaitExpression: + this.visitNode(node.expression); + return anyOk ? false : this.check(node); + case ts.SyntaxKind.YieldExpression: + return this.checkYieldExpression(node, anyOk); + case ts.SyntaxKind.ClassExpression: + case ts.SyntaxKind.ClassDeclaration: + this.checkClassLikeDeclaration(node); + return false; + case ts.SyntaxKind.ArrayLiteralExpression: { + for (var _s = 0, _t = node.elements; _s < _t.length; _s++) { + var element = _t[_s]; + this.checkContextualType(element, true); } - return; - } - function check() { - var isUnsafe = !anyOk && isNodeAny(node, checker); - if (isUnsafe) { - ctx.addFailureAtNode(node, Rule.FAILURE_STRING); + return false; } - return isUnsafe; + case ts.SyntaxKind.JsxExpression: + return node.expression !== undefined && + this.checkContextualType(node.expression); } - } - /** OK for this value to be 'any' if that's its contextual type. */ - function checkContextual(arg) { - return cb(arg, /*anyOk*/ isAny(checker.getContextualType(arg))); - } - // Allow `const x = foo;` and `const x: any = foo`, but not `const x: Foo = foo;`. - function checkVariableDeclaration(_a) { - var type = _a.type, initializer = _a.initializer; - // Always allow the LHS to be `any`. Just don't allow RHS to be `any` when LHS isn't. - // TODO: handle destructuring - if (initializer !== undefined) { - return cb(initializer, /*anyOk*/ type === undefined || type.kind === ts.SyntaxKind.AnyKeyword); + if (tsutils_1.isTypeNodeKind(node.kind) || tsutils_1.isTokenKind(node.kind)) { + return false; } - return; - } - function checkBinaryExpression(node) { - var _a = node, left = _a.left, right = _a.right, operatorToken = _a.operatorToken; - // Allow equality since all values support equality. - if (Lint.getEqualsKind(operatorToken) !== undefined) { - return; + return ts.forEachChild(node, this.visitNodeCallback); + }; + NoUnsafeAnyWalker.prototype.check = function (node) { + if (!isNodeAny(node, this.checker)) { + return false; } - switch (operatorToken.kind) { - case ts.SyntaxKind.InstanceOfKeyword:// Allow test - return cb(right); + this.addFailureAtNode(node, Rule.FAILURE_STRING); + return true; + }; + NoUnsafeAnyWalker.prototype.checkContextualType = function (node, allowIfNoContextualType) { + var type = this.checker.getContextualType(node); + return this.visitNode(node, type === undefined && allowIfNoContextualType || isAny(type)); + }; + // Allow `const x = foo;` and `const x: any = foo`, but not `const x: Foo = foo;`. + NoUnsafeAnyWalker.prototype.checkVariableOrParameterDeclaration = function (_a) { + var name = _a.name, type = _a.type, initializer = _a.initializer; + this.checkBindingName(name); + // Always allow the LHS to be `any`. Just don't allow RHS to be `any` when LHS isn't. + return initializer !== undefined && + this.visitNode(initializer, + /*anyOk*/ + name.kind === ts.SyntaxKind.Identifier && (type === undefined || type.kind === ts.SyntaxKind.AnyKeyword) || + type !== undefined && type.kind === ts.SyntaxKind.AnyKeyword); + }; + NoUnsafeAnyWalker.prototype.checkBinaryExpression = function (node, anyOk) { + var allowAnyLeft = false; + var allowAnyRight = false; + switch (node.operatorToken.kind) { + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsToken: + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.EqualsEqualsToken: case ts.SyntaxKind.CommaToken: // Allow `any, any` case ts.SyntaxKind.BarBarToken: // Allow `any || any` case ts.SyntaxKind.AmpersandAmpersandToken:// Allow `any && any` - cb(left, /*anyOk*/ true); - return cb(right, /*anyOk*/ true); + allowAnyLeft = allowAnyRight = true; + break; + case ts.SyntaxKind.InstanceOfKeyword:// Allow test + allowAnyLeft = true; + break; case ts.SyntaxKind.EqualsToken: // Allow assignment if the lhs is also *any*. - // TODO: handle destructuring - cb(right, /*anyOk*/ isNodeAny(left, checker)); - return; + allowAnyLeft = true; + allowAnyRight = isNodeAny(node.left, this.checker); + break; case ts.SyntaxKind.PlusToken: // Allow implicit stringification case ts.SyntaxKind.PlusEqualsToken: - var anyOk = isStringLike(left, checker) - || (isStringLike(right, checker) && operatorToken.kind === ts.SyntaxKind.PlusToken); - cb(left, anyOk); - return cb(right, anyOk); - default: - cb(left); - return cb(right); + allowAnyLeft = allowAnyRight = isStringLike(node.left, this.checker) + || (isStringLike(node.right, this.checker) && node.operatorToken.kind === ts.SyntaxKind.PlusToken); + } + this.visitNode(node.left, allowAnyLeft); + this.visitNode(node.right, allowAnyRight); + return anyOk ? false : this.check(node); + }; + NoUnsafeAnyWalker.prototype.checkYieldExpression = function (node, anyOk) { + if (node.expression !== undefined) { + this.checkContextualType(node.expression, true); + } + if (anyOk) { + return false; + } + this.addFailureAtNode(node, Rule.FAILURE_STRING); + return true; + }; + NoUnsafeAnyWalker.prototype.checkClassLikeDeclaration = function (node) { + if (node.decorators !== undefined) { + node.decorators.forEach(this.visitNodeCallback); + } + if (node.heritageClauses !== undefined) { + node.heritageClauses.forEach(this.visitNodeCallback); + } + return node.members.forEach(this.visitNodeCallback); + }; + NoUnsafeAnyWalker.prototype.checkBindingName = function (node) { + if (node.kind !== ts.SyntaxKind.Identifier) { + if (isNodeAny(node, this.checker)) { + this.addFailureAtNode(node, Rule.FAILURE_STRING); + } + for (var _i = 0, _a = node.elements; _i < _a.length; _i++) { + var element = _a[_i]; + if (element.kind !== ts.SyntaxKind.OmittedExpression) { + if (element.propertyName !== undefined && element.propertyName.kind === ts.SyntaxKind.ComputedPropertyName) { + this.visitNode(element.propertyName.expression); + } + this.checkBindingName(element.name); + if (element.initializer !== undefined) { + this.checkContextualType(element.initializer); + } + } + } + } + }; + return NoUnsafeAnyWalker; +}(Lint.AbstractWalker)); +/** Check if property has no type annotation in this class and the base class */ +function isPropertyAny(node, checker) { + if (!isNodeAny(node.name, checker) || node.name.kind === ts.SyntaxKind.ComputedPropertyName) { + return false; + } + for (var _i = 0, _a = checker.getBaseTypes(checker.getTypeAtLocation(node.parent)); _i < _a.length; _i++) { + var base = _a[_i]; + var prop = base.getProperty(node.name.text); + if (prop !== undefined && prop.declarations !== undefined) { + return isAny(checker.getTypeOfSymbolAtLocation(prop, prop.declarations[0])); } } + return true; } function isNodeAny(node, checker) { return isAny(checker.getTypeAtLocation(node)); |