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