tslint-etc
Version:
More rules for TSLint
86 lines (85 loc) • 3.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rule = void 0;
const tsquery_1 = require("@phenomnomnominal/tsquery");
const Lint = require("tslint");
const ts = require("typescript");
const support_1 = require("../support");
class Rule extends Lint.Rules.TypedRule {
applyWithProgram(sourceFile, program) {
const { ruleArguments: [options], } = this.getOptions();
const allowExplicitAny = options && options.hasOwnProperty("allowExplicitAny")
? options.allowExplicitAny
: false;
const failures = [];
const typeChecker = program.getTypeChecker();
const callExpressions = tsquery_1.tsquery(sourceFile, `CallExpression[expression.name.text=/^(catch|then)$/]`);
callExpressions.forEach((callExpression) => {
const { expression } = callExpression;
if (!ts.isPropertyAccessExpression(expression)) {
return;
}
const arg = expression.name.text === "catch"
? callExpression.arguments[0]
: callExpression.arguments[1];
if (!arg) {
return;
}
if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
const [parameter] = arg.parameters;
if (!parameter) {
return;
}
const object = expression.expression;
if (!support_1.couldBeType(typeChecker.getTypeAtLocation(object), "Promise")) {
return;
}
this.checkErrorNode(sourceFile, failures, allowExplicitAny, parameter);
}
});
const catchClauses = tsquery_1.tsquery(sourceFile, `CatchClause`);
catchClauses.forEach((catchClause) => {
const { variableDeclaration } = catchClause;
if (variableDeclaration) {
this.checkErrorNode(sourceFile, failures, allowExplicitAny, variableDeclaration);
}
});
return failures;
}
checkErrorNode(sourceFile, failures, allowExplicitAny, node) {
if (node.type) {
if (node.type.kind === ts.SyntaxKind.AnyKeyword) {
if (allowExplicitAny) {
return;
}
failures.push(new Lint.RuleFailure(sourceFile, node.getStart(), node.getStart() + node.getWidth(), Rule.EXPLICIT_ANY, this.ruleName, Lint.Replacement.replaceNode(node.type, "unknown")));
}
else if (node.type.kind !== ts.SyntaxKind.UnknownKeyword) {
failures.push(new Lint.RuleFailure(sourceFile, node.getStart(), node.getStart() + node.getWidth(), Rule.NARROWED, this.ruleName));
}
}
else {
failures.push(new Lint.RuleFailure(sourceFile, node.getStart(), node.getStart() + node.getWidth(), Rule.IMPLICIT_ANY, this.ruleName, Lint.Replacement.appendText(node.getStart() + node.getWidth(), ": unknown")));
}
}
}
exports.Rule = Rule;
Rule.metadata = {
deprecationMessage: undefined,
description: "Disallows implicit `any` errors in catch clauses and promise rejections.",
options: {
properties: {
allowExplicitAny: { type: "boolean" },
},
type: "object",
},
optionsDescription: Lint.Utils.dedent `
An optional object with an optional \`allowExplicitAny\` property.`,
requiresTypeInfo: true,
ruleName: "no-implicit-any-catch",
type: "functionality",
typescriptOnly: true,
};
Rule.EXPLICIT_ANY = "Explicit any";
Rule.IMPLICIT_ANY = "Implicit any";
Rule.NARROWED = "Error type must be unknown or any";