/** * @fileoverview Disallows multiple blank lines. * implementation adapted from the no-trailing-spaces rule. * @author Greg Cochard * @copyright 2014 Greg Cochard. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { // Use options.max or 2 as default var max = 2, maxEOF; // store lines that appear empty but really aren't var notEmpty = []; if (context.options.length) { max = context.options[0].max; maxEOF = context.options[0].maxEOF; } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { "TemplateLiteral": function(node) { var start = node.loc.start.line; var end = node.loc.end.line; while (start <= end) { notEmpty.push(start); start++; } }, "Program:exit": function checkBlankLines(node) { var lines = context.getSourceLines(), currentLocation = -1, lastLocation, blankCounter = 0, location, trimmedLines = lines.map(function(str) { return str.trim(); }), firstOfEndingBlankLines; // add the notEmpty lines in there with a placeholder notEmpty.forEach(function(x, i) { trimmedLines[i] = x; }); if (typeof maxEOF === "undefined") { // swallow the final newline, as some editors add it // automatically and we don't want it to cause an issue if (trimmedLines[trimmedLines.length - 1] === "") { trimmedLines = trimmedLines.slice(0, -1); } firstOfEndingBlankLines = trimmedLines.length; } else { // save the number of the first of the last blank lines firstOfEndingBlankLines = trimmedLines.length; while (trimmedLines[firstOfEndingBlankLines - 1] === "" && firstOfEndingBlankLines > 0) { firstOfEndingBlankLines--; } } // Aggregate and count blank lines lastLocation = currentLocation; currentLocation = trimmedLines.indexOf("", currentLocation + 1); while (currentLocation !== -1) { lastLocation = currentLocation; currentLocation = trimmedLines.indexOf("", currentLocation + 1); if (lastLocation === currentLocation - 1) { blankCounter++; } else { location = { line: lastLocation + 1, column: 1 }; if (lastLocation < firstOfEndingBlankLines) { // within the file, not at the end if (blankCounter >= max) { context.report(node, location, "More than " + max + " blank " + (max === 1 ? "line" : "lines") + " not allowed."); } } else { // inside the last blank lines if (blankCounter >= maxEOF) { context.report(node, location, "Too many blank lines at the end of file. Max of " + maxEOF + " allowed."); } } // Finally, reset the blank counter blankCounter = 0; } } } }; }; module.exports.schema = [ { "type": "object", "properties": { "max": { "type": "integer" }, "maxEOF": { "type": "integer" } }, "required": ["max"], "additionalProperties": false } ];