Skip to content

Commit

Permalink
Added ban rule for banning specified functions
Browse files Browse the repository at this point in the history
  • Loading branch information
gscshoyru committed Dec 4, 2013
1 parent 4ff9296 commit 7bf5b52
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 34 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ A linter for the TypeScript language.
Supported Rules
-----

* `ban` bans the use of specific functions. Options are ["object", "function"] pairs that ban the use of object.function()
* `class-name` enforces PascalCased class and interface names.
* `curly` enforces braces for `if`/`for`/`do`/`while` statements.
* `eofline` enforces the file to end with a newline.
Expand All @@ -16,7 +17,7 @@ Supported Rules
* `max-line-length` sets the maximum length of a line.
* `no-arg` disallows access to `arguments.callee`.
* `no-bitwise` disallows bitwise operators.
* `no-console` disallows access to the specified properties on `console`. Rule options are properties to ban on the console variable.
* `no-console` disallows access to the specified functions on `console`. Rule options are functions to ban on the console variable.
* `no-construct` disallows access to the constructors of `String`, `Number`, and `Boolean`.
* `no-debugger` disallows `debugger` statements.
* `no-duplicate-key` disallows duplicate keys in object literals.
Expand Down
64 changes: 64 additions & 0 deletions src/rules/banRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2013 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/// <reference path='../../lib/tslint.d.ts' />

export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING_PART = "use of the following function is disallowed: ";

public apply(syntaxTree: TypeScript.SyntaxTree): Lint.RuleFailure[] {
var options = this.getOptions();
var banFunctionWalker = new BanFunctionWalker(syntaxTree, options);
var functionsToBan = options;
functionsToBan.forEach((functionToBan) => {
banFunctionWalker.addBannedFunction(functionToBan);
});
return this.applyWithWalker(banFunctionWalker);
}
}

export class BanFunctionWalker extends Lint.RuleWalker {

private bannedFunctions: string[][] = [];

public addBannedFunction(bannedFunction: string[]) {
this.bannedFunctions.push(bannedFunction);
}

public visitInvocationExpression(node: TypeScript.InvocationExpressionSyntax): void {
var expression = node.expression;

if (expression.kind() === TypeScript.SyntaxKind.MemberAccessExpression &&
expression.childCount() >= 3) {

var firstToken = expression.firstToken();
var secondToken = expression.childAt(1);
var thirdToken = expression.childAt(2);

if (secondToken.kind() === TypeScript.SyntaxKind.DotToken) {
this.bannedFunctions.forEach((bannedFunction) => {
if (firstToken.text() === bannedFunction[0] && thirdToken.fullText() === bannedFunction[1]) {
var position = this.position() + node.leadingTriviaWidth();
this.addFailure(this.createFailure(position, expression.width(), Rule.FAILURE_STRING_PART +
firstToken.text() + "." + thirdToken.fullText()));
}
});
}
}

super.visitInvocationExpression(node);
}
}
36 changes: 8 additions & 28 deletions src/rules/noConsoleRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,15 @@

/// <reference path='../../lib/tslint.d.ts' />

export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "access forbidden to console property";
import BanRule = require("banRule");

export class Rule extends BanRule.Rule {
public apply(syntaxTree: TypeScript.SyntaxTree): Lint.RuleFailure[] {
return this.applyWithWalker(new NoConsoleWalker(syntaxTree, this.getOptions()));
}
}

class NoConsoleWalker extends Lint.RuleWalker {
public visitInvocationExpression(node: TypeScript.InvocationExpressionSyntax): void {
var options = this.getOptions();
var expression = node.expression;

if (expression.kind() === TypeScript.SyntaxKind.MemberAccessExpression &&
expression.childCount() >= 3) {

var firstToken = expression.firstToken();
var secondToken = expression.childAt(1);
var thirdToken = expression.childAt(2);

if (firstToken.text() === "console" &&
secondToken.kind() === TypeScript.SyntaxKind.DotToken &&
options.indexOf(thirdToken.fullText()) !== -1) {

var position = this.position() + node.leadingTriviaWidth();
this.addFailure(this.createFailure(position, expression.width(), Rule.FAILURE_STRING));
}
}

super.visitInvocationExpression(node);
var consoleBanWalker = new BanRule.BanFunctionWalker(syntaxTree, this.getOptions());
options.forEach((option) => {
consoleBanWalker.addBannedFunction(["console", option]);
});
return this.applyWithWalker(consoleBanWalker);
}
}
}
3 changes: 3 additions & 0 deletions test/files/rules/ban.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
console.time();
window.toString();
console.log();
28 changes: 28 additions & 0 deletions test/rules/banRuleTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2013 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/// <reference path='../references.ts' />

describe("<ban>", () => {
it("bans access to specified functions", () => {
var fileName = "rules/ban.test.ts";
var BanRule = Lint.Test.getRule("ban");
var dirFailure = Lint.Test.createFailuresOnFile(fileName, BanRule.FAILURE_STRING_PART + "window.toString")([2, 1], [2, 16]);

var actualFailures = Lint.Test.applyRuleOnFile(fileName, BanRule, [true, ["window", "toString"]]);
Lint.Test.assertContainsFailure(actualFailures, dirFailure);
});
});
12 changes: 7 additions & 5 deletions test/rules/noConsoleRuleTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ describe("<no-console>", () => {
it("forbids access to specified console properties", () => {
var fileName = "rules/noconsole.test.ts";
var NoConsoleRule = Lint.Test.getRule("no-console");
var createFailure = Lint.Test.createFailuresOnFile(fileName, NoConsoleRule.FAILURE_STRING);
var dirFailure = createFailure([3, 1], [3, 12]);
var errorFailure = createFailure([7, 1], [7, 14]);
var logFailure = createFailure([2, 1], [2, 12]);
var warnFailure = createFailure([6, 1], [6, 13]);
var dirFailure = Lint.Test.createFailuresOnFile(fileName, NoConsoleRule.FAILURE_STRING_PART + "console.dir")([3, 1], [3, 12]);
var errorFailure = Lint.Test.createFailuresOnFile(fileName, NoConsoleRule.FAILURE_STRING_PART + "console.error")([7, 1], [7, 14]);
var logFailure = Lint.Test.createFailuresOnFile(fileName, NoConsoleRule.FAILURE_STRING_PART + "console.log")([2, 1], [2, 12]);
var warnFailure = Lint.Test.createFailuresOnFile(fileName, NoConsoleRule.FAILURE_STRING_PART + "console.warn")([6, 1], [6, 13]);

var actualFailures = Lint.Test.applyRuleOnFile(fileName, NoConsoleRule, [true, "dir", "error", "log", "warn"]);
Lint.Test.assertContainsFailure(actualFailures, dirFailure);
Lint.Test.assertContainsFailure(actualFailures, errorFailure);
Lint.Test.assertContainsFailure(actualFailures, logFailure);
Lint.Test.assertContainsFailure(actualFailures, warnFailure);
});
});

0 comments on commit 7bf5b52

Please sign in to comment.