UNPKG

tslint-etc

Version:
78 lines (77 loc) 3.25 kB
"use strict"; 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";