Skip to content

Commit

Permalink
Merge pull request palantir#440 from adidahiya/bugfix-var-keyword-style
Browse files Browse the repository at this point in the history
Style improvements to no-var-keyword rule
  • Loading branch information
adidahiya committed Jun 23, 2015
2 parents 3b3c56c + 785614a commit 3df72a8
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 24 deletions.
3 changes: 2 additions & 1 deletion lib/tslint.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ declare module Lint {
function abstract(): string;
function scanAllTokens(scanner: ts.Scanner, callback: (scanner: ts.Scanner) => void): void;
function hasModifier(modifiers: ts.ModifiersArray, ...modifierKinds: ts.SyntaxKind[]): boolean;
function isBlockScopedVariable(node: ts.VariableDeclaration): boolean;
function isBlockScopedVariable(node: ts.VariableDeclaration | ts.VariableStatement): boolean;
function isBlockScopedBindingElement(node: ts.BindingElement): boolean;
}
declare module Lint {
class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> {
Expand Down
40 changes: 34 additions & 6 deletions src/language/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module Lint {
const normalizedName = path.normalize(fileName).replace(/\\/g, "/");
const compilerOptions = createCompilerOptions();

const compilerHost = {
const compilerHost: ts.CompilerHost = {
getCanonicalFileName: (filename: string) => filename,
getCurrentDirectory: () => "",
getDefaultLibFileName: () => "lib.d.ts",
Expand Down Expand Up @@ -84,10 +84,38 @@ module Lint {
});
}

export function isBlockScopedVariable(node: ts.VariableDeclaration): boolean {
// determine if the appropriate bit in the parent (VariableDeclarationList) is set,
// which indicates this is a "let" or "const"
return (Math.floor(node.parent.flags / ts.NodeFlags.Let) % 2) === 1
|| (Math.floor(node.parent.flags / ts.NodeFlags.Const) % 2) === 1;
/**
* Determines if the appropriate bit in the parent (VariableDeclarationList) is set,
* which indicates this is a "let" or "const".
*/
export function isBlockScopedVariable(node: ts.VariableDeclaration | ts.VariableStatement): boolean {
const parentNode = (node.kind === ts.SyntaxKind.VariableDeclaration)
? (<ts.VariableDeclaration> node).parent
: (<ts.VariableStatement> node).declarationList;

return isNodeFlagSet(parentNode, ts.NodeFlags.Let)
|| isNodeFlagSet(parentNode, ts.NodeFlags.Const);
}

export function isBlockScopedBindingElement(node: ts.BindingElement): boolean {
let currentParent = node.parent;
while (currentParent.kind !== ts.SyntaxKind.VariableDeclaration) {
if (currentParent.parent == null) {
// if we didn't encounter a VariableDeclaration, this must be a function parameter, which is block scoped
return true;
} else {
currentParent = currentParent.parent;
}
}
return isBlockScopedVariable(<ts.VariableDeclaration> currentParent);
}

/**
* Bitwise check for node flags.
*/
function isNodeFlagSet(node: ts.Node, flagToCheck: ts.NodeFlags): boolean {
/* tslint:disable:no-bitwise */
return (node.flags & flagToCheck) !== 0;
/* tslint:enable:no-bitwise */
}
}
3 changes: 1 addition & 2 deletions src/rules/noDuplicateVariableRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class NoDuplicateVariableWalker extends Lint.BlockScopeAwareRuleWalker<{}, Scope
public visitBindingElement(node: ts.BindingElement) {
// TODO: handle node.dotdotToken?
const isSingleVariable = node.name.kind === ts.SyntaxKind.Identifier;
const isBlockScoped = Lint.isBlockScopedVariable(<ts.VariableDeclaration> node.parent.parent);
const isBlockScoped = Lint.isBlockScopedBindingElement(node);

if (isSingleVariable && !isBlockScoped) {
this.handleSingleVariableIdentifier(<ts.Identifier> node.name);
Expand Down Expand Up @@ -83,7 +83,6 @@ class NoDuplicateVariableWalker extends Lint.BlockScopeAwareRuleWalker<{}, Scope
const failureString = `${Rule.FAILURE_STRING}${ident.text}'`;
this.addFailure(this.createFailure(ident.getStart(), ident.getWidth(), failureString));
}

}

class ScopeInfo {
Expand Down
13 changes: 3 additions & 10 deletions src/rules/noVarKeywordRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
* limitations under the License.
*/

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

const OPTION_LEADING_UNDERSCORE = "no-var-keyword";

export class Rule extends Lint.Rules.AbstractRule {
Expand All @@ -29,14 +27,9 @@ export class Rule extends Lint.Rules.AbstractRule {

class NoVarKeywordWalker extends Lint.RuleWalker {
public visitVariableStatement(node: ts.VariableStatement) {
if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)
&& !Lint.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword)) {
const flags = node.declarationList.flags;
const declarationIsLet = (Math.floor(flags / ts.NodeFlags.Let) % 2) === 1;
const declarationIsConst = (Math.floor(flags / ts.NodeFlags.Const) % 2) === 1;
if (!declarationIsConst && !declarationIsLet) {
this.addFailure(this.createFailure(node.getStart(), "var".length, Rule.FAILURE_STRING));
}
if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword, ts.SyntaxKind.DeclareKeyword)
&& !Lint.isBlockScopedVariable(node)) {
this.addFailure(this.createFailure(node.getStart(), "var".length, Rule.FAILURE_STRING));
}

super.visitVariableStatement(node);
Expand Down
5 changes: 5 additions & 0 deletions test/files/rules/no-duplicate-variable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,9 @@ function testDestructuring() {

var [a2, [b2, c2]] = [1, [2, 3]];
var [{a2, d2}] = [{a2: 1, d2: 4}]; // failure

function myFunc2([a, b]) {
var a; // not a failure; caught by no-shadowed-variable
return b;
}
}
10 changes: 5 additions & 5 deletions test/rules/noVarKeywordRuleTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ describe("<no-var-keyword>", () => {
const fileName = "rules/novarkeyword.test.ts";

it("disallows use of creating variables with 'var'", () => {
const failure = Lint.Test.createFailuresOnFile(fileName, NoVarKeywordRule.FAILURE_STRING);
const createFailure = Lint.Test.createFailuresOnFile(fileName, NoVarKeywordRule.FAILURE_STRING);
const expectedFailures = [
failure([1, 1], [1, 4]),
failure([4, 5], [4, 8]),
failure([7, 1], [7, 4]),
failure([10, 1], [10, 4]),
createFailure([1, 1], [1, 4]),
createFailure([4, 5], [4, 8]),
createFailure([7, 1], [7, 4]),
createFailure([10, 1], [10, 4]),
];
const actualFailures = Lint.Test.applyRuleOnFile(fileName, NoVarKeywordRule);

Expand Down

0 comments on commit 3df72a8

Please sign in to comment.