01394ed238
- 新增 scripts/check-generated-bindings.mjs 并接入 lint 与 ai-game-creator-shell:check:rust:crates:重跑 export_bindings 前后逐字节比对共享契约绑定。 - check:native-shells 的 AGC 边界改为负向门禁:渲染源码不得出现 fetch(/XHR/EventSource/sendBeacon/WebSocket/plugin-http,客户端 capability 不得授予 http:default。 - check-pingora-gateway-smoke 在 Windows 上找 pingora-gateway.exe,并修掉「API 并发保护」先关客户端连接再读响应的竞态。 - mobile-shell 三个 smoke 改成固定命令串启动 npm(绕开 npm.cmd EINVAL 与 DEP0190),desktop-shell 的 stage-release-binary 改用 fileURLToPath 修掉 F:\F:\… 路径拼接。 - vitest.config.ts 白名单补回现役根用例;三份 nginx 模板的 SPA allowlist 补回 /components 与 /design-system。
82 lines
2.4 KiB
JavaScript
82 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* 校验 ts-rs 生成的共享契约绑定与 Rust 声明一致。
|
|
*
|
|
* 做法是「重新生成一遍并与工作区现有内容逐字节比较」:只比 git diff 会漏掉「Rust 改了但
|
|
* 生成文件没重新跑」以外的情形,也很容易被本地未提交改动掩盖;比较生成前后快照更直接——
|
|
* 只要重新生成后的内容与现有内容不同,就说明仓库里的绑定是陈旧的。
|
|
*/
|
|
import { spawnSync } from 'node:child_process';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const repoRoot = path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
'..',
|
|
);
|
|
const generatedDir = path.join(
|
|
repoRoot,
|
|
'packages/shared/src/contracts/generated',
|
|
);
|
|
|
|
function snapshot() {
|
|
if (!fs.existsSync(generatedDir)) return new Map();
|
|
return new Map(
|
|
fs
|
|
.readdirSync(generatedDir, { withFileTypes: true })
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => [
|
|
entry.name,
|
|
fs.readFileSync(path.join(generatedDir, entry.name)),
|
|
]),
|
|
);
|
|
}
|
|
|
|
const before = snapshot();
|
|
const result = spawnSync(
|
|
'cargo',
|
|
[
|
|
'test',
|
|
'--locked',
|
|
'-p',
|
|
'shared-contracts',
|
|
'--features',
|
|
'ts-bindings',
|
|
'--manifest-path',
|
|
'server-rs/Cargo.toml',
|
|
'export_bindings',
|
|
],
|
|
{ cwd: repoRoot, encoding: 'utf8' },
|
|
);
|
|
if (result.status !== 0) {
|
|
console.error('生成绑定校验无法运行:export_bindings 未通过');
|
|
if (result.stdout) console.error(result.stdout.trim());
|
|
if (result.stderr) console.error(result.stderr.trim());
|
|
process.exit(result.status ?? 1);
|
|
}
|
|
const after = snapshot();
|
|
|
|
const problems = [];
|
|
for (const [name, content] of after) {
|
|
const previous = before.get(name);
|
|
if (!previous) problems.push(`新增 ${name}`);
|
|
else if (!previous.equals(content)) problems.push(`内容变化 ${name}`);
|
|
}
|
|
for (const name of before.keys()) {
|
|
if (!after.has(name)) problems.push(`删除 ${name}`);
|
|
}
|
|
|
|
if (problems.length > 0) {
|
|
console.error('生成绑定与 Rust 声明不一致:');
|
|
for (const problem of problems) console.error(` - ${problem}`);
|
|
console.error(
|
|
'请运行 `cargo test -p shared-contracts --features ts-bindings export_bindings`,并把重新生成的结果与 Rust 改动一并提交。',
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(
|
|
`生成绑定校验通过:${after.size} 个文件与 Rust 声明一致(${path.relative(repoRoot, generatedDir)})。`,
|
|
);
|