命令行工具
fallow-rs/fallow avatar
fallow-rs/fallow

fallow:一个不依赖 Node.js 的 TypeScript 代码库静态分析器

TypeScript 和 JavaScript 的代码库智能。免费静态分析代码和风格:未使用的代码、重复、循环依赖、复杂性热点、架构边界、设计系统漂移。可选的付费运行时层(Fallow Runtime):来自实际生产流量的热路径审查和冷路径删除证据。

4,506 个 Star158 个 ForkRustMIT

秒懂

它是什么?
fallow 用单一 Rust 二进制分析 TypeScript 与 JavaScript 代码库,覆盖未使用代码、循环依赖、重复、复杂度与设计系统漂移。它不调用 TypeScript 编译器,也不要求 Node.js 运行时,结果确定且输出为类型化 JSON。
适合谁用?
适合需要快速、确定性静态分析的中大型 TypeScript 或 JavaScript 代码库,尤其是 monorepo 和设计系统维护者。不适合需要精确类型信息或运行时行为证据的场景,也不适合期待零误报的团队。
能商用吗?
可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
还在维护吗?
在维护。仓库最近一次提交在 2 天前。
用什么语言写的?
主要是 Rust(依据 GitHub 的语言统计)。

以上回答依据项目的 GitHub 数据(最近同步于 2026年9月14日)和我们的分析,不构成法律意见。

开源项目深度解析

它解决的问题:删除代码的举证责任

大多数仓库里都有没人敢删的代码,因为删除意味着证明一个否定命题:这段代码没有被任何地方用到。fallow 的切入点就是这个痛点。它把整个仓库读成一个依赖图,从 import 边到样式 token,然后报告这个图显示的内容。目标用户是维护大型 TypeScript 或 JavaScript 代码库的工程师,尤其是 monorepo 和设计系统团队。免费层覆盖静态分析,付费层 Fallow Runtime 才引入生产流量证据,但静态部分是完整的。

机制:不跑 TypeScript 编译器,也不用 Node.js

fallow 的核心设计是不依赖 TypeScript 编译器或 Node.js 运行时。这意味着它用 Rust 自己解析语法,构建依赖图。文档明确说分析器内部没有 AI,结果是确定性的:相同输入产生相同输出,带稳定指纹。这个设计选择有直接后果。一方面,启动快,适合 CI 门禁;另一方面,它默认做的是语法级分析,而不是类型级分析。可选的 --type-aware 参数会引入基于 checker 的 TypeScript 证据,用于精确符号使用、跨文件私有类型泄漏和公共签名耦合,但文档警告这个模式更慢。所以 fallow 的定位是快速扫描,而不是类型系统的替代品。

安装与首次运行:零配置起步,但有例外

安装方式很多。最简单的是一行命令:npx fallow,它会走完整流程,包括死代码、重复和健康度。作为 devDependency 安装用 npm install --save-dev fallow。npm 包自带 fallow、fallow-lsp 和 fallow-mcp 三个启动器,以及版本匹配的 agent skill,这样编辑器集成会解析项目本地的二进制,而不是 PATH 上随便什么版本。首次运行通常会有发现,但文档说这多半意味着 fallow 漏了入口点或框架约定,或者正在分析生成文件。生成文件通常需要手动提示,配置里用 ignorePatterns,例如 ["**/*.generated.ts"]。你不必手写配置,npx fallow recommend 会检测技术栈并打印建议配置,它只读且总是退出 0。配置优先级是首个匹配生效,不合并:.fallowrc.json 大于 .fallowrc.jsonc 大于 fallow.toml 大于 .fallow.toml。

audit 门禁:只检查改动文件,退出码有讲究

fallow audit 是面向 PR 的门禁命令,只审计变更的文件。README 里有个 vitest monorepo 的例子,审计最近 15 个提交,19 个变更文件,发现 156 个死代码问题、6 个复杂度发现、8 个克隆组,耗时 1.05 秒。这个例子展示了继承发现的设计:163 个继承发现被默认排除,所以门禁通过。要强制检查全部,用 --gate all。退出码语义很明确:0 和 1 都表示运行成功,1 表示有发现,2 才是真正的错误,错误会作为 JSON 信封输出到 stdout。配合 --format json --quiet 可以喂给脚本。这个设计对 CI 友好,但注意默认排除继承发现意味着旧债不会阻塞新改动,这既是优点也是风险。

