.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / max-lines.js
1 /**
2  * @fileoverview enforce a maximum file length
3  * @author Alberto Rodríguez
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const lodash = require("lodash");
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 module.exports = {
19     meta: {
20         type: "suggestion",
21
22         docs: {
23             description: "enforce a maximum number of lines per file",
24             category: "Stylistic Issues",
25             recommended: false,
26             url: "https://eslint.org/docs/rules/max-lines"
27         },
28
29         schema: [
30             {
31                 oneOf: [
32                     {
33                         type: "integer",
34                         minimum: 0
35                     },
36                     {
37                         type: "object",
38                         properties: {
39                             max: {
40                                 type: "integer",
41                                 minimum: 0
42                             },
43                             skipComments: {
44                                 type: "boolean"
45                             },
46                             skipBlankLines: {
47                                 type: "boolean"
48                             }
49                         },
50                         additionalProperties: false
51                     }
52                 ]
53             }
54         ],
55         messages: {
56             exceed:
57                 "File has too many lines ({{actual}}). Maximum allowed is {{max}}."
58         }
59     },
60
61     create(context) {
62         const option = context.options[0];
63         let max = 300;
64
65         if (
66             typeof option === "object" &&
67             Object.prototype.hasOwnProperty.call(option, "max")
68         ) {
69             max = option.max;
70         } else if (typeof option === "number") {
71             max = option;
72         }
73
74         const skipComments = option && option.skipComments;
75         const skipBlankLines = option && option.skipBlankLines;
76
77         const sourceCode = context.getSourceCode();
78
79         /**
80          * Returns whether or not a token is a comment node type
81          * @param {Token} token The token to check
82          * @returns {boolean} True if the token is a comment node
83          */
84         function isCommentNodeType(token) {
85             return token && (token.type === "Block" || token.type === "Line");
86         }
87
88         /**
89          * Returns the line numbers of a comment that don't have any code on the same line
90          * @param {Node} comment The comment node to check
91          * @returns {number[]} The line numbers
92          */
93         function getLinesWithoutCode(comment) {
94             let start = comment.loc.start.line;
95             let end = comment.loc.end.line;
96
97             let token;
98
99             token = comment;
100             do {
101                 token = sourceCode.getTokenBefore(token, {
102                     includeComments: true
103                 });
104             } while (isCommentNodeType(token));
105
106             if (token && astUtils.isTokenOnSameLine(token, comment)) {
107                 start += 1;
108             }
109
110             token = comment;
111             do {
112                 token = sourceCode.getTokenAfter(token, {
113                     includeComments: true
114                 });
115             } while (isCommentNodeType(token));
116
117             if (token && astUtils.isTokenOnSameLine(comment, token)) {
118                 end -= 1;
119             }
120
121             if (start <= end) {
122                 return lodash.range(start, end + 1);
123             }
124             return [];
125         }
126
127         return {
128             "Program:exit"() {
129                 let lines = sourceCode.lines.map((text, i) => ({
130                     lineNumber: i + 1,
131                     text
132                 }));
133
134                 /*
135                  * If file ends with a linebreak, `sourceCode.lines` will have one extra empty line at the end.
136                  * That isn't a real line, so we shouldn't count it.
137                  */
138                 if (lines.length > 1 && lodash.last(lines).text === "") {
139                     lines.pop();
140                 }
141
142                 if (skipBlankLines) {
143                     lines = lines.filter(l => l.text.trim() !== "");
144                 }
145
146                 if (skipComments) {
147                     const comments = sourceCode.getAllComments();
148
149                     const commentLines = lodash.flatten(
150                         comments.map(comment => getLinesWithoutCode(comment))
151                     );
152
153                     lines = lines.filter(
154                         l => !commentLines.includes(l.lineNumber)
155                     );
156                 }
157
158                 if (lines.length > max) {
159                     const loc = {
160                         start: {
161                             line: lines[max].lineNumber,
162                             column: 0
163                         },
164                         end: {
165                             line: sourceCode.lines.length,
166                             column: lodash.last(sourceCode.lines).length
167                         }
168                     };
169
170                     context.report({
171                         loc,
172                         messageId: "exceed",
173                         data: {
174                             max,
175                             actual: lines.length
176                         }
177                     });
178                 }
179             }
180         };
181     }
182 };