diff --git a/lib/rules/no-multiple-empty-lines.js b/lib/rules/no-multiple-empty-lines.js index daab826f4c3d..5d1fe271eccf 100644 --- a/lib/rules/no-multiple-empty-lines.js +++ b/lib/rules/no-multiple-empty-lines.js @@ -17,6 +17,8 @@ module.exports = { recommended: false }, + fixable: "whitespace", + schema: [ { type: "object", @@ -82,15 +84,23 @@ module.exports = { location, firstOfEndingBlankLines, firstNonBlankLine = -1, - trimmedLines = []; - + trimmedLines = [], + linesRangeStart = [], + diff, + fix, + rangeStart, + rangeEnd; + + linesRangeStart.push(0); lines.forEach(function(str, i) { + var length = str.length + 1; // + 1 for the newline at the end of each line var trimmed = str.trim(); if ((firstNonBlankLine === -1) && (trimmed !== "")) { firstNonBlankLine = i; } + linesRangeStart.push(linesRangeStart[linesRangeStart.length - 1] + length); trimmedLines.push(trimmed); }); @@ -122,11 +132,26 @@ module.exports = { // Aggregate and count blank lines if (firstNonBlankLine > maxBOF) { - context.report(node, 0, - "Too many blank lines at the beginning of file. Max of " + maxBOF + " allowed."); + diff = firstNonBlankLine - maxBOF; + rangeStart = linesRangeStart[firstNonBlankLine - diff]; + rangeEnd = linesRangeStart[firstNonBlankLine]; + fix = function(fixer) { + + return fixer.removeRange([rangeStart, rangeEnd]); + }; + context.report({ + node: node, + loc: node.loc.start, + message: "Too many blank lines at the beginning of file. Max of " + maxBOF + " allowed.", + fix: fix + }); } currentLocation = firstNonBlankLine - 1; + fix = function(fixer) { + return fixer.removeRange([rangeStart, rangeEnd]); + }; + lastLocation = currentLocation; currentLocation = trimmedLines.indexOf("", currentLocation + 1); while (currentLocation !== -1) { @@ -144,20 +169,29 @@ module.exports = { // within the file, not at the end if (blankCounter >= max) { + diff = blankCounter - max + 1; + rangeStart = linesRangeStart[location.line - diff]; + rangeEnd = linesRangeStart[location.line]; + context.report({ node: node, loc: location, - message: "More than " + max + " blank " + (max === 1 ? "line" : "lines") + " not allowed." + message: "More than " + max + " blank " + (max === 1 ? "line" : "lines") + " not allowed.", + fix: fix }); } } else { // inside the last blank lines if (blankCounter > maxEOF) { + diff = blankCounter - maxEOF + 1; + rangeStart = linesRangeStart[location.line - diff]; + rangeEnd = linesRangeStart[location.line - 1]; context.report({ node: node, loc: location, - message: "Too many blank lines at the end of file. Max of " + maxEOF + " allowed." + message: "Too many blank lines at the end of file. Max of " + maxEOF + " allowed.", + fix: fix }); } } diff --git a/tests/lib/rules/no-multiple-empty-lines.js b/tests/lib/rules/no-multiple-empty-lines.js index 428dc98aac62..3b23f3a087fc 100644 --- a/tests/lib/rules/no-multiple-empty-lines.js +++ b/tests/lib/rules/no-multiple-empty-lines.js @@ -151,96 +151,115 @@ ruleTester.run("no-multiple-empty-lines", rule, { invalid: [ { code: "// invalid 1\nvar a = 5;\n\n\nvar b = 3;", + output: "// invalid 1\nvar a = 5;\n\nvar b = 3;", errors: [ getExpectedError(1) ], options: [ { max: 1 } ] }, { code: "// invalid 2\n\n\n\n\nvar a = 5;", + output: "// invalid 2\n\n\nvar a = 5;", errors: [ getExpectedError(2) ], options: [ { max: 2 } ] }, { code: "// invalid 3\nvar a = 5;\n\n\n\n", + output: "// invalid 3\nvar a = 5;\n\n\n", errors: [ getExpectedErrorEOF(2) ], options: [ { max: 2 } ] }, { code: "// invalid 4\nvar a = 5;\n \n \n \n", + output: "// invalid 4\nvar a = 5;\n \n \n", errors: [ getExpectedErrorEOF(2) ], options: [ { max: 2 } ] }, { code: "// invalid 5\nvar a=5;\n\n\n\nvar b = 3;", + output: "// invalid 5\nvar a=5;\n\n\nvar b = 3;", errors: [ getExpectedError(2) ], options: [ { max: 2 } ] }, { code: "// invalid 6\nvar a=5;\n\n\n\nvar b = 3;\n", + output: "// invalid 6\nvar a=5;\n\n\nvar b = 3;\n", errors: [ getExpectedError(2) ], options: [ { max: 2 } ] }, { code: "// invalid 7\nvar a = 5;\n\n\n\nb = 3;\nvar c = 5;\n\n\n\nvar d = 3;", + output: "// invalid 7\nvar a = 5;\n\n\nb = 3;\nvar c = 5;\n\n\nvar d = 3;", errors: 2, options: [ { max: 2 } ] }, { code: "// invalid 8\nvar a = 5;\n\n\n\n\n\n\n\n\n\n\n\n\n\nb = 3;", + output: "// invalid 8\nvar a = 5;\n\n\nb = 3;", errors: [ getExpectedError(2) ], options: [ { max: 2 } ] }, { code: "// invalid 9\nvar a=5;\n\n\n\n\n", + output: "// invalid 9\nvar a=5;\n\n\n", errors: [ getExpectedErrorEOF(2) ], options: [ { max: 2 } ] }, { code: "// invalid 10\nvar a = 5;\n\nvar b = 3;", + output: "// invalid 10\nvar a = 5;\nvar b = 3;", errors: [ getExpectedError(0) ], options: [ { max: 0 } ] }, { code: "// invalid 11\nvar a = 5;\n\n\n", + output: "// invalid 11\nvar a = 5;\n\n", errors: [ getExpectedErrorEOF(1) ], options: [ { max: 5, maxEOF: 1 } ] }, { code: "// invalid 12\nvar a = 5;\n\n\n\n\n\n", + output: "// invalid 12\nvar a = 5;\n\n\n\n\n", errors: [ getExpectedErrorEOF(4) ], options: [ { max: 0, maxEOF: 4 } ] }, { code: "// invalid 13\n\n\n\n\n\n\n\n\nvar a = 5;\n\n\n", + output: "// invalid 13\n\n\n\n\n\n\n\n\nvar a = 5;\n\n", errors: [ getExpectedErrorEOF(1) ], options: [ { max: 10, maxEOF: 1 } ] }, { code: "// invalid 14\nvar a = 5;\n\n", + output: "// invalid 14\nvar a = 5;\n", errors: [ getExpectedErrorEOF(0) ], options: [ { max: 2, maxEOF: 0 } ] }, { code: "\n\n// invalid 15\nvar a = 5;\n", + output: "\n// invalid 15\nvar a = 5;\n", errors: [ getExpectedErrorBOF(1) ], options: [ { max: 5, maxBOF: 1 } ] }, { code: "\n\n\n\n\n// invalid 16\nvar a = 5;\n", + output: "\n\n\n\n// invalid 16\nvar a = 5;\n", errors: [ getExpectedErrorBOF(4)], options: [ { max: 0, maxBOF: 4 } ] }, { code: "\n\n// invalid 17\n\n\n\n\n\n\n\n\nvar a = 5;\n", + output: "\n// invalid 17\n\n\n\n\n\n\n\n\nvar a = 5;\n", errors: [ getExpectedErrorBOF(1) ], options: [ { max: 10, maxBOF: 1 } ] }, { code: "\n// invalid 18\nvar a = 5;\n", + output: "// invalid 18\nvar a = 5;\n", errors: [ getExpectedErrorBOF(0) ], options: [ { max: 2, maxBOF: 0 } ] }, { code: "\n\n\n// invalid 19\nvar a = 5;\n\n", + output: "// invalid 19\nvar a = 5;\n", errors: [ getExpectedErrorBOF(0), getExpectedErrorEOF(0) ], options: [ { max: 2, maxBOF: 0, maxEOF: 0 } ]