UNPKG

3.58 kBJavaScriptView Raw
1/**
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, whilte, try, switch/case,
4 * @author Patrick Brosset
5 */
6
7"use strict";
8
9//------------------------------------------------------------------------------
10// Rule Definition
11//------------------------------------------------------------------------------
12
13module.exports = function(context) {
14
15 var THRESHOLD = (typeof context.options[0] !== "undefined") ? context.options[0] : 20;
16
17 //--------------------------------------------------------------------------
18 // Helpers
19 //--------------------------------------------------------------------------
20
21 // Using a stack to store complexity (handling nested functions)
22 var fns = [];
23
24 /**
25 * When parsing a new function, store it in our function stack
26 * @returns {void}
27 * @private
28 */
29 function startFunction() {
30 fns.push(1);
31 }
32
33 /**
34 * Evaluate the node at the end of function
35 * @param {ASTNode} node node to evaluate
36 * @returns {void}
37 * @private
38 */
39 function endFunction(node) {
40 var complexity = fns.pop(),
41 name = "anonymous";
42
43 if (node.id) {
44 name = node.id.name;
45 } else if (node.parent.type === "MethodDefinition" || node.parent.type === "Property") {
46 name = node.parent.key.name;
47 }
48
49 if (complexity > THRESHOLD) {
50 context.report(node, "Function '{{name}}' has a complexity of {{complexity}}.", { name: name, complexity: complexity });
51 }
52 }
53
54 /**
55 * Increase the complexity of the function in context
56 * @returns {void}
57 * @private
58 */
59 function increaseComplexity() {
60 if (fns.length) {
61 fns[fns.length - 1] ++;
62 }
63 }
64
65 /**
66 * Increase the switch complexity in context
67 * @param {ASTNode} node node to evaluate
68 * @returns {void}
69 * @private
70 */
71 function increaseSwitchComplexity(node) {
72 // Avoiding `default`
73 if (node.test) {
74 increaseComplexity(node);
75 }
76 }
77
78 /**
79 * Increase the logical path complexity in context
80 * @param {ASTNode} node node to evaluate
81 * @returns {void}
82 * @private
83 */
84 function increaseLogicalComplexity(node) {
85 // Avoiding &&
86 if (node.operator === "||") {
87 increaseComplexity(node);
88 }
89 }
90
91 //--------------------------------------------------------------------------
92 // Public API
93 //--------------------------------------------------------------------------
94
95 return {
96 "FunctionDeclaration": startFunction,
97 "FunctionExpression": startFunction,
98 "ArrowFunctionExpression": startFunction,
99 "FunctionDeclaration:exit": endFunction,
100 "FunctionExpression:exit": endFunction,
101 "ArrowFunctionExpression:exit": endFunction,
102
103 "CatchClause": increaseComplexity,
104 "ConditionalExpression": increaseComplexity,
105 "LogicalExpression": increaseLogicalComplexity,
106 "ForStatement": increaseComplexity,
107 "ForInStatement": increaseComplexity,
108 "ForOfStatement": increaseComplexity,
109 "IfStatement": increaseComplexity,
110 "SwitchCase": increaseSwitchComplexity,
111 "WhileStatement": increaseComplexity,
112 "DoWhileStatement": increaseComplexity
113 };
114
115};
116
117module.exports.schema = [
118 {
119 "type": "integer",
120 "minimum": 0
121 }
122];