UNPKG

4.62 kBJavaScriptView Raw
1/**
2 * @fileoverview enforce a maximum file length
3 * @author Alberto Rodríguez
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Requirements
9//------------------------------------------------------------------------------
10
11const lodash = require("lodash");
12const astUtils = require("../ast-utils");
13
14//------------------------------------------------------------------------------
15// Rule Definition
16//------------------------------------------------------------------------------
17
18module.exports = {
19 meta: {
20 docs: {
21 description: "enforce a maximum number of lines per file",
22 category: "Stylistic Issues",
23 recommended: false,
24 url: "https://eslint.org/docs/rules/max-lines"
25 },
26
27 schema: [
28 {
29 oneOf: [
30 {
31 type: "integer",
32 minimum: 0
33 },
34 {
35 type: "object",
36 properties: {
37 max: {
38 type: "integer",
39 minimum: 0
40 },
41 skipComments: {
42 type: "boolean"
43 },
44 skipBlankLines: {
45 type: "boolean"
46 }
47 },
48 additionalProperties: false
49 }
50 ]
51 }
52 ]
53 },
54
55 create(context) {
56 const option = context.options[0];
57 let max = 300;
58
59 if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
60 max = option.max;
61 }
62
63 if (typeof option === "number") {
64 max = option;
65 }
66
67 const skipComments = option && option.skipComments;
68 const skipBlankLines = option && option.skipBlankLines;
69
70 const sourceCode = context.getSourceCode();
71
72 /**
73 * Returns whether or not a token is a comment node type
74 * @param {Token} token The token to check
75 * @returns {boolean} True if the token is a comment node
76 */
77 function isCommentNodeType(token) {
78 return token && (token.type === "Block" || token.type === "Line");
79 }
80
81 /**
82 * Returns the line numbers of a comment that don't have any code on the same line
83 * @param {Node} comment The comment node to check
84 * @returns {int[]} The line numbers
85 */
86 function getLinesWithoutCode(comment) {
87 let start = comment.loc.start.line;
88 let end = comment.loc.end.line;
89
90 let token;
91
92 token = comment;
93 do {
94 token = sourceCode.getTokenBefore(token, { includeComments: true });
95 } while (isCommentNodeType(token));
96
97 if (token && astUtils.isTokenOnSameLine(token, comment)) {
98 start += 1;
99 }
100
101 token = comment;
102 do {
103 token = sourceCode.getTokenAfter(token, { includeComments: true });
104 } while (isCommentNodeType(token));
105
106 if (token && astUtils.isTokenOnSameLine(comment, token)) {
107 end -= 1;
108 }
109
110 if (start <= end) {
111 return lodash.range(start, end + 1);
112 }
113 return [];
114 }
115
116 return {
117 "Program:exit"() {
118 let lines = sourceCode.lines.map((text, i) => ({ lineNumber: i + 1, text }));
119
120 if (skipBlankLines) {
121 lines = lines.filter(l => l.text.trim() !== "");
122 }
123
124 if (skipComments) {
125 const comments = sourceCode.getAllComments();
126
127 const commentLines = lodash.flatten(comments.map(comment => getLinesWithoutCode(comment)));
128
129 lines = lines.filter(l => !lodash.includes(commentLines, l.lineNumber));
130 }
131
132 if (lines.length > max) {
133 context.report({
134 loc: { line: 1, column: 0 },
135 message: "File must be at most {{max}} lines long. It's {{actual}} lines long.",
136 data: {
137 max,
138 actual: lines.length
139 }
140 });
141 }
142 }
143 };
144 }
145};