From 5ada90e08348254c36af2b84edc6a61be9dc4fb0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 26 Jul 2026 11:09:12 +0000 Subject: [PATCH] =?UTF-8?q?fix(bds-tools):=20=E6=81=A2=E5=A4=8D=20scanDest?= =?UTF-8?q?Occupancy=20=E2=86=92=20readPackDirOccupancy=EF=BC=88=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E6=8D=9F=E5=9D=8F=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #80/#81 合并后 facts 声明与旧 uuid/version 赋值体拼在一起,tsc 构建失败并阻断 ootb / changeset-release。恢复 DRY 调用并补占用扫描回归测。 Co-authored-by: Shiroha --- .changeset/fix-scan-dest-occupancy-merge.md | 5 +++ bds-tools/src/world-packs.ts | 18 ++------ bds-tools/world-packs.test.mjs | 48 +++++++++++++++++++++ 3 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 .changeset/fix-scan-dest-occupancy-merge.md diff --git a/.changeset/fix-scan-dest-occupancy-merge.md b/.changeset/fix-scan-dest-occupancy-merge.md new file mode 100644 index 0000000..ed6e42e --- /dev/null +++ b/.changeset/fix-scan-dest-occupancy-merge.md @@ -0,0 +1,5 @@ +--- +"@sfmc-bds/bds-tools": patch +--- + +修复 #80/#81 合并后 `scanDestOccupancy` 未赋值 `facts`、引用未声明标识符导致 tsc 构建失败;恢复经 `readPackDirOccupancy` 的 DRY 占用扫描。 diff --git a/bds-tools/src/world-packs.ts b/bds-tools/src/world-packs.ts index 1ac04ba..2659b4b 100644 --- a/bds-tools/src/world-packs.ts +++ b/bds-tools/src/world-packs.ts @@ -566,7 +566,7 @@ export type PackInstallPlan = /** * 读单目录占用事实(info 优先,否则 header)。 - * Utf8BomError 上抛,由调用方决定跳过或仍占文件夹名。 + * 解析失败返回 null;不抛 BOM(readJsonFile 已剥离)。 */ export function readPackDirOccupancy(dir: string): { uuid: string; @@ -590,24 +590,14 @@ export function readPackDirOccupancy(dir: string): { return null; } -/** 扫描 destParent 下含 manifest 的目录占用 */ +/** 扫描 destParent 下含 manifest 的目录占用(单一事实源:readPackDirOccupancy) */ export function scanDestOccupancy(destParent: string): DestOccupancy[] { const out: DestOccupancy[] = []; for (const dir of listPackDirsIn(destParent)) { let facts: ReturnType = null; try { - const info = readPackManifestInfo(dir); - if (info) { - uuid = info.uuid; - version = info.version; - name = info.name; - } else { - const header = readPackManifestHeader(dir); - if (header) { - uuid = header.uuid; - version = header.version; - } - } + // DRY:与 readPackDirOccupancy 共用 info→header 回退,禁止内联双读 + facts = readPackDirOccupancy(dir); } catch { /* manifest 不可读则占位 uuid 为空 */ } diff --git a/bds-tools/world-packs.test.mjs b/bds-tools/world-packs.test.mjs index 0a734f7..67caf3a 100644 --- a/bds-tools/world-packs.test.mjs +++ b/bds-tools/world-packs.test.mjs @@ -283,6 +283,54 @@ describe("world-packs primitives", () => { assert.deepEqual(version, [2, 0, 1]); }); + it("scanDestOccupancy / readPackDirOccupancy:完整与残缺 manifest", async () => { + const { scanDestOccupancy, readPackDirOccupancy, formatWorldPackFolderName } = await import( + "./dist/world-packs.js" + ); + const parent = path.join(tmp, "occupancy-scan"); + const fullName = formatWorldPackFolderName("Full", "resource"); + const brokenName = formatWorldPackFolderName("Broken", "behavior"); + const fullDir = path.join(parent, fullName); + const brokenDir = path.join(parent, brokenName); + writeManifest(fullDir, { + name: "Full Pack", + uuid: "11111111-1111-1111-1111-111111111111", + version: [2, 3, 4], + type: "resources", + }); + fs.mkdirSync(brokenDir, { recursive: true }); + fs.writeFileSync( + path.join(brokenDir, "manifest.json"), + JSON.stringify({ + format_version: 2, + header: { + name: "Broken Pack", + uuid: "22222222-2222-2222-2222-222222222222", + version: [9, 0, 1], + }, + modules: [], + }) + ); + + const fullFacts = readPackDirOccupancy(fullDir); + assert.equal(fullFacts?.uuid, "11111111-1111-1111-1111-111111111111"); + assert.deepEqual(fullFacts?.version, [2, 3, 4]); + assert.equal(fullFacts?.kind, "resource"); + + const brokenFacts = readPackDirOccupancy(brokenDir); + assert.equal(brokenFacts?.uuid, "22222222-2222-2222-2222-222222222222"); + assert.deepEqual(brokenFacts?.version, [9, 0, 1]); + assert.equal(brokenFacts?.kind, undefined); + + const occ = scanDestOccupancy(parent); + assert.equal(occ.length, 2); + const byFolder = Object.fromEntries(occ.map((o) => [o.folderName, o])); + assert.equal(byFolder[fullName]?.uuid, "11111111-1111-1111-1111-111111111111"); + assert.equal(byFolder[fullName]?.kind, "resource"); + assert.equal(byFolder[brokenName]?.uuid, "22222222-2222-2222-2222-222222222222"); + assert.equal(byFolder[brokenName]?.kind, undefined); + }); + it("decidePackInstallPlan 表驱动", async () => { const { decidePackInstallPlan, formatWorldPackFolderName } = await import("./dist/world-packs.js"); const uuidA = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa";