-
Notifications
You must be signed in to change notification settings - Fork 179
/
Copy pathcode-complexity.js
137 lines (110 loc) · 2.9 KB
/
code-complexity.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
const BaseChecker = require('../base-checker')
const { severityDescription } = require('../../doc/utils')
const ruleId = 'code-complexity'
const DEFAULT_SEVERITY = 'warn'
const DEFAULT_COMPLEXITY = 7
const meta = {
type: 'best-practices',
docs: {
description: 'Function has cyclomatic complexity "current" but allowed no more than maxcompl.',
category: 'Best Practice Rules',
options: [
{
description: severityDescription,
default: DEFAULT_SEVERITY,
},
{
description: 'Maximum allowed cyclomatic complexity',
default: DEFAULT_COMPLEXITY,
},
],
examples: {
good: [
{
description: 'Low code complexity',
code: require('../../../test/fixtures/best-practices/code-complexity-low'),
},
],
bad: [
{
description: 'High code complexity',
code: require('../../../test/fixtures/best-practices/code-complexity-high'),
},
],
},
},
isDefault: false,
recommended: false,
defaultSetup: [DEFAULT_SEVERITY, DEFAULT_COMPLEXITY],
schema: { type: 'integer' },
}
class CodeComplexityChecker extends BaseChecker {
constructor(reporter, config) {
super(reporter, ruleId, meta)
this.maxComplexity = (config && config.getNumber('code-complexity', 7)) || 7
}
FunctionDefinition(node) {
this._attachComplexityScope(node)
}
ModifierDefinition(node) {
this._attachComplexityScope(node)
}
IfStatement(node) {
this._complexityPlusOne(node)
}
WhileStatement(node) {
this._complexityPlusOne(node)
}
DoWhileStatement(node) {
this._complexityPlusOne(node)
}
ForStatement(node) {
this._complexityPlusOne(node)
}
'FunctionDefinition:exit'(node) {
this._verifyComplexityScope(node)
}
'ModifierDefinition:exit'(node) {
this._verifyComplexityScope(node)
}
_attachComplexityScope(node) {
ComplexityScope.activate(node)
}
_complexityPlusOne(node) {
const scope = ComplexityScope.of(node)
if (scope) {
scope.complexityPlusOne()
}
}
_verifyComplexityScope(node) {
const scope = ComplexityScope.of(node)
if (scope && scope.complexity > this.maxComplexity) {
this._error(node, scope)
}
}
_error(node, scope) {
const curComplexity = scope.complexity
const maxComplexity = this.maxComplexity
const message = `Function has cyclomatic complexity ${curComplexity} but allowed no more than ${maxComplexity}`
this.error(node, message)
}
}
class ComplexityScope {
static of(node) {
let curNode = node
while (curNode && !curNode.complexityScope) {
curNode = curNode.parent
}
return curNode && curNode.complexityScope
}
static activate(node) {
node.complexityScope = new ComplexityScope()
}
constructor() {
this.complexity = 1
}
complexityPlusOne() {
this.complexity += 1
}
}
module.exports = CodeComplexityChecker