// 游戏合集的文案必须是**它自己那个游戏**的——产物里不许出现别家的标题。 // // 这条门禁来自一个真实缺陷:addGame 曾经把 title 取全局 meta(那一层是给「全部合集」写的), // 于是 collection-ys 顶着《崩坏:星穹铁道》昔涟。三条断言都只看产物,不看实现: // ① 前置条件:dist/releases 必须存在。否则"一个分发都没有"会被当成通过(空验证比不验证更危险)。 // ② 游戏合集的 title 必须提到本游戏的显示名,且逐字等于 wallpapers/<游戏id>/meta.json 的 title。 // ③ 全部合集 collection-all 的 title 必须来自 wallpapers/meta.json。 // // 前置:先 `pnpm build`(只用产物与源数据,不需要服务器)。 import { existsSync, readFileSync, readdirSync } from "node:fs"; import { join } from "node:path"; const RELEASES = "dist/releases"; if (!existsSync(RELEASES)) { console.error(`前置条件不满足:${RELEASES} 不存在。先跑 pnpm build。`); process.exit(1); } let failures = 0; const check = (ok: boolean, label: string, detail?: string): void => { if (!ok) failures++; console.log(` ${ok ? "✓" : "✗"} ${label}${detail !== undefined ? ` → ${detail}` : ""}`); }; const readJson = (path: string): Record => JSON.parse(readFileSync(path, "utf8")) as Record; const str = (value: unknown): string => (typeof value === "string" ? value : ""); const globalMeta = readJson("wallpapers/meta.json"); const releases = readdirSync(RELEASES).filter((name) => name.startsWith("collection-")); let checkedGames = 0; for (const dir of releases) { const projectPath = join(RELEASES, dir, "project.json"); if (!existsSync(projectPath)) { check(false, `${dir} 缺少 project.json`); continue; } const project = readJson(projectPath); const gameId = dir.slice("collection-".length); if (gameId === "all") { check(str(project.title) === str(globalMeta.title), "collection-all 的 title 来自全局 meta", str(project.title)); continue; } const gameMetaPath = `wallpapers/${gameId}/meta.json`; if (!existsSync(gameMetaPath)) { check(false, `${dir} 找不到对应的 ${gameMetaPath}`); continue; } const gameMeta = readJson(gameMetaPath); checkedGames++; check( str(project.title) === str(gameMeta.title), `${dir} 的 title 逐字等于它自己游戏的 title`, `产物 ${str(project.title) || "(空)"} / 源 ${str(gameMeta.title) || "(未声明)"}`, ); check( str(project.title).includes(str(gameMeta.name)), `${dir} 的 title 提到了本游戏「${str(gameMeta.name)}」`, str(project.title), ); if (gameMeta.description !== undefined) { check(str(project.description) === str(gameMeta.description), `${dir} 的 description 用的是游戏级声明`); } } // 数量断言:目录命名一变(比如以后换成别的前缀),上面整个循环会静默变成空验证。 check(checkedGames > 0, "至少检查到一个游戏合集", `实际 ${checkedGames} 个`); console.log(failures === 0 ? "\n游戏合集文案归属:通过" : `\n游戏合集文案归属:失败 ${failures} 处`); process.exit(failures === 0 ? 0 : 1);