原来只有 `apps/web` 在 Prettier 下(配置在 `apps/web/.prettierrc.toml`、脚本在 web 的 package.json),后端和契约从来没格式化过 —— 手写在 100 列上下,`db/schema.ts` 还是 drizzle-kit pull 留下的 tab 缩进。两套口径分叉久了,跨端改一处就得记着「这边 什么风格」。 - 配置搬到根目录 `.prettierrc.toml`,内容不变(`semi=false`,其余全默认, printWidth 80 —— 和前端已有的格式一致,不另立一套宽度); - 脚本统一成根目录 `bun run fmt`,覆盖 `apps/*/src`、`apps/web/tests` 和两个构建 配置;web 自己那份 `fmt` 和重复的 prettier 依赖删掉; - `.prettierignore` 挡掉两类不该碰的:drizzle-kit 生成的 `src/db/meta/` 结构快照 (它是 db:generate 的比对输入,只该由 drizzle-kit 写)、unplugin 每次 dev 都会 重写的 `auto-imports.d.ts` / `components.d.ts`; - 全量跑了一遍。纯格式,无行为改动:api typecheck / check:routes / check:ast、 前端 type-check 全过,起 api 打了接口确认正常。前端这 39 个文件的小改动是 prettier 版本漂移(类型断言的换行口径变了),不是新配置带来的。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## check:ast 判题机拿 target 的 node 去比 tree-sitter 节点类型,**对不上不报错**:collectNodes 一个 都收不到,于是「必须使用 X」永远失败、「不能使用 X」永远通过,两头不报错,只有学生 受着。上一个提交把两张表合成一张,杜绝了「漏配」,但「配错」照样静默 —— 所以加一个 检查,逐个 target 去问语法:这个节点类型你到底有没有。 bun run --filter '@oj2/api' check:ast 升级 tree-sitter-* 之后必须跑:语法改节点名是常事,后果全静默。它只验节点类型存在, 不验语义对不对(把 while_loop 配成 for_statement 这种两个都存在,机器看不出来)。 ## 它抓出来的那个 56 个 target 里坏了一个:Python3 的 f_string 一直配的是 format_string,而这个版本的 tree-sitter-python **根本没有这种节点** —— f-string 是一个 string,靠 string_start 为 f" 和内部的 interpolation 子节点来认。也就是说「不能使用 f-string」这条规则从上线起 就一直判成通过,「必须使用 f-string」一直判成失败。 改成 interpolation。实测:带占位符的 f-string(单双引号都有)命中,而 % 格式化、 .format()、普通字符串、字符串拼接都不误伤。代价是 f"abc" 这种没有占位符的 f-string 认不出来 —— 它确实不含 interpolation,但没占位符的 f-string 本来也没意义,比起原来 「一个都认不出来」是严格的改善。这条写在表里的注释上了。 ## 验证 给题目 1004 配「必须有 for 循环 + 不能用 f-string」两条规则实跑: - 有 for、用了 f-string → 修复前 ACCEPTED(0),修复后 AST_CHECK_FAILED(10), ast_results 为「必须使用 for 循环/通过」「不能使用 f-string/不通过」; - 有 for、不用 f-string → ACCEPTED(0); - check:ast 修复前 exit 1 并指出这一条,修复后 56 个全过、exit 0。 tsc、check:routes、vue-tsc、vite build、单二进制编译均通过。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012j1vgeDqay8wKCh8dPgPcH