// Requirements
//------------------------------------------------------------------------------
-const lodash = require("lodash");
const astUtils = require("./utils/ast-utils");
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Creates an array of numbers from `start` up to, but not including, `end`
+ * @param {number} start The start of the range
+ * @param {number} end The end of the range
+ * @returns {number[]} The range of numbers
+ */
+function range(start, end) {
+ return [...Array(end - start).keys()].map(x => x + start);
+}
+
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
+/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
- description: "enforce a maximum number of lines per file",
- category: "Stylistic Issues",
+ description: "Enforce a maximum number of lines per file",
recommended: false,
url: "https://eslint.org/docs/rules/max-lines"
},
}
],
messages: {
- exceed: "File has too many lines ({{actual}}). Maximum allowed is {{max}}."
+ exceed:
+ "File has too many lines ({{actual}}). Maximum allowed is {{max}}."
}
},
const option = context.options[0];
let max = 300;
- if (typeof option === "object" && Object.prototype.hasOwnProperty.call(option, "max")) {
+ if (
+ typeof option === "object" &&
+ Object.prototype.hasOwnProperty.call(option, "max")
+ ) {
max = option.max;
} else if (typeof option === "number") {
max = option;
token = comment;
do {
- token = sourceCode.getTokenBefore(token, { includeComments: true });
+ token = sourceCode.getTokenBefore(token, {
+ includeComments: true
+ });
} while (isCommentNodeType(token));
if (token && astUtils.isTokenOnSameLine(token, comment)) {
token = comment;
do {
- token = sourceCode.getTokenAfter(token, { includeComments: true });
+ token = sourceCode.getTokenAfter(token, {
+ includeComments: true
+ });
} while (isCommentNodeType(token));
if (token && astUtils.isTokenOnSameLine(comment, token)) {
}
if (start <= end) {
- return lodash.range(start, end + 1);
+ return range(start, end + 1);
}
return [];
}
return {
"Program:exit"() {
- let lines = sourceCode.lines.map((text, i) => ({ lineNumber: i + 1, text }));
+ let lines = sourceCode.lines.map((text, i) => ({
+ lineNumber: i + 1,
+ text
+ }));
+
+ /*
+ * If file ends with a linebreak, `sourceCode.lines` will have one extra empty line at the end.
+ * That isn't a real line, so we shouldn't count it.
+ */
+ if (lines.length > 1 && lines[lines.length - 1].text === "") {
+ lines.pop();
+ }
if (skipBlankLines) {
lines = lines.filter(l => l.text.trim() !== "");
if (skipComments) {
const comments = sourceCode.getAllComments();
- const commentLines = lodash.flatten(comments.map(comment => getLinesWithoutCode(comment)));
+ const commentLines = new Set(comments.flatMap(getLinesWithoutCode));
- lines = lines.filter(l => !lodash.includes(commentLines, l.lineNumber));
+ lines = lines.filter(
+ l => !commentLines.has(l.lineNumber)
+ );
}
if (lines.length > max) {
+ const loc = {
+ start: {
+ line: lines[max].lineNumber,
+ column: 0
+ },
+ end: {
+ line: sourceCode.lines.length,
+ column: sourceCode.lines[sourceCode.lines.length - 1].length
+ }
+ };
+
context.report({
- loc: { line: 1, column: 0 },
+ loc,
messageId: "exceed",
data: {
max,