diff --git a/src/rules/noTrailingWhitespaceRule.ts b/src/rules/noTrailingWhitespaceRule.ts index ca5a52985c7..6cc85e2eacd 100644 --- a/src/rules/noTrailingWhitespaceRule.ts +++ b/src/rules/noTrailingWhitespaceRule.ts @@ -26,6 +26,7 @@ export class Rule extends Lint.Rules.AbstractRule { description: "Disallows trailing whitespace at the end of a line.", rationale: "Keeps version control diffs clean as it prevents accidental whitespace from being committed.", optionsDescription: "Not configurable.", + hasFix: true, options: null, optionExamples: ["true"], type: "maintainability", @@ -44,18 +45,52 @@ class NoTrailingWhitespaceWalker extends Lint.RuleWalker { public visitSourceFile(node: ts.SourceFile) { let lastSeenWasWhitespace = false; let lastSeenWhitespacePosition = 0; - Lint.forEachToken(node, false, (_text, kind, pos) => { - if (kind === ts.SyntaxKind.NewLineTrivia) { + Lint.forEachToken(node, false, (fullText, kind, pos) => { + if (kind === ts.SyntaxKind.NewLineTrivia || kind === ts.SyntaxKind.EndOfFileToken) { if (lastSeenWasWhitespace) { - this.addFailureFromStartToEnd(lastSeenWhitespacePosition, pos.tokenStart, Rule.FAILURE_STRING); + this.reportFailure(lastSeenWhitespacePosition, pos.tokenStart); } lastSeenWasWhitespace = false; } else if (kind === ts.SyntaxKind.WhitespaceTrivia) { lastSeenWasWhitespace = true; lastSeenWhitespacePosition = pos.tokenStart; } else { + if (kind === ts.SyntaxKind.SingleLineCommentTrivia) { + const commentText = fullText.substring(pos.tokenStart + 2, pos.end); + const match = /\s+$/.exec(commentText); + if (match !== null) { + this.reportFailure(pos.end - match[0].length, pos.end); + } + } else if (kind === ts.SyntaxKind.MultiLineCommentTrivia) { + let startPos = pos.tokenStart + 2; + const commentText = fullText.substring(startPos, pos.end - 2); + const lines = commentText.split("\n"); + // we don't want to check the content of the last comment line, as it is always followed by */ + const len = lines.length - 1; + for (let i = 0; i < len; ++i) { + let line = lines[i]; + // remove carriage return at the end, it is does not account to trailing whitespace + if (line.endsWith("\r")) { + line = line.substr(0, line.length - 1); + } + const start = line.search(/\s+$/); + if (start !== -1) { + this.reportFailure(startPos + start, startPos + line.length); + } + startPos += lines[i].length + 1; + } + } lastSeenWasWhitespace = false; } }); } + + private reportFailure(start: number, end: number) { + this.addFailureFromStartToEnd( + start, + end, + Rule.FAILURE_STRING, + this.createFix(this.deleteText(start, end - start)), + ); + } } diff --git a/test/rules/no-trailing-whitespace/test.js.fix b/test/rules/no-trailing-whitespace/test.js.fix new file mode 100644 index 00000000000..c2b659fb154 --- /dev/null +++ b/test/rules/no-trailing-whitespace/test.js.fix @@ -0,0 +1,10 @@ +class Clazz { + public funcxion() { + console.log("test") ; + } + + + private foobar() { + } +} + diff --git a/test/rules/no-trailing-whitespace/test.ts.fix b/test/rules/no-trailing-whitespace/test.ts.fix new file mode 100644 index 00000000000..9ca5d289dde --- /dev/null +++ b/test/rules/no-trailing-whitespace/test.ts.fix @@ -0,0 +1,20 @@ +class Clazz { + public funcxion() { + console.log("test") ; + } + + + private foobar() { + } +} +// single line comment without trailing whitespace +// single line comment with trailing whitespace + /* single line multiline comment */ +/* whitespace after comment */ +/* first line has trailing whitespace + second line is ok + last line is not checked */ +/* + */ + +// following line checks for trailing whitespace before EOF diff --git a/test/rules/no-trailing-whitespace/test.ts.lint b/test/rules/no-trailing-whitespace/test.ts.lint index 6ef8b5e18b4..7067008dc5d 100644 --- a/test/rules/no-trailing-whitespace/test.ts.lint +++ b/test/rules/no-trailing-whitespace/test.ts.lint @@ -1,16 +1,30 @@ class Clazz { public funcxion() { - ~~~~ [0] + ~~~~ [trailing whitespace] console.log("test") ; - ~~~~ [0] + ~~~~ [trailing whitespace] } -~~~~ [0] +~~~~ [trailing whitespace] -~~~~ [0] +~~~~ [trailing whitespace] private foobar() { } } - ~~~~ [0] + ~~~~ [trailing whitespace] +// single line comment without trailing whitespace +// single line comment with trailing whitespace + ~~~ [trailing whitespace] + /* single line multiline comment */ +/* whitespace after comment */ + ~ [trailing whitespace] +/* first line has trailing whitespace + ~~ [trailing whitespace] + second line is ok + last line is not checked */ +/* + */ -[0]: trailing whitespace +// following line checks for trailing whitespace before EOF + +~~~ [trailing whitespace] \ No newline at end of file