All files noObjectMutationRule.ts

100% Statements 41/41
93.33% Branches 28/30
100% Functions 11/11
100% Lines 34/34
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 811x 1x   1x 1x   1x 1x 1x   1x   1x         1x                               1x         1x   1x   190x 16x 31x 106x 15x         190x 2x 3x 2x         190x 4x 8x 7x 2x         190x 3x 6x 4x 3x       190x     1x  
import * as ts from "typescript";
import * as Lint from "tslint";
 
export class Rule extends Lint.Rules.AbstractRule {
  public static FAILURE_STRING = "Modifying properties of existing object not allowed.";
 
  public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
    const noObjectMutationWalker = new NoObjectMutationWalker(sourceFile, this.getOptions());
    return this.applyWithWalker(noObjectMutationWalker);
  }
}
 
const objPropAccessors: ReadonlyArray<ts.SyntaxKind> = [
  ts.SyntaxKind.ElementAccessExpression,
  ts.SyntaxKind.PropertyAccessExpression
];
 
const forbidObjPropOnLeftSideOf: ReadonlyArray<ts.SyntaxKind> = [
  ts.SyntaxKind.EqualsToken,
  ts.SyntaxKind.PlusEqualsToken,
  ts.SyntaxKind.MinusEqualsToken,
  ts.SyntaxKind.AsteriskEqualsToken,
  ts.SyntaxKind.AsteriskAsteriskEqualsToken,
  ts.SyntaxKind.SlashEqualsToken,
  ts.SyntaxKind.PercentEqualsToken,
  ts.SyntaxKind.LessThanLessThanEqualsToken,
  ts.SyntaxKind.GreaterThanGreaterThanEqualsToken,
  ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
  ts.SyntaxKind.AmpersandEqualsToken,
  ts.SyntaxKind.BarEqualsToken,
  ts.SyntaxKind.CaretEqualsToken
];
 
const forbidUnaryOps: ReadonlyArray<ts.SyntaxKind> = [
  ts.SyntaxKind.PlusPlusToken,
  ts.SyntaxKind.MinusMinusToken
];
 
class NoObjectMutationWalker extends Lint.RuleWalker {
 
  public visitNode(node: ts.Node): void {
    // No assignment with object.property on the left
    if (node && node.kind === ts.SyntaxKind.BinaryExpression) {
      const binExp = node as ts.BinaryExpression;
      if (objPropAccessors.some((k) => k === binExp.left.kind) &&
        forbidObjPropOnLeftSideOf.some((k) => k === binExp.operatorToken.kind)) {
        this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
      }
    }
 
    // No deleting object properties
    if (node && node.kind === ts.SyntaxKind.DeleteExpression) {
      const delExp = node as ts.DeleteExpression;
      Eif (objPropAccessors.some((k) => k === delExp.expression.kind)) {
        this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
      }
    }
 
    // No prefix inc/dec
    if (node && node.kind === ts.SyntaxKind.PrefixUnaryExpression) {
      const preExp = node as ts.PrefixUnaryExpression;
      if (objPropAccessors.some((k) => k === preExp.operand.kind) &&
        forbidUnaryOps.some((o) => o === preExp.operator)) {
        this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
      }
    }
 
    // No postfix inc/dec
    if (node && node.kind === ts.SyntaxKind.PostfixUnaryExpression) {
      const postExp = node as ts.PostfixUnaryExpression;
      Eif (objPropAccessors.some((k) => k === postExp.operand.kind) &&
        forbidUnaryOps.some((o) => o === postExp.operator)) {
        this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
      }
    }
 
    super.visitNode(node);
  }
 
}