【工具】检测代码复杂度

对给定 JavaScript 代码通过复杂度分析工具分析代码的复杂度和可维护性评分。

相关文章

检测代码复杂度


功能清单

  • 使用了 escomplex 模块对代码进行了复杂度分析
  • 输出整体分析结果和每个函数的详细分析结果,包括逻辑行数、物理行数、圈复杂度、参数数量等。
  • 输出了整体代码的可维护性评分。

一、escomplex 是什么

escomplex 是一个 JavaScript 代码复杂度分析工具,用于评估 JavaScript 代码的复杂度和可维护性。它可以分析代码的各种指标,包括逻辑行数、物理行数、圈复杂度、参数数量、代码长度、代码词汇量、代码难度、代码体积、代码工作量等。通过分析这些指标,可以帮助开发人员了解代码的复杂度情况,从而进行代码质量评估、性能优化和重构工作。

二、使用 escomplex 分析代码

1、安装 escomplex

1
npm i escomplex

2、进行复杂度分析

1
2
// 使用 escomplex 分析更复杂的代码
const analysis = escomplex.analyse(code);

3、解析报告

  • 整体分析结果 (analysis.aggregate):

    • sloc: 代码的逻辑行数和物理行数。
    • cyclomatic: 代码的圈复杂度。
    • params: 整体代码中的参数数量。
    • line: 整体代码的定义所在行数。
    • halstead: 哈斯特德度量,包括操作符和操作数的总数、代码长度、词汇量、难度、体积、工作量、可能存在的错误数量估计以及编写和测试所需的时间估计。
    • cyclomaticDensity: 代码的圈复杂度密度。
  • 函数分析结果 (analysis.functions):

    • 每个函数的名称或标识符 (func.name)。
    • 每个函数的逻辑行数和物理行数 (func.sloc.logical 和 func.sloc.physical)。
    • 每个函数的圈复杂度 (func.cyclomatic)。
    • 每个函数的参数数量 (func.params)。
    • 每个函数的定义所在行数 (func.line)。
    • 每个函数的哈斯特德度量,包括操作符和操作数的总数、代码长度、词汇量、难度、体积、工作量、可能存在的错误数量估计以及编写和测试所需的时间估计 (func.halstead)。
    • 每个函数的圈复杂度密度 (func.cyclomaticDensity)。

三、完整示例

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
const escomplex = require('escomplex');

// 定义更复杂的代码
const code = `function removeDuplicates(dataset) {
return Array.from(new Set(dataset)); // 使用 Set 去重
}

function binarySearch(dataset, target) {
let left = 0;
let right = dataset.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (dataset[mid] === target) {
return mid; // 如果找到目标值,返回索引
} else if (dataset[mid] < target) {
left = mid + 1; // 如果目标值在右侧,更新左边界
} else {
right = mid - 1; // 如果目标值在左侧,更新右边界
}
}
return -1; // 如果未找到目标值,返回 -1
}`;

// 使用 escomplex 分析更复杂的代码
const analysis = escomplex.analyse(code);

// 打印整体分析结果
function logAggregateDetails(aggregate) {
console.log(`--- 整体分析结果 ---`);
console.log(`-----------------------------`);
console.log(`逻辑行数: ${aggregate.sloc.logical}`);
console.log(`物理行数: ${aggregate.sloc.physical}`);
console.log(`圈复杂度: ${aggregate.cyclomatic}`);
console.log(`参数数量: ${aggregate.params}`);
console.log(`定义所在行数: ${aggregate.line}`);
console.log(`-----------------------------`);
console.log(`哈斯特德度量:`);
console.log(` - 操作符总类: ${aggregate.halstead.operators.distinct} (总数: ${aggregate.halstead.operators.total})`);
console.log(` - 操作数总类: ${aggregate.halstead.operands.distinct} (总数: ${aggregate.halstead.operands.total})`);
console.log(` - 代码长度: ${aggregate.halstead.length.toFixed(2)}`);
console.log(` - 代码词汇量: ${aggregate.halstead.vocabulary.toFixed(2)}`);
console.log(` - 代码难度: ${aggregate.halstead.difficulty.toFixed(2)}`);
console.log(` - 代码体积: ${aggregate.halstead.volume.toFixed(2)}`);
console.log(` - 代码工作量: ${aggregate.halstead.effort.toFixed(2)}`);
console.log(` - 可能存在的错误数量估计: ${aggregate.halstead.bugs.toFixed(2)}`);
console.log(` - 编写和测试所需时间估计: ${aggregate.halstead.time.toFixed(2)}`);
console.log(`-----------------------------`);
console.log(`圈复杂度密度: ${aggregate.cyclomaticDensity}`);
console.log(`\n`);
}

// 打印函数分析结果
function logFunctionDetails(func) {
console.log(`--- 详细分析结果 ---`);
console.log(`-----------------------------`);
console.log(`函数名称或标识符: ${func.name}`);
console.log(`-----------------------------`);
console.log(`逻辑行数: ${func.sloc.logical}`);
console.log(`物理行数: ${func.sloc.physical}`);
console.log(`圈复杂度: ${func.cyclomatic}`);
console.log(`参数数量: ${func.params}`);
console.log(`定义所在行数: ${func.line}`);
console.log(`-----------------------------`);
console.log(`哈斯特德度量:`);
console.log(` - 操作符总类: ${func.halstead.operators.distinct} (总数: ${func.halstead.operators.total})`);
console.log(` - 操作数总类: ${func.halstead.operands.distinct} (总数: ${func.halstead.operands.total})`);
console.log(` - 代码长度: ${func.halstead.length.toFixed(2)}`);
console.log(` - 代码词汇量: ${func.halstead.vocabulary.toFixed(2)}`);
console.log(` - 代码难度: ${func.halstead.difficulty.toFixed(2)}`);
console.log(` - 代码体积: ${func.halstead.volume.toFixed(2)}`);
console.log(` - 代码工作量: ${func.halstead.effort.toFixed(2)}`);
console.log(` - 可能存在的错误数量估计: ${func.halstead.bugs.toFixed(2)}`);
console.log(` - 编写和测试所需时间估计: ${func.halstead.time.toFixed(2)}`);
console.log(`-----------------------------`);
console.log(`圈复杂度密度: ${func.cyclomaticDensity}`);
console.log(`\n`);
}

// // 打印整体分析结果
logAggregateDetails(analysis.aggregate);

// // 打印每个函数的分析结果
analysis.functions.forEach(logFunctionDetails);

console.log('\n整体可维护性评分:');
console.log(`评分: ${analysis.maintainability}`);

输出结果

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
--- 整体分析结果 ---
-----------------------------
逻辑行数: 15
物理行数: 20
圈复杂度: 4
参数数量: 3
定义所在行数: 3
-----------------------------
哈斯特德度量:
- 操作符总类: 18 (总数: 35)
- 操作数总类: 16 (总数: 37)
- 代码长度: 72.00
- 代码词汇量: 34.00
- 代码难度: 20.81
- 代码体积: 366.30
- 代码工作量: 7623.56
- 可能存在的错误数量估计: 0.12
- 编写和测试所需时间估计: 423.53
-----------------------------
圈复杂度密度: 26.666666666666668


--- 详细分析结果 ---
-----------------------------
函数名称或标识符: removeDuplicates
-----------------------------
逻辑行数: 1
物理行数: 3
圈复杂度: 1
参数数量: 1
定义所在行数: 3
-----------------------------
哈斯特德度量:
- 操作符总类: 4 (总数: 4)
- 操作数总类: 4 (总数: 5)
- 代码长度: 9.00
- 代码词汇量: 8.00
- 代码难度: 2.50
- 代码体积: 27.00
- 代码工作量: 67.50
- 可能存在的错误数量估计: 0.01
- 编写和测试所需时间估计: 3.75
-----------------------------
圈复杂度密度: 100

--- 详细分析结果 ---
-----------------------------
函数名称或标识符: binarySearch
-----------------------------
逻辑行数: 12
物理行数: 15
圈复杂度: 4
参数数量: 2
定义所在行数: 8
-----------------------------
哈斯特德度量:
- 操作符总类: 16 (总数: 29)
- 操作数总类: 11 (总数: 30)
- 代码长度: 59.00
- 代码词汇量: 27.00
- 代码难度: 21.82
- 代码体积: 280.54
- 代码工作量: 6120.84
- 可能存在的错误数量估计: 0.09
- 编写和测试所需时间估计: 340.05
-----------------------------
圈复杂度密度: 33.33333333333333

整体可维护性评分:
评分: 112.9785791088806

喜欢这篇文章?打赏一下支持一下作者吧!
【工具】检测代码复杂度
https://www.cccccl.com/20240201/工具/检测代码复杂度/
作者
Jeffrey
发布于
2024年2月1日
许可协议