修复:生成绑定校验不再用 prettier 改写生成文件
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m54s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m36s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 4m44s
Project CI / Backend tests (pull_request) Successful in 5m46s
Project CI / Frontend tests (pull_request) Successful in 2m50s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m41s
Project CI / Native shell tests (pull_request) Successful in 6m39s
Project CI / Repository checks (pull_request) Successful in 6m12s

- scripts/check-generated-bindings.mjs:删掉生成后的 prettier 归一化,直接逐字节比较 ts-rs 原始输出
- .prettierignore 与 .eslintrc.cjs:四个 ts-rs 生成目录统一排除,禁止格式化工具二次改写
- .prettierrc.json:删除 contracts/generated 的 printWidth / singleQuote 覆盖
- .gitattributes:生成目录标 linguist-generated 并豁免 trailing-space,保证 git diff --check 通过
- 重新生成 AGC chat/generated 与 services/generated 的 51 个绑定,改为提交 ts-rs 原始输出(纯格式,语义不变)
- docs/project-memory:记录生成绑定不再经 prettier 的口径,修正旧流程说明
This commit is contained in:
2026-10-03 15:40:21 +08:00
parent 141e59c971
commit 0e313405d6
60 changed files with 240 additions and 455 deletions
+9 -33
View File
@@ -6,13 +6,13 @@
* 生成文件没重新跑」以外的情形,也很容易被本地未提交改动掩盖;比较生成前后快照更直接——
* 只要重新生成后的内容与现有内容不同,就说明仓库里的绑定是陈旧的。
*
* 覆盖两套 crate、三个目录:
* - `shared-contracts` → `packages/shared/src/contracts/generated`(原样落盘);
* - AGC shell → `chat/generated` + `services/generated`(随仓库统一走 prettier)。
* 覆盖两套 crate、四个目录:
* - `shared-contracts` → `packages/shared/src/contracts/generated`;
* - AGC shell → `chat/generated` + `services/generated` + `features/ui-editor/types`。
*
* AGC 那两个目录是 prettier 格式化过的,而 ts-rs 输出的是双引号、不换行的原始形态;所以
* 重生成后要按仓库格式再跑一遍 prettier 才能比较,否则每次都会报"格式不同"的假漂移。
* 格式化范围只限这两个生成目录,不碰其它源码。
* 生成文件一律以 ts-rs 原始输出提交,不接受 prettier / eslint 等工具二次改写:这些目录
* 同时登记在 `.prettierignore` 与 `.eslintrc.cjs` 的 `ignorePatterns`,所以这里直接逐字节
* 比较原始输出即可,不需要(也不允许)再跑格式化。
*/
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
@@ -24,14 +24,10 @@ const repoRoot = path.resolve(
'..',
);
// Windows 上 `npx` 以 `npx.cmd` 落地,`spawnSync` 不带 shell 时解析不到(ENOENT)。
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
const SHARED_CONTRACTS_DIR = 'packages/shared/src/contracts/generated';
const AGC_CHAT_DIR =
'apps/ai-game-creator-shell/src/view/project-development/chat/generated';
const AGC_SERVICES_DIR = 'apps/ai-game-creator-shell/src/services/generated';
// ui-editor 的绑定在 `.prettierignore` 里,ts-rs 原始输出就是提交形态,不需要再格式化。
const AGC_UI_EDITOR_DIR =
'apps/ai-game-creator-shell/src/features/ui-editor/types';
@@ -51,7 +47,6 @@ const targets = [
'server-rs/Cargo.toml',
'export_bindings',
],
formatDirs: [],
hint: 'cargo test --locked -p shared-contracts --features ts-bindings --manifest-path server-rs/Cargo.toml export_bindings',
},
{
@@ -64,10 +59,7 @@ const targets = [
'apps/ai-game-creator-shell/src-tauri/Cargo.toml',
'export_bindings',
],
// ts-rs 落盘后按仓库格式跑一遍 prettier,比较的才是"提交时应有的内容"
// (ui-editor 的绑定被 `.prettierignore` 忽略,不在里面)。
formatDirs: [AGC_CHAT_DIR, AGC_SERVICES_DIR],
hint: 'cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings && npx prettier --write apps/ai-game-creator-shell/src/view/project-development/chat/generated apps/ai-game-creator-shell/src/services/generated',
hint: 'cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings',
},
];
@@ -92,8 +84,8 @@ function snapshot(dir) {
}
function run(command, args) {
// Windows 上 `.cmd` / `.bat` 不带 shell 无法执行(Node 修 CVE-2024-27980 后直接 EINVAL),
// `npx.cmd` 也不例外;仓库既有脚本统一用 `shell: process.platform === 'win32'`。
// Windows 上 `.cmd` / `.bat` 不带 shell 无法执行(Node 修 CVE-2024-27980 后直接 EINVAL);
// 仓库既有脚本统一用 `shell: process.platform === 'win32'`。
const result = spawnSync(command, args, {
cwd: repoRoot,
encoding: 'utf8',
@@ -134,22 +126,6 @@ for (const target of targets) {
if (result.stderr) console.error(result.stderr.trim());
continue;
}
if (target.formatDirs.length > 0) {
const formatted = run(npxCommand, [
'prettier',
'--write',
...target.formatDirs,
]);
if (formatted.status !== 0) {
failed = true;
console.error(
`生成绑定校验无法运行:${target.label} 的 prettier 格式化失败`,
);
if (formatted.stdout) console.error(formatted.stdout.trim());
if (formatted.stderr) console.error(formatted.stderr.trim());
continue;
}
}
const after = new Map(
target.dirs.flatMap((dir) => [...snapshot(dir).entries()]),
);