import * as Lint from "tslint/lib"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { public static POSTFIX_FAILURE_STRING = "Don't use '++' or '--' postfix operators outside statements or for loops."; public static PREFIX_FAILURE_STRING = "Don't use '++' or '--' prefix operators."; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithFunction(sourceFile, walk); } } function walk(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, recur); function recur(node: ts.Node): void { switch (node.kind) { case ts.SyntaxKind.PrefixUnaryExpression: const { operator } = node as ts.PrefixUnaryExpression; if (operator === ts.SyntaxKind.PlusPlusToken || operator === ts.SyntaxKind.MinusMinusToken) { check(node as ts.PrefixUnaryExpression); } break; case ts.SyntaxKind.PostfixUnaryExpression: check(node as ts.PostfixUnaryExpression); break; } } function check(node: ts.UnaryExpression): void { if (!isAllowedLocation(node.parent!)) { ctx.addFailureAtNode(node, Rule.POSTFIX_FAILURE_STRING); } } } function isAllowedLocation(node: ts.Node): boolean { switch (node.kind) { // Can be a statement case ts.SyntaxKind.ExpressionStatement: return true; // Can be directly in a for-statement case ts.SyntaxKind.ForStatement: return true; // Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`) case ts.SyntaxKind.BinaryExpression: return (node as ts.BinaryExpression).operatorToken.kind === ts.SyntaxKind.CommaToken && node.parent!.kind === ts.SyntaxKind.ForStatement; default: return false; } }