tslint-immutable
Version:
TSLint rules to disable mutation in TypeScript.
75 lines • 3.54 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("typescript");
var utils = require("tsutils/typeguard/2.8");
var util_1 = require("tsutils/util");
var check_node_1 = require("./shared/check-node");
var Ignore = require("./shared/ignore");
var typeguard_1 = require("./shared/typeguard");
// tslint:disable-next-line:variable-name
exports.Rule = check_node_1.createCheckNodeTypedRule(checkNode, "Modifying properties of existing object not allowed.");
var forbidUnaryOps = [
ts.SyntaxKind.PlusPlusToken,
ts.SyntaxKind.MinusMinusToken
];
function checkNode(node, ctx, checker) {
var invalidNodes = [];
// No assignment with object.property on the left
if (utils.isBinaryExpression(node) &&
typeguard_1.isAccessExpression(node.left) &&
utils.isBinaryExpression(node) &&
util_1.isAssignmentKind(node.operatorToken.kind) &&
!Ignore.isIgnoredPrefix(node.getText(node.getSourceFile()), ctx.options.ignorePrefix) &&
!inConstructor(node)) {
invalidNodes = invalidNodes.concat([check_node_1.createInvalidNode(node, [])]);
}
// No deleting object properties
if (utils.isDeleteExpression(node) &&
typeguard_1.isAccessExpression(node.expression) &&
!Ignore.isIgnoredPrefix(node.expression.getText(node.getSourceFile()), ctx.options.ignorePrefix)) {
invalidNodes = invalidNodes.concat([check_node_1.createInvalidNode(node, [])]);
}
// No prefix inc/dec
if (utils.isPrefixUnaryExpression(node) &&
typeguard_1.isAccessExpression(node.operand) &&
forbidUnaryOps.some(function (o) { return o === node.operator; }) &&
!Ignore.isIgnoredPrefix(node.operand.getText(node.getSourceFile()), ctx.options.ignorePrefix)) {
invalidNodes = invalidNodes.concat([check_node_1.createInvalidNode(node, [])]);
}
// No postfix inc/dec
if (utils.isPostfixUnaryExpression(node) &&
typeguard_1.isAccessExpression(node.operand) &&
forbidUnaryOps.some(function (o) { return o === node.operator; }) &&
!Ignore.isIgnoredPrefix(node.getText(node.getSourceFile()), ctx.options.ignorePrefix)) {
invalidNodes = invalidNodes.concat([check_node_1.createInvalidNode(node, [])]);
}
// No Object.assign on identifiers.
if (utils.isCallExpression(node) &&
utils.isPropertyAccessExpression(node.expression) &&
utils.isIdentifier(node.expression.name) &&
node.expression.name.text === "assign" &&
node.arguments.length >= 2 &&
(utils.isIdentifier(node.arguments[0]) ||
utils.isPropertyAccessExpression(node.arguments[0])) &&
!Ignore.isIgnoredPrefix(node.arguments[0].getText(node.arguments[0].getSourceFile()), ctx.options.ignorePrefix) &&
// Do type checking as late as possible as it is expensive.
isObjectConstructorType(checker.getTypeAtLocation(node.expression.expression))) {
invalidNodes = invalidNodes.concat([check_node_1.createInvalidNode(node, [])]);
}
return { invalidNodes: invalidNodes };
}
function inConstructor(nodeIn) {
var node = nodeIn.parent;
while (node) {
if (utils.isConstructorDeclaration(node)) {
return true;
}
node = node.parent;
}
return false;
}
function isObjectConstructorType(type) {
return Boolean(type.symbol && type.symbol.name === "ObjectConstructor");
}
exports.isObjectConstructorType = isObjectConstructorType;
//# sourceMappingURL=noObjectMutationRule.js.map
;