diff --git a/.changeset/build-deps-world-packs-solid.md b/.changeset/build-deps-world-packs-solid.md index a0a50ab..21ae0f8 100644 --- a/.changeset/build-deps-world-packs-solid.md +++ b/.changeset/build-deps-world-packs-solid.md @@ -3,4 +3,4 @@ "@sfmc-bds/bds-tools": patch --- -发版:build-publishable 拓扑 + listPublishableBuildDeps(npm-publish 应急补发不再硬编码只 build SDK);push 缺失态 DRY 对齐 listUnpushedExistingVersionTags。世界包:readPackDirOccupancy DRY,去掉死不变式,occupancy 保留真实 kind(LSP)。 +发版:build-publishable 拓扑 + listPublishableBuildDeps(npm-publish 应急补发不再硬编码只 build SDK);push 缺失态 DRY 对齐 listUnpushedExistingVersionTags。世界包:readPackDirOccupancy DRY,去掉死不变式,occupancy 保留真实 kind(LSP)。修 #80/#81 合并冲突:scanDestOccupancy 须赋值 facts=readPackDirOccupancy,禁止残留未声明 uuid/version/name 赋值(否则 --dts 挂掉且 catch 吞掉 ReferenceError 导致占用 uuid 恒空)。 diff --git a/bds-tools/src/world-packs.ts b/bds-tools/src/world-packs.ts index 9201999..7e0411f 100644 --- a/bds-tools/src/world-packs.ts +++ b/bds-tools/src/world-packs.ts @@ -566,7 +566,8 @@ export type PackInstallPlan = /** * 读单目录占用事实(info 优先,否则 header)。 - * 解析失败返回 null;BOM 已由 readJsonFile 剥离,不再抛 Utf8BomError。 + * info/header 解析失败返回 null;BOM 已由 readJsonFile 剥离。 + * 其它异常上抛,由 scanDestOccupancy 决定仍占文件夹名(uuid 置空)。 */ export function readPackDirOccupancy(dir: string): { uuid: string; @@ -594,7 +595,13 @@ export function readPackDirOccupancy(dir: string): { export function scanDestOccupancy(destParent: string): DestOccupancy[] { const out: DestOccupancy[] = []; for (const dir of listPackDirsIn(destParent)) { - const facts = readPackDirOccupancy(dir); + let facts: ReturnType = null; + try { + // DRY:单目录占用只走 readPackDirOccupancy,禁止再内联一份 info/header 分支 + facts = readPackDirOccupancy(dir); + } catch { + /* manifest 不可读则占位 uuid 为空(#81 契约:扫描本身不因单目录失败而中断) */ + } out.push({ folderName: path.basename(dir), dir, diff --git a/bds-tools/world-packs.test.mjs b/bds-tools/world-packs.test.mjs index 08e2377..174eb21 100644 --- a/bds-tools/world-packs.test.mjs +++ b/bds-tools/world-packs.test.mjs @@ -283,52 +283,49 @@ 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); + 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: "11111111-1111-1111-1111-111111111111", - version: [2, 3, 4], + uuid: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + version: [2, 1, 0], type: "resources", }); - fs.mkdirSync(brokenDir, { recursive: true }); + const partialDir = path.join(dest, "[RP] Partial"); + fs.mkdirSync(partialDir, { recursive: true }); fs.writeFileSync( - path.join(brokenDir, "manifest.json"), + path.join(partialDir, "manifest.json"), JSON.stringify({ format_version: 2, header: { - name: "Broken Pack", - uuid: "22222222-2222-2222-2222-222222222222", - version: [9, 0, 1], + name: "Partial", + uuid: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", + version: [3, 0, 0], }, modules: [], }) ); const fullFacts = readPackDirOccupancy(fullDir); - assert.equal(fullFacts?.uuid, "11111111-1111-1111-1111-111111111111"); - assert.deepEqual(fullFacts?.version, [2, 3, 4]); + 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 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 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(parent); + const occ = scanDestOccupancy(dest); 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); + 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("decidePackInstallPlan 表驱动", async () => {