/** * 契约副本工具:比对 / 同步 src/IShrimpType.ts 与 shrimp-server 那份。 * * node scripts/check-contract.mjs 比对,漂了就非零退出 * node scripts/check-contract.mjs --fix 从 shrimp-server 复制过来(自动保留前端副本的注释头) * * 为什么需要它:副本靠人工同步,漂了一整代都没被发现—— * 副本停在旧的 json 类型、缺 object/array/fields/item/parse/refs。 * 前端对未注册的字段类型静默回落到 string,所以漂移不报错、只悄悄渲染错。 * (同样是"改了就复制过去"的约定,goby 的 GobyClient.ts 四份拷贝已经全漂了, * 区别只在于那份复制后归消费侧拥有、漂了无所谓,而这份两边必须字节一致。) * * 只比对注释块之后的正文:两边的头部本来就该不同,一份是契约、一份声明自己是副本。 */ import { readFileSync, writeFileSync, existsSync } from "node:fs" import { fileURLToPath } from "node:url" import { dirname, resolve } from "node:path" const here = dirname(fileURLToPath(import.meta.url)) const mine = resolve(here, "../src/IShrimpType.ts") const fix = process.argv.includes("--fix") const argPath = process.argv.find(a => !a.startsWith("--") && a !== process.argv[0] && a !== process.argv[1]) const theirs = [ argPath && resolve(argPath, "src/IShrimpType.ts"), resolve(here, "../node_modules/shrimp-server/src/IShrimpType.ts"), resolve(here, "../../shrimp-server/src/IShrimpType.ts"), ].filter(Boolean).find(existsSync) if (!theirs) { // 消费侧的前端项目不装后端包,找不到是正常的,不该让它们的构建挂掉 console.log("skip: 找不到 shrimp-server 源码,无从比对") process.exit(0) } const split = f => { const s = readFileSync(f, "utf8") const i = s.indexOf("*/") + 2 return { head: s.slice(0, i), body: s.slice(i) } } const a = split(mine) const b = split(theirs) if (a.body === b.body) { console.log("✅ 契约副本与 shrimp-server 一致") process.exit(0) } if (fix) { writeFileSync(mine, a.head + b.body) console.log("✅ 已从 shrimp-server 同步契约副本(保留原注释头)") console.log(" " + theirs + "\n → " + mine) process.exit(0) } console.error("❌ 契约副本已漂移") console.error(" 副本: " + mine) console.error(" 契约: " + theirs) console.error(" 修法: npm run sync:contract") process.exit(1)