一个确定性的、零 token 的 Cognitive Complexity 计算库、CLI 工具,以及针对 Dart 和 Flutter 仓库的 GitHub Action。
与 Cyclomatic Complexity(衡量控制流分支密度)不同,Cognitive Complexity 衡量的是人类工程师阅读和理解一个方法的难度,遵循 G. Ann Campbell 的白皮书规范。
功能
- 现代 Dart 3 AST 支持:原生解析 switch 表达式、模式
守卫(
when子句)以及集合控制流结构。 - 确定性引擎:通过算法计算复杂度,无需调用 LLM 或发起外部网络请求。
- Git Diff 分析:将当前工作区声明与目标 base ref 进行比较,以隔离已修改函数中的复杂度增量(Δ)。
- 轻量级 GitHub Action:为 CI 检查集成提供工作流注释和步骤摘要
评分模型
评分遵循 SonarSource 认知复杂度白皮书 (G. Ann Campbell,v1.7):
| 构造 / 语法 | 基础成本 | 嵌套乘数 | 是否加深嵌套? | 备注 |
|---|---|---|---|---|
if, for, while, do-while, catch / on | +1 | +D(当前深度) | 是 | 标准流程中断结构 |
switch 语句与表达式 | +1 | +D(当前深度) | 是 | 整个块的成本为 +1,与分支数量无关 |
else / else if | +1 | +0(固定惩罚) | 否 | 分支内容位于头部 if 下方一级 |
逻辑运算符(&&, ||) | +1 | +0(固定惩罚) | 否 | 每个序列 +1;每次交替 +1 |
模式 when 守卫 | +1 | +0(固定惩罚) | 否 | Dart 3 特定解释 |
| Lambda 与局部函数 | +0 | +0 | 是 | 为封闭的主体加深嵌套深度 |
空值感知(??, ?., ??=)、assert、try / finally | +0 | +0 | 否 | 良性语法;完全免费 |
| Switch 案例标签与模式组合器 | +0 | +0 | 否 | 堆叠分支 / 或模式(1 || 2)是免费的 |
Dart 对规范的特定解释:
- 模式
when守卫添加 +1(守卫是一个额外的求值条件)。 - 模式级组合子(
case 1 || 2:、case > 0 && < 10)是免费的—— or-pattern 是堆叠 case 标签的现代写法, 规范将其评分为零。 - 白皮书中“递归循环中每个方法 +1” 并未实现,这与 SonarSource 自身的参考实现 (sonar-java)一致,后者同样省略了这一点。
💻 CLI 用法
您可以在不安装的情况下按需运行扫描器,在本地项目内运行,或全局运行。(需要 Dart SDK 3.12.0 或更高版本)。
按需运行(推荐)
使用 Dart SDK 在任何 Dart 或 Flutter 项目根目录中直接运行扫描器:
dart run cognitive_complexity@ [options] [targets]
(注:末尾的 @ 指示 Dart VM 按需解析并执行该包的最新已发布版本。)
项目依赖
在 pubspec.yaml 中将包添加到您的 dev_dependencies:
dev_dependencies:
cognitive_complexity: ^0.2.0
并运行:
dart run cognitive_complexity [options] [targets]
全局安装
要在您的系统上全局安装扫描器:
dart install cognitive_complexity
cognitive_complexity [options] [targets]
选项
-t, --threshold <value>: 在终端中显示的最小分数(默认:0)。-f, --fail-threshold <value>: 分数上限。如果任何 声明超过此值,则以代码1退出。-d, --git-diff <git-ref>: 将当前代码与 git 提交/引用进行比较, 评估已修改函数的复杂度增量(Δ)。--fail-on-increase: 使用--git-diff时,如果任何 已修改函数的复杂度分数增加,则以代码1退出。--format <text|json|github>: 报告输出格式(默认:text)。
📦 Library API 使用
为 Dart 和 Flutter 应用程序提供程序化分析器。
添加到 pubspec.yaml:
dependencies:
cognitive_complexity: ^0.2.0
程序化扫描示例
import 'package:cognitive_complexity/cognitive_complexity.dart';
void main() {
final analyzer = ComplexityAnalyzer();
// Scan a directory or file path
final results = analyzer.analyzePath('lib/src');
for (final res in results) {
print('${res.name}: score is ${res.score} (${res.filePath}:L${res.startLine})');
}
}
🤖 GitHub Actions 集成
你可以使用集成的复合 GitHub Action 在拉取请求上自动运行复杂度检查。
PR 增量审计工作流示例
此工作流仅扫描拉取请求中修改的文件和函数。它直接在修改的 PR 行上注入内联代码审查警告,并在工作流摘要中打印一个美观的 Markdown 转换表格。
创建 .github/workflows/complexity.yml:
name: Cognitive Complexity Audit
on:
pull_request:
branches: [ main ]
jobs:
audit:
runs-on: ubuntu-latest
permissions:
pull-requests: write # Required to post/update sticky PR comments
contents: read # Required for actions/checkout
steps:
- name: Checkout Repository
uses: actions/checkout@v7
with:
# Fetch full history so merge-base comparison can locate common ancestor
fetch-depth: 0
- name: Setup Dart SDK
uses: dart-lang/setup-dart@v1
- name: Run Complexity Scanner
uses: kevmoo/cognitive_complexity.dart@main
with:
# Auto-configures pull request merge base comparison
diff-base: origin/${{ github.base_ref }}
fail-threshold: 15
fail-on-increase: true
操作配置参数 (with:)
targets: 以空格分隔的待扫描目录或文件(默认:lib)。threshold: 纳入报告表格的最低分数(默认:0)。fail-threshold: 最大复杂度上限(默认:15)。diff-base: 用于比较的 Git 引用(例如origin/main)。留空 以比较整个仓库的文件。fail-on-increase: 设置true以在复杂度增加时阻止 PR 合并。format: 摘要格式:github(GHA 注释 + 摘要)、text或json。
权限与安全
默认情况下,GitHub Actions 以只读权限运行。若要直接在 PR 线程中发布和更新置顶 PR 评论摘要,必须显式授予 pull-requests 写入权限:
permissions:
pull-requests: write
contents: read
如果未授予写入权限,扫描器将正常执行,并输出注释和步骤摘要,但会跳过发布 PR 评论,而不会导致构建失败。
Fork PR 安全说明
由外部 fork 的拉取请求触发的工作流,在 GitHub 上以受限的只读权限执行。出于安全原因,该 action 将优雅地跳过在 fork 上发布 PR 评论,以防止远程代码执行(RCE)风险,同时仍在 GHA 注释和构建状态中验证代码复杂度。
🧠 AI Agent 集成(Skill)
本仓库打包了一个权威的 Agent Skill(dart-cognitive-complexity),
旨在训练 LLM 和自主智能体掌握认知复杂度数学、
阈值边界以及结构性 Dart 重构模式(例如 Dart 3
switch 表达式和 guard clauses)。(注意:通过 CLI 执行自动化技能扫描需要智能体运行时中的 Dart SDK 版本为 3.12.0 或更高)。
安装技能
您可以将此技能安装到您的 AI 代理环境中:
npx skills add kevmoo/cognitive_complexity.dart --skill dart-cognitive-complexity