From aab0f74e494a13ebb40c5ba40536d3abe6e18d21 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Thu, 3 Sep 2015 10:37:27 -0400 Subject: [PATCH 01/15] Fix typescript version to 1.6.0-beta --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61f7c11f7bf..4e3d4914c02 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "grunt-tslint": "latest", "mocha": "^2.2.5", "tslint": "latest", - "typescript": "next" + "typescript": "1.6.0-beta" }, "license": "Apache-2.0" } From cae63443050d901b12076d785cc2773ca00e070c Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Thu, 3 Sep 2015 10:41:46 -0400 Subject: [PATCH 02/15] Prepare release v2.5.0-beta --- CHANGELOG.md | 16 +++++++++++----- package.json | 2 +- src/tslint.ts | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae218b2eb2..a0d1ce3eab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,33 @@ Change Log === +v2.5.0-beta +--- +* Use TypeScript compiler `v1.6.0-beta` +* [bugfix] Fix `no-internal-module` false positives on nested namespaces (#600) +* [docs] Add documentation for `sort-object-literal-keys` rule + v2.5.0-dev.5 --- -* Upgrade TypeScript compiler to v1.7.0-dev.20150828 +* Upgrade TypeScript compiler to `v1.7.0-dev.20150828` * [bugfix] Handle .tsx files appropriately (#597, #558) v2.5.0-dev.4 --- -* Upgrade TypeScript compiler to v1.6.0-dev.20150825 +* Upgrade TypeScript compiler to `v1.6.0-dev.20150825` v2.5.0-dev.3 --- -* Upgrade TypeScript compiler to v1.6.0-dev.20150821 +* Upgrade TypeScript compiler to `v1.6.0-dev.20150821` v2.5.0-dev.2 --- -* Upgrade TypeScript compiler to v1.6.0-dev.20150811 +* Upgrade TypeScript compiler to `v1.6.0-dev.20150811` * [bug] fix `whitespace` false positive in JSX elements (#559) v2.5.0-dev.1 --- -* Upgrade TypeScript compiler to v1.6.0-dev.20150805 +* Upgrade TypeScript compiler to `v1.6.0-dev.20150805` * [enhancement] Support `.tsx` syntax (#490) v2.4.5 diff --git a/package.json b/package.json index 4e3d4914c02..c84abe17899 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tslint", - "version": "2.5.0-dev.5", + "version": "2.5.0-beta", "description": "a static analysis linter for TypeScript", "bin": { "tslint": "./bin/tslint" diff --git a/src/tslint.ts b/src/tslint.ts index 53f8d5e1433..1614389c60c 100644 --- a/src/tslint.ts +++ b/src/tslint.ts @@ -33,7 +33,7 @@ module Lint { } export class Linter { - public static VERSION = "2.5.0-dev.5"; + public static VERSION = "2.5.0-beta"; private fileName: string; private source: string; From 6a3cb137fa1380d1057ae8d85fdb08bf5774ce3b Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Fri, 4 Sep 2015 15:04:08 -0400 Subject: [PATCH 03/15] Fix one-line bug (Issue #637) --- src/rules/oneLineRule.ts | 21 +++++++++++++++------ test/files/rules/oneline.test.ts | 24 ++++++++++++++++++++++++ test/rules/oneLineRuleTests.ts | 9 +++++++-- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/rules/oneLineRule.ts b/src/rules/oneLineRule.ts index 28be132a989..56fc183c3ff 100644 --- a/src/rules/oneLineRule.ts +++ b/src/rules/oneLineRule.ts @@ -165,16 +165,12 @@ class OneLineWalker extends Lint.RuleWalker { } public visitInterfaceDeclaration(node: ts.InterfaceDeclaration) { - const nameNode = node.name; - const openBraceToken = getFirstChildOfKind(node, ts.SyntaxKind.OpenBraceToken); - this.handleOpeningBrace(nameNode, openBraceToken); + this.handleClassLikeDeclaration(node); super.visitInterfaceDeclaration(node); } public visitClassDeclaration(node: ts.ClassDeclaration) { - const nameNode = node.name; - const openBraceToken = getFirstChildOfKind(node, ts.SyntaxKind.OpenBraceToken); - this.handleOpeningBrace(nameNode, openBraceToken); + this.handleClassLikeDeclaration(node); super.visitClassDeclaration(node); } @@ -216,6 +212,19 @@ class OneLineWalker extends Lint.RuleWalker { } } + private handleClassLikeDeclaration(node: ts.ClassDeclaration | ts.InterfaceDeclaration) { + let lastNodeOfDeclaration: ts.Node = node.name; + const openBraceToken = getFirstChildOfKind(node, ts.SyntaxKind.OpenBraceToken); + + if (node.heritageClauses != null) { + lastNodeOfDeclaration = node.heritageClauses[node.heritageClauses.length - 1]; + } else if (node.typeParameters != null) { + lastNodeOfDeclaration = node.typeParameters[node.typeParameters.length - 1]; + } + + this.handleOpeningBrace(lastNodeOfDeclaration, openBraceToken); + } + private handleIterationStatement(node: ts.IterationStatement) { // last child is the statement, second to last child is the close paren const closeParenToken = node.getChildAt(node.getChildCount() - 2); diff --git a/test/files/rules/oneline.test.ts b/test/files/rules/oneline.test.ts index 80c540c6991..8272feeb0d2 100644 --- a/test/files/rules/oneline.test.ts +++ b/test/files/rules/oneline.test.ts @@ -65,3 +65,27 @@ function f(): return 5; } + +class BarBooBaz +{ + +} + +class FooBarBaz { +} + +// Valid multiline declarations +export class LongDescriptiveClassName, S> + extends SomeAbstractBaseClass implements IImportantInterface { +} + +export interface LongDescriptiveInterfaceName + extends AThirdInterface { +} + +function longFunctionNameWithLotsOfParams( + x: number, + y: number, + z: number, + a: T) { +} diff --git a/test/rules/oneLineRuleTests.ts b/test/rules/oneLineRuleTests.ts index 285ea4bf22a..50450e99512 100644 --- a/test/rules/oneLineRuleTests.ts +++ b/test/rules/oneLineRuleTests.ts @@ -26,7 +26,7 @@ describe("", () => { before(() => { const options = [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"]; actualFailures = Lint.Test.applyRuleOnFile(fileName, OneLineRule, options); - assert.lengthOf(actualFailures, 13); + assert.lengthOf(actualFailures, 14); }); it("enforces rules only when enabled", () => { @@ -59,7 +59,7 @@ describe("", () => { Lint.Test.assertContainsFailure(actualFailures, expectedFailure); }); - it("enforces class brace", () => { + it("enforces interface brace", () => { const expectedFailure = Lint.Test.createFailure(fileName, [25, 1], [25, 2], braceFailure); Lint.Test.assertContainsFailure(actualFailures, expectedFailure); }); @@ -94,6 +94,11 @@ describe("", () => { Lint.Test.assertContainsFailure(actualFailures, expectedFailure); }); + it("enforces class brace", () => { + const expectedFailure = Lint.Test.createFailure(fileName, [70, 1], [70, 2], braceFailure); + Lint.Test.assertContainsFailure(actualFailures, expectedFailure); + }); + it("enforces whitespace before a brace", () => { const expectedFailure = Lint.Test.createFailure(fileName, [59, 14], [59, 15], whitespaceFailure); Lint.Test.assertContainsFailure(actualFailures, expectedFailure); From 936524b912cde433165cfedaf5c29eef8dbc467f Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Tue, 8 Sep 2015 10:56:44 -0400 Subject: [PATCH 04/15] Fix various bugs with align-rule * Align rule won't crash on new expression without parens * Align rule now checks constructor and method declarations * Align rule test file now uses valid/normal TS syntax --- src/rules/alignRule.ts | 12 +++++++++++- test/files/rules/align.test.ts | 34 +++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/rules/alignRule.ts b/src/rules/alignRule.ts index d77d6cf0d43..66a9dce69d4 100644 --- a/src/rules/alignRule.ts +++ b/src/rules/alignRule.ts @@ -33,6 +33,11 @@ type SourcePosition = { } class AlignWalker extends Lint.RuleWalker { + public visitConstructorDeclaration(node: ts.ConstructorDeclaration) { + this.checkAlignment(Rule.PARAMETERS_OPTION, node.parameters); + super.visitConstructorDeclaration(node); + } + public visitFunctionDeclaration(node: ts.FunctionDeclaration) { this.checkAlignment(Rule.PARAMETERS_OPTION, node.parameters); super.visitFunctionDeclaration(node); @@ -43,6 +48,11 @@ class AlignWalker extends Lint.RuleWalker { super.visitFunctionExpression(node); } + public visitMethodDeclaration(node: ts.MethodDeclaration) { + this.checkAlignment(Rule.PARAMETERS_OPTION, node.parameters); + super.visitMethodDeclaration(node); + } + public visitCallExpression(node: ts.CallExpression) { this.checkAlignment(Rule.ARGUMENTS_OPTION, node.arguments); super.visitCallExpression(node); @@ -59,7 +69,7 @@ class AlignWalker extends Lint.RuleWalker { } private checkAlignment(kind: string, nodes: ts.Node[]) { - if (nodes.length === 0 || !this.hasOption(kind)) { + if (nodes == null || nodes.length === 0 || !this.hasOption(kind)) { return; } diff --git a/test/files/rules/align.test.ts b/test/files/rules/align.test.ts index c8c8783ddf0..220e6d94550 100644 --- a/test/files/rules/align.test.ts +++ b/test/files/rules/align.test.ts @@ -15,14 +15,14 @@ function invalidParametersAlignment3(a: number, } class C1 { - function invalidParametersAlignment(a: number, + invalidParametersAlignment(a: number, b: number) { } } class InvalidAlignmentInConstructor { - function constructor(a: number, + constructor(a: number, str: string) { } @@ -59,22 +59,22 @@ var validParametersAlignment6 = function(xxx: foo, /////// -void invalidArgumentsAlignment1() +function invalidArgumentsAlignment1() { f(10, 'abcd', 0); } -void invalidArgumentsAlignment2() +function invalidArgumentsAlignment2() { f(10, 'abcd', 0); } -class foo { - function constructor(a: number, - str: string) +class Foo { + constructor(a: number, + str: string) { } } @@ -82,12 +82,12 @@ class foo { var invalidConstructorArgsAlignment = new foo(10, "abcd"); -void validArgumentsAlignment1() +function validArgumentsAlignment1() { f(101, 'xyz', 'abc'); } -void validArgumentsAlignment2() +function validArgumentsAlignment2() { f(1, 2, @@ -95,7 +95,7 @@ void validArgumentsAlignment2() 4); } -void validArgumentsAlignment3() +function validArgumentsAlignment3() { f( 1, @@ -104,7 +104,7 @@ void validArgumentsAlignment3() 4); } -void validArgumentsAlignment3() +function validArgumentsAlignment3() { f(1, 2, 3, 4); @@ -112,14 +112,14 @@ void validArgumentsAlignment3() //////// -void invalidStatementsAlignment1() +function invalidStatementsAlignment1() { var i = 0; var j = 0; var k = 1; } -void invalidStatementsAlignment1() +function invalidStatementsAlignment1() { var i = 0; { @@ -128,14 +128,14 @@ void invalidStatementsAlignment1() } } -void validStatementsAlignment1() +function validStatementsAlignment1() { var i = 0; var j = 0; var k = 1; } -void validStatementsAlignment2() +function validStatementsAlignment2() { var i = 0; { @@ -143,3 +143,7 @@ void validStatementsAlignment2() var k = 1; } } + +function shouldntCrash() { + let f = new Foo; +} From ea3fddf53127a032c7412380ce0aa92b8310605e Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Thu, 10 Sep 2015 14:38:39 -0400 Subject: [PATCH 05/15] Don't check parameters in call signatures --- lib/tslint.d.ts | 1 + src/language/walker/syntaxWalker.ts | 8 ++++++++ src/rules/noShadowedVariableRule.ts | 4 ++++ test/files/rules/no-shadowed-variable.test.ts | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/lib/tslint.d.ts b/lib/tslint.d.ts index a1c460059af..a4075eda50c 100644 --- a/lib/tslint.d.ts +++ b/lib/tslint.d.ts @@ -8,6 +8,7 @@ declare module Lint { protected visitBlock(node: ts.Block): void; protected visitBreakStatement(node: ts.BreakOrContinueStatement): void; protected visitCallExpression(node: ts.CallExpression): void; + protected visitCallSignature(node: ts.SignatureDeclaration): void; protected visitCaseClause(node: ts.CaseClause): void; protected visitClassDeclaration(node: ts.ClassDeclaration): void; protected visitCatchClause(node: ts.CatchClause): void; diff --git a/src/language/walker/syntaxWalker.ts b/src/language/walker/syntaxWalker.ts index 20fe515ce46..bfb51072ef1 100644 --- a/src/language/walker/syntaxWalker.ts +++ b/src/language/walker/syntaxWalker.ts @@ -48,6 +48,10 @@ module Lint { this.walkChildren(node); } + protected visitCallSignature(node: ts.SignatureDeclaration) { + this.walkChildren(node); + } + protected visitCaseClause(node: ts.CaseClause) { this.walkChildren(node); } @@ -310,6 +314,10 @@ module Lint { this.visitCallExpression( node); break; + case ts.SyntaxKind.CallSignature: + this.visitCallSignature( node); + break; + case ts.SyntaxKind.CaseClause: this.visitCaseClause( node); break; diff --git a/src/rules/noShadowedVariableRule.ts b/src/rules/noShadowedVariableRule.ts index 8fe02139a36..03fc1d6e28c 100644 --- a/src/rules/noShadowedVariableRule.ts +++ b/src/rules/noShadowedVariableRule.ts @@ -48,6 +48,10 @@ class NoShadowedVariableWalker extends Lint.BlockScopeAwareRuleWalker number; pos: number; } + +interface FalsePositive4 { + (parameters: T, runSynchonous: boolean): TResult; + (parameters: T, callback: (error: Error, result: TResult) => void): void; +} From 7ea332335312ded612567b70f0eb70f2ef556e0b Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Thu, 10 Sep 2015 15:00:53 -0400 Subject: [PATCH 06/15] Fix crash when linting object destructuring In a variable destructuring assignment, the name node starts after the start of the parent node. We want the position of the name specifically instead of the position of the parent --- src/rules/noUseBeforeDeclareRule.ts | 2 +- test/files/rules/nousebeforedeclare.test.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/rules/noUseBeforeDeclareRule.ts b/src/rules/noUseBeforeDeclareRule.ts index 2d4abbea1f1..f4273e8a565 100644 --- a/src/rules/noUseBeforeDeclareRule.ts +++ b/src/rules/noUseBeforeDeclareRule.ts @@ -45,7 +45,7 @@ class NoUseBeforeDeclareWalker extends Lint.ScopeAwareRuleWalker node.name).text; - this.validateUsageForVariable(variableName, node.getStart()); + this.validateUsageForVariable(variableName, node.name.getStart()); } super.visitBindingElement(node); diff --git a/test/files/rules/nousebeforedeclare.test.ts b/test/files/rules/nousebeforedeclare.test.ts index 6878e1f2df6..06fb820f482 100644 --- a/test/files/rules/nousebeforedeclare.test.ts +++ b/test/files/rules/nousebeforedeclare.test.ts @@ -58,3 +58,9 @@ export { var undeclaredA = 42; let { undeclaredB } = { undeclaredB: 43 }; const [ undeclaredC, [undeclaredD] ] = [ 1, [2] ]; + +// shouldn't crash tslint +function a() { + var b = ({c: dog}) => { dog++; }; + b({ c: 5 }); +} From ce15a878e0b95f4a7cc2a6f3c6b010105efea780 Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Fri, 11 Sep 2015 13:24:02 -0400 Subject: [PATCH 07/15] Fix bug with false positives in unused variable rule and other problems when using language services --- src/language/languageServiceHost.ts | 5 +-- .../nounusedvariable-falsepositives.test.ts | 42 +++++++++++++++++++ test/rules/noUnusedVariableRuleTests.ts | 11 ++++- 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 test/files/rules/nounusedvariable-falsepositives.test.ts diff --git a/src/language/languageServiceHost.ts b/src/language/languageServiceHost.ts index cb95f32734c..03186886c1f 100644 --- a/src/language/languageServiceHost.ts +++ b/src/language/languageServiceHost.ts @@ -21,7 +21,7 @@ module Lint { getCurrentDirectory: () => "", getDefaultLibFileName: () => "lib.d.ts", getScriptFileNames: () => [fileName], - getScriptSnapshot: () => ts.ScriptSnapshot.fromString(source), + getScriptSnapshot: (name) => ts.ScriptSnapshot.fromString(name === fileName ? source : ""), getScriptVersion: () => "1", log: (message) => { /* */ } }; @@ -30,8 +30,7 @@ module Lint { } export function createLanguageService(fileName: string, source: string) { - const documentRegistry = ts.createDocumentRegistry(); const languageServiceHost = Lint.createLanguageServiceHost(fileName, source); - return ts.createLanguageService(languageServiceHost, documentRegistry); + return ts.createLanguageService(languageServiceHost); } } diff --git a/test/files/rules/nounusedvariable-falsepositives.test.ts b/test/files/rules/nounusedvariable-falsepositives.test.ts new file mode 100644 index 00000000000..30cd304ee5b --- /dev/null +++ b/test/files/rules/nounusedvariable-falsepositives.test.ts @@ -0,0 +1,42 @@ +// case 1 +const fs = require("fs"); + +module Foo { + const path = require("path"); + + console.log(fs); + console.log(path); +} + +// case 2 +class HelloWorld { + constructor(public name: string) { } + sayHello() { + return `Hello, ${this.name}!`; + } +}; + +let hello = new HelloWorld("TSLint"); +hello.sayHello(); + +// case 3 +import Bar = whatever.that.Foo; + +module some.module.blah { + export class bar { + private bar: Bar; + constructor() { + console.log(this.bar); + } + } +} + +// case 4 +import DateTimeOpts = Intl.DateTimeFormatOptions; + +interface MyDateTimeOpts extends DateTimeOpts { + timezoneOffset: number; +} + +let opts: MyDateTimeOpts; +console.log(opts.timezoneOffset - 1); diff --git a/test/rules/noUnusedVariableRuleTests.ts b/test/rules/noUnusedVariableRuleTests.ts index 12bc267560d..1cdb9db3fab 100644 --- a/test/rules/noUnusedVariableRuleTests.ts +++ b/test/rules/noUnusedVariableRuleTests.ts @@ -41,9 +41,9 @@ describe("", () => { const failure3 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'b'")([23, 13], [23, 14]); const failure4 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'d'")([26, 10], [26, 11]); const failure5 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'e'")([26, 13], [26, 14]); - const failure6 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'a'")([35, 7] , [35, 8 ]); + const failure6 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'a'")([35, 7], [35, 8]); const failure7 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'e'")([43, 9], [43, 10]); - const failure8 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'b'")([49, 11] , [49, 12]); + const failure8 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'b'")([49, 11], [49, 12]); const actualFailures = Lint.Test.applyRuleOnFile(fileName, Rule); @@ -105,4 +105,11 @@ describe("", () => { Lint.Test.assertContainsFailure(actualFailures, failure7); Lint.Test.assertContainsFailure(actualFailures, failure8); }); + + it("shouldn't find false positives", () => { + const fileName = "rules/nounusedvariable-falsepositives.test.ts"; + const actualFailures = Lint.Test.applyRuleOnFile(fileName, Rule); + + assert.lengthOf(actualFailures, 0); + }); }); From e636eb1938208747b79ca5d19a42b9a74a470079 Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Wed, 16 Sep 2015 23:19:00 +0200 Subject: [PATCH 08/15] unused variable rule shouldn't error on abstract methods with parameters fixes #663 --- src/rules/noUnusedVariableRule.ts | 6 ++++++ test/files/rules/nounusedvariable-parameter.test.ts | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index cfa988d3a8a..d77e39df62a 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -193,7 +193,13 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { } } + // skip checking parameter declarations for abstract methods + // They can't have a body so parameters are always unused + if (Lint.hasModifier(node.modifiers, ts.SyntaxKind.AbstractKeyword)) { + this.skipParameterDeclaration = true; + } super.visitMethodDeclaration(node); + this.skipParameterDeclaration = false; } private validateReferencesForVariable(name: string, position: number) { diff --git a/test/files/rules/nounusedvariable-parameter.test.ts b/test/files/rules/nounusedvariable-parameter.test.ts index f9e85f5aea0..cececc3f9af 100644 --- a/test/files/rules/nounusedvariable-parameter.test.ts +++ b/test/files/rules/nounusedvariable-parameter.test.ts @@ -56,3 +56,7 @@ export class DestructuringTests { return; } } + +abstract class AbstractTest { + abstract foo(x); +} \ No newline at end of file From b1eb389a27608e84befb22d15dd9134befcd28c5 Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Thu, 17 Sep 2015 00:12:31 +0200 Subject: [PATCH 09/15] no-unused-variable-rule: Changed comment for abstract methods --- src/rules/noUnusedVariableRule.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index d77e39df62a..120ef8cc901 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -193,8 +193,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { } } - // skip checking parameter declarations for abstract methods - // They can't have a body so parameters are always unused + // abstract methods can't have a body so their parameters are always unused if (Lint.hasModifier(node.modifiers, ts.SyntaxKind.AbstractKeyword)) { this.skipParameterDeclaration = true; } From c01d82edcd652bc69cd82743cb922eae22cad531 Mon Sep 17 00:00:00 2001 From: Dick van den Brink Date: Thu, 17 Sep 2015 00:31:39 +0200 Subject: [PATCH 10/15] VSCode uses .vscode instead of .settings since 0.8.0 --- {.settings => .vscode}/settings.json | 0 {.settings => .vscode}/tasks.json | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {.settings => .vscode}/settings.json (100%) rename {.settings => .vscode}/tasks.json (100%) diff --git a/.settings/settings.json b/.vscode/settings.json similarity index 100% rename from .settings/settings.json rename to .vscode/settings.json diff --git a/.settings/tasks.json b/.vscode/tasks.json similarity index 100% rename from .settings/tasks.json rename to .vscode/tasks.json From 02c5b17b8022f2845bf01fb6dfcd9bae624a83f1 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Wed, 16 Sep 2015 23:22:31 -0700 Subject: [PATCH 11/15] Use TS 1.6.2 --- package.json | 2 +- typings/typescriptServices.d.ts | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index c84abe17899..995787db66c 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "grunt-tslint": "latest", "mocha": "^2.2.5", "tslint": "latest", - "typescript": "1.6.0-beta" + "typescript": "1.6.2" }, "license": "Apache-2.0" } diff --git a/typings/typescriptServices.d.ts b/typings/typescriptServices.d.ts index 3d4418a9750..4ce3cd34cb5 100644 --- a/typings/typescriptServices.d.ts +++ b/typings/typescriptServices.d.ts @@ -1382,9 +1382,12 @@ declare namespace ts { } interface ResolvedModule { resolvedFileName: string; + isExternalLibraryImport?: boolean; + } + interface ResolvedModuleWithFailedLookupLocations { + resolvedModule: ResolvedModule; failedLookupLocations: string[]; } - type ModuleNameResolver = (moduleName: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => ResolvedModule; interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; getCancellationToken?(): CancellationToken; @@ -1394,7 +1397,7 @@ declare namespace ts { getCanonicalFileName(fileName: string): string; useCaseSensitiveFileNames(): boolean; getNewLine(): string; - resolveModuleNames?(moduleNames: string[], containingFile: string): string[]; + resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[]; } interface TextSpan { start: number; @@ -1515,10 +1518,9 @@ declare namespace ts { const version: string; function findConfigFile(searchPath: string): string; function resolveTripleslashReference(moduleName: string, containingFile: string): string; - function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule; - function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModule; - function baseUrlModuleNameResolver(moduleName: string, containingFile: string, baseUrl: string, host: ModuleResolutionHost): ResolvedModule; - function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule; + function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; + function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; + function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost; function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string; @@ -1649,7 +1651,7 @@ declare namespace ts { trace?(s: string): void; error?(s: string): void; useCaseSensitiveFileNames?(): boolean; - resolveModuleNames?(moduleNames: string[], containingFile: string): string[]; + resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[]; } interface LanguageService { cleanupSemanticCache(): void; From 96b91f3a3bcb551a551e0dce05a0e1096f499543 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Wed, 16 Sep 2015 23:28:48 -0700 Subject: [PATCH 12/15] Prepare release v2.5.0 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- src/tslint.ts | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0d1ce3eab5..1bb1c6ab3a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Change Log === +v2.5.0 +--- +* Use TypeScript compiler `v1.6.2` +* [bugfixes] #637, #642, #650, #652 +* [bugfixes] fix various false positives in `no-unused-variable` rule (#570, #613, #663) +* Update project setup for latest VSCode (#662) + v2.5.0-beta --- * Use TypeScript compiler `v1.6.0-beta` diff --git a/package.json b/package.json index 995787db66c..c47cce51ca5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tslint", - "version": "2.5.0-beta", + "version": "2.5.0", "description": "a static analysis linter for TypeScript", "bin": { "tslint": "./bin/tslint" diff --git a/src/tslint.ts b/src/tslint.ts index 1614389c60c..8863dc74dd8 100644 --- a/src/tslint.ts +++ b/src/tslint.ts @@ -33,7 +33,7 @@ module Lint { } export class Linter { - public static VERSION = "2.5.0-beta"; + public static VERSION = "2.5.0"; private fileName: string; private source: string; From 95cd790d70eb75efd63ae539a1630bcd25b0c02a Mon Sep 17 00:00:00 2001 From: Kuniwak Date: Wed, 26 Aug 2015 14:47:47 +0900 Subject: [PATCH 13/15] Add a relax option "avoid-escape" for quotemark This rule allow to use "other" quote mark for escaping. It is similar to the "escape" option of JSCS or the "avoid-escape" option of ESLint. > Allow the "other" quote mark to be used, but only to avoid having to escape. > > from "JSCS - validateQuoteMarks rule" > http://jscs.info/rule/validateQuoteMarks.html > The third parameter enables an exception to the rule to avoid escaping > quotes. > > from "Rule quotes - ESLint - Pluggable JavaScript linter" > http://eslint.org/docs/rules/quotes Related #543 --- README.md | 3 ++- docs/sample.tslint.json | 2 +- src/rules/quotemarkRule.ts | 33 ++++++++++++++++-------------- test/files/rules/quotemark.test.ts | 2 ++ test/rules/quotemarkRuleTests.ts | 28 +++++++++++++++++++++++-- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 4e6379a36b9..c383003abc1 100644 --- a/README.md +++ b/README.md @@ -189,9 +189,10 @@ A sample configuration file with all options is available [here](https://github. * `"check-else"` checks that `else` is on the same line as the closing brace for `if` * `"check-open-brace"` checks that an open brace falls on the same line as its preceding expression. * `"check-whitespace"` checks preceding whitespace for the specified tokens. -* `quotemark` enforces consistent single or double quoted string literals. Rule options (one is required): +* `quotemark` enforces consistent single or double quoted string literals. Rule options (at least one of `"double"` or `"single"` is required): * `"single"` enforces single quotes * `"double"` enforces double quotes + * `"avoid-escape"` allows you to use the "other" quotemark in cases where escaping would normally be required. For example, `[true, "double", "avoid-escape"]` would not report a failure on the string literal `'Hello "World"'`. * `radix` enforces the radix parameter of `parseInt` * `semicolon` enforces semicolons at the end of every statement. * `sort-object-literal-keys` checks that keys in object literals are declared in alphabetical order diff --git a/docs/sample.tslint.json b/docs/sample.tslint.json index 5fe480a3d2d..dfbd841cce2 100644 --- a/docs/sample.tslint.json +++ b/docs/sample.tslint.json @@ -62,7 +62,7 @@ "check-else", "check-whitespace" ], - "quotemark": [true, "double"], + "quotemark": [true, "double", "avoid-escape"], "radix": true, "semicolon": true, "sort-object-literal-keys": true, diff --git a/src/rules/quotemarkRule.ts b/src/rules/quotemarkRule.ts index edf2fae3fca..882bf30eba4 100644 --- a/src/rules/quotemarkRule.ts +++ b/src/rules/quotemarkRule.ts @@ -38,17 +38,21 @@ export class Rule extends Lint.Rules.AbstractRule { } class QuoteWalker extends Lint.RuleWalker { - private quoteMark: QuoteMark; + private quoteMark = QuoteMark.DOUBLE_QUOTES; + private avoidEscape: boolean; constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { super(sourceFile, options); - const quoteMarkString = this.getOptions()[0]; + const ruleArguments = this.getOptions(); + const quoteMarkString = ruleArguments[0]; if (quoteMarkString === "single") { this.quoteMark = QuoteMark.SINGLE_QUOTES; } else { this.quoteMark = QuoteMark.DOUBLE_QUOTES; } + + this.avoidEscape = ruleArguments.indexOf("avoid-escape") > 0; } public visitNode(node : ts.Node) { @@ -57,8 +61,6 @@ class QuoteWalker extends Lint.RuleWalker { } private handleNode(node: ts.Node) { - let failure: Lint.RuleFailure; - if (node.kind === ts.SyntaxKind.StringLiteral) { const text = node.getText(); const width = node.getWidth(); @@ -67,19 +69,20 @@ class QuoteWalker extends Lint.RuleWalker { const firstCharacter = text.charAt(0); const lastCharacter = text.charAt(text.length - 1); - if (this.quoteMark === QuoteMark.SINGLE_QUOTES) { - if (firstCharacter !== "'" || lastCharacter !== "'") { - failure = this.createFailure(position, width, Rule.SINGLE_QUOTE_FAILURE); - } - } else if (this.quoteMark === QuoteMark.DOUBLE_QUOTES) { - if (firstCharacter !== "\"" || lastCharacter !== "\"") { - failure = this.createFailure(position, width, Rule.DOUBLE_QUOTE_FAILURE); + const expectedQuoteMark = (this.quoteMark === QuoteMark.SINGLE_QUOTES) ? "'" : "\""; + + if (firstCharacter !== expectedQuoteMark || lastCharacter !== expectedQuoteMark) { + // allow the "other" quote mark to be used, but only to avoid having to escape + const includesOtherQuoteMark = text.slice(1, -1).indexOf(expectedQuoteMark) !== -1; + + if (!(this.avoidEscape && includesOtherQuoteMark)) { + const failureMessage = (this.quoteMark === QuoteMark.SINGLE_QUOTES) + ? Rule.SINGLE_QUOTE_FAILURE + : Rule.DOUBLE_QUOTE_FAILURE; + + this.addFailure(this.createFailure(position, width, failureMessage)); } } } - - if (failure != null) { - this.addFailure(failure); - } } } diff --git a/test/files/rules/quotemark.test.ts b/test/files/rules/quotemark.test.ts index d19c910626a..6e5900cee4b 100644 --- a/test/files/rules/quotemark.test.ts +++ b/test/files/rules/quotemark.test.ts @@ -1,2 +1,4 @@ var single = 'single'; var doublee = "married"; +var singleWithinDouble = "'singleWithinDouble'"; +var doubleWithinSingle = '"doubleWithinSingle"'; diff --git a/test/rules/quotemarkRuleTests.ts b/test/rules/quotemarkRuleTests.ts index 4ec00e8d268..7e28127799f 100644 --- a/test/rules/quotemarkRuleTests.ts +++ b/test/rules/quotemarkRuleTests.ts @@ -22,14 +22,38 @@ describe("", () => { it("enforces single quotes", () => { const actualFailures = Lint.Test.applyRuleOnFile(fileName, QuoteMarkRule, [true, "single"]); + const expectedFailures = [ + Lint.Test.createFailure(fileName, [2, 19], [2, 28], singleFailureString), + Lint.Test.createFailure(fileName, [3, 26], [3, 48], singleFailureString) + ]; + + assert.equal(actualFailures.length, 2); + assert.isTrue(actualFailures[0].equals(expectedFailures[0])); + assert.isTrue(actualFailures[1].equals(expectedFailures[1])); + }); + + it("enforces double quotes", () => { + const actualFailures = Lint.Test.applyRuleOnFile(fileName, QuoteMarkRule, [true, "double"]); + const expectedFailures = [ + Lint.Test.createFailure(fileName, [1, 14], [1, 22], doubleFailureString), + Lint.Test.createFailure(fileName, [4, 26], [4, 48], doubleFailureString) + ]; + + assert.equal(actualFailures.length, 2); + assert.isTrue(actualFailures[0].equals(expectedFailures[0])); + assert.isTrue(actualFailures[1].equals(expectedFailures[1])); + }); + + it("enforces single quotes but allow other quote marks to avoid having to escape", () => { + const actualFailures = Lint.Test.applyRuleOnFile(fileName, QuoteMarkRule, [true, "single", "avoid-escape"]); const expectedFailure = Lint.Test.createFailure(fileName, [2, 19], [2, 28], singleFailureString); assert.equal(actualFailures.length, 1); assert.isTrue(actualFailures[0].equals(expectedFailure)); }); - it("enforces double quotes", () => { - const actualFailures = Lint.Test.applyRuleOnFile(fileName, QuoteMarkRule, [true, "double"]); + it("enforces double quotes but allow other quote marks to avoid having to escape", () => { + const actualFailures = Lint.Test.applyRuleOnFile(fileName, QuoteMarkRule, [true, "double", "avoid-escape"]); const expectedFailure = Lint.Test.createFailure(fileName, [1, 14], [1, 22], doubleFailureString); assert.equal(actualFailures.length, 1); From e42ba557f21f5a5aecd15044a9fe6ef683fd21da Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Thu, 24 Sep 2015 13:03:19 -0400 Subject: [PATCH 14/15] Update typings --- package.json | 2 +- typings/typescriptServices.d.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c47cce51ca5..a18ff5d8652 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "grunt-tslint": "latest", "mocha": "^2.2.5", "tslint": "latest", - "typescript": "1.6.2" + "typescript": "next" }, "license": "Apache-2.0" } diff --git a/typings/typescriptServices.d.ts b/typings/typescriptServices.d.ts index 4ce3cd34cb5..761ce39d418 100644 --- a/typings/typescriptServices.d.ts +++ b/typings/typescriptServices.d.ts @@ -1208,9 +1208,11 @@ declare namespace ts { UnionOrIntersection = 49152, StructuredType = 130048, } + type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { flags: TypeFlags; symbol?: Symbol; + pattern?: DestructuringPattern; } interface StringLiteralType extends Type { text: string; @@ -1237,7 +1239,6 @@ declare namespace ts { } interface TupleType extends ObjectType { elementTypes: Type[]; - baseArrayType: TypeReference; } interface UnionOrIntersectionType extends Type { types: Type[]; @@ -1532,7 +1533,7 @@ declare namespace ts { * Read tsconfig.json file * @param fileName The path to the config file */ - function readConfigFile(fileName: string): { + function readConfigFile(fileName: string, readFile: (path: string) => string): { config?: any; error?: Diagnostic; }; From 7fd165f2d0cb149d67244687462f887596aa7f0a Mon Sep 17 00:00:00 2001 From: Jason Killian Date: Thu, 24 Sep 2015 13:07:45 -0400 Subject: [PATCH 15/15] Prepare release 2.6.0-dev.1 --- CHANGELOG.md | 4 ++++ package.json | 2 +- src/tslint.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bb1c6ab3a6..71f6a1f10a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Change Log === +v2.6.0-dev.1 +--- +* Upgrade TypeScript compiler to `v1.7.0-dev.20150924` + v2.5.0 --- * Use TypeScript compiler `v1.6.2` diff --git a/package.json b/package.json index a18ff5d8652..f7e5a2450ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tslint", - "version": "2.5.0", + "version": "2.6.0-dev.1", "description": "a static analysis linter for TypeScript", "bin": { "tslint": "./bin/tslint" diff --git a/src/tslint.ts b/src/tslint.ts index 8863dc74dd8..65870b07481 100644 --- a/src/tslint.ts +++ b/src/tslint.ts @@ -33,7 +33,7 @@ module Lint { } export class Linter { - public static VERSION = "2.5.0"; + public static VERSION = "2.6.0-dev.1"; private fileName: string; private source: string;