From 7c801625c28aa9a2bddf8cb401f5fcd65cc30775 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 26 Jul 2026 11:08:13 +0000 Subject: [PATCH] =?UTF-8?q?fix(bds-tools):=20=E6=81=A2=E5=A4=8D=20scanDest?= =?UTF-8?q?Occupancy=20=E8=B5=B0=20readPackDirOccupancy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #80 合入与 #81 BOM 契约冲突解决时留下半成品:声明了 facts 却仍写未声明的 uuid/version/name,导致 ootb / changeset-release 在 tsc7 --dts 阶段 TS2304 挂掉。恢复 DRY 单入口,并补占用扫描单测; 顺带同步 #84 后 package-lock 中 sdk/cli 的 beta.1 版本。 Co-authored-by: Shiroha --- .changeset/fix-scan-dest-occupancy-dry.md | 5 +++ bds-tools/src/world-packs.ts | 22 ++--------- bds-tools/world-packs.test.mjs | 45 +++++++++++++++++++++++ package-lock.json | 8 ++-- 4 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 .changeset/fix-scan-dest-occupancy-dry.md diff --git a/.changeset/fix-scan-dest-occupancy-dry.md b/.changeset/fix-scan-dest-occupancy-dry.md new file mode 100644 index 0000000..2753592 --- /dev/null +++ b/.changeset/fix-scan-dest-occupancy-dry.md @@ -0,0 +1,5 @@ +--- +"@sfmc-bds/bds-tools": patch +--- + +修复 #80 合入冲突残留:`scanDestOccupancy` 恢复走 `readPackDirOccupancy`(DRY),消除未声明标识符导致的 tsc7 构建失败。 diff --git a/bds-tools/src/world-packs.ts b/bds-tools/src/world-packs.ts index 1ac04ba..9201999 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 剥离,不再抛 Utf8BomError。 */ export function readPackDirOccupancy(dir: string): { uuid: string; @@ -590,27 +590,11 @@ 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; - } - } - } catch { - /* manifest 不可读则占位 uuid 为空 */ - } + const facts = readPackDirOccupancy(dir); out.push({ folderName: path.basename(dir), dir, diff --git a/bds-tools/world-packs.test.mjs b/bds-tools/world-packs.test.mjs index 0a734f7..10f8cd7 100644 --- a/bds-tools/world-packs.test.mjs +++ b/bds-tools/world-packs.test.mjs @@ -502,6 +502,51 @@ describe("world-packs primitives", () => { assert.equal(readPackManifestInfo(existingB)?.name, "Slash Blade v2b"); }); + it("scanDestOccupancy 走 readPackDirOccupancy(完整 + 残缺 header)", async () => { + const { scanDestOccupancy, readPackDirOccupancy } = await import("./dist/world-packs.js"); + const dest = path.join(tmp, "occupancy-dry"); + const fullDir = path.join(dest, "[RP] Full"); + writeManifest(fullDir, { + name: "Full Pack", + uuid: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + version: [2, 1, 0], + type: "resources", + }); + const partialDir = path.join(dest, "[RP] Partial"); + fs.mkdirSync(partialDir, { recursive: true }); + fs.writeFileSync( + path.join(partialDir, "manifest.json"), + JSON.stringify({ + format_version: 2, + header: { + name: "Partial", + uuid: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", + version: [3, 0, 0], + }, + modules: [], + }) + ); + + const fullFacts = readPackDirOccupancy(fullDir); + assert.equal(fullFacts?.uuid, "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"); + assert.deepEqual(fullFacts?.version, [2, 1, 0]); + assert.equal(fullFacts?.name, "Full Pack"); + assert.equal(fullFacts?.kind, "resource"); + + const partialFacts = readPackDirOccupancy(partialDir); + assert.equal(partialFacts?.uuid, "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"); + assert.deepEqual(partialFacts?.version, [3, 0, 0]); + assert.equal(partialFacts?.kind, undefined); + + const occ = scanDestOccupancy(dest); + assert.equal(occ.length, 2); + const byUuid = new Map(occ.map((o) => [o.uuid, o])); + assert.equal(byUuid.get("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")?.name, "Full Pack"); + assert.equal(byUuid.get("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")?.kind, "resource"); + assert.equal(byUuid.get("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb")?.version?.[0], 3); + assert.equal(byUuid.get("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb")?.name, undefined); + }); + it("installPackDirectory:残缺 manifest 占用目录时换名而非覆盖", async () => { const { installPackDirectory, formatWorldPackFolderName } = await import("./dist/world-packs.js"); const dest = path.join(tmp, "broken-parent"); diff --git a/package-lock.json b/package-lock.json index 11ba367..935e961 100644 --- a/package-lock.json +++ b/package-lock.json @@ -93,7 +93,7 @@ }, "modules/sdk/@sfmc-sdk": { "name": "@sfmc-bds/sdk", - "version": "0.2.0-beta.0", + "version": "0.2.0-beta.1", "license": "ISC", "engines": { "node": ">=22.13.0" @@ -4623,18 +4623,18 @@ "name": "@sfmc-bds/remote-controller", "version": "0.1.0", "dependencies": { - "@sfmc-bds/sdk": "^0.2.0-beta.0", + "@sfmc-bds/sdk": "^0.2.0-beta.1", "ws": "^8.21.1" } }, "sfmc": { "name": "@sfmc-bds/cli", - "version": "0.2.0-beta.0", + "version": "0.2.0-beta.1", "license": "ISC", "dependencies": { "@clack/prompts": "^1.7.0", "@sfmc-bds/bds-tools": "^0.2.0-beta.0", - "@sfmc-bds/sdk": "^0.2.0-beta.0", + "@sfmc-bds/sdk": "^0.2.0-beta.1", "chalk": "^5.4.1", "ws": "^8.21.1" },