momiji-rs/oxidecop
GitHub: momiji-rs/oxidecop
OxideCop 是一款基于 Rust 和 Prism 解析器的 Ruby 代码检查与自动修复工具,旨在以极快的原生速度提供与 RuboCop 逐字节兼容的 lint 体验。
Stars: 0 | Forks: 0
# OxideCop
一款快速、原生且 **兼容 RuboCop** 的 Ruby linter 和 autocorrector —— 使用 Rust 编写,基于官方的 [Prism](https://github.com/ruby/prism) parser。可以把它看作 *ruff 的 Ruby 版,并且与大家已经在用的 RuboCop 保持 bug 级别的兼容。*
```
cargo install oxidecop
oxidecop . # same offenses, same messages, same exit code — just fast
```
## 为什么选择 OxideCop
RuboCop 是事实上的标准 Ruby linter,但它运行在 CRuby 上,且**在解释型的 `parser` gem 中,解析时间占据了主导地位**。一个能够处理 Prism 的原生 linter 速度要快上一个数量级,同时能产生**逐字节一致的输出**,因此它可以零配置改动地直接接入现有项目。
只有当我们对 **RuboCop 的实际行为保持绝对忠诚**(而不是仅仅是“本质上的等效”)时,这个赌注才会奏效。这就是为什么保真度是对照 RuboCop *自己的* 测试套件来衡量的,而不是靠肉眼观察:
| | |
|---|---|
| 整个 tree lint,Rails(约 3,400 个文件) | **57 ms** |
| 对比 [oxicop](https://crates.io/crates/oxicop)(基于 regex,无 parser) | 快 2–5 倍 — 并且在 oxicop 误报数千个问题的地方能得出正确结果 |
| 对比 [nitrocop](https://github.com/6/nitrocop)(基于 prism,915 个 cops) | 冷启动快 4–31 倍;在 RuboCop 自己的 CI-clean repo 中,它报告了 17,174 个 offenses,而 OxideCop 报告了真正的零 |
| 热重跑(没有任何改动) | **~29 ms**(基于 stat 键入的结果缓存,无文件读取) |
## 可量化的保真度
RuboCop 的 spec 套件内联了确切的预期结果:
```
expect_offense(<<~RUBY)
x == nil
^^ Prefer the use of the `nil?` predicate.
RUBY
```
**oracle** (`oracle/oracle.rb`) 会解析这些 fixtures,在*该示例自己的* `cop_config` 下,通过 `oxidecop` 二进制文件运行去除了注释的源码,并在三个层级上进行 diff:**LOC**(正确的 line:col),**FULL**(line:col *以及* 相同的消息),和 **FIX**(对照 `expect_correction` 的 `--fix` 输出)。
当前的排行榜(`ruby oracle/leaderboard.rb`),对照 RuboCop v1.88.0:
```
47 cops implemented — every one at 100% FULL match, 100% FIX (autocorrect).
TOTAL (representable examples) 1051 108 1051/1051 100% FIX 477/477
```
**客观解读:** 该分数仅针对*可表示的*示例计算。RuboCop 的 specs 动态编码了一些文本(RSpec 循环变量,`%{identifier}` 替换,在调用者配置下运行的 `shared_examples`);oracle 会渲染静态内容并**跳过**非静态内容,而不是将测试套件的限制计为 cop 的遗漏 —— 因此有了 `skip` 列。
在端到端测试中,`tools/parity.sh ` 会使用两个 linter 对同一个 tree 进行 lint(两者都在 `--only` 下使用已实现的 cop 列表,RuboCop 会强制启用它们),并对标准化后的 offense 列表进行 diff。在所有四个语料库上实现了逐字节一致:**Rails(12,271 行 offense),Mastodon(4,123),rubygems.org(772),以及 RuboCop 自己的 1,712 个文件的源码 tree(0 对 0)**。CI 在每次推送时都会重新验证 oracle 是否达到 100% 以及一致性。
## 用法
```
oxidecop lib/ spec/ # lint trees in parallel (nearest .rubocop.yml per file)
oxidecop file.rb my.yml # explicit config
oxidecop -a . # autocorrect in place (like rubocop -a)
oxidecop file.rb --fix # autocorrect a single file -> stdout
oxidecop --only Style/SymbolProc --format json .
```
输出模仿了 RuboCop 的 simple formatter(严重性字母,`[Correctable]` 标签,遵守每个 cop 的 `Severity` 配置);`--format json` 会输出兼容 RuboCop 的 JSON。当发现 offenses 时,退出代码为 1。
配置支持涵盖了实际项目会使用的常用功能:`.rubocop.yml` 发现(每个文件查找最近的配置),`inherit_from` 链,`inherit_gem`,`AllCops: DisabledByDefault / Exclude / Include`,每个 cop 的 `Enabled` / `Exclude` / `EnforcedStyle` / `AllowedMethods` / `AllowedPatterns`(包括 `!ruby/regexp`),magic-comment `rubocop:disable` 指令(带有 `-- reason` 尾部说明),以及 `TargetRubyVersion`。**所有 606 个 cops** 的参数默认值都是从 RuboCop 自己的 `config/default.yml` 生成到一个 schema 表中的,因此新移植的 cop 的默认值已经是正确的。
结果缓存(基于 stat 键入,content-hash 后备机制)使得未更改 tree 的重新运行速度提高了约 2 倍;`--cache false` 可以禁用它。
## Repo 布局
```
src/main.rs the runner: argv, file/config discovery, output, --fix loop
src/config.rs .rubocop.yml subset + the generated per-cop SCHEMA
src/declarative.rs the DECLARATIVE pattern-cop table (node-pattern rows)
src/nodepattern.rs RuboCop's node-pattern DSL, parsed and matched over Prism
src/cops/ the visitor + per-department cop logic
src/cops/breakable.rs Layout/LineLength autocorrection (CheckLineBreakable port)
oracle/ the spec-suite oracle + leaderboard (fidelity measurement)
tools/parity.sh whole-tree byte-identical diff vs reference RuboCop
bench/compare.sh the speed scoreboard vs competing linters
```
## 如何添加 / 改进 cop
1. **找到 RuboCop 的真实模式。** 从 RuboCop 的源码中*逐字*复制 `def_node_matcher` 字符串和 `MSG` —— 不要改写。(主观猜测的模式通常会过于宽泛;oracle 每次都能捕捉到这一点。)
2. **表达它。** 一个 pattern cop -> `DECLARATIVE` 表中的一行。一个 logic cop -> 一个小型的 `Visit` 方法。如果 DSL 还不能表达该模式,请扩展 `src/nodepattern.rs`。
3. **衡量。** 将 cop 映射到 `oracle/leaderboard.rb` 中的 spec,运行它 —— 遗漏列表就是你精确的 TODO,一直到具体的失败示例。
4. **端到端验证。** 针对真实 tree 的 `tools/parity.sh` 必须保持逐字节一致。
## Roadmap
- **拓宽范围**:移植下一层级的 cops(schema 和 node-pattern DSL 已经覆盖了它们的配置面)。
- **分发**:预编译二进制文件,`brew install oxidecop`。
- **缩小热重跑差距**:缓存目录遍历,将无更改的重跑时间从 ~29 ms 缩短至接近 ~5 ms。
## License
MIT — 详见 [LICENSE](https://github.com/momiji-rs/oxidecop/blob/master/LICENSE)。
OxideCop 与 RuboCop 项目无隶属关系;RuboCop 是其作者和贡献者的作品,而这个项目的存在是为了忠实于它。
标签:Apache Flink, AST解析, Ruby, Rust, SOC Prime, 云安全监控, 代码规范检查, 可视化界面, 开发工具, 知识库, 网络流量审计, 通知系统, 静态分析