分析范围:从死代码到设计系统漂移

fallow 报告的内容超过常见的死代码和循环依赖。它覆盖未使用的文件、导出、类型、枚举和类成员,还有依赖本身。循环依赖和再导出循环被归入 dead-code 命令。重复检测用后缀数组算法,覆盖 JS/TS 和 CSS 家族样式表,以及 Vue、Svelte、Astro 组件区域。复杂度热点和 0 到 100 的健康度评分带字母等级。架构边界检查有 bulletproof、layered、hexagonal、feature-sliced 四种预设。设计系统样式漂移针对 CSS 和 CSS-in-JS。还有自动修复,带 dry-run 预览。可选的 security 命令按入口点的可达性排序安全候选。超过 100 个内置框架插件自动检测入口点和框架消费的导出,所以第一次运行不需要配置。这个范围在静态分析工具里算相当广。

局限性与失败模式:语法分析的边界

fallow 的确定性来自语法分析,但这也是它的边界。文档明确列出默认语法分析和可选类型感知分析的局限。没有类型信息,某些未使用代码的判断可能不准。例如一个导出只被类型位置引用,语法分析可能误报。生成文件是另一个常见失败点,需要手动 ignorePatterns。还有类似代码检测,它用固定本地模型,需要显式审查,这说明它不保证语义等价,只是候选。如果你需要精确到类型层面的证据,必须接受 --type-aware 的额外耗时。另外,静态分析永远无法证明运行时行为,这正是 Fallow Runtime 存在的理由,但那是付费层。对纯静态需求,fallow 可能过于激进或过于保守,取决于你的代码风格。

替代方案:与 TypeScript 编译器生态的对比

最直接的替代是 TypeScript 编译器自带的工具链,比如 tsc --noEmit 配合 ts-prune 或 ts-morph 脚本。这些工具运行在 Node.js 上,利用 TypeScript 的语义信息,能识别类型位置引用,误报率通常更低。但它们慢,而且每个工具只解决一个问题。另一个方向是 knip,它专门做未使用代码检测,也基于 TypeScript 编译器,支持 monorepo。knip 的差异在于它需要 Node.js 环境,而 fallow 是独立二进制。如果你已经在 CI 里有 Node.js,knip 可能更精准;如果你想要一个不依赖运行时、覆盖多种分析类型的工具,fallow 更合适。复杂度分析方面,ESLint 的 complexity 规则是常见选择,但它只覆盖函数复杂度,不构建整个依赖图。

维护与升级成本:版本节奏和许可证

fallow 的发布节奏很快。近期版本包括 v3.20.0 加入 Yarn PnP 解析和 monorepo tsconfig 作用域,v3.19.0 加入单次 agent 安装和 MCP 资源,v3.18.0 改进了图准确性和诊断一致性。这种节奏意味着新功能持续进入,但升级时需要关注 review schema 版本,v3.20.0 提到了 review schema 8,说明输出契约会演进。许可证是 MIT,没有使用限制。但注意 Fallow Runtime 是付费层,虽然静态分析免费,运行时证据需要订阅。维护成本主要在配置调优,特别是 ignorePatterns 和边界预设。由于结果确定性,回归测试容易做,但每次升级后应重新跑一次 audit 确认没有行为变化。

编辑结论

适合需要快速、确定性静态分析的中大型 TypeScript 或 JavaScript 代码库,尤其是 monorepo 和设计系统维护者。不适合需要精确类型信息或运行时行为证据的场景,也不适合期待零误报的团队。采用前应先用 npx fallow recommend 生成配置,检查 ignorePatterns 是否覆盖了生成文件,再在 CI 中试跑 fallow audit 观察误报率。若需要类型感知分析,明确接受 --type-aware 的额外耗时。最终决定应基于一次真实仓库的试运行结果,而不是功能列表。

官方来源

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
社区笔记

社区笔记