From 39846f9d952147cf500a3c8af4ab085d51f2d3c6 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 25 Mar 2019 18:17:36 -0400 Subject: [PATCH 1/2] Fixed false positive in unnecessary-else after non-jumping statement --- src/rules/unnecessaryElseRule.ts | 69 +++++++++++++++++---- test/rules/unnecessary-else/test.ts.lint | 79 ++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 11 deletions(-) diff --git a/src/rules/unnecessaryElseRule.ts b/src/rules/unnecessaryElseRule.ts index 02f4a712b64..87315592925 100644 --- a/src/rules/unnecessaryElseRule.ts +++ b/src/rules/unnecessaryElseRule.ts @@ -50,27 +50,74 @@ export class Rule extends Lint.Rules.AbstractRule { } } +interface IJumpAndIfStatement { + jumpStatement: string | undefined; + node: ts.IfStatement; +} + function walk(ctx: Lint.WalkContext): void { - ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { - if (utils.isIfStatement(node)) { - const jumpStatement = utils.isBlock(node.thenStatement) - ? getJumpStatement(getLastStatement(node.thenStatement)) - : getJumpStatement(node.thenStatement); + const ifStatementStack: IJumpAndIfStatement[] = []; + + function visitIfStatement(node: ts.IfStatement) { + const jumpStatement = utils.isBlock(node.thenStatement) + ? getJumpStatement(getLastStatement(node.thenStatement)) + : getJumpStatement(node.thenStatement); + + ifStatementStack.push({ node, jumpStatement }); + + if ( + jumpStatement !== undefined && + node.elseStatement !== undefined && + !recentStackParentMissingJumpStatement() + ) { + const elseKeyword = getPositionOfElseKeyword(node, ts.SyntaxKind.ElseKeyword); + ctx.addFailureAtNode(elseKeyword, Rule.FAILURE_STRING(jumpStatement)); + } + + ts.forEachChild(node, visitNode); + ifStatementStack.pop(); + } + + function recentStackParentMissingJumpStatement() { + if (ifStatementStack.length <= 1) { + return false; + } + + for (let i = ifStatementStack.length - 2; i >= 0; i -= 1) { + const { jumpStatement, node } = ifStatementStack[i]; - if (jumpStatement !== undefined && node.elseStatement !== undefined) { - const elseKeyword = getPositionOfElseKeyword(node, ts.SyntaxKind.ElseKeyword); - ctx.addFailureAtNode(elseKeyword, Rule.FAILURE_STRING(jumpStatement)); + if (node.elseStatement !== ifStatementStack[i + 1].node) { + return false; + } + + if (jumpStatement === undefined) { + return true; } } - return ts.forEachChild(node, cb); - }); + + return false; + } + + function visitNode(node: ts.Node): void { + if (utils.isIfStatement(node)) { + visitIfStatement(node); + } else { + ts.forEachChild(node, visitNode); + } + } + + ts.forEachChild(ctx.sourceFile, visitNode); } function getPositionOfElseKeyword(node: ts.Node, kind: ts.SyntaxKind) { return node.getChildren().filter(child => child.kind === kind)[0]; } -function getJumpStatement(node: ts.Statement): string | undefined { +function getJumpStatement(node: ts.Statement | undefined): string | undefined { + if (node === undefined) { + return undefined; + } + switch (node.kind) { case ts.SyntaxKind.BreakStatement: return "break"; diff --git a/test/rules/unnecessary-else/test.ts.lint b/test/rules/unnecessary-else/test.ts.lint index 959dd5ce5ff..b36386fb80b 100644 --- a/test/rules/unnecessary-else/test.ts.lint +++ b/test/rules/unnecessary-else/test.ts.lint @@ -252,6 +252,85 @@ const testNoJump = (a) => { } } +const testConsoleLogIf = (a) => { + if (a) { + // ... + } else if (!a) { + // ... + } +} + +const testNonJumpingElse = (a) => { + if (a === 1) { + console.log("a"); + } else if (a === 2) { + return; + } else { + console.log("b"); + } + + console.log("c"); +} + +const testNonJumpingIf = (a) => { + if (a === 1) { + console.log("a"); + } else if (a === 2) { + return; + } else if (a % 2 === 1) { + console.log("b"); + } + + console.log("c"); +} + +const testNonJumpingIfNestedJumping = (a) => { + if (a === 1) { + if (a) { + return; + } + else { } + ~~~~ [return] + } else if (a === 2) { + return; + } else if (a % 2 === 1) { + console.log("b"); + } + + console.log("c"); +} + +const testNonJumpingIfNestedNonJumping = (a) => { + if (a === 1) { + if (a) {} + else if (a) { + return; + } + else { } + } else if (a === 2) { + return; + } else if (a % 2 === 1) { + console.log("b"); + } + + console.log("c"); +} + +const testNonJumpingIfAndUnrelated = (a) => { + if (a === 1) { + console.log("a"); + if (a) {} + else if (a) { } + else { } + } else if (a === 2) { + return; + } else if (a % 2 === 1) { + console.log("b"); + } + + console.log("c"); +} + [return]: The preceding `if` block ends with a `return` statement. This `else` is unnecessary. [throw]: The preceding `if` block ends with a `throw` statement. This `else` is unnecessary. [break]: The preceding `if` block ends with a `break` statement. This `else` is unnecessary. From 22a4266ac7e6cc971d9e561f2b631cc9389fed41 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 25 Mar 2019 18:18:48 -0400 Subject: [PATCH 2/2] Merge branch 'master' --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- docs/develop/custom-rules/walker-design.md | 16 +-- package.json | 2 +- src/language/rule/abstractRule.ts | 2 +- src/language/walker/scopeAwareRuleWalker.ts | 2 +- src/language/walker/walkContext.ts | 2 +- src/language/walker/walker.ts | 2 +- src/rules/adjacentOverloadSignaturesRule.ts | 2 +- src/rules/banCommaOperatorRule.ts | 2 +- src/rules/banTsIgnoreRule.ts | 2 +- src/rules/binaryExpressionOperandOrderRule.ts | 2 +- src/rules/callableTypesRule.ts | 2 +- src/rules/classNameRule.ts | 2 +- src/rules/code-examples/noAny.examples.ts | 12 ++ src/rules/curlyRule.ts | 2 +- src/rules/deprecationRule.ts | 2 +- src/rules/encodingRule.ts | 2 +- src/rules/fileHeaderRule.ts | 136 +++++++++++++++--- src/rules/forinRule.ts | 2 +- src/rules/functionConstructorRule.ts | 2 +- src/rules/importSpacingRule.ts | 2 +- src/rules/interfaceOverTypeLiteralRule.ts | 2 +- src/rules/labelPositionRule.ts | 2 +- src/rules/matchDefaultExportNameRule.ts | 2 +- src/rules/newParensRule.ts | 2 +- src/rules/newlineBeforeReturnRule.ts | 2 +- src/rules/newlinePerChainedCallRule.ts | 2 +- src/rules/noAngleBracketTypeAssertionRule.ts | 2 +- src/rules/noAnyRule.ts | 45 +++++- src/rules/noArgRule.ts | 2 +- src/rules/noBitwiseRule.ts | 2 +- src/rules/noBooleanLiteralCompareRule.ts | 2 +- src/rules/noConditionalAssignmentRule.ts | 2 +- src/rules/noConstructRule.ts | 2 +- src/rules/noDebuggerRule.ts | 2 +- src/rules/noDefaultExportRule.ts | 2 +- src/rules/noDuplicateSuperRule.ts | 2 +- src/rules/noDuplicateSwitchCaseRule.ts | 2 +- src/rules/noDynamicDeleteRule.ts | 2 +- src/rules/noEmptyInterfaceRule.ts | 2 +- src/rules/noEvalRule.ts | 2 +- src/rules/noForInArrayRule.ts | 2 +- src/rules/noInferredEmptyObjectTypeRule.ts | 2 +- src/rules/noInternalModuleRule.ts | 2 +- src/rules/noInvalidTemplateStringsRule.ts | 2 +- src/rules/noIrregularWhitespaceRule.ts | 2 +- src/rules/noMergeableNamespaceRule.ts | 2 +- src/rules/noMisusedNewRule.ts | 2 +- src/rules/noNonNullAssertionRule.ts | 2 +- src/rules/noNullKeywordRule.ts | 2 +- src/rules/noParameterPropertiesRule.ts | 2 +- src/rules/noParameterReassignmentRule.ts | 2 +- src/rules/noRedundantJsdocRule.ts | 2 +- src/rules/noReferenceImportRule.ts | 2 +- src/rules/noReferenceRule.ts | 2 +- src/rules/noRequireImportsRule.ts | 2 +- src/rules/noReturnAwaitRule.ts | 2 +- src/rules/noSparseArraysRule.ts | 2 +- src/rules/noStringLiteralRule.ts | 2 +- src/rules/noStringThrowRule.ts | 2 +- src/rules/noSwitchCaseFallThroughRule.ts | 2 +- src/rules/noTautologyExpressionRule.ts | 2 +- src/rules/noUnnecessaryCallbackWrapperRule.ts | 2 +- src/rules/noUnnecessaryInitializerRule.ts | 2 +- src/rules/noUnnecessaryQualifierRule.ts | 2 +- src/rules/noUnsafeAnyRule.ts | 2 +- src/rules/noUnsafeFinallyRule.ts | 2 +- src/rules/noUseBeforeDeclareRule.ts | 2 +- src/rules/noVarKeywordRule.ts | 2 +- src/rules/numberLiteralFormatRule.ts | 2 +- src/rules/objectLiteralShorthandRule.ts | 4 +- src/rules/orderedImportsRule.ts | 4 +- src/rules/preferForOfRule.ts | 2 +- src/rules/preferMethodSignatureRule.ts | 2 +- src/rules/preferObjectSpreadRule.ts | 2 +- src/rules/radixRule.ts | 2 +- src/rules/restrictPlusOperandsRule.ts | 2 +- src/rules/returnUndefinedRule.ts | 2 +- src/rules/staticThisRule.ts | 2 +- src/rules/strictTypePredicatesRule.ts | 2 +- src/rules/switchDefaultRule.ts | 2 +- src/rules/typeofCompareRule.ts | 2 +- src/rules/unifiedSignaturesRule.ts | 2 +- src/rules/unnecessaryBindRule.ts | 2 +- src/rules/unnecessaryConstructorRule.ts | 2 +- src/rules/unnecessaryElseRule.ts | 2 +- src/rules/useDefaultTypeParameterRule.ts | 2 +- src/rules/useIsnanRule.ts | 2 +- test/rules/file-header/bad/test2.ts.fix | 7 + test/rules/file-header/bad/test2.ts.lint | 4 + .../test.ts.lint | 4 + .../tslint.json | 8 ++ test/rules/no-any/{ => default}/test.ts.lint | 18 ++- test/rules/no-any/{ => default}/tslint.json | 0 .../no-any/ignore-rest-args/test.ts.lint | 38 +++++ .../rules/no-any/ignore-rest-args/tslint.json | 5 + .../groups-complex/test.ts.fix | 2 + .../groups-complex/test.ts.lint | 1 + yarn.lock | 24 ++-- 99 files changed, 362 insertions(+), 130 deletions(-) create mode 100644 test/rules/file-header/bad/test2.ts.fix create mode 100644 test/rules/file-header/bad/test2.ts.lint create mode 100644 test/rules/file-header/good-allow-single-line-comments/test.ts.lint create mode 100644 test/rules/file-header/good-allow-single-line-comments/tslint.json rename test/rules/no-any/{ => default}/test.ts.lint (59%) rename test/rules/no-any/{ => default}/tslint.json (100%) create mode 100644 test/rules/no-any/ignore-rest-args/test.ts.lint create mode 100644 test/rules/no-any/ignore-rest-args/tslint.json diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2547d888d82..d784dc42bd4 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ #### PR checklist -- [ ] Addresses an existing issue: #0000 +- [ ] Addresses an existing issue: fixes #0000 - [ ] New feature, bugfix, or enhancement - [ ] Includes tests - [ ] Documentation update diff --git a/docs/develop/custom-rules/walker-design.md b/docs/develop/custom-rules/walker-design.md index cb82cc42dca..fd41a4635a1 100644 --- a/docs/develop/custom-rules/walker-design.md +++ b/docs/develop/custom-rules/walker-design.md @@ -30,23 +30,23 @@ export class Rule extends Lint.Rules.AbstractRule { } } -// Here, the options object type is `void` because we don't pass any options in this example. +// Here, the options object type is `void` (which is the default, so can be omitted) because we don't pass any options in this example. function walk(ctx: Lint.WalkContext) { // Recursively walk the AST starting with root node, `ctx.sourceFile`. // Call the function `cb` (defined below) for each child. return ts.forEachChild(ctx.sourceFile, cb); - + function cb(node: ts.Node): void { // Stop recursing further into the AST by returning early. Here, we ignore type nodes. if (node.kind >= ts.SyntaxKind.FirstTypeNode && node.kind <= ts.SyntaxKind.LastTypeNode) { return; } - + // Add failures using the `WalkContext` object. Here, we add a failure if we find the null keyword. if (node.kind === ts.SyntaxKind.NullKeyword) { return ctx.addFailureAtNode(node, Rule.FAILURE_STRING); } - + // Continue recursion into the AST by calling function `cb` for every child of the current node. return ts.forEachChild(node, cb); } @@ -90,7 +90,7 @@ class NoMagicNumbersWalker extends Lint.AbstractWalker> { return ts.forEachChild(node, cb); } }; - + // Start recursion for all children of `sourceFile`. return ts.forEachChild(sourceFile, cb); } @@ -108,7 +108,7 @@ class NoMagicNumbersWalker extends Lint.AbstractWalker> { ## Migrating from RuleWalker to AbstractWalker The main difference between `RuleWalker` and `AbstractWalker` is that you need to implement the AST recursion yourself. But why would you want to do that? -__Performance!__ `RuleWalker` wants to be "one walker to rule them all" (pun intended). It's easy to use but that convenience +__Performance!__ `RuleWalker` wants to be "one walker to rule them all" (pun intended). It's easy to use but that convenience makes it slow by default. When implementing the walking yourself, you only need to do as much work as needed. Besides that you *should* convert the `ruleArguments` to a useful format before passing it to `AbstractWalker` as seen above. @@ -125,8 +125,8 @@ This table describes the equivalent methods between the two classes: `this.appendText()` | `Lint.Replacement.appendText()` `this.hasOption()` and `this.getOptions()` | use `this.options` directly `this.getLineAndCharacterOfPosition()` | `ts.getLineAndCharacterOfPosition(this.sourceFile, ...)` -`this.getLimit()` | `this.sourceFile.end` -`this.getSourceFile()` | is available to be compatible, but prefer `this.sourceFile` +`this.getLimit()` | `this.sourceFile.end` +`this.getSourceFile()` | is available to be compatible, but prefer `this.sourceFile` `this.getFailures()` | is available to be compatible, but prefer `this.failures` `this.skip()` | just don't use it, it's a noop `this.getRuleName()` | `this.ruleName` diff --git a/package.json b/package.json index c024bb533d2..2880a5dd347 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "commander": "^2.12.1", "diff": "^3.2.0", "glob": "^7.1.1", - "js-yaml": "^3.7.0", + "js-yaml": "^3.13.0", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "resolve": "^1.3.2", diff --git a/src/language/rule/abstractRule.ts b/src/language/rule/abstractRule.ts index a8e96e5acd6..53dc9156f72 100644 --- a/src/language/rule/abstractRule.ts +++ b/src/language/rule/abstractRule.ts @@ -52,7 +52,7 @@ export abstract class AbstractRule implements IRule { protected applyWithFunction( sourceFile: ts.SourceFile, - walkFn: (ctx: WalkContext) => void, + walkFn: (ctx: WalkContext) => void, ): RuleFailure[]; protected applyWithFunction( sourceFile: ts.SourceFile, diff --git a/src/language/walker/scopeAwareRuleWalker.ts b/src/language/walker/scopeAwareRuleWalker.ts index a46ea4c9a14..55fa061eb67 100644 --- a/src/language/walker/scopeAwareRuleWalker.ts +++ b/src/language/walker/scopeAwareRuleWalker.ts @@ -27,7 +27,7 @@ import { RuleWalker } from "./ruleWalker"; * * For example, imagine a `no-break` rule that warns on `break` in `for` but not in `switch`: * - * function walk(ctx: Lint.WalkContext): void { + * function walk(ctx: Lint.WalkContext): void { * let isInFor = false; * ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { * switch (node.kind) { diff --git a/src/language/walker/walkContext.ts b/src/language/walker/walkContext.ts index 781633f2f32..522af77174d 100644 --- a/src/language/walker/walkContext.ts +++ b/src/language/walker/walkContext.ts @@ -19,7 +19,7 @@ import * as ts from "typescript"; import { Fix, RuleFailure } from "../rule/rule"; -export class WalkContext { +export class WalkContext { public readonly failures: RuleFailure[] = []; constructor( diff --git a/src/language/walker/walker.ts b/src/language/walker/walker.ts index 1b1b3b97693..de92391e82e 100644 --- a/src/language/walker/walker.ts +++ b/src/language/walker/walker.ts @@ -27,7 +27,7 @@ export interface IWalker { getFailures(): RuleFailure[]; } -export abstract class AbstractWalker extends WalkContext implements IWalker { +export abstract class AbstractWalker extends WalkContext implements IWalker { public abstract walk(sourceFile: ts.SourceFile): void; public getSourceFile() { diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index 0135780d2a3..2a83db53c8b 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; visitStatements(sourceFile.statements); return ts.forEachChild(sourceFile, function cb(node: ts.Node): void { diff --git a/src/rules/banCommaOperatorRule.ts b/src/rules/banCommaOperatorRule.ts index 22304f80c0f..b942e4e76c1 100644 --- a/src/rules/banCommaOperatorRule.ts +++ b/src/rules/banCommaOperatorRule.ts @@ -64,7 +64,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( isBinaryExpression(node) && diff --git a/src/rules/banTsIgnoreRule.ts b/src/rules/banTsIgnoreRule.ts index f238f08702f..3dd6378a961 100644 --- a/src/rules/banTsIgnoreRule.ts +++ b/src/rules/banTsIgnoreRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { const ignoreDiagnosticCommentRegEx = /^\s*\/\/\/?\s*@ts-ignore/; forEachComment(ctx.sourceFile, (fullText, comment) => { const commentText = fullText.slice(comment.pos, comment.end); diff --git a/src/rules/binaryExpressionOperandOrderRule.ts b/src/rules/binaryExpressionOperandOrderRule.ts index 95751c2c207..547c9e26ad2 100644 --- a/src/rules/binaryExpressionOperandOrderRule.ts +++ b/src/rules/binaryExpressionOperandOrderRule.ts @@ -50,7 +50,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, function cb(node) { if ( isBinaryExpression(node) && diff --git a/src/rules/callableTypesRule.ts b/src/rules/callableTypesRule.ts index 5cc3e15285e..e247459f377 100644 --- a/src/rules/callableTypesRule.ts +++ b/src/rules/callableTypesRule.ts @@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( ((isInterfaceDeclaration(node) && noSupertype(node)) || isTypeLiteralNode(node)) && diff --git a/src/rules/classNameRule.ts b/src/rules/classNameRule.ts index d03f7e2d1da..8033d29a304 100644 --- a/src/rules/classNameRule.ts +++ b/src/rules/classNameRule.ts @@ -50,7 +50,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( (isClassLikeDeclaration(node) && node.name !== undefined) || diff --git a/src/rules/code-examples/noAny.examples.ts b/src/rules/code-examples/noAny.examples.ts index 46fc15ec49c..731678ce80f 100644 --- a/src/rules/code-examples/noAny.examples.ts +++ b/src/rules/code-examples/noAny.examples.ts @@ -31,4 +31,16 @@ export const codeExamples = [ let foo: any; `, }, + { + description: + "Disallows usages of `any` as a type declaration except rest spread parameters.", + config: Lint.Utils.dedent` + "rules": { "no-any": [true, { "ignore-rest-args": true }] } + `, + pass: Lint.Utils.dedent` + function foo(a: number, ...rest: any[]): void { + return; + } + `, + }, ]; diff --git a/src/rules/curlyRule.ts b/src/rules/curlyRule.ts index 2b51c2b5df8..e62e3f5eb49 100644 --- a/src/rules/curlyRule.ts +++ b/src/rules/curlyRule.ts @@ -86,7 +86,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walkAsNeeded(ctx: Lint.WalkContext): void { +function walkAsNeeded(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, function cb(node) { if (isBlock(node) && isBlockUnnecessary(node)) { ctx.addFailureAt(node.statements.pos - 1, 1, Rule.FAILURE_STRING_AS_NEEDED); diff --git a/src/rules/deprecationRule.ts b/src/rules/deprecationRule.ts index 79753d13edf..e5342617e43 100644 --- a/src/rules/deprecationRule.ts +++ b/src/rules/deprecationRule.ts @@ -62,7 +62,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { +function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (isIdentifier(node)) { if (!isDeclaration(node)) { diff --git a/src/rules/encodingRule.ts b/src/rules/encodingRule.ts index aac0c9a876b..0a5ce13be83 100644 --- a/src/rules/encodingRule.ts +++ b/src/rules/encodingRule.ts @@ -43,7 +43,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const encoding = detectEncoding(ctx.sourceFile.fileName); if (encoding !== "utf8") { ctx.addFailure(0, 1, Rule.FAILURE_STRING(encoding)); diff --git a/src/rules/fileHeaderRule.ts b/src/rules/fileHeaderRule.ts index 03d44d342ff..764404d3f44 100644 --- a/src/rules/fileHeaderRule.ts +++ b/src/rules/fileHeaderRule.ts @@ -19,7 +19,17 @@ import * as ts from "typescript"; import * as Lint from "../index"; -const ENFORCE_TRAILING_NEWLINE = "enforce-trailing-newline"; +const OPTION_MATCH = "match"; +const OPTION_ALLOW_SINGLE_LINE_COMMENTS = "allow-single-line-comments"; +const OPTION_DEFAULT = "default"; +const OPTION_ENFORCE_TRAILING_NEWLINE = "enforce-trailing-newline"; + +interface FileHeaderRuleOptions { + [OPTION_MATCH]: string; + [OPTION_ALLOW_SINGLE_LINE_COMMENTS]?: boolean; + [OPTION_DEFAULT]?: string; + [OPTION_ENFORCE_TRAILING_NEWLINE]?: boolean; +} export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -28,29 +38,76 @@ export class Rule extends Lint.Rules.AbstractRule { description: "Enforces a certain header comment for all files, matched by a regular expression.", optionsDescription: Lint.Utils.dedent` + A single object may be passed in for configuration that must contain: + + * \`${OPTION_MATCH}\`: a regular expression that all headers should match + + Any of the following optional fields may also be provided: + + * \`${OPTION_ALLOW_SINGLE_LINE_COMMENTS}\`: a boolean for whether \`//\` should be considered file headers in addition to \`/*\` comments + * \`${OPTION_DEFAULT}\`: text to add for file headers when running in \`--fix\` mode + * \`${OPTION_ENFORCE_TRAILING_NEWLINE}\`: a boolean for whether a newline must follow the header + + The rule will also accept array of strings as a legacy form of options, though the object form is recommended. The first option, which is mandatory, is a regular expression that all headers should match. The second argument, which is optional, is a string that should be inserted as a header comment if fixing is enabled and no header that matches the first argument is found. The third argument, which is optional, is a string that denotes whether or not a newline should exist on the header.`, options: { - type: "array", - items: [ + oneOf: [ { - type: "string", + type: "array", + items: { + type: "object", + properties: { + [OPTION_MATCH]: { + type: "string", + }, + [OPTION_ALLOW_SINGLE_LINE_COMMENTS]: { + type: "boolean", + }, + [OPTION_DEFAULT]: { + type: "string", + }, + [OPTION_ENFORCE_TRAILING_NEWLINE]: { + type: "boolean", + }, + }, + additionalProperties: false, + }, }, { - type: "string", + type: "array", + items: [ + { + type: "string", + }, + { + type: "string", + }, + { + type: "string", + }, + ], + additionalItems: false, + minLength: 1, + maxLength: 3, }, + ], + }, + optionExamples: [ + [ + true, { - type: "string", + [OPTION_MATCH]: "Copyright \\d{4}", + [OPTION_ALLOW_SINGLE_LINE_COMMENTS]: true, + [OPTION_DEFAULT]: "Copyright 2018", + [OPTION_ENFORCE_TRAILING_NEWLINE]: true, }, ], - additionalItems: false, - minLength: 1, - maxLength: 3, - }, - optionExamples: [[true, "Copyright \\d{4}", "Copyright 2018", ENFORCE_TRAILING_NEWLINE]], + [true, "Copyright \\d{4}", "Copyright 2018", OPTION_ENFORCE_TRAILING_NEWLINE], + ], hasFix: true, type: "style", typescriptOnly: false, @@ -61,17 +118,18 @@ export class Rule extends Lint.Rules.AbstractRule { public static MISSING_NEW_LINE_FAILURE_STRING = "missing new line following the file header"; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + const options = this.getRuleOptions(); + const { text } = sourceFile; - const headerFormat = new RegExp(this.ruleArguments[0] as string); - const textToInsert = this.ruleArguments[1] as string | undefined; - const enforceExtraTrailingLine = - this.ruleArguments.indexOf(ENFORCE_TRAILING_NEWLINE) !== -1; + const headerFormat = new RegExp(options[OPTION_MATCH]); + const textToInsert = options[OPTION_DEFAULT]; // ignore shebang if it exists let offset = text.startsWith("#!") ? text.indexOf("\n") : 0; - // returns the text of the first comment or undefined - const commentText = ts.forEachLeadingCommentRange(text, offset, (pos, end, kind) => - text.substring(pos + 2, kind === ts.SyntaxKind.SingleLineCommentTrivia ? end : end - 2), + const commentText = this.getFileHeaderText( + text, + offset, + !!options[OPTION_ALLOW_SINGLE_LINE_COMMENTS], ); if (commentText === undefined || !headerFormat.test(commentText)) { @@ -107,7 +165,7 @@ export class Rule extends Lint.Rules.AbstractRule { } const trailingNewLineViolation = - enforceExtraTrailingLine && + options[OPTION_ENFORCE_TRAILING_NEWLINE] && headerFormat.test(commentText) && this.doesNewLineEndingViolationExist(text, offset); @@ -135,6 +193,24 @@ export class Rule extends Lint.Rules.AbstractRule { return []; } + private getRuleOptions(): FileHeaderRuleOptions { + const options = this.ruleArguments; + if (options.length === 1 && typeof options[0] === "object") { + return options[0] as FileHeaderRuleOptions; + } + + // Legacy options + const args = this.ruleArguments as string[]; + return { + [OPTION_DEFAULT]: args[1], + [OPTION_ENFORCE_TRAILING_NEWLINE]: + args[2] !== undefined + ? args[2].indexOf(OPTION_ENFORCE_TRAILING_NEWLINE) !== -1 + : undefined, + [OPTION_MATCH]: args[0], + }; + } + private createComment( sourceFile: ts.SourceFile, commentText: string, @@ -172,4 +248,26 @@ export class Rule extends Lint.Rules.AbstractRule { entireComment !== undefined && NEW_LINE_FOLLOWING_HEADER.test(entireComment) !== null ); } + + private getFileHeaderText( + text: string, + offset: number, + allowSingleLineComments: boolean, + ): string | undefined { + const ranges = ts.getLeadingCommentRanges(text, offset); + if (ranges === undefined || ranges.length === 0) { + return undefined; + } + + const fileHeaderRanges = !allowSingleLineComments ? ranges.slice(0, 1) : ranges; + return fileHeaderRanges + .map(range => { + const { pos, kind, end } = range; + return text.substring( + pos + 2, + kind === ts.SyntaxKind.SingleLineCommentTrivia ? end : end - 2, + ); + }) + .join("\n"); + } } diff --git a/src/rules/forinRule.ts b/src/rules/forinRule.ts index e4b93e6b443..b935ae4f40c 100644 --- a/src/rules/forinRule.ts +++ b/src/rules/forinRule.ts @@ -58,7 +58,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (isForInStatement(node) && isBlock(node.statement) && !isFiltered(node.statement)) { ctx.addFailureAtNode(node, Rule.FAILURE_STRING); diff --git a/src/rules/functionConstructorRule.ts b/src/rules/functionConstructorRule.ts index 1e1e5ef19cf..bc2eec91918 100644 --- a/src/rules/functionConstructorRule.ts +++ b/src/rules/functionConstructorRule.ts @@ -49,7 +49,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(context: Lint.WalkContext): void { +function walk(context: Lint.WalkContext): void { ts.forEachChild(context.sourceFile, function cb(node): void { if (isFunctionCallOrNewExpression(node)) { addFailureAtNode(node); diff --git a/src/rules/importSpacingRule.ts b/src/rules/importSpacingRule.ts index fc568a6f231..9d6c9385a87 100644 --- a/src/rules/importSpacingRule.ts +++ b/src/rules/importSpacingRule.ts @@ -49,7 +49,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -class Walker extends Lint.AbstractWalker { +class Walker extends Lint.AbstractWalker { public walk({ statements }: ts.SourceFile): void { for (const statement of statements) { if (!isImportDeclaration(statement)) { diff --git a/src/rules/interfaceOverTypeLiteralRule.ts b/src/rules/interfaceOverTypeLiteralRule.ts index 1ee9fab03a3..9d8c984ea22 100644 --- a/src/rules/interfaceOverTypeLiteralRule.ts +++ b/src/rules/interfaceOverTypeLiteralRule.ts @@ -43,7 +43,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isTypeAliasDeclaration(node) && isTypeLiteralNode(node.type)) { const typeKeyword = getChildOfKind(node, ts.SyntaxKind.TypeKeyword, ctx.sourceFile)!; diff --git a/src/rules/labelPositionRule.ts b/src/rules/labelPositionRule.ts index 17b8e9b04a8..03efd7542d7 100644 --- a/src/rules/labelPositionRule.ts +++ b/src/rules/labelPositionRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isLabeledStatement(node) && !isLabelable(node.statement)) { ctx.addFailureAtNode(node.label, Rule.FAILURE_STRING); diff --git a/src/rules/matchDefaultExportNameRule.ts b/src/rules/matchDefaultExportNameRule.ts index 59121222335..44186c5a5be 100644 --- a/src/rules/matchDefaultExportNameRule.ts +++ b/src/rules/matchDefaultExportNameRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { +function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { for (const statement of ctx.sourceFile.statements) { if ( !isImportDeclaration(statement) || diff --git a/src/rules/newParensRule.ts b/src/rules/newParensRule.ts index c0448fa3ae0..8788226021b 100644 --- a/src/rules/newParensRule.ts +++ b/src/rules/newParensRule.ts @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( node.kind === ts.SyntaxKind.NewExpression && diff --git a/src/rules/newlineBeforeReturnRule.ts b/src/rules/newlineBeforeReturnRule.ts index 61f479053b4..c961d348db7 100644 --- a/src/rules/newlineBeforeReturnRule.ts +++ b/src/rules/newlineBeforeReturnRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -class NewlineBeforeReturnWalker extends Lint.AbstractWalker { +class NewlineBeforeReturnWalker extends Lint.AbstractWalker { public walk(sourceFile: ts.SourceFile) { const cb = (node: ts.Node): void => { if (node.kind === ts.SyntaxKind.ReturnStatement) { diff --git a/src/rules/newlinePerChainedCallRule.ts b/src/rules/newlinePerChainedCallRule.ts index 8814d217924..2fe3367692a 100644 --- a/src/rules/newlinePerChainedCallRule.ts +++ b/src/rules/newlinePerChainedCallRule.ts @@ -48,7 +48,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -class NewlinePerChainedCallWalker extends Lint.AbstractWalker { +class NewlinePerChainedCallWalker extends Lint.AbstractWalker { public walk(sourceFile: ts.SourceFile) { const checkForSameLine = (node: ts.Node): void => { if ( diff --git a/src/rules/noAngleBracketTypeAssertionRule.ts b/src/rules/noAngleBracketTypeAssertionRule.ts index 225ce14f596..093ead1a124 100644 --- a/src/rules/noAngleBracketTypeAssertionRule.ts +++ b/src/rules/noAngleBracketTypeAssertionRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isTypeAssertion(node)) { let { expression } = node; diff --git a/src/rules/noAnyRule.ts b/src/rules/noAnyRule.ts index 88cfd9b5483..890ea29adfe 100644 --- a/src/rules/noAnyRule.ts +++ b/src/rules/noAnyRule.ts @@ -15,12 +15,15 @@ * limitations under the License. */ +import { isArrayTypeNode, isParameterDeclaration } from "tsutils"; import * as ts from "typescript"; import * as Lint from "../index"; import { codeExamples } from "./code-examples/noAny.examples"; +const OPTION_IGNORE_REST_ARGS = "ignore-rest-args"; + export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { @@ -38,9 +41,16 @@ export class Rule extends Lint.Rules.AbstractRule { Also see the \`no-unsafe-any\` rule. `, - optionsDescription: "Not configurable.", - options: null, - optionExamples: [true], + optionsDescription: Lint.Utils.dedent` + If \`"${OPTION_IGNORE_REST_ARGS}": true\` is provided rest arguments will be ignored. + `, + options: { + type: "object", + properties: { + [OPTION_IGNORE_REST_ARGS]: { type: "boolean" }, + }, + }, + optionExamples: [true, [true, { [OPTION_IGNORE_REST_ARGS]: true }]], type: "typescript", typescriptOnly: true, codeExamples, @@ -51,16 +61,41 @@ export class Rule extends Lint.Rules.AbstractRule { "Type declaration of 'any' loses type-safety. Consider replacing it with a more precise type."; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithFunction(sourceFile, walk); + const options: Options = getOptions(this.ruleArguments[0] as Partial | undefined); + return this.applyWithFunction(sourceFile, walk, options); } } -function walk(ctx: Lint.WalkContext) { +interface Options { + [OPTION_IGNORE_REST_ARGS]: boolean; +} + +function getOptions(options: Partial | undefined): Options { + return { + [OPTION_IGNORE_REST_ARGS]: false, + ...options, + }; +} + +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (node.kind === ts.SyntaxKind.AnyKeyword) { + if (ctx.options[OPTION_IGNORE_REST_ARGS] && isRestParameterArrayType(node)) { + return; + } + const start = node.end - 3; return ctx.addFailure(start, node.end, Rule.FAILURE_STRING); } + return ts.forEachChild(node, cb); }); } + +function isRestParameterArrayType(anyTypeNode: ts.Node) { + return ( + isArrayTypeNode(anyTypeNode.parent) && + isParameterDeclaration(anyTypeNode.parent.parent) && + anyTypeNode.parent.parent.getChildAt(0).kind === ts.SyntaxKind.DotDotDotToken + ); +} diff --git a/src/rules/noArgRule.ts b/src/rules/noArgRule.ts index a8d0297cbb9..1d4b26afa23 100644 --- a/src/rules/noArgRule.ts +++ b/src/rules/noArgRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( isPropertyAccessExpression(node) && diff --git a/src/rules/noBitwiseRule.ts b/src/rules/noBitwiseRule.ts index d4594ba2e78..b7c4132d4e9 100644 --- a/src/rules/noBitwiseRule.ts +++ b/src/rules/noBitwiseRule.ts @@ -48,7 +48,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (node.kind === ts.SyntaxKind.BinaryExpression) { switch ((node as ts.BinaryExpression).operatorToken.kind) { diff --git a/src/rules/noBooleanLiteralCompareRule.ts b/src/rules/noBooleanLiteralCompareRule.ts index bbafa974c80..0fd3584d109 100644 --- a/src/rules/noBooleanLiteralCompareRule.ts +++ b/src/rules/noBooleanLiteralCompareRule.ts @@ -50,7 +50,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (utils.isBinaryExpression(node)) { const cmp = getBooleanComparison(node, checker); diff --git a/src/rules/noConditionalAssignmentRule.ts b/src/rules/noConditionalAssignmentRule.ts index a1bc0bf7deb..eca1c06d786 100644 --- a/src/rules/noConditionalAssignmentRule.ts +++ b/src/rules/noConditionalAssignmentRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { let checking = 0; return ts.forEachChild(ctx.sourceFile, cb); diff --git a/src/rules/noConstructRule.ts b/src/rules/noConstructRule.ts index b0297d921d9..0de031bfd5c 100644 --- a/src/rules/noConstructRule.ts +++ b/src/rules/noConstructRule.ts @@ -47,7 +47,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isNewExpression(node) && node.expression.kind === ts.SyntaxKind.Identifier) { switch ((node.expression as ts.Identifier).text) { diff --git a/src/rules/noDebuggerRule.ts b/src/rules/noDebuggerRule.ts index d849a83b8d4..ee20b84fe80 100644 --- a/src/rules/noDebuggerRule.ts +++ b/src/rules/noDebuggerRule.ts @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (node.kind === ts.SyntaxKind.DebuggerStatement) { return ctx.addFailureAtNode(node, Rule.FAILURE_STRING); diff --git a/src/rules/noDefaultExportRule.ts b/src/rules/noDefaultExportRule.ts index be54752c5cb..8e3d698b7dc 100644 --- a/src/rules/noDefaultExportRule.ts +++ b/src/rules/noDefaultExportRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { if (ctx.sourceFile.isDeclarationFile || !ts.isExternalModule(ctx.sourceFile)) { return; } diff --git a/src/rules/noDuplicateSuperRule.ts b/src/rules/noDuplicateSuperRule.ts index 7146b72d5c3..b9f88502645 100644 --- a/src/rules/noDuplicateSuperRule.ts +++ b/src/rules/noDuplicateSuperRule.ts @@ -43,7 +43,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isConstructorDeclaration(node) && node.body !== undefined) { getSuperForNode(node.body); diff --git a/src/rules/noDuplicateSwitchCaseRule.ts b/src/rules/noDuplicateSwitchCaseRule.ts index a191341cfaf..d426a653f51 100644 --- a/src/rules/noDuplicateSwitchCaseRule.ts +++ b/src/rules/noDuplicateSwitchCaseRule.ts @@ -38,7 +38,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (node.kind === ts.SyntaxKind.CaseBlock) { visitCaseBlock(node as ts.CaseBlock); diff --git a/src/rules/noDynamicDeleteRule.ts b/src/rules/noDynamicDeleteRule.ts index 76fcdd3098c..fb9c58fb633 100644 --- a/src/rules/noDynamicDeleteRule.ts +++ b/src/rules/noDynamicDeleteRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(context: Lint.WalkContext) { +function walk(context: Lint.WalkContext) { function checkDeleteAccessExpression(node: ts.Expression | undefined): void { if (node === undefined || !tsutils.isElementAccessExpression(node)) { return; diff --git a/src/rules/noEmptyInterfaceRule.ts b/src/rules/noEmptyInterfaceRule.ts index a4b06706da2..134cf191511 100644 --- a/src/rules/noEmptyInterfaceRule.ts +++ b/src/rules/noEmptyInterfaceRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( isInterfaceDeclaration(node) && diff --git a/src/rules/noEvalRule.ts b/src/rules/noEvalRule.ts index ddcce6437e3..9543fed1fb9 100644 --- a/src/rules/noEvalRule.ts +++ b/src/rules/noEvalRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( isCallExpression(node) && diff --git a/src/rules/noForInArrayRule.ts b/src/rules/noForInArrayRule.ts index 89a1436e144..67cdfb03907 100644 --- a/src/rules/noForInArrayRule.ts +++ b/src/rules/noForInArrayRule.ts @@ -55,7 +55,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker) { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (node.kind === ts.SyntaxKind.ForInStatement) { const type = checker.getTypeAtLocation((node as ts.ForInStatement).expression); diff --git a/src/rules/noInferredEmptyObjectTypeRule.ts b/src/rules/noInferredEmptyObjectTypeRule.ts index 70d0d60ae4f..d0b21dc98ce 100644 --- a/src/rules/noInferredEmptyObjectTypeRule.ts +++ b/src/rules/noInferredEmptyObjectTypeRule.ts @@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -class NoInferredEmptyObjectTypeRule extends Lint.AbstractWalker { +class NoInferredEmptyObjectTypeRule extends Lint.AbstractWalker { constructor( sourceFile: ts.SourceFile, ruleName: string, diff --git a/src/rules/noInternalModuleRule.ts b/src/rules/noInternalModuleRule.ts index 9671bf64e4b..4f8ad5cd850 100644 --- a/src/rules/noInternalModuleRule.ts +++ b/src/rules/noInternalModuleRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -class NoInternalModuleWalker extends Lint.AbstractWalker { +class NoInternalModuleWalker extends Lint.AbstractWalker { public walk(sourceFile: ts.SourceFile) { return this.checkStatements(sourceFile.statements); } diff --git a/src/rules/noInvalidTemplateStringsRule.ts b/src/rules/noInvalidTemplateStringsRule.ts index d64210d01f5..5e4e2c8c24e 100644 --- a/src/rules/noInvalidTemplateStringsRule.ts +++ b/src/rules/noInvalidTemplateStringsRule.ts @@ -42,7 +42,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (utils.isStringLiteral(node)) { check(node); diff --git a/src/rules/noIrregularWhitespaceRule.ts b/src/rules/noIrregularWhitespaceRule.ts index 9492d380eb0..5564ada3f9a 100644 --- a/src/rules/noIrregularWhitespaceRule.ts +++ b/src/rules/noIrregularWhitespaceRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { export const IRREGULAR_WHITESPACE_REGEX = /[\u000b\u000c\u0085\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]+/gm; /* tslint:enable:max-line-length */ -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { IRREGULAR_WHITESPACE_REGEX.lastIndex = 0; let match: RegExpExecArray | null; // tslint:disable-next-line no-conditional-assignment diff --git a/src/rules/noMergeableNamespaceRule.ts b/src/rules/noMergeableNamespaceRule.ts index f29cac32aac..782531cf7b1 100644 --- a/src/rules/noMergeableNamespaceRule.ts +++ b/src/rules/noMergeableNamespaceRule.ts @@ -41,7 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -class Walker extends Lint.AbstractWalker { +class Walker extends Lint.AbstractWalker { public walk(node: ts.SourceFile) { return this.checkStatements(node.statements); } diff --git a/src/rules/noMisusedNewRule.ts b/src/rules/noMisusedNewRule.ts index 90b6ae062c9..089ddf9c2b1 100644 --- a/src/rules/noMisusedNewRule.ts +++ b/src/rules/noMisusedNewRule.ts @@ -55,7 +55,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isMethodSignature(node)) { if (getPropertyName(node.name) === "constructor") { diff --git a/src/rules/noNonNullAssertionRule.ts b/src/rules/noNonNullAssertionRule.ts index e55f838332f..d3c86865956 100644 --- a/src/rules/noNonNullAssertionRule.ts +++ b/src/rules/noNonNullAssertionRule.ts @@ -68,7 +68,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (node.kind === ts.SyntaxKind.NonNullExpression) { ctx.addFailureAtNode(node, Rule.FAILURE_STRING); diff --git a/src/rules/noNullKeywordRule.ts b/src/rules/noNullKeywordRule.ts index 9aa1c2ab306..57777607213 100644 --- a/src/rules/noNullKeywordRule.ts +++ b/src/rules/noNullKeywordRule.ts @@ -65,7 +65,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, cb); function cb(node: ts.Node): void { if (isTypeNodeKind(node.kind)) { diff --git a/src/rules/noParameterPropertiesRule.ts b/src/rules/noParameterPropertiesRule.ts index 5b1f0e990c5..e9e0cfb4e25 100644 --- a/src/rules/noParameterPropertiesRule.ts +++ b/src/rules/noParameterPropertiesRule.ts @@ -49,7 +49,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (node.kind === ts.SyntaxKind.Constructor) { for (const parameter of (node as ts.ConstructorDeclaration).parameters) { diff --git a/src/rules/noParameterReassignmentRule.ts b/src/rules/noParameterReassignmentRule.ts index b0a47a781cd..2688a92da7e 100644 --- a/src/rules/noParameterReassignmentRule.ts +++ b/src/rules/noParameterReassignmentRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { collectVariableUsage(ctx.sourceFile).forEach((variable, identifier) => { if (!isParameter(identifier.parent)) { return; diff --git a/src/rules/noRedundantJsdocRule.ts b/src/rules/noRedundantJsdocRule.ts index 2989c969855..b249d8abac6 100644 --- a/src/rules/noRedundantJsdocRule.ts +++ b/src/rules/noRedundantJsdocRule.ts @@ -47,7 +47,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; // Intentionally exclude EndOfFileToken: it can have JSDoc, but it is only relevant in JavaScript files return sourceFile.statements.forEach(function cb(node: ts.Node): void { diff --git a/src/rules/noReferenceImportRule.ts b/src/rules/noReferenceImportRule.ts index 656e3bf326d..9aa187a79a0 100644 --- a/src/rules/noReferenceImportRule.ts +++ b/src/rules/noReferenceImportRule.ts @@ -41,7 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { if (ctx.sourceFile.typeReferenceDirectives.length === 0) { return; } diff --git a/src/rules/noReferenceRule.ts b/src/rules/noReferenceRule.ts index 31d18f41d19..4f511266528 100644 --- a/src/rules/noReferenceRule.ts +++ b/src/rules/noReferenceRule.ts @@ -42,7 +42,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { for (const ref of ctx.sourceFile.referencedFiles) { ctx.addFailure(ref.pos, ref.end, Rule.FAILURE_STRING); } diff --git a/src/rules/noRequireImportsRule.ts b/src/rules/noRequireImportsRule.ts index fccd1d09f64..e359b47f4b9 100644 --- a/src/rules/noRequireImportsRule.ts +++ b/src/rules/noRequireImportsRule.ts @@ -41,7 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { for (const name of findImports(ctx.sourceFile, ImportKind.AllRequireLike)) { ctx.addFailureAtNode(name.parent, Rule.FAILURE_STRING); } diff --git a/src/rules/noReturnAwaitRule.ts b/src/rules/noReturnAwaitRule.ts index 5ff5c398ae1..7a9ce2a06f9 100644 --- a/src/rules/noReturnAwaitRule.ts +++ b/src/rules/noReturnAwaitRule.ts @@ -46,7 +46,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (node.kind === ts.SyntaxKind.AwaitExpression && isUnnecessaryAwait(node)) { const { expression } = node as ts.AwaitExpression; diff --git a/src/rules/noSparseArraysRule.ts b/src/rules/noSparseArraysRule.ts index 5654ddeb75e..d595f0f6756 100644 --- a/src/rules/noSparseArraysRule.ts +++ b/src/rules/noSparseArraysRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (!utils.isArrayLiteralExpression(node)) { if ( diff --git a/src/rules/noStringLiteralRule.ts b/src/rules/noStringLiteralRule.ts index bef6f08a2b6..1180e92e005 100644 --- a/src/rules/noStringLiteralRule.ts +++ b/src/rules/noStringLiteralRule.ts @@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isElementAccessExpression(node)) { const argument = node.argumentExpression; diff --git a/src/rules/noStringThrowRule.ts b/src/rules/noStringThrowRule.ts index a970d890a74..6b0f0f98273 100644 --- a/src/rules/noStringThrowRule.ts +++ b/src/rules/noStringThrowRule.ts @@ -67,7 +67,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isThrowStatement(node)) { diff --git a/src/rules/noSwitchCaseFallThroughRule.ts b/src/rules/noSwitchCaseFallThroughRule.ts index e2944784aba..4d2342aac06 100644 --- a/src/rules/noSwitchCaseFallThroughRule.ts +++ b/src/rules/noSwitchCaseFallThroughRule.ts @@ -70,7 +70,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -export class NoSwitchCaseFallThroughWalker extends Lint.AbstractWalker { +export class NoSwitchCaseFallThroughWalker extends Lint.AbstractWalker { public walk(sourceFile: ts.SourceFile) { const cb = (node: ts.Node): void => { if (utils.isSwitchStatement(node)) { diff --git a/src/rules/noTautologyExpressionRule.ts b/src/rules/noTautologyExpressionRule.ts index 8ec352836ae..60b5c556dba 100644 --- a/src/rules/noTautologyExpressionRule.ts +++ b/src/rules/noTautologyExpressionRule.ts @@ -42,7 +42,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(context: Lint.WalkContext) { +function walk(context: Lint.WalkContext) { const cb = (node: ts.Node): void => { if (tsutils.isBinaryExpression(node) && isRelationalOrLogicalOperator(node.operatorToken)) { if ( diff --git a/src/rules/noUnnecessaryCallbackWrapperRule.ts b/src/rules/noUnnecessaryCallbackWrapperRule.ts index ce4cb41e5f6..8bd1b7fa685 100644 --- a/src/rules/noUnnecessaryCallbackWrapperRule.ts +++ b/src/rules/noUnnecessaryCallbackWrapperRule.ts @@ -57,7 +57,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, cb); function cb(node: ts.Node): void { if ( diff --git a/src/rules/noUnnecessaryInitializerRule.ts b/src/rules/noUnnecessaryInitializerRule.ts index e3f9ca9dd50..f16dca0efb3 100644 --- a/src/rules/noUnnecessaryInitializerRule.ts +++ b/src/rules/noUnnecessaryInitializerRule.ts @@ -49,7 +49,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { switch (node.kind) { case ts.SyntaxKind.BindingElement: diff --git a/src/rules/noUnnecessaryQualifierRule.ts b/src/rules/noUnnecessaryQualifierRule.ts index e4bd28d3c23..623255dc0ee 100644 --- a/src/rules/noUnnecessaryQualifierRule.ts +++ b/src/rules/noUnnecessaryQualifierRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { const namespacesInScope: Array = []; ts.forEachChild(ctx.sourceFile, cb); diff --git a/src/rules/noUnsafeAnyRule.ts b/src/rules/noUnsafeAnyRule.ts index 37f18a2ccb8..9831168a883 100644 --- a/src/rules/noUnsafeAnyRule.ts +++ b/src/rules/noUnsafeAnyRule.ts @@ -65,7 +65,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -class NoUnsafeAnyWalker extends Lint.AbstractWalker { +class NoUnsafeAnyWalker extends Lint.AbstractWalker { constructor( sourceFile: ts.SourceFile, ruleName: string, diff --git a/src/rules/noUnsafeFinallyRule.ts b/src/rules/noUnsafeFinallyRule.ts index cd90093db59..487099cb2eb 100644 --- a/src/rules/noUnsafeFinallyRule.ts +++ b/src/rules/noUnsafeFinallyRule.ts @@ -57,7 +57,7 @@ type JumpStatement = | ts.ThrowStatement | ts.ReturnStatement; -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { let inFinally = false; ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { switch (node.kind) { diff --git a/src/rules/noUseBeforeDeclareRule.ts b/src/rules/noUseBeforeDeclareRule.ts index 9dac76cb4e4..ae3bf5deddd 100644 --- a/src/rules/noUseBeforeDeclareRule.ts +++ b/src/rules/noUseBeforeDeclareRule.ts @@ -54,7 +54,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { return ts.forEachChild(ctx.sourceFile, function recur(node: ts.Node): void { switch (node.kind) { case ts.SyntaxKind.TypeReference: diff --git a/src/rules/noVarKeywordRule.ts b/src/rules/noVarKeywordRule.ts index 958b1c43b76..d0da8fae1c9 100644 --- a/src/rules/noVarKeywordRule.ts +++ b/src/rules/noVarKeywordRule.ts @@ -56,7 +56,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; return ts.forEachChild(sourceFile, function cb(node: ts.Node): void { const parent = node.parent; diff --git a/src/rules/numberLiteralFormatRule.ts b/src/rules/numberLiteralFormatRule.ts index a672e24d9a5..26fbd17f8b1 100644 --- a/src/rules/numberLiteralFormatRule.ts +++ b/src/rules/numberLiteralFormatRule.ts @@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; return ts.forEachChild(sourceFile, function cb(node: ts.Node): void { if (isNumericLiteral(node)) { diff --git a/src/rules/objectLiteralShorthandRule.ts b/src/rules/objectLiteralShorthandRule.ts index de9a2d070bd..7e3db815242 100644 --- a/src/rules/objectLiteralShorthandRule.ts +++ b/src/rules/objectLiteralShorthandRule.ts @@ -62,7 +62,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function disallowShorthandWalker(ctx: Lint.WalkContext) { +function disallowShorthandWalker(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (isShorthandPropertyAssignment(node)) { ctx.addFailureAtNode( @@ -84,7 +84,7 @@ function disallowShorthandWalker(ctx: Lint.WalkContext) { }); } -function enforceShorthandWalker(ctx: Lint.WalkContext) { +function enforceShorthandWalker(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node): void { if (isPropertyAssignment(node)) { if ( diff --git a/src/rules/orderedImportsRule.ts b/src/rules/orderedImportsRule.ts index 8316b542c36..3a2a7655391 100644 --- a/src/rules/orderedImportsRule.ts +++ b/src/rules/orderedImportsRule.ts @@ -538,7 +538,9 @@ class Walker extends Lint.AbstractWalker { if (index > 0) { const prevItems = groupedDeclarations[index - 1]; const last = prevItems[prevItems.length - 1]; - if (/[\r\n]+/.test(this.sourceFile.text.slice(last.nodeEndOffset, start))) { + + const textFragment = this.sourceFile.text.slice(last.nodeEndOffset, start); + if (!/\S/.test(textFragment)) { // remove whitespace between blocks start = last.nodeEndOffset; } diff --git a/src/rules/preferForOfRule.ts b/src/rules/preferForOfRule.ts index b75b1fdeb93..4802c6400bc 100644 --- a/src/rules/preferForOfRule.ts +++ b/src/rules/preferForOfRule.ts @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; let variables: Map | undefined; diff --git a/src/rules/preferMethodSignatureRule.ts b/src/rules/preferMethodSignatureRule.ts index 7cc10220bb3..dd38a7123cd 100644 --- a/src/rules/preferMethodSignatureRule.ts +++ b/src/rules/preferMethodSignatureRule.ts @@ -61,7 +61,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isPropertySignature(node)) { const { type } = node; diff --git a/src/rules/preferObjectSpreadRule.ts b/src/rules/preferObjectSpreadRule.ts index 6822272a8e1..c3fb52c380c 100644 --- a/src/rules/preferObjectSpreadRule.ts +++ b/src/rules/preferObjectSpreadRule.ts @@ -53,7 +53,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( isCallExpression(node) && diff --git a/src/rules/radixRule.ts b/src/rules/radixRule.ts index b5871d81c4a..5f3749a11bf 100644 --- a/src/rules/radixRule.ts +++ b/src/rules/radixRule.ts @@ -82,7 +82,7 @@ function isPropertyAccessOfProperty( ); } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( isCallExpression(node) && diff --git a/src/rules/restrictPlusOperandsRule.ts b/src/rules/restrictPlusOperandsRule.ts index b4b8d7e4827..207ec49a56f 100644 --- a/src/rules/restrictPlusOperandsRule.ts +++ b/src/rules/restrictPlusOperandsRule.ts @@ -44,7 +44,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { +function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) { const leftType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.left)); diff --git a/src/rules/returnUndefinedRule.ts b/src/rules/returnUndefinedRule.ts index 315cc50f00e..5e8ff40c6fa 100644 --- a/src/rules/returnUndefinedRule.ts +++ b/src/rules/returnUndefinedRule.ts @@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker) { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isReturnStatement(node)) { check(node); diff --git a/src/rules/staticThisRule.ts b/src/rules/staticThisRule.ts index dc20101de98..5a320d9cdc5 100644 --- a/src/rules/staticThisRule.ts +++ b/src/rules/staticThisRule.ts @@ -52,7 +52,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { let currentParentClass: ts.ClassLikeDeclaration | undefined; const cb = (node: ts.Node): void => { diff --git a/src/rules/strictTypePredicatesRule.ts b/src/rules/strictTypePredicatesRule.ts index 78db5c10eb9..988d5a16fde 100644 --- a/src/rules/strictTypePredicatesRule.ts +++ b/src/rules/strictTypePredicatesRule.ts @@ -72,7 +72,7 @@ export class Rule extends Lint.Rules.TypedRule { } } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isBinaryExpression(node)) { const equals = Lint.getEqualsKind(node.operatorToken); diff --git a/src/rules/switchDefaultRule.ts b/src/rules/switchDefaultRule.ts index ac99f66445f..879826356d7 100644 --- a/src/rules/switchDefaultRule.ts +++ b/src/rules/switchDefaultRule.ts @@ -43,7 +43,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if ( node.kind === ts.SyntaxKind.SwitchStatement && diff --git a/src/rules/typeofCompareRule.ts b/src/rules/typeofCompareRule.ts index 2a1afbc1889..d9f779d3bab 100644 --- a/src/rules/typeofCompareRule.ts +++ b/src/rules/typeofCompareRule.ts @@ -57,7 +57,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (tsutils.isBinaryExpression(node)) { const { operatorToken, left, right } = node; diff --git a/src/rules/unifiedSignaturesRule.ts b/src/rules/unifiedSignaturesRule.ts index ab35dd6d77c..47beef82cf2 100644 --- a/src/rules/unifiedSignaturesRule.ts +++ b/src/rules/unifiedSignaturesRule.ts @@ -64,7 +64,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; checkStatements(sourceFile.statements); return ts.forEachChild(sourceFile, function cb(node: ts.Node): void { diff --git a/src/rules/unnecessaryBindRule.ts b/src/rules/unnecessaryBindRule.ts index c96522375fd..4ead10cec8b 100644 --- a/src/rules/unnecessaryBindRule.ts +++ b/src/rules/unnecessaryBindRule.ts @@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.OptionallyTypedRule { } } -function walk(context: Lint.WalkContext, typeChecker?: ts.TypeChecker) { +function walk(context: Lint.WalkContext, typeChecker?: ts.TypeChecker) { const variableUsage = tsutils.collectVariableUsage(context.sourceFile); function checkArrowFunction(node: ts.CallExpression): void { diff --git a/src/rules/unnecessaryConstructorRule.ts b/src/rules/unnecessaryConstructorRule.ts index 34c63f9945f..f060c617da8 100644 --- a/src/rules/unnecessaryConstructorRule.ts +++ b/src/rules/unnecessaryConstructorRule.ts @@ -55,7 +55,7 @@ const containsConstructorParameter = (node: ts.ConstructorDeclaration): boolean return false; }; -function walk(context: Lint.WalkContext) { +function walk(context: Lint.WalkContext) { const callback = (node: ts.Node): void => { if ( isConstructorDeclaration(node) && diff --git a/src/rules/unnecessaryElseRule.ts b/src/rules/unnecessaryElseRule.ts index 87315592925..564cb29f1be 100644 --- a/src/rules/unnecessaryElseRule.ts +++ b/src/rules/unnecessaryElseRule.ts @@ -55,7 +55,7 @@ interface IJumpAndIfStatement { node: ts.IfStatement; } -function walk(ctx: Lint.WalkContext): void { +function walk(ctx: Lint.WalkContext): void { const ifStatementStack: IJumpAndIfStatement[] = []; function visitIfStatement(node: ts.IfStatement) { diff --git a/src/rules/useDefaultTypeParameterRule.ts b/src/rules/useDefaultTypeParameterRule.ts index 4879a65583e..82da66b9144 100644 --- a/src/rules/useDefaultTypeParameterRule.ts +++ b/src/rules/useDefaultTypeParameterRule.ts @@ -54,7 +54,7 @@ interface ArgsAndParams { typeParameters: ReadonlyArray; } -function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { +function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { const argsAndParams = getArgsAndParameters(node, checker); if (argsAndParams !== undefined) { diff --git a/src/rules/useIsnanRule.ts b/src/rules/useIsnanRule.ts index 6d44a0cde89..3a79b088326 100644 --- a/src/rules/useIsnanRule.ts +++ b/src/rules/useIsnanRule.ts @@ -47,7 +47,7 @@ export class Rule extends Lint.Rules.AbstractRule { } } -function walk(ctx: Lint.WalkContext) { +function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { if (isBinaryExpression(node)) { switch (node.operatorToken.kind) { diff --git a/test/rules/file-header/bad/test2.ts.fix b/test/rules/file-header/bad/test2.ts.fix new file mode 100644 index 00000000000..29f5b546f57 --- /dev/null +++ b/test/rules/file-header/bad/test2.ts.fix @@ -0,0 +1,7 @@ +/*! + * Good header 2 + */ + +// ********************************** +// Bad header +// ********************************** diff --git a/test/rules/file-header/bad/test2.ts.lint b/test/rules/file-header/bad/test2.ts.lint new file mode 100644 index 00000000000..ef259de4caf --- /dev/null +++ b/test/rules/file-header/bad/test2.ts.lint @@ -0,0 +1,4 @@ +// ********************************** +~nil [missing file header] +// Bad header +// ********************************** diff --git a/test/rules/file-header/good-allow-single-line-comments/test.ts.lint b/test/rules/file-header/good-allow-single-line-comments/test.ts.lint new file mode 100644 index 00000000000..8aa13d57e2e --- /dev/null +++ b/test/rules/file-header/good-allow-single-line-comments/test.ts.lint @@ -0,0 +1,4 @@ +// ********************************** +// Good header +// ********************************** + diff --git a/test/rules/file-header/good-allow-single-line-comments/tslint.json b/test/rules/file-header/good-allow-single-line-comments/tslint.json new file mode 100644 index 00000000000..5f1256bb402 --- /dev/null +++ b/test/rules/file-header/good-allow-single-line-comments/tslint.json @@ -0,0 +1,8 @@ +{ + "rules": { + "file-header": [true, { + "match": "Good header", + "allow-single-line-comments": true + }] + } + } diff --git a/test/rules/no-any/test.ts.lint b/test/rules/no-any/default/test.ts.lint similarity index 59% rename from test/rules/no-any/test.ts.lint rename to test/rules/no-any/default/test.ts.lint index 5a1de903ef7..66200e514a1 100644 --- a/test/rules/no-any/test.ts.lint +++ b/test/rules/no-any/default/test.ts.lint @@ -7,9 +7,25 @@ function foo(a: any) : any { // 2 errors return; } +const fooArrow(a: any[]) => { + ~~~ [0] + return; +} + +function bar(...a: any[]) { + ~~~ [0] + return; +} + +const barArrow = (...a: any[]): any => { + ~~~ [0] + ~~~ [0] + return; +} + let a: any = 2, // error ~~~ [0] - b: any = 4; // error + b: any[] = 4; // error ~~~ [0] let {a: c, b: d}: {c: any, d: number} = {c: 99, d: 100}; // error diff --git a/test/rules/no-any/tslint.json b/test/rules/no-any/default/tslint.json similarity index 100% rename from test/rules/no-any/tslint.json rename to test/rules/no-any/default/tslint.json diff --git a/test/rules/no-any/ignore-rest-args/test.ts.lint b/test/rules/no-any/ignore-rest-args/test.ts.lint new file mode 100644 index 00000000000..9cf2ae897f1 --- /dev/null +++ b/test/rules/no-any/ignore-rest-args/test.ts.lint @@ -0,0 +1,38 @@ +var x: any; // error + ~~~ [0] + +function foo(a: any) : any { // 2 errors + ~~~ [0] + ~~~ [0] + return; +} + +const fooArrow(a: any[]) => { + ~~~ [0] + return; +} + +function bar(...a: any[]) { + return; +} + +const barArrow = (...a: any[]): any => { + ~~~ [0] + return; +} + +const function(...a: { [key: any]: any }[]) { + ~~~ [0] + ~~~ [0] + return; +} + +let a: any = 2, // error + ~~~ [0] + b: any[] = 4; // error + ~~~ [0] + +let {a: c, b: d}: {c: any, d: number} = {c: 99, d: 100}; // error + ~~~ [0] + +[0]: Type declaration of 'any' loses type-safety. Consider replacing it with a more precise type. diff --git a/test/rules/no-any/ignore-rest-args/tslint.json b/test/rules/no-any/ignore-rest-args/tslint.json new file mode 100644 index 00000000000..8ec5fb037c2 --- /dev/null +++ b/test/rules/no-any/ignore-rest-args/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-any": [true, { "ignore-rest-args": true }] + } +} diff --git a/test/rules/ordered-imports/groups-complex/test.ts.fix b/test/rules/ordered-imports/groups-complex/test.ts.fix index c7b2def97cd..f9ee5865e32 100644 --- a/test/rules/ordered-imports/groups-complex/test.ts.fix +++ b/test/rules/ordered-imports/groups-complex/test.ts.fix @@ -17,6 +17,8 @@ import './baz'; // required import {bar} from '../bar'; import {xbar} from '../xbar'; +x.fnCall(); + export class Test {} diff --git a/test/rules/ordered-imports/groups-complex/test.ts.lint b/test/rules/ordered-imports/groups-complex/test.ts.lint index c14f4304134..36772342a19 100644 --- a/test/rules/ordered-imports/groups-complex/test.ts.lint +++ b/test/rules/ordered-imports/groups-complex/test.ts.lint @@ -20,6 +20,7 @@ import {foo, afoo} from 'foo'; ~~~~~~~~~ [Named imports must be alphabetized.] import x = require('y'); +x.fnCall(); import './baz'; // required import './baa'; diff --git a/yarn.lock b/yarn.lock index d59216638d3..499562ef62e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -124,9 +124,9 @@ archy@^1.0.0: integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - integrity sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY= + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" @@ -540,10 +540,10 @@ eslint-plugin-prettier@^2.2.0: fast-diff "^1.1.1" jest-docblock "^21.0.0" -esprima@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esutils@^2.0.2: version "2.0.2" @@ -1035,13 +1035,13 @@ js-tokens@^3.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" integrity sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc= -js-yaml@^3.7.0: - version "3.8.4" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" - integrity sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY= +js-yaml@^3.13.0, js-yaml@^3.7.0: + version "3.13.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" + integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ== dependencies: argparse "^1.0.7" - esprima "^3.1.1" + esprima "^4.0.0" jsesc@^1.3.0: version "1.3.0"