Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Converted no-increment-decrement to use a walk function #801

Merged
merged 1 commit into from
Jan 28, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 43 additions & 36 deletions src/noIncrementDecrementRule.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import * as ts from 'typescript';
import * as Lint from 'tslint';
import * as tsutils from 'tsutils';

import { ExtendedMetadata } from './utils/ExtendedMetadata';

const OPTION_ALLOW_FOR_LOOPS = 'allow-for-loops';

interface Options {
allowForLoops: boolean;
}

/**
* Implementation of the no-increment-decrement rule.
*/
Expand Down Expand Up @@ -44,51 +49,53 @@ export class Rule extends Lint.Rules.AbstractRule {
Rule.isWarningShown = true;
}

return this.applyWithWalker(new NoIncrementDecrementWalker(sourceFile, this.getOptions()));
return this.applyWithFunction(sourceFile, walk, this.parseOptions(this.getOptions()));
}
}

class NoIncrementDecrementWalker extends Lint.RuleWalker {
private readonly allowForLoops: boolean;

constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) {
super(sourceFile, options);

this.allowForLoops = options.ruleArguments.indexOf(OPTION_ALLOW_FOR_LOOPS) > -1;
private parseOptions(options: Lint.IOptions): Options {
return {
allowForLoops: options.ruleArguments.indexOf(OPTION_ALLOW_FOR_LOOPS) > -1
};
}
}

protected visitForStatement(node: ts.ForStatement): void {
if (this.allowForLoops) {
// If for loops are allowed to contain increment and decrement,
// check everything except the incrementor
super.visitNode(node.statement);
if (node.initializer) {
super.visitNode(node.initializer);
}
if (node.condition) {
super.visitNode(node.condition);
}
} else {
// Otherwise check the node
super.visitForStatement(node);
function walk(ctx: Lint.WalkContext<Options>) {
function validateUnaryExpression(node: ts.PrefixUnaryExpression | ts.PostfixUnaryExpression) {
if (node.operator === ts.SyntaxKind.PlusPlusToken) {
ctx.addFailureAt(node.getStart(), node.getWidth(), 'Forbidden ++ operator');
} else if (node.operator === ts.SyntaxKind.MinusMinusToken) {
ctx.addFailureAt(node.getStart(), node.getWidth(), 'Forbidden -- operator');
}
}

protected visitPostfixUnaryExpression(node: ts.PostfixUnaryExpression): void {
this.validateUnaryExpression(node);
super.visitPostfixUnaryExpression(node);
}
function cb(node: ts.Node): void {
if (tsutils.isForStatement(node)) {
if (ctx.options.allowForLoops) {
// If for loops are allowed to contain increment and decrement,
// check everything except the incrementor
cb(node.statement);
if (node.initializer) {
cb(node.initializer);
}
if (node.condition) {
cb(node.condition);
}
} else {
// Otherwise check the node
ts.forEachChild(node, cb);
}

protected visitPrefixUnaryExpression(node: ts.PrefixUnaryExpression): void {
this.validateUnaryExpression(node);
super.visitPrefixUnaryExpression(node);
}
return;
}

private validateUnaryExpression(node: ts.PrefixUnaryExpression | ts.PostfixUnaryExpression) {
if (node.operator === ts.SyntaxKind.PlusPlusToken) {
this.addFailureAt(node.getStart(), node.getWidth(), 'Forbidden ++ operator');
} else if (node.operator === ts.SyntaxKind.MinusMinusToken) {
this.addFailureAt(node.getStart(), node.getWidth(), 'Forbidden -- operator');
if (tsutils.isPostfixUnaryExpression(node)) {
validateUnaryExpression(node);
} else if (tsutils.isPrefixUnaryExpression(node)) {
validateUnaryExpression(node);
}

return ts.forEachChild(node, cb);
}

return ts.forEachChild(ctx.sourceFile, cb);
}