blob: 6f48c9218a9dd18a660412dd3cffc5b6e5cf94e1 [file] [log] [blame]
Yang Guo4fd355c2019-09-19 10:59:03 +02001/**
2 * @fileoverview A rule to set the maximum number of statements in a function.
3 * @author Ian Christian Myers
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
Yang Guo4fd355c2019-09-19 10:59:03 +020012const astUtils = require("./utils/ast-utils");
Simon Zünd52e20202021-06-16 08:34:28 +020013const { upperCaseFirst } = require("../shared/string-utils");
Yang Guo4fd355c2019-09-19 10:59:03 +020014
15//------------------------------------------------------------------------------
16// Rule Definition
17//------------------------------------------------------------------------------
18
19module.exports = {
20 meta: {
21 type: "suggestion",
22
23 docs: {
24 description: "enforce a maximum number of statements allowed in function blocks",
Yang Guo4fd355c2019-09-19 10:59:03 +020025 recommended: false,
26 url: "https://eslint.org/docs/rules/max-statements"
27 },
28
29 schema: [
30 {
31 oneOf: [
32 {
33 type: "integer",
34 minimum: 0
35 },
36 {
37 type: "object",
38 properties: {
39 maximum: {
40 type: "integer",
41 minimum: 0
42 },
43 max: {
44 type: "integer",
45 minimum: 0
46 }
47 },
48 additionalProperties: false
49 }
50 ]
51 },
52 {
53 type: "object",
54 properties: {
55 ignoreTopLevelFunctions: {
56 type: "boolean"
57 }
58 },
59 additionalProperties: false
60 }
61 ],
62 messages: {
63 exceed: "{{name}} has too many statements ({{count}}). Maximum allowed is {{max}}."
64 }
65 },
66
67 create(context) {
68
69 //--------------------------------------------------------------------------
70 // Helpers
71 //--------------------------------------------------------------------------
72
73 const functionStack = [],
74 option = context.options[0],
75 ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false,
76 topLevelFunctions = [];
77 let maxStatements = 10;
78
79 if (
80 typeof option === "object" &&
81 (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
82 ) {
83 maxStatements = option.maximum || option.max;
84 } else if (typeof option === "number") {
85 maxStatements = option;
86 }
87
88 /**
89 * Reports a node if it has too many statements
90 * @param {ASTNode} node node to evaluate
91 * @param {int} count Number of statements in node
92 * @param {int} max Maximum number of statements allowed
93 * @returns {void}
94 * @private
95 */
96 function reportIfTooManyStatements(node, count, max) {
97 if (count > max) {
Simon Zünd52e20202021-06-16 08:34:28 +020098 const name = upperCaseFirst(astUtils.getFunctionNameWithKind(node));
Yang Guo4fd355c2019-09-19 10:59:03 +020099
100 context.report({
101 node,
102 messageId: "exceed",
103 data: { name, count, max }
104 });
105 }
106 }
107
108 /**
109 * When parsing a new function, store it in our function stack
110 * @returns {void}
111 * @private
112 */
113 function startFunction() {
114 functionStack.push(0);
115 }
116
117 /**
118 * Evaluate the node at the end of function
119 * @param {ASTNode} node node to evaluate
120 * @returns {void}
121 * @private
122 */
123 function endFunction(node) {
124 const count = functionStack.pop();
125
126 if (ignoreTopLevelFunctions && functionStack.length === 0) {
127 topLevelFunctions.push({ node, count });
128 } else {
129 reportIfTooManyStatements(node, count, maxStatements);
130 }
131 }
132
133 /**
134 * Increment the count of the functions
135 * @param {ASTNode} node node to evaluate
136 * @returns {void}
137 * @private
138 */
139 function countStatements(node) {
140 functionStack[functionStack.length - 1] += node.body.length;
141 }
142
143 //--------------------------------------------------------------------------
144 // Public API
145 //--------------------------------------------------------------------------
146
147 return {
148 FunctionDeclaration: startFunction,
149 FunctionExpression: startFunction,
150 ArrowFunctionExpression: startFunction,
151
152 BlockStatement: countStatements,
153
154 "FunctionDeclaration:exit": endFunction,
155 "FunctionExpression:exit": endFunction,
156 "ArrowFunctionExpression:exit": endFunction,
157
158 "Program:exit"() {
159 if (topLevelFunctions.length === 1) {
160 return;
161 }
162
163 topLevelFunctions.forEach(element => {
164 const count = element.count;
165 const node = element.node;
166
167 reportIfTooManyStatements(node, count, maxStatements);
168 });
169 }
170 };
171
172 }
173};