Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
Merge pull request #713 from palantir/update-next
Browse files Browse the repository at this point in the history
Merge master and prepare v2.6.0-dev.2 release
  • Loading branch information
jkillian committed Oct 5, 2015
2 parents 07aae95 + c17a8c2 commit dec0920
Show file tree
Hide file tree
Showing 26 changed files with 194 additions and 44 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ language: node_js
node_js:
- "0.10"
- "0.12"
- "4.1"
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
Change Log
===

v2.6.0-dev.2
---
* Upgrade TypeScript compiler to `v1.7.0-dev.20151003`
* [bugfix] `no-unused-expression` rule now handles yield expressions properly (#706)

v2.6.0-dev.1
---
* Upgrade TypeScript compiler to `v1.7.0-dev.20150924`

v2.5.1
---
* [new-rule] no-inferrable-types rule (#676)
* [new-rule-option] "avoid-escape" option for quotemark rule (#543)
* [bugfix] type declaration for tslint external module #686
* [enhancement] `AbstractRule` and `AbstractFormatter` are now abstract classes (#631)
* Note: `Lint.abstract()` is now deprecated

v2.5.0
---
* Use TypeScript compiler `v1.6.2`
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ A sample configuration file with all options is available [here](https://github.
* `jsdoc-format` enforces basic format rules for jsdoc comments -- comments starting with `/**`
* each line contains an asterisk and asterisks must be aligned
* each asterisk must be followed by either a space or a newline (except for the first and the last)
* the only characters before the asterisk on each line must be whitepace characters
* the only characters before the asterisk on each line must be whitespace characters
* one line comments must start with `/** ` and end with ` */`
* `label-position` enforces labels only on sensible statements.
* `label-undefined` checks that labels are defined before usage.
Expand All @@ -170,6 +170,7 @@ A sample configuration file with all options is available [here](https://github.
* `no-shadowed-variable` disallows shadowed variable declarations.
* `no-empty` disallows empty blocks.
* `no-eval` disallows `eval` function invocations.
* `no-inferrable-types` disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean
* `no-internal-module` disallows internal `module`, use `namespace` instead.
* `no-require-imports` disallows require() style imports
* `no-string-literal` disallows object access via string literals.
Expand Down Expand Up @@ -245,10 +246,11 @@ TSLint ships with a set of core rules that can be configured. However, users are

Rule names are always camel-cased and *must* contain the suffix `Rule`. Let us take the example of how to write a new rule to forbid all import statements (you know, *for science*). Let us name the rule file `noImportsRule.ts`. Rules can be referenced in `tslint.json` in their dasherized forms, so `"no-imports": true` would turn on the rule.

Now, let us first write the rule in TypeScript. At the top, we reference TSLint's [definition](https://github.com/palantir/tslint/blob/master/lib/tslint.d.ts) file. The exported class name must always be named `Rule` and extend from `Lint.Rules.AbstractRule`.
Now, let us first write the rule in TypeScript. At the top, we reference TSLint's [definition file](https://github.com/palantir/tslint/blob/master/lib/tslint.d.ts) and the [definition file](https://github.com/palantir/tslint/blob/master/typings/typescriptServices.d.ts) for TypeScript's language services. The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`.

```typescript
/// <reference path='tslint.d.ts' />
/// <reference path='../node_modules/tslint/typings/typescriptServices.d.ts' />
/// <reference path='../node_modules/tslint/lib/tslint.d.ts' />

export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "import statement forbidden";
Expand Down Expand Up @@ -280,7 +282,6 @@ We still need to hook up this new rule to TSLint. First make sure to compile `no
Now, let us rewrite the same rule in Javascript.

```javascript

function Rule() {
Lint.Rules.AbstractRule.apply(this, arguments);
}
Expand Down Expand Up @@ -314,8 +315,9 @@ Custom Formatters
-----------------
Just like rules, additional formatters can also be supplied to TSLint via `--formatters-dir` on the CLI or `formattersDirectory` option on the library or `grunt-tslint`. Writing a new formatter is simpler than writing a new rule, as shown in the JSON formatter's code.

```javascript
/// <reference path='tslint.d.ts' />
```typescript
/// <reference path='../node_modules/tslint/typings/typescriptServices.d.ts' />
/// <reference path='../node_modules/tslint/lib/tslint.d.ts' />

export class Formatter extends Lint.Formatters.AbstractFormatter {
public format(failures: Lint.RuleFailure[]): string {
Expand Down
1 change: 1 addition & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment:
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4.1"

install:
- ps: Install-Product node $env:nodejs_version
Expand Down
1 change: 1 addition & 0 deletions docs/sample.tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-inferrable-types": true,
"no-internal-module": true,
"no-require-imports": true,
"no-string-literal": true,
Expand Down
19 changes: 10 additions & 9 deletions lib/tslint.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ declare module Lint {
}
}
declare module Lint {
class ScopeAwareRuleWalker<T> extends RuleWalker {
abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
private scopeStack;
constructor(sourceFile: ts.SourceFile, options?: any);
createScope(): T;
abstract createScope(): T;
getCurrentScope(): T;
getAllScopes(): T[];
getCurrentDepth(): number;
Expand All @@ -106,8 +106,8 @@ declare module Lint {
}
}
declare module Lint.Formatters {
class AbstractFormatter implements Lint.IFormatter {
format(failures: Lint.RuleFailure[]): string;
abstract class AbstractFormatter implements Lint.IFormatter {
abstract format(failures: Lint.RuleFailure[]): string;
}
}
declare module Lint {
Expand All @@ -120,12 +120,12 @@ declare module Lint {
function createLanguageService(fileName: string, source: string): ts.LanguageService;
}
declare module Lint.Rules {
class AbstractRule implements Lint.IRule {
abstract class AbstractRule implements Lint.IRule {
private value;
private options;
constructor(ruleName: string, value: any, disabledIntervals: Lint.IDisabledInterval[]);
getOptions(): Lint.IOptions;
apply(sourceFile: ts.SourceFile): RuleFailure[];
abstract apply(sourceFile: ts.SourceFile): RuleFailure[];
applyWithWalker(walker: Lint.RuleWalker): RuleFailure[];
isEnabled(): boolean;
}
Expand Down Expand Up @@ -189,10 +189,10 @@ declare module Lint {
function isNodeFlagSet(node: ts.Node, flagToCheck: ts.NodeFlags): boolean;
}
declare module Lint {
class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> {
abstract class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> {
private blockScopeStack;
constructor(sourceFile: ts.SourceFile, options?: any);
createBlockScope(): U;
abstract createBlockScope(): U;
getCurrentBlockScope(): U;
onBlockScopeStart(): void;
getCurrentBlockDepth(): number;
Expand Down Expand Up @@ -265,5 +265,6 @@ declare module Lint {
}
}
declare module "tslint" {
export = Lint;
import Linter = Lint.Linter;
export = Linter;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tslint",
"version": "2.6.0-dev.1",
"version": "2.6.0-dev.2",
"description": "a static analysis linter for TypeScript",
"bin": {
"tslint": "./bin/tslint"
Expand Down
2 changes: 1 addition & 1 deletion src/formatters/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.5.0-beta",
"version": "1.6.2",
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
Expand Down
6 changes: 2 additions & 4 deletions src/language/formatter/abstractFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
*/

module Lint.Formatters {
export class AbstractFormatter implements Lint.IFormatter {
public format(failures: Lint.RuleFailure[]): string {
throw Lint.abstract();
}
export abstract class AbstractFormatter implements Lint.IFormatter {
public abstract format(failures: Lint.RuleFailure[]): string;
}
}
8 changes: 2 additions & 6 deletions src/language/rule/abstractRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

module Lint.Rules {
export class AbstractRule implements Lint.IRule {
export abstract class AbstractRule implements Lint.IRule {
private value: any;
private options: Lint.IOptions;

Expand All @@ -38,11 +38,7 @@ module Lint.Rules {
return this.options;
}

/* tslint:disable:no-unused-variable */
public apply(sourceFile: ts.SourceFile): RuleFailure[] {
throw Lint.abstract();
}
/* tslint:enable:no-unused-variable */
public abstract apply(sourceFile: ts.SourceFile): RuleFailure[];

public applyWithWalker(walker: Lint.RuleWalker): RuleFailure[] {
walker.walk(walker.getSourceFile());
Expand Down
1 change: 1 addition & 0 deletions src/language/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ module Lint {
}

export function abstract() {
console.warn("Lint.abstract() is deprecated and will be removed in a future release. TSLint now uses abstract classes.");
return "abstract method not implemented";
}

Expand Down
6 changes: 2 additions & 4 deletions src/language/walker/blockScopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module Lint {
* An AST walker that is aware of block scopes in addition to regular scopes. Block scopes
* are a superset of regular scopes (new block scopes are created more frequently in a program).
*/
export class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> {
export abstract class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> {
private blockScopeStack: U[];

constructor(sourceFile: ts.SourceFile, options?: any) {
Expand All @@ -29,9 +29,7 @@ module Lint {
this.blockScopeStack = [this.createBlockScope()];
}

public createBlockScope(): U {
throw Lint.abstract();
}
public abstract createBlockScope(): U;

public getCurrentBlockScope(): U {
return this.blockScopeStack[this.blockScopeStack.length - 1];
Expand Down
6 changes: 2 additions & 4 deletions src/language/walker/scopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

module Lint {
export class ScopeAwareRuleWalker<T> extends RuleWalker {
export abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
private scopeStack: T[];

constructor(sourceFile: ts.SourceFile, options?: any) {
Expand All @@ -25,9 +25,7 @@ module Lint {
this.scopeStack = [this.createScope()];
}

public createScope(): T {
throw Lint.abstract();
}
public abstract createScope(): T;

public getCurrentScope(): T {
return this.scopeStack[this.scopeStack.length - 1];
Expand Down
67 changes: 67 additions & 0 deletions src/rules/noInferrableTypesRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2015 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.
*/

export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING_FACTORY = (type: string) => `LHS type (${type}) inferred by RHS expression, remove type annotation`;

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new InferrableTypeWalker(sourceFile, this.getOptions()));
}
}

class InferrableTypeWalker extends Lint.RuleWalker {
public visitVariableDeclaration(node: ts.VariableDeclaration) {
this.checkDeclaration(node);
super.visitVariableDeclaration(node);
}

public visitParameterDeclaration(node: ts.ParameterDeclaration) {
this.checkDeclaration(node);
super.visitParameterDeclaration(node);
}

private checkDeclaration(node: ts.ParameterDeclaration | ts.VariableDeclaration) {
if (node.type != null && node.initializer != null) {
let failure: string;
switch (node.type.kind) {
case ts.SyntaxKind.BooleanKeyword:
if (node.initializer.kind === ts.SyntaxKind.TrueKeyword || node.initializer.kind === ts.SyntaxKind.FalseKeyword) {
failure = "boolean";
}
break;
case ts.SyntaxKind.NumberKeyword:
if (node.initializer.kind === ts.SyntaxKind.NumericLiteral) {
failure = "number";
}
break;
case ts.SyntaxKind.StringKeyword:
switch (node.initializer.kind) {
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
case ts.SyntaxKind.TemplateExpression:
failure = "string";
break;
default:
break;
}
break;
}
if (failure) {
this.addFailure(this.createFailure(node.type.getStart(), node.type.getWidth(), Rule.FAILURE_STRING_FACTORY(failure)));
}
}
}
}
2 changes: 1 addition & 1 deletion src/rules/noUnusedExpressionRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class UnusedExpressionWalker extends Lint.RuleWalker {
if (expressionText === "\"use strict\"" || expressionText === "'use strict'") {
return;
}
} else if (node.expression.kind === ts.SyntaxKind.DeleteExpression) {
} else if (node.expression.kind === ts.SyntaxKind.DeleteExpression || node.expression.kind === ts.SyntaxKind.YieldExpression) {
return;
}

Expand Down
3 changes: 2 additions & 1 deletion src/rules/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.5.0-beta",
"version": "1.6.2",
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
Expand Down Expand Up @@ -44,6 +44,7 @@
"./noDuplicateVariableRule.ts",
"./noEmptyRule.ts",
"./noEvalRule.ts",
"./noInferrableTypesRule.ts",
"./noInternalModuleRule.ts",
"./noRequireImportsRule.ts",
"./noShadowedVariableRule.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.5.0-beta",
"version": "1.6.2",
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
Expand Down
5 changes: 3 additions & 2 deletions src/tslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module Lint {
}

export class Linter {
public static VERSION = "2.6.0-dev.1";
public static VERSION = "2.6.0-dev.2";

private fileName: string;
private source: string;
Expand Down Expand Up @@ -114,5 +114,6 @@ module.exports = Lint.Linter;
module.exports.findConfiguration = Lint.Configuration.findConfiguration;

declare module "tslint" {
export = Lint;
import Linter = Lint.Linter;
export = Linter;
}
21 changes: 21 additions & 0 deletions test/files/rules/noinferrabletypes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// errors, inferrable type is declared
let x: number = 7;
let y: boolean = false;
let z: string = "foo";

// errors, types are inferrable
function foo (a: number = 5, b: boolean = true, c: string = "bah") { }

// not errors, inferrable type is not declared
let _x = 7;
let _y = false;
let _z = "foo";

// not error, type is not inferrable
let weird: any = 123;

// not errors, inferrable type is not declared
function bar(a = 5, b = true, c = "bah") { }

// not errors, types are not inferrable
function baz(a: any = 5, b: any = true, c: any = "bah") { }
5 changes: 5 additions & 0 deletions test/files/rules/unused.expression.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ a => fun2(a);

var obj = {};
delete obj.key;
function* g(): Iterable<number> {
for (let i = 0; i < 100; i++) {
yield i;
}
}
Loading

0 comments on commit dec0920

Please sign in to comment.