2 * @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity.
3 * Counts the number of if, conditional, for, while, try, switch/case,
4 * @author Patrick Brosset
9 //------------------------------------------------------------------------------
11 //------------------------------------------------------------------------------
13 const lodash = require("lodash");
15 const astUtils = require("./utils/ast-utils");
17 //------------------------------------------------------------------------------
19 //------------------------------------------------------------------------------
26 description: "enforce a maximum cyclomatic complexity allowed in a program",
27 category: "Best Practices",
29 url: "https://eslint.org/docs/rules/complexity"
51 additionalProperties: false
58 complex: "{{name}} has a complexity of {{complexity}}. Maximum allowed is {{max}}."
63 const option = context.options[0];
67 typeof option === "object" &&
68 (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
70 THRESHOLD = option.maximum || option.max;
71 } else if (typeof option === "number") {
75 //--------------------------------------------------------------------------
77 //--------------------------------------------------------------------------
79 // Using a stack to store complexity (handling nested functions)
83 * When parsing a new function, store it in our function stack
87 function startFunction() {
92 * Evaluate the node at the end of function
93 * @param {ASTNode} node node to evaluate
97 function endFunction(node) {
98 const name = lodash.upperFirst(astUtils.getFunctionNameWithKind(node));
99 const complexity = fns.pop();
101 if (complexity > THRESHOLD) {
104 messageId: "complex",
105 data: { name, complexity, max: THRESHOLD }
111 * Increase the complexity of the function in context
115 function increaseComplexity() {
117 fns[fns.length - 1]++;
122 * Increase the switch complexity in context
123 * @param {ASTNode} node node to evaluate
127 function increaseSwitchComplexity(node) {
129 // Avoiding `default`
131 increaseComplexity();
135 //--------------------------------------------------------------------------
137 //--------------------------------------------------------------------------
140 FunctionDeclaration: startFunction,
141 FunctionExpression: startFunction,
142 ArrowFunctionExpression: startFunction,
143 "FunctionDeclaration:exit": endFunction,
144 "FunctionExpression:exit": endFunction,
145 "ArrowFunctionExpression:exit": endFunction,
147 CatchClause: increaseComplexity,
148 ConditionalExpression: increaseComplexity,
149 LogicalExpression: increaseComplexity,
150 ForStatement: increaseComplexity,
151 ForInStatement: increaseComplexity,
152 ForOfStatement: increaseComplexity,
153 IfStatement: increaseComplexity,
154 SwitchCase: increaseSwitchComplexity,
155 WhileStatement: increaseComplexity,
156 DoWhileStatement: increaseComplexity,
158 AssignmentExpression(node) {
159 if (astUtils.isLogicalAssignmentOperator(node.operator)) {
160 increaseComplexity();