mcpField
C
codebase-refactoring

codebase-refactoring

github.com/kucherenko开发6.5k617 次安装今天更新
代码仓库

关于 codebase-refactoring

codebase-refactoring 是一套使用 jscpd 检查并处理代码重复、死代码和复杂度的引导式技能,适用于代码库维护与技术债清理。它先测量健康状况并确定优先级,再分步骤指导分析、重构和复查。

主要功能

  1. 01评估代码库健康状况
  2. 02检查重复代码与死代码
  3. 03分析复杂度并定位重点文件
  4. 04按优先级分步指导重构
  5. 05复查改动后的指标

适用场景

  1. 01为代码库维护任务确定先后顺序
  2. 02查找并合并重复实现
  3. 03确认未使用的文件、导出和导入
  4. 04简化高复杂度文件并核对结果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kucherenko/jscpd --skill codebase-refactoring

安装后在 Claude Code 中输入/codebase-refactoring确认已加载。

详细介绍

codebase-refactoring

通过 jscpd 查找代码库中三项最大的维护成本——重复代码、死代码和复杂度,并使用相应策略进行修复。当有人要求“清理”“改进”“重构”或“偿还”代码库中的技术债务时,使用此技能;如果是要修复某个特定 Bug,则不要使用。

从这里开始:先衡量,再确定优先级

npx jscpd --health --reporters ai <path>
health 74 B (duplication 75, dead-code 72, complexity 76; 93 code lines)

健康评分是三个子评分的加权组合,每个子评分都按代码行数占比计算——分数越高越好,100 表示干净。最低的子评分指出代码库最突出的问题;如果它不是下面列出的顺序中的第一项,就先处理对应维度。某个维度显示 n/a(例如 dead code n/a),表示 jscpd 无法衡量该维度——死代码检测需要 JavaScript、TypeScript 或 Python,才能计算出实际占比;此时应跳过这一步,而不是将其视为干净。

如需全面了解此评分背后的情况——最大的重复代码格式、最复杂的文件、最大的死代码发现项,一屏尽览——请运行 npx jscpd --dashboard。其 console 输出(默认值)是唯一能提供逐文件详细信息的报告器;在 --dashboard 上使用 --reporters ai 只会打印上方显示的同一行摘要,而不会提供细分信息,因此不要指望它能提供评分以外的内容。如果需要可解析格式的详细信息,请在 --dashboard 上使用 --reporters json。

除此之外,以下三项检查相互独立,可以按任意顺序安全执行;默认顺序为 重复代码 → 死代码 → 复杂度,因为先修复重复代码,就能避免第 2 步浪费精力追踪调用位置——之后的提取函数操作会移动这些调用位置;而在第 3 步之前清理死代码,则能确保被列为简化对象的文件确实值得简化,而不是即将被删除的文件。

第 1 步 — 重复代码

npx jscpd --reporters ai --summary <path>

查找并阅读每个克隆,判断它是否是真正值得合并的副本,然后应用相应的重构策略(提取函数、参数化、提取共享模块或常量,或针对结构重复使用基类/模板)。完整的指导式工作流、针对重命名/近似匹配克隆的分类规则,以及各类克隆的实例:

→ dry-refactoring — 现在运行此技能,然后回到这里执行第 2 步和第 3 步。它自身的 --summary 热点排名与健康评分的重复代码维度使用的排名相同,因此它标记为重复代码热点的文件,也正是拉低评分的文件。

第 2 步 — 死代码

npx jscpd --dead-code --reporters ai <path>
basta dead code report — 18 findings across 30 files (22.1% of 272 lines)
Confidence is 0-100; anything below 90 has a listed reason it may be wrong. Verify a finding before deleting the code.
unused-file typescript/src/legacy-export.ts:1:1 confidence=95 typescript/src/legacy-export.ts is never imported and is not an entry point
unused-export typescript/src/invoice.ts:21:17 confidence=85 exported function `renderReceipt` is never imported
unused-symbol typescript/src/invoice.ts:29:10 confidence=90 function `describeTotal` is never used in typescript/src/invoice.ts
unused-import typescript/src/invoice.ts:2:10 confidence=100 `roundToCents` is imported but never used

这是从项目入口点(package.json 的 main/bin/exports/scripts、pyproject.toml 中的 scripts、框架约定或 --entry <glob>)开始的图遍历,而不是引用计数——即使某个辅助函数的唯一调用方本身也是死代码,该函数也会被报告,因此删除一个发现项后,可能会暴露另一个此前尚未报告的真正死代码。支持 JavaScript、TypeScript、JSX、TSX、Vue、Svelte、Astro 和 Python。

四种类别,以及各自的处理方法
类别含义常见修复方式
unused-file从未在任何地方导入,也不是入口点删除文件
unused-export已导出,但没有其他文件导入它删除它,或删除 export 关键字(如果同一文件中的内容仍在使用它)
unused-symbol模块私有声明,且其所在文件中没有任何内容引用它删除它
unused-import已导入,但在文件中从未被引用删除导入行
工作流
  1. 使用 --reporters ai 运行(添加 --dead-code-categories 可聚焦于某个类别;如果不应将仅在测试中的用法视为“已使用”,则添加 --include-tests;添加 --include-entry-exports 还会标记入口文件自身未使用的导出,通常会排除这些导出,因为入口文件的全部接口都是公共 API)
  2. 按置信度从高到低排序。置信度范围为 0–100;低于 90 时,发现结果会附上可能出错的原因——eval/getattr 调用、分析器无法识别的装饰器、通配符重新导出、名称只出现在字符串字面量中,或其他位置有文件解析失败(参见 JSON 报告中的 statistics.unparsedFiles)。删除前先阅读原因;--min-confidence(默认值为 60)只设置报告结果的下限,并不会让低置信度的发现变得安全
  3. 对每个高于你所能接受阈值的发现,手动确认——在整个代码仓库中搜索该符号名称(动态访问、基于字符串的路由器、jscpd 无法解析的模板文件都可能隐藏实际用法),然后应用上表中的修复方法
  4. 每批删除后都运行项目自身的测试套件和构建,而不只是重新运行 jscpd:死代码分析只能证明从入口点无法到达这段代码,不能证明删除它不会破坏构建步骤
  5. 每批删除后重新运行 --dead-code:某个文件唯一的导入可能正是你刚删除的那一个,此时该文件本身也可能变成死代码——这种连锁反应是预期的,持续处理直到检查结果干净,而不是只运行一次
  6. 将跳过的内容及原因(置信度低、无法排除的风险,或有意保留的死代码,例如公共库导出)与实际删除的内容分开报告

步骤 3 — 大型且复杂的文件

npx jscpd --complexity --reporters ai --summary-top 10 <path>
# or, ranked alongside duplication and size:
npx jscpd --reporters ai --summary --summary-by complexity <path>
Complexity by complexity (6 files, 6 folders):
files (tokens/lines/size/cx):
c/checkout.c 176/32/710/13
rust/status.rs 112/24/481/9
swift/Profile.swift 88/21/446/8

cx 是一种对语言敏感的圈复杂度估算值——大致为每个函数一条路径,每个分支再增加一条路径(if、循环、&&/||、match/switch 分支、三元运算符和 Elvis 运算符,均按照各语言的实际语法计数)——应将其视为排序信号,而非精确指标。文档和数据文件(Markdown、JSON、YAML、锁文件等)的得分始终为 0;大型 README 不是重构目标。jscpd 自身的健康度评分会将复杂度不低于 50 的文件视为“复杂”(其“死代码”式半衰期曲线以此阈值为校准基准)——如果摘要没有明确指出合适的对象,这可以作为“值得阅读”的合理默认阈值。

工作流
  1. 按复杂度选出排名靠前的 N 个文件(使用 --summary 格式时,还要按大小排序——复杂度低但体积巨大的文件,例如大型数据表,与体积小但复杂度高的文件是不同的问题)
  2. 阅读每个文件,找出实际成因:深层嵌套、承担多项无关工作的长函数、针对某种类型或状态的大型 switch/if 链,或实际上由多个模块拼接而成的文件
  3. 选择相应的策略:
    • 深层嵌套 → 使用守卫子句/提前返回,简化正常执行路径
    • 承担多项职责的长函数 → 按职责提取函数,并以其执行的操作命名
    • 针对固定的一组情况分支(类型、枚举、状态)→ 替换为查找表/映射;如果每种情况已有自己的类型,也可使用多态
    • 职责过多的文件 → 按实际边界拆分(每组导出放在一个文件中),不要随意按行数切割
  4. 每次重构一个文件;保持行为不变——这是一次复杂度处理,不是重写。阅读时如果发现重复代码克隆(步骤 1)或死分支(步骤 2),仍应在各自对应的步骤中处理,以便追踪每项更改的原因
  5. 对修改过的文件重新运行 --complexity,确认 cx 确实下降了——如果拆分后每个函数的分支数量没有减少,只是移动了代码,那就没有解决问题,只是给问题换了个位置

第 4 步 — 确认改进效果

npx jscpd --health --reporters ai <path>

将分数和等级与第 0 步的测量结果进行比较。如果某个维度变差了(比如,在提取共享复杂度修复时又出现了重复代码),这就是需要重新检查该步骤的信号,而不只是记录下来——重新运行相关检查(--summary、--dead-code、--complexity),而不是只相信一个汇总数字。

提示

  • 不要在尚未了解的代码库上直接运行全部三项检查,务必先查看 --dashboard——如果项目只有一个维度确实存在问题,却在三项检查上平均花费精力,就会在另外两个已经正常的维度上浪费时间
  • 如果项目已经在跟踪覆盖率、安全扫描结果等指标,可以将 --health-input 文件叠加到同一分数中;这不会改变工作流的任何内容,只会为第 0 步增加更多维度
  • 只有基于相同维度得出的两次运行的健康分数才可比较——如果文件组合发生变化,导致某个维度从 n/a 变为已测量(或反之),应说明这一点,而不要将原始分数差值解读为改进或退步
  • 分别提交每个步骤(修复重复代码、移除死代码、简化复杂度)——审核者要验证“这是否确实减少了 X”,需要查看范围限定在 X 上的差异

评论

支持 Markdown