tslint-etc
Version:
More rules for TSLint
78 lines (77 loc) • 3.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rule = void 0;
const tsquery_1 = require("@phenomnomnominal/tsquery");
const Lint = require("tslint");
const tsutils = require("tsutils");
const support_1 = require("../support");
const mutatorRegExp = /^(fill|reverse|sort)$/;
const creatorRegExp = /^(concat|entries|filter|keys|map|slice|splice|values)$/;
class Rule extends Lint.Rules.TypedRule {
applyWithProgram(sourceFile, program) {
const failures = [];
const typeChecker = program.getTypeChecker();
const identifiers = tsquery_1.tsquery(sourceFile, `CallExpression PropertyAccessExpression Identifier[name=${mutatorRegExp.toString()}]`);
identifiers.forEach((node) => {
const identifier = node;
const propertyAccessExpression = identifier.parent;
const callExpression = identifier.parent.parent;
const parent = callExpression.parent;
if (!tsutils.isExpressionStatement(parent)) {
const type = typeChecker.getTypeAtLocation(propertyAccessExpression.expression);
if (support_1.couldBeType(type, "Array") &&
this.mutatesReferencedArray(callExpression)) {
failures.push(new Lint.RuleFailure(sourceFile, identifier.getStart(), identifier.getStart() + identifier.getWidth(), Rule.FAILURE_STRING, this.ruleName));
}
}
});
return failures;
}
isNewArray(expression) {
if (tsutils.isArrayLiteralExpression(expression)) {
return true;
}
if (tsutils.isNewExpression(expression)) {
return true;
}
if (tsutils.isCallExpression(expression)) {
const callee = expression.expression;
if (tsutils.isIdentifier(callee) && callee.text === "Array") {
return true;
}
if (tsutils.isPropertyAccessExpression(callee) &&
tsutils.isIdentifier(callee.expression) &&
callee.expression.text === "Array") {
return true;
}
}
return false;
}
mutatesReferencedArray(callExpression) {
if (tsutils.isPropertyAccessExpression(callExpression.expression)) {
const propertyAccessExpression = callExpression.expression;
const { expression, name } = propertyAccessExpression;
if (creatorRegExp.test(name.getText())) {
return false;
}
if (this.isNewArray(expression)) {
return false;
}
if (tsutils.isCallExpression(expression)) {
return this.mutatesReferencedArray(expression);
}
}
return true;
}
}
exports.Rule = Rule;
Rule.metadata = {
description: "Disallows the assignment of returned, mutated arrays.",
options: null,
optionsDescription: "Not configurable.",
requiresTypeInfo: true,
ruleName: "no-assign-mutated-array",
type: "functionality",
typescriptOnly: true,
};
Rule.FAILURE_STRING = "Assignment of mutated arrays is forbidden";