2 * @fileoverview enforce a maximum file length
3 * @author Alberto RodrÃguez
7 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
11 const astUtils = require("./utils/ast-utils");
13 //------------------------------------------------------------------------------
15 //------------------------------------------------------------------------------
18 * Creates an array of numbers from `start` up to, but not including, `end`
19 * @param {number} start The start of the range
20 * @param {number} end The end of the range
21 * @returns {number[]} The range of numbers
23 function range(start, end) {
24 return [...Array(end - start).keys()].map(x => x + start);
27 //------------------------------------------------------------------------------
29 //------------------------------------------------------------------------------
36 description: "enforce a maximum number of lines per file",
37 category: "Stylistic Issues",
39 url: "https://eslint.org/docs/rules/max-lines"
63 additionalProperties: false
70 "File has too many lines ({{actual}}). Maximum allowed is {{max}}."
75 const option = context.options[0];
79 typeof option === "object" &&
80 Object.prototype.hasOwnProperty.call(option, "max")
83 } else if (typeof option === "number") {
87 const skipComments = option && option.skipComments;
88 const skipBlankLines = option && option.skipBlankLines;
90 const sourceCode = context.getSourceCode();
93 * Returns whether or not a token is a comment node type
94 * @param {Token} token The token to check
95 * @returns {boolean} True if the token is a comment node
97 function isCommentNodeType(token) {
98 return token && (token.type === "Block" || token.type === "Line");
102 * Returns the line numbers of a comment that don't have any code on the same line
103 * @param {Node} comment The comment node to check
104 * @returns {number[]} The line numbers
106 function getLinesWithoutCode(comment) {
107 let start = comment.loc.start.line;
108 let end = comment.loc.end.line;
114 token = sourceCode.getTokenBefore(token, {
115 includeComments: true
117 } while (isCommentNodeType(token));
119 if (token && astUtils.isTokenOnSameLine(token, comment)) {
125 token = sourceCode.getTokenAfter(token, {
126 includeComments: true
128 } while (isCommentNodeType(token));
130 if (token && astUtils.isTokenOnSameLine(comment, token)) {
135 return range(start, end + 1);
141 * Returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.
142 * TODO(stephenwade): Replace this with array.flatMap when we drop support for Node v10
143 * @param {any[]} array The array to process
144 * @param {Function} fn The function to use
145 * @returns {any[]} The result array
147 function flatMap(array, fn) {
148 const mapped = array.map(fn);
149 const flattened = [].concat(...mapped);
156 let lines = sourceCode.lines.map((text, i) => ({
162 * If file ends with a linebreak, `sourceCode.lines` will have one extra empty line at the end.
163 * That isn't a real line, so we shouldn't count it.
165 if (lines.length > 1 && lines[lines.length - 1].text === "") {
169 if (skipBlankLines) {
170 lines = lines.filter(l => l.text.trim() !== "");
174 const comments = sourceCode.getAllComments();
176 const commentLines = flatMap(comments, comment => getLinesWithoutCode(comment));
178 lines = lines.filter(
179 l => !commentLines.includes(l.lineNumber)
183 if (lines.length > max) {
186 line: lines[max].lineNumber,
190 line: sourceCode.lines.length,
191 column: sourceCode.lines[sourceCode.lines.length - 1].length