@sfmc-bds/bds-tools 0.2.0-beta.1 → 0.2.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +663 -0
- package/dist/bds-manager.d.ts +16 -6
- package/dist/bds-manager.d.ts.map +1 -1
- package/dist/bds-manager.js +40 -65
- package/dist/bds-manager.js.map +2 -2
- package/dist/check-update.d.ts.map +1 -1
- package/dist/check-update.js +4 -6
- package/dist/check-update.js.map +2 -2
- package/dist/cli-pack-manager.js +0 -0
- package/dist/fsx.d.ts +2 -6
- package/dist/fsx.d.ts.map +1 -1
- package/dist/fsx.js +3 -14
- package/dist/fsx.js.map +2 -2
- package/dist/host-platform.d.ts +25 -0
- package/dist/host-platform.d.ts.map +1 -0
- package/dist/host-platform.js +50 -0
- package/dist/host-platform.js.map +7 -0
- package/dist/http.d.ts +49 -11
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js.map +2 -2
- package/dist/log.d.ts +2 -3
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +0 -1
- package/dist/log.js.map +2 -2
- package/dist/pack-manager-lifecycle.test.js +252 -0
- package/dist/pack-manager-lifecycle.test.js.map +7 -0
- package/dist/pack-manager.d.ts +24 -29
- package/dist/pack-manager.d.ts.map +1 -1
- package/dist/pack-manager.js +11 -5
- package/dist/pack-manager.js.map +2 -2
- package/dist/pack-update/bindings.d.ts +16 -0
- package/dist/pack-update/bindings.d.ts.map +1 -0
- package/dist/pack-update/bindings.js +69 -0
- package/dist/pack-update/bindings.js.map +7 -0
- package/dist/pack-update/config.d.ts +16 -0
- package/dist/pack-update/config.d.ts.map +1 -0
- package/dist/pack-update/config.js +146 -0
- package/dist/pack-update/config.js.map +7 -0
- package/dist/pack-update/config.test.js +75 -0
- package/dist/pack-update/config.test.js.map +7 -0
- package/dist/pack-update/deps.d.ts +28 -0
- package/dist/pack-update/deps.d.ts.map +1 -0
- package/dist/pack-update/deps.js +20 -0
- package/dist/pack-update/deps.js.map +7 -0
- package/dist/pack-update/index.d.ts +55 -0
- package/dist/pack-update/index.d.ts.map +1 -0
- package/dist/pack-update/index.js +72 -0
- package/dist/pack-update/index.js.map +7 -0
- package/dist/pack-update/providers/curseforge.d.ts +23 -0
- package/dist/pack-update/providers/curseforge.d.ts.map +1 -0
- package/dist/pack-update/providers/curseforge.js +229 -0
- package/dist/pack-update/providers/curseforge.js.map +7 -0
- package/dist/pack-update/providers/index.d.ts +16 -0
- package/dist/pack-update/providers/index.d.ts.map +1 -0
- package/dist/pack-update/providers/index.js +37 -0
- package/dist/pack-update/providers/index.js.map +7 -0
- package/dist/pack-update/service.d.ts +28 -0
- package/dist/pack-update/service.d.ts.map +1 -0
- package/dist/pack-update/service.js +570 -0
- package/dist/pack-update/service.js.map +7 -0
- package/dist/pack-update/types.d.ts +126 -0
- package/dist/pack-update/types.d.ts.map +1 -0
- package/dist/pack-update/types.js +8 -0
- package/dist/pack-update/types.js.map +7 -0
- package/dist/pack-update/version-policy.d.ts +81 -0
- package/dist/pack-update/version-policy.d.ts.map +1 -0
- package/dist/pack-update/version-policy.js +210 -0
- package/dist/pack-update/version-policy.js.map +7 -0
- package/dist/pack-update/version-policy.test.js +137 -0
- package/dist/pack-update/version-policy.test.js.map +7 -0
- package/dist/paths.d.ts +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +3 -5
- package/dist/paths.js.map +2 -2
- package/dist/process-probe.d.ts +34 -0
- package/dist/process-probe.d.ts.map +1 -0
- package/dist/process-probe.js +152 -0
- package/dist/process-probe.js.map +7 -0
- package/dist/process-probe.test.js +76 -0
- package/dist/process-probe.test.js.map +7 -0
- package/dist/qq-events-notify.d.ts +16 -0
- package/dist/qq-events-notify.d.ts.map +1 -0
- package/dist/qq-events-notify.js +70 -0
- package/dist/qq-events-notify.js.map +7 -0
- package/dist/qqutil.d.ts +10 -5
- package/dist/qqutil.d.ts.map +1 -1
- package/dist/qqutil.js +49 -8
- package/dist/qqutil.js.map +2 -2
- package/dist/upstream.d.ts +18 -9
- package/dist/upstream.d.ts.map +1 -1
- package/dist/upstream.js +8 -7
- package/dist/upstream.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +2 -2
- package/dist/world-packs.d.ts +98 -7
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +129 -57
- package/dist/world-packs.js.map +2 -2
- package/dist/world-packs.test.js +676 -0
- package/dist/world-packs.test.js.map +7 -0
- package/dist/zipx.test.js +36 -0
- package/dist/zipx.test.js.map +7 -0
- package/package.json +43 -39
package/dist/world-packs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { copyDirAsync, readJsonFile
|
|
4
|
+
import { copyDirAsync, readJsonFile } from "./fsx.js";
|
|
5
5
|
import {
|
|
6
6
|
bdsWorldLevelDir,
|
|
7
7
|
bdsWorldsDir,
|
|
@@ -32,15 +32,13 @@ function isGenericPackFolderStem(rawName) {
|
|
|
32
32
|
if (s.length <= 2) return true;
|
|
33
33
|
return /^(bp|rp|b|r|pack|packs|behavior|behaviours?|resource|resources)$/i.test(s);
|
|
34
34
|
}
|
|
35
|
-
function
|
|
35
|
+
function allocatePackFolderName(opts) {
|
|
36
36
|
const hint = opts.hint && opts.hint.trim() || "";
|
|
37
37
|
const preferred = isGenericPackFolderStem(hint) ? opts.info.name || hint || "pack" : hint;
|
|
38
38
|
let folderName = formatWorldPackFolderName(preferred, opts.info.kind);
|
|
39
39
|
const allow = opts.allowFolderName ? path.basename(opts.allowFolderName) : null;
|
|
40
40
|
if (allow && folderName === allow) return folderName;
|
|
41
|
-
const taken = new Set(
|
|
42
|
-
listPackDirsIn(opts.destParent).map((d) => path.basename(d)).filter((n) => n !== allow)
|
|
43
|
-
);
|
|
41
|
+
const taken = new Set([...opts.takenFolderNames].filter((n) => n !== allow));
|
|
44
42
|
if (!taken.has(folderName)) return folderName;
|
|
45
43
|
const withUuid = formatWorldPackFolderName(
|
|
46
44
|
`${stripWorldPackFolderPrefix(preferred)} ${opts.info.uuid.slice(0, 8)}`,
|
|
@@ -51,6 +49,15 @@ function choosePackInstallFolderName(opts) {
|
|
|
51
49
|
while (taken.has(`${withUuid}_${i}`)) i++;
|
|
52
50
|
return `${withUuid}_${i}`;
|
|
53
51
|
}
|
|
52
|
+
function choosePackInstallFolderName(opts) {
|
|
53
|
+
const taken = listPackDirsIn(opts.destParent).map((d) => path.basename(d));
|
|
54
|
+
return allocatePackFolderName({
|
|
55
|
+
info: opts.info,
|
|
56
|
+
takenFolderNames: taken,
|
|
57
|
+
...opts.hint !== void 0 ? { hint: opts.hint } : {},
|
|
58
|
+
...opts.allowFolderName !== void 0 ? { allowFolderName: opts.allowFolderName } : {}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
54
61
|
function detectPackKindFromManifest(raw) {
|
|
55
62
|
const types = (raw.modules ?? []).map((m) => String(m.type ?? "").toLowerCase());
|
|
56
63
|
if (types.includes("resources")) return "resource";
|
|
@@ -77,8 +84,7 @@ function readPackManifestInfo(packDir) {
|
|
|
77
84
|
kind,
|
|
78
85
|
...typeof description === "string" ? { description } : {}
|
|
79
86
|
};
|
|
80
|
-
} catch
|
|
81
|
-
if (e instanceof Utf8BomError) throw e;
|
|
87
|
+
} catch {
|
|
82
88
|
return null;
|
|
83
89
|
}
|
|
84
90
|
}
|
|
@@ -253,21 +259,9 @@ function listInstalledWorldPacks(bdsRoot, levelName) {
|
|
|
253
259
|
const enabledList = readWorldPackList(worldsDir, levelName, kind);
|
|
254
260
|
const enabledMap = new Map(enabledList.map((e) => [e.pack_id, e.version]));
|
|
255
261
|
for (const dir of listPackDirsIn(parent)) {
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
info = readPackManifestInfo(dir);
|
|
259
|
-
} catch (e) {
|
|
260
|
-
if (e instanceof Utf8BomError) continue;
|
|
261
|
-
throw e;
|
|
262
|
-
}
|
|
262
|
+
const info = readPackManifestInfo(dir);
|
|
263
263
|
if (!info || info.kind !== kind) {
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
header = readPackManifestHeader(dir);
|
|
267
|
-
} catch (e) {
|
|
268
|
-
if (e instanceof Utf8BomError) continue;
|
|
269
|
-
throw e;
|
|
270
|
-
}
|
|
264
|
+
const header = readPackManifestHeader(dir);
|
|
271
265
|
if (!header) continue;
|
|
272
266
|
result.push({
|
|
273
267
|
kind,
|
|
@@ -325,8 +319,7 @@ function readPackDependencyUuids(packDir) {
|
|
|
325
319
|
try {
|
|
326
320
|
const raw = readJsonFile(file);
|
|
327
321
|
return (raw.dependencies ?? []).map((d) => d.uuid).filter((u) => typeof u === "string" && u.length > 0);
|
|
328
|
-
} catch
|
|
329
|
-
if (e instanceof Utf8BomError) throw e;
|
|
322
|
+
} catch {
|
|
330
323
|
return [];
|
|
331
324
|
}
|
|
332
325
|
}
|
|
@@ -352,61 +345,136 @@ function ensureVersionGreaterThan(packDir, previous, component = "patch") {
|
|
|
352
345
|
const next = nextEnabledVersion(info.version, previous, component);
|
|
353
346
|
return writePackHeaderVersion(packDir, next);
|
|
354
347
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
348
|
+
function readPackDirOccupancy(dir) {
|
|
349
|
+
const info = readPackManifestInfo(dir);
|
|
350
|
+
if (info) {
|
|
351
|
+
return {
|
|
352
|
+
uuid: info.uuid,
|
|
353
|
+
version: info.version,
|
|
354
|
+
name: info.name,
|
|
355
|
+
kind: info.kind
|
|
356
|
+
};
|
|
364
357
|
}
|
|
365
|
-
|
|
366
|
-
|
|
358
|
+
const header = readPackManifestHeader(dir);
|
|
359
|
+
if (header) {
|
|
360
|
+
return { uuid: header.uuid, version: header.version };
|
|
367
361
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
function scanDestOccupancy(destParent) {
|
|
365
|
+
const out = [];
|
|
366
|
+
for (const dir of listPackDirsIn(destParent)) {
|
|
367
|
+
let facts = null;
|
|
373
368
|
try {
|
|
374
|
-
|
|
375
|
-
} catch
|
|
376
|
-
if (!(e instanceof Utf8BomError)) throw e;
|
|
369
|
+
facts = readPackDirOccupancy(dir);
|
|
370
|
+
} catch {
|
|
377
371
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
372
|
+
out.push({
|
|
373
|
+
folderName: path.basename(dir),
|
|
374
|
+
dir,
|
|
375
|
+
uuid: facts?.uuid ?? null,
|
|
376
|
+
version: facts?.version ?? null,
|
|
377
|
+
...facts?.name ? { name: facts.name } : {},
|
|
378
|
+
...facts?.kind ? { kind: facts.kind } : {}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return out;
|
|
382
|
+
}
|
|
383
|
+
function decidePackInstallPlan(opts) {
|
|
384
|
+
const force = Boolean(opts.force);
|
|
385
|
+
const incomingUuid = opts.incoming.uuid.toLowerCase();
|
|
386
|
+
const same = opts.occupancy.find((o) => o.uuid != null && o.uuid.toLowerCase() === incomingUuid);
|
|
387
|
+
if (same) {
|
|
388
|
+
const existingVersion = same.version ?? [0, 0, 0];
|
|
389
|
+
const existing = {
|
|
390
|
+
name: same.name ?? same.folderName,
|
|
391
|
+
uuid: same.uuid,
|
|
392
|
+
version: existingVersion,
|
|
393
|
+
kind: same.kind ?? opts.incoming.kind,
|
|
394
|
+
dir: same.dir
|
|
395
|
+
};
|
|
396
|
+
const newer = compareSemVer3(opts.incoming.version, existing.version) > 0;
|
|
397
|
+
if (force || newer) {
|
|
398
|
+
return {
|
|
399
|
+
kind: "overwriteInPlace",
|
|
400
|
+
folderName: same.folderName,
|
|
401
|
+
dir: same.dir,
|
|
402
|
+
incoming: opts.incoming,
|
|
403
|
+
existing
|
|
404
|
+
};
|
|
382
405
|
}
|
|
406
|
+
return {
|
|
407
|
+
kind: "needConfirm",
|
|
408
|
+
folderName: same.folderName,
|
|
409
|
+
dir: same.dir,
|
|
410
|
+
incoming: opts.incoming,
|
|
411
|
+
existing
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const folderName = allocatePackFolderName({
|
|
415
|
+
info: opts.incoming,
|
|
416
|
+
takenFolderNames: opts.occupancy.map((o) => o.folderName),
|
|
417
|
+
...opts.hint !== void 0 ? { hint: opts.hint } : {}
|
|
418
|
+
});
|
|
419
|
+
return { kind: "fresh", folderName, incoming: opts.incoming };
|
|
420
|
+
}
|
|
421
|
+
function verifyInstalledPack(destDir, incoming) {
|
|
422
|
+
const info = readPackManifestInfo(destDir);
|
|
423
|
+
if (!info) return { ok: false, reason: "verify: dest has no readable manifest" };
|
|
424
|
+
if (info.uuid.toLowerCase() !== incoming.uuid.toLowerCase()) {
|
|
425
|
+
return { ok: false, reason: `verify: uuid mismatch got=${info.uuid} want=${incoming.uuid}` };
|
|
426
|
+
}
|
|
427
|
+
if (info.kind !== incoming.kind) {
|
|
428
|
+
return { ok: false, reason: `verify: kind mismatch got=${info.kind} want=${incoming.kind}` };
|
|
383
429
|
}
|
|
384
|
-
|
|
430
|
+
if (compareSemVer3(info.version, incoming.version) !== 0) {
|
|
431
|
+
return {
|
|
432
|
+
ok: false,
|
|
433
|
+
reason: `verify: version mismatch got=${info.version.join(".")} want=${incoming.version.join(".")}`
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
return { ok: true, info };
|
|
437
|
+
}
|
|
438
|
+
async function installPackDirectory(opts) {
|
|
439
|
+
const info = readPackManifestInfo(opts.srcDir);
|
|
440
|
+
if (!info) {
|
|
441
|
+
return { ok: false, reason: "invalid or unrecognized manifest.json" };
|
|
442
|
+
}
|
|
443
|
+
await fs.promises.mkdir(opts.destParent, { recursive: true });
|
|
444
|
+
const occupancy = scanDestOccupancy(opts.destParent);
|
|
445
|
+
const plan = decidePackInstallPlan({
|
|
446
|
+
incoming: info,
|
|
385
447
|
hint: opts.folderName ?? path.basename(opts.srcDir),
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
...conflictDir ? { allowFolderName: path.basename(conflictDir) } : {}
|
|
448
|
+
occupancy,
|
|
449
|
+
...opts.force !== void 0 ? { force: opts.force } : {}
|
|
389
450
|
});
|
|
390
|
-
if (
|
|
451
|
+
if (plan.kind === "needConfirm") {
|
|
391
452
|
return {
|
|
392
453
|
ok: false,
|
|
393
454
|
skipped: true,
|
|
394
455
|
reason: "conflict",
|
|
395
456
|
conflict: {
|
|
396
|
-
existing:
|
|
457
|
+
existing: plan.existing,
|
|
397
458
|
incoming: info
|
|
398
459
|
}
|
|
399
460
|
};
|
|
400
461
|
}
|
|
401
|
-
const destDir = path.join(opts.destParent, folderName);
|
|
402
|
-
if (
|
|
403
|
-
|
|
462
|
+
const destDir = path.join(opts.destParent, plan.folderName);
|
|
463
|
+
if (plan.kind === "overwriteInPlace" && path.resolve(plan.dir) !== path.resolve(destDir)) {
|
|
464
|
+
return {
|
|
465
|
+
ok: false,
|
|
466
|
+
reason: `invariant: overwrite path drift plan.dir=${plan.dir} destDir=${destDir}`
|
|
467
|
+
};
|
|
404
468
|
}
|
|
405
469
|
if (fs.existsSync(destDir)) {
|
|
406
470
|
await fs.promises.rm(destDir, { recursive: true, force: true });
|
|
407
471
|
}
|
|
408
472
|
await copyDirAsync(opts.srcDir, destDir);
|
|
409
|
-
|
|
473
|
+
const verified = verifyInstalledPack(destDir, info);
|
|
474
|
+
if (!verified.ok) {
|
|
475
|
+
return { ok: false, reason: verified.reason, folderName: plan.folderName, info };
|
|
476
|
+
}
|
|
477
|
+
return { ok: true, destDir, folderName: plan.folderName, info: verified.info };
|
|
410
478
|
}
|
|
411
479
|
async function enableInstalledPack(opts) {
|
|
412
480
|
await enablePackInWorld({
|
|
@@ -475,11 +543,12 @@ function findInstalledPackById(packs, id) {
|
|
|
475
543
|
) ?? null;
|
|
476
544
|
}
|
|
477
545
|
export {
|
|
478
|
-
|
|
546
|
+
allocatePackFolderName,
|
|
479
547
|
bumpPackPatchVersion,
|
|
480
548
|
bumpSemVer3,
|
|
481
549
|
choosePackInstallFolderName,
|
|
482
550
|
compareSemVer3,
|
|
551
|
+
decidePackInstallPlan,
|
|
483
552
|
detectPackKindFromManifest,
|
|
484
553
|
disableInstalledPack,
|
|
485
554
|
discoverPackRoots,
|
|
@@ -499,10 +568,13 @@ export {
|
|
|
499
568
|
maxSemVer3,
|
|
500
569
|
nextEnabledVersion,
|
|
501
570
|
readPackDependencyUuids,
|
|
571
|
+
readPackDirOccupancy,
|
|
502
572
|
readPackManifestInfo,
|
|
503
573
|
resolvePackRoots,
|
|
574
|
+
scanDestOccupancy,
|
|
504
575
|
stripWorldPackFolderPrefix,
|
|
505
576
|
uninstallInstalledPack,
|
|
577
|
+
verifyInstalledPack,
|
|
506
578
|
worldPackParentDir,
|
|
507
579
|
writePackHeaderVersion
|
|
508
580
|
};
|
package/dist/world-packs.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/world-packs.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * world-packs.ts \u2014 \u901A\u7528\u4E16\u754C BP/RP \u53D1\u73B0 / \u5B89\u88C5 / bump\uFF08\u975E SFMC \u6A21\u5757\u805A\u5408\uFF09\n */\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { copyDirAsync, readJsonFile, Utf8BomError } from \"./fsx.js\";\nimport {\n bdsWorldLevelDir,\n bdsWorldsDir,\n disablePackInWorld,\n enablePackInWorld,\n readPackManifestHeader,\n readWorldPackList,\n readWorldPackListResult,\n type WorldPackListReadResult,\n} from \"./pack-manager.js\";\nimport { extractZipFileToDir } from \"./zipx.js\";\n\nexport type WorldPackKind = \"behavior\" | \"resource\";\n\nexport interface PackManifestInfo {\n name: string;\n uuid: string;\n version: [number, number, number];\n kind: WorldPackKind;\n description?: string;\n}\n\nexport interface InstalledWorldPack {\n kind: WorldPackKind;\n folderName: string;\n dir: string;\n name: string;\n uuid: string;\n version: [number, number, number];\n enabled: boolean;\n}\n\nconst ARCHIVE_EXTS = [\".zip\", \".mcpack\", \".mcaddon\"] as const;\n\n/** \u6EE4\u6389 \u00A7x\uFF08Minecraft \u683C\u5F0F\u7801\uFF09\u3001\u6B8B\u4F59\u538B\u7F29\u540E\u7F00\uFF0C\u52A0 [BP]/[RP] \u524D\u7F00 */\nexport function formatWorldPackFolderName(rawName: string, kind: WorldPackKind): string {\n let s = String(rawName ?? \"\");\n s = s.replace(/\u00A7[0-9a-zA-Z]/g, \"\");\n s = s.replace(/\\.(zip|mcpack|mcaddon)$/i, \"\");\n s = s.replace(/\\s+/g, \" \").trim();\n if (!s) s = \"pack\";\n const prefix = kind === \"resource\" ? \"[RP]\" : \"[BP]\";\n if (s.startsWith(\"[RP]\") || s.startsWith(\"[BP]\")) return s;\n return `${prefix} ${s}`;\n}\n\n/** \u53BB\u6389\u5DF2\u6709 [BP]/[RP] \u524D\u7F00\uFF0C\u5F97\u5230\u6587\u4EF6\u5939\u540D\u4E3B\u5E72 */\nexport function stripWorldPackFolderPrefix(rawName: string): string {\n return String(rawName ?? \"\")\n .replace(/^\\[BP\\]\\s*/i, \"\")\n .replace(/^\\[RP\\]\\s*/i, \"\")\n .replace(/\\.(zip|mcpack|mcaddon)$/i, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * \u5F52\u6863\u5185\u5E38\u89C1\u5360\u4F4D\u76EE\u5F55\u540D\uFF08B / R / BP / RP\uFF09\u8FC7\u77ED\u6216\u8FC7\u6CDB\uFF0C\u4E0D\u80FD\u4F5C\u4E3A\u4E16\u754C\u76EE\u5F55\u540D\uFF0C\n * \u5426\u5219\u4E0D\u540C\u5305\u4F1A\u649E\u5230\u540C\u4E00\u8DEF\u5F84\u5E76\u88AB\u8BEF\u5224\u4E3A\u300C\u8986\u76D6\u300D\u3002\n */\nexport function isGenericPackFolderStem(rawName: string): boolean {\n const s = stripWorldPackFolderPrefix(rawName);\n if (!s) return true;\n if (s.length <= 2) return true;\n return /^(bp|rp|b|r|pack|packs|behavior|behaviours?|resource|resources)$/i.test(s);\n}\n\n/**\n * \u9009\u5B9A\u5B89\u88C5\u6587\u4EF6\u5939\u540D\uFF1Ahint \u8FC7\u6CDB\u65F6\u6539\u7528 manifest.name\uFF1B\u518D\u4E0E dest \u5185\u5DF2\u6709\u76EE\u5F55\u907F\u8BA9\uFF08\u4E0D\u540C uuid \u4E0D\u4E92\u76F8\u8986\u76D6\uFF09\u3002\n */\nexport function choosePackInstallFolderName(opts: {\n hint?: string;\n info: PackManifestInfo;\n destParent: string;\n /** \u540C uuid \u66F4\u65B0\u65F6\u5141\u8BB8\u5360\u7528\u7684\u5DF2\u6709\u76EE\u5F55\u540D\uFF08\u4E0D\u89E6\u53D1\u907F\u8BA9\uFF09 */\n allowFolderName?: string;\n}): string {\n const hint = (opts.hint && opts.hint.trim()) || \"\";\n const preferred = isGenericPackFolderStem(hint) ? opts.info.name || hint || \"pack\" : hint;\n let folderName = formatWorldPackFolderName(preferred, opts.info.kind);\n const allow = opts.allowFolderName ? path.basename(opts.allowFolderName) : null;\n if (allow && folderName === allow) return folderName;\n\n const taken = new Set(\n listPackDirsIn(opts.destParent)\n .map((d) => path.basename(d))\n .filter((n) => n !== allow)\n );\n if (!taken.has(folderName)) return folderName;\n\n /* \u540C\u540D\u4E0D\u540C\u5305\uFF1Amanifest \u540D + uuid \u524D\u7F00\uFF1B\u4ECD\u649E\u5219\u9012\u589E */\n const withUuid = formatWorldPackFolderName(\n `${stripWorldPackFolderPrefix(preferred)} ${opts.info.uuid.slice(0, 8)}`,\n opts.info.kind\n );\n if (!taken.has(withUuid)) return withUuid;\n let i = 2;\n while (taken.has(`${withUuid}_${i}`)) i++;\n return `${withUuid}_${i}`;\n}\n\n/** \u6839\u636E manifest modules[].type \u5224\u5B9A BP / RP */\nexport function detectPackKindFromManifest(raw: {\n modules?: Array<{ type?: string }>;\n}): WorldPackKind | null {\n const types = (raw.modules ?? []).map((m) => String(m.type ?? \"\").toLowerCase());\n if (types.includes(\"resources\")) return \"resource\";\n if (types.some((t) => t === \"script\" || t === \"data\" || t === \"javascript\")) return \"behavior\";\n return null;\n}\n\nexport function readPackManifestInfo(packDir: string): PackManifestInfo | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = readJsonFile<{\n header?: { name?: string; uuid?: string; version?: number[]; description?: string };\n modules?: Array<{ type?: string }>;\n }>(file);\n const kind = detectPackKindFromManifest(raw);\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n const name = raw.header?.name;\n if (!kind || typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n if (typeof name !== \"string\" || !name) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const description = raw.header?.description;\n return {\n name,\n uuid,\n version,\n kind,\n ...(typeof description === \"string\" ? { description } : {}),\n };\n } catch (e) {\n /* BOM \u5FC5\u987B\u4E0A\u629B\uFF0C\u7531\u5B89\u88C5\u5C42\u6253\u660E\u786E\u9519\u8BEF\uFF1B\u5176\u5B83\u89E3\u6790\u5931\u8D25\u4ECD\u8FD4\u56DE null */\n if (e instanceof Utf8BomError) throw e;\n return null;\n }\n}\n\nexport { Utf8BomError };\n\n/** \u6DF1\u5EA6\u4F18\u5148\u627E\u542B manifest.json \u7684\u5305\u6839\uFF08\u9ED8\u8BA4 maxDepth=2\uFF0Croot \u81EA\u8EAB\u4E3A depth 0\uFF09 */\nexport function discoverPackRoots(root: string, opts?: { maxDepth?: number }): string[] {\n const maxDepth = opts?.maxDepth ?? 2;\n const out: string[] = [];\n const abs = path.resolve(root);\n if (!fs.existsSync(abs)) return out;\n\n function walk(dir: string, depth: number): void {\n const manifest = path.join(dir, \"manifest.json\");\n if (fs.existsSync(manifest) && fs.statSync(manifest).isFile()) {\n out.push(dir);\n return; // \u5305\u6839\u4E0D\u518D\u4E0B\u94BB\n }\n if (depth >= maxDepth) return;\n let entries;\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n if (e.name.startsWith(\".\") || e.name === \"node_modules\") continue;\n walk(path.join(dir, e.name), depth + 1);\n }\n }\n\n const st = fs.statSync(abs);\n if (st.isDirectory()) walk(abs, 0);\n return out;\n}\n\nexport function isPackArchive(filePath: string): boolean {\n const lower = filePath.toLowerCase();\n return ARCHIVE_EXTS.some((ext) => lower.endsWith(ext));\n}\n\n/** \u53BB\u6389 .zip/.mcpack/.mcaddon \u540E\u7F00\u5F97\u5230 stem */\nfunction archiveStem(filePath: string): string {\n const base = path.basename(filePath);\n const lower = base.toLowerCase();\n for (const ext of ARCHIVE_EXTS) {\n if (lower.endsWith(ext)) return base.slice(0, -ext.length);\n }\n return path.parse(base).name;\n}\n\n/** \u5F52\u6863\u89E3\u538B\u76EE\u6807\uFF1A\u540C\u7EA7 stem \u76EE\u5F55\uFF1B\u91CD\u540D\u5219\u52A0 _2/_3\u2026 */\nfunction uniqueSiblingExtractDir(archivePath: string): string {\n const parent = path.dirname(archivePath);\n let dest = path.join(parent, archiveStem(archivePath) || \"pack\");\n if (!fs.existsSync(dest)) return dest;\n let i = 2;\n while (fs.existsSync(`${dest}_${i}`)) i++;\n return `${dest}_${i}`;\n}\n\n/**\n * \u5217\u51FA\u76EE\u5F55\u6811\u5185\u7684\u5305\u5F52\u6863\u6587\u4EF6\u3002\n * \u5DF2\u662F\u5305\u6839\uFF08\u542B manifest.json\uFF09\u7684\u76EE\u5F55\u4E0D\u518D\u4E0B\u94BB\uFF0C\u907F\u514D\u8BEF\u89E3\u538B\u5305\u5185\u8D44\u6E90\u3002\n */\nexport function listPackArchiveFiles(root: string, opts?: { maxDepth?: number }): string[] {\n const maxDepth = opts?.maxDepth ?? 4;\n const out: string[] = [];\n const abs = path.resolve(root);\n if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) return out;\n\n function walk(dir: string, depth: number): void {\n if (fs.existsSync(path.join(dir, \"manifest.json\"))) return;\n let entries;\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (e.name.startsWith(\".\") || e.name === \"node_modules\") continue;\n const full = path.join(dir, e.name);\n if (e.isFile() && isPackArchive(full)) {\n out.push(full);\n continue;\n }\n if (e.isDirectory() && depth < maxDepth) walk(full, depth + 1);\n }\n }\n\n walk(abs, 0);\n return out;\n}\n\n/**\n * \u5728\u4E34\u65F6\u6811\u5185\u539F\u5730\u5C55\u5F00\u5D4C\u5957\u5F52\u6863\uFF1A\u89E3\u538B\u5230\u540C\u7EA7\u76EE\u5F55\u5E76\u5220\u9664\u5F52\u6863\u6587\u4EF6\uFF0C\u591A\u8F6E\u76F4\u81F3\u6CA1\u6709\u65B0\u5F52\u6863\u3002\n * \u4EC5\u5E94\u5BF9\u6211\u4EEC\u81EA\u5DF1\u7684 staging\uFF0C\u7981\u6B62\u7528\u4E8E\u7528\u6237 inbox \u539F\u76EE\u5F55\u3002\n */\nexport async function expandNestedArchivesInPlace(\n workDir: string,\n opts?: { maxRounds?: number; maxScanDepth?: number }\n): Promise<number> {\n const maxRounds = opts?.maxRounds ?? 3;\n const maxScanDepth = opts?.maxScanDepth ?? 4;\n let expanded = 0;\n for (let round = 0; round < maxRounds; round++) {\n const archives = listPackArchiveFiles(workDir, { maxDepth: maxScanDepth });\n if (archives.length === 0) break;\n for (const arch of archives) {\n const dest = uniqueSiblingExtractDir(arch);\n await fs.promises.mkdir(dest, { recursive: true });\n await extractZipFileToDir(arch, dest);\n await fs.promises.unlink(arch);\n expanded++;\n }\n }\n return expanded;\n}\n\nexport type ResolvePackRootsResult = {\n roots: string[];\n /** \u6E05\u7406\u672C\u8F6E\u521B\u5EFA\u7684\u5168\u90E8\u4E34\u65F6\u76EE\u5F55\uFF08\u53EF\u5B89\u5168\u591A\u6B21\u8C03\u7528\uFF09 */\n dispose: () => void;\n};\n\n/**\n * \u7EDF\u4E00\u5305\u6839\u89E3\u6790\uFF1A\u76EE\u5F55 / \u9876\u5C42\u5F52\u6863 / \u5D4C\u5957 .mcpack|.zip|.mcaddon\u3002\n * \u89C4\u5219\uFF1A\u5148\u5C55\u5F00\u5F52\u6863\u4E3A\u76EE\u5F55\u6811\uFF0C\u518D\u53EA\u8BA4\u542B manifest.json \u7684\u76EE\u5F55\u4E3A\u5305\u6839\u3002\n * \u7528\u6237\u76EE\u5F55\u5185\u7684\u5D4C\u5957\u5F52\u6863\u89E3\u5230\u72EC\u7ACB temp\uFF0C\u4E0D\u4FEE\u6539\u539F\u76EE\u5F55\u3002\n */\nexport async function resolvePackRoots(\n src: string,\n opts?: { maxDirDepth?: number; maxArchiveRounds?: number }\n): Promise<ResolvePackRootsResult> {\n const maxDirDepth = opts?.maxDirDepth ?? 4;\n const maxArchiveRounds = opts?.maxArchiveRounds ?? 3;\n const temps: string[] = [];\n const dispose = (): void => {\n for (const d of temps.splice(0, temps.length)) {\n try {\n fs.rmSync(d, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n }\n };\n\n const abs = path.resolve(src);\n if (!fs.existsSync(abs)) return { roots: [], dispose };\n\n try {\n const st = fs.statSync(abs);\n if (st.isFile()) {\n if (!isPackArchive(abs)) return { roots: [], dispose };\n const tmp = await extractArchiveToTemp(abs);\n temps.push(tmp);\n await expandNestedArchivesInPlace(tmp, {\n maxRounds: maxArchiveRounds,\n maxScanDepth: maxDirDepth,\n });\n return { roots: discoverPackRoots(tmp, { maxDepth: maxDirDepth }), dispose };\n }\n\n if (!st.isDirectory()) return { roots: [], dispose };\n\n const nestedArchives = listPackArchiveFiles(abs, { maxDepth: maxDirDepth });\n if (nestedArchives.length === 0) {\n return { roots: discoverPackRoots(abs, { maxDepth: maxDirDepth }), dispose };\n }\n\n /* \u76EE\u5F55\u5305\u6839 + \u5404\u5D4C\u5957\u5F52\u6863\u5404\u81EA\u89E3\u5230 temp\uFF08\u4E0D\u6539\u7528\u6237\u76EE\u5F55\uFF09 */\n const roots = discoverPackRoots(abs, { maxDepth: maxDirDepth });\n const seen = new Set(roots.map((r) => path.resolve(r)));\n for (const arch of nestedArchives) {\n const tmp = await extractArchiveToTemp(arch);\n temps.push(tmp);\n await expandNestedArchivesInPlace(tmp, {\n maxRounds: maxArchiveRounds,\n maxScanDepth: maxDirDepth,\n });\n for (const r of discoverPackRoots(tmp, { maxDepth: maxDirDepth })) {\n const key = path.resolve(r);\n if (seen.has(key)) continue;\n seen.add(key);\n roots.push(r);\n }\n }\n return { roots, dispose };\n } catch (e) {\n dispose();\n throw e;\n }\n}\n\n/** \u89E3\u538B zip/mcpack/mcaddon \u5230\u4E34\u65F6\u76EE\u5F55\uFF0C\u8FD4\u56DE\u8BE5\u76EE\u5F55\uFF08\u7ECF zipx \u9632 zip-slip\uFF09 */\nexport async function extractArchiveToTemp(filePath: string): Promise<string> {\n const tmp = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-pack-\"));\n await extractZipFileToDir(filePath, tmp);\n return tmp;\n}\n\nfunction listPackDirsIn(parent: string): string[] {\n if (!fs.existsSync(parent)) return [];\n const out: string[] = [];\n for (const e of fs.readdirSync(parent, { withFileTypes: true })) {\n if (!e.isDirectory()) continue;\n const dir = path.join(parent, e.name);\n if (fs.existsSync(path.join(dir, \"manifest.json\"))) out.push(dir);\n }\n return out;\n}\n\n/** \u626B\u63CF\u4E16\u754C\u5185\u5DF2\u5B89\u88C5 BP/RP \u76EE\u5F55 */\nexport function listInstalledWorldPacks(bdsRoot: string, levelName: string): InstalledWorldPack[] {\n const worldRoot = bdsWorldLevelDir(bdsRoot, levelName);\n const worldsDir = bdsWorldsDir(bdsRoot);\n const result: InstalledWorldPack[] = [];\n\n for (const kind of [\"behavior\", \"resource\"] as const) {\n const parent = path.join(\n worldRoot,\n kind === \"behavior\" ? \"behavior_packs\" : \"resource_packs\"\n );\n const enabledList = readWorldPackList(worldsDir, levelName, kind);\n const enabledMap = new Map(enabledList.map((e) => [e.pack_id, e.version] as const));\n\n for (const dir of listPackDirsIn(parent)) {\n let info: PackManifestInfo | null = null;\n try {\n info = readPackManifestInfo(dir);\n } catch (e) {\n /* \u5DF2\u88C5\u76EE\u5F55\u82E5\u542B BOM\uFF1A\u8DF3\u8FC7\u8BE5\u9879\uFF0C\u907F\u514D list \u6574\u8868\u70B8\u6389\uFF1B\u5B89\u88C5\u8DEF\u5F84\u4F1A\u5355\u72EC\u62A5\u9519 */\n if (e instanceof Utf8BomError) continue;\n throw e;\n }\n if (!info || info.kind !== kind) {\n // \u4ECD\u5C1D\u8BD5\u7528 header \u5C55\u793A\uFF08enabled \u4E0E\u6B63\u5E38\u8DEF\u5F84\u540C\u5951\u7EA6\uFF1Aenable-list \u542B uuid \u2192 LSP\uFF09\n let header;\n try {\n header = readPackManifestHeader(dir);\n } catch (e) {\n if (e instanceof Utf8BomError) continue;\n throw e;\n }\n if (!header) continue;\n result.push({\n kind,\n folderName: path.basename(dir),\n dir,\n name: path.basename(dir),\n uuid: header.uuid,\n version: header.version,\n enabled: enabledMap.has(header.uuid),\n });\n continue;\n }\n result.push({\n kind: info.kind,\n folderName: path.basename(dir),\n dir,\n name: info.name,\n uuid: info.uuid,\n version: info.version,\n enabled: enabledMap.has(info.uuid),\n });\n }\n }\n return result;\n}\n\n/** RP/BP \u7B2C\u4E09\u4F4D\u7248\u672C +1\uFF0C\u5199\u56DE manifest */\nexport function bumpPackPatchVersion(packDir: string): [number, number, number] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) throw new Error(`manifest.json missing: ${packDir}`);\n const raw = readJsonFile<{\n header?: { version?: number[] };\n modules?: Array<{ version?: number[] }>;\n }>(file);\n const ver = raw.header?.version;\n if (!Array.isArray(ver) || ver.length < 3) throw new Error(`invalid header.version in ${file}`);\n const next: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2]) + 1];\n return writePackHeaderVersion(packDir, next);\n}\n\n/** \u5199\u5165 header.version\uFF08\u5E76\u540C\u6B65 modules[].version \u7684 patch\uFF09 */\nexport function writePackHeaderVersion(\n packDir: string,\n next: [number, number, number]\n): [number, number, number] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) throw new Error(`manifest.json missing: ${packDir}`);\n const raw = readJsonFile<{\n header?: { version?: number[] };\n modules?: Array<{ version?: number[] }>;\n }>(file);\n if (!raw.header) raw.header = {};\n raw.header.version = next;\n if (Array.isArray(raw.modules)) {\n for (const m of raw.modules) {\n if (Array.isArray(m.version) && m.version.length >= 3) {\n m.version = [Number(m.version[0]), Number(m.version[1]), next[2]];\n }\n }\n }\n fs.writeFileSync(file, `${JSON.stringify(raw, null, 2)}\\n`, \"utf8\");\n return next;\n}\n\n/** \u8BFB\u53D6 BP manifest \u4E2D\u4F9D\u8D56\u7684\u8D44\u6E90\u5305 uuid\uFF08\u975E @minecraft \u6A21\u5757\uFF09 */\nexport function readPackDependencyUuids(packDir: string): string[] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return [];\n try {\n const raw = readJsonFile<{\n dependencies?: Array<{ uuid?: string; module_name?: string }>;\n }>(file);\n return (raw.dependencies ?? [])\n .map((d) => d.uuid)\n .filter((u): u is string => typeof u === \"string\" && u.length > 0);\n } catch (e) {\n if (e instanceof Utf8BomError) throw e;\n return [];\n }\n}\n\n/** \u6BD4\u8F83 SemVer \u4E09\u5143\u7EC4\uFF1Ba>b \u6B63\uFF0Ca<b \u8D1F\uFF0C\u76F8\u7B49 0 */\nexport function compareSemVer3(\n a: [number, number, number],\n b: [number, number, number]\n): number {\n for (let i = 0; i < 3; i++) {\n const d = a[i]! - b[i]!;\n if (d !== 0) return d;\n }\n return 0;\n}\n\n/** \u53D6\u8F83\u5927\u7684 SemVer \u4E09\u5143\u7EC4 */\nexport function maxSemVer3(\n a: [number, number, number],\n b: [number, number, number]\n): [number, number, number] {\n return compareSemVer3(a, b) >= 0 ? a : b;\n}\n\n/** \u6309 component \u62AC\u4E00\u7EA7 */\nexport function bumpSemVer3(\n v: [number, number, number],\n component: \"patch\" | \"minor\"\n): [number, number, number] {\n return component === \"minor\" ? [v[0], v[1] + 1, 0] : [v[0], v[1], v[2] + 1];\n}\n\n/**\n * \u8FDB\u670D\u542F\u7528\u7248\u672C\uFF1Amax(\u8FDC\u7A0B/\u65B0\u5305, \u65E7\u542F\u7528) \u518D\u62AC\u4E00\u7EA7\u3002\n * \u5355\u4E00\u89C4\u5219\uFF0C\u7981\u6B62 while \u8FFD\u8D76\uFF08\u4F5C\u8005\u4E71\u5199\u9AD8\u7248\u672C\u5982 [1,21,100] \u65F6\u4E5F\u80FD\u4E00\u6B21\u7B97\u5B8C\uFF09\u3002\n */\nexport function nextEnabledVersion(\n remote: [number, number, number],\n previous: [number, number, number],\n component: \"patch\" | \"minor\" = \"patch\"\n): [number, number, number] {\n return bumpSemVer3(maxSemVer3(remote, previous), component);\n}\n\n/**\n * \u5C06\u5305\u76EE\u5F55 manifest \u62AC\u5230 nextEnabledVersion(\u5F53\u524D, previous)\u3002\n * previous \u4E00\u822C\u4E3A\u66F4\u65B0\u524D\u5DF2\u5B89\u88C5 RP / \u4E16\u754C enable \u5217\u8868\u4E2D\u7684\u7248\u672C\u3002\n */\nexport function ensureVersionGreaterThan(\n packDir: string,\n previous: [number, number, number],\n component: \"patch\" | \"minor\" = \"patch\"\n): [number, number, number] {\n const info = readPackManifestInfo(packDir);\n if (!info) throw new Error(`cannot read pack version: ${packDir}`);\n const next = nextEnabledVersion(info.version, previous, component);\n return writePackHeaderVersion(packDir, next);\n}\n\nexport interface InstallPackResult {\n ok: boolean;\n skipped?: boolean;\n reason?: string;\n destDir?: string;\n folderName?: string;\n info?: PackManifestInfo;\n conflict?: { existing: PackManifestInfo & { dir: string }; incoming: PackManifestInfo };\n}\n\n/**\n * \u5C06\u5305\u76EE\u5F55\u5B89\u88C5\u5230 destParent\uFF08behavior_packs \u6216 resource_packs\uFF09\u3002\n * force=true \u65F6\u8986\u76D6\u300C\u540C uuid\u300D\u51B2\u7A81\uFF1B\u540C\u540D\u4E0D\u540C uuid \u4F1A\u81EA\u52A8\u6362\u6587\u4EF6\u5939\u540D\uFF0C\u4E0D\u5220\u522B\u4EBA\u7684\u5305\u3002\n */\nexport async function installPackDirectory(opts: {\n srcDir: string;\n destParent: string;\n folderName?: string;\n force?: boolean;\n}): Promise<InstallPackResult> {\n let info: PackManifestInfo | null;\n try {\n info = readPackManifestInfo(opts.srcDir);\n } catch (e) {\n if (e instanceof Utf8BomError) {\n return { ok: false, reason: e.message };\n }\n throw e;\n }\n if (!info) {\n return { ok: false, reason: \"invalid or unrecognized manifest.json\" };\n }\n\n await fs.promises.mkdir(opts.destParent, { recursive: true });\n\n /* \u4EC5\u540C uuid \u89C6\u4E3A\u53EF\u8986\u76D6\u51B2\u7A81\uFF1B\u540C\u540D\u4E0D\u540C\u5305\u7531 choosePackInstallFolderName \u907F\u8BA9 */\n let conflictDir: string | null = null;\n let conflictExisting: PackManifestInfo | null = null;\n for (const dir of listPackDirsIn(opts.destParent)) {\n let existing: PackManifestInfo | null = null;\n try {\n existing = readPackManifestInfo(dir);\n } catch (e) {\n if (!(e instanceof Utf8BomError)) throw e;\n }\n if (existing && existing.uuid === info.uuid) {\n conflictDir = dir;\n conflictExisting = existing;\n break;\n }\n }\n\n const folderName = choosePackInstallFolderName({\n hint: opts.folderName ?? path.basename(opts.srcDir),\n info,\n destParent: opts.destParent,\n ...(conflictDir ? { allowFolderName: path.basename(conflictDir) } : {}),\n });\n\n if (conflictDir && !opts.force) {\n return {\n ok: false,\n skipped: true,\n reason: \"conflict\",\n conflict: {\n existing: { ...(conflictExisting ?? info), dir: conflictDir },\n incoming: info,\n },\n };\n }\n\n const destDir = path.join(opts.destParent, folderName);\n if (conflictDir && path.resolve(conflictDir) !== path.resolve(destDir)) {\n await fs.promises.rm(conflictDir, { recursive: true, force: true });\n }\n if (fs.existsSync(destDir)) {\n await fs.promises.rm(destDir, { recursive: true, force: true });\n }\n await copyDirAsync(opts.srcDir, destDir);\n return { ok: true, destDir, folderName, info };\n}\n\n/** \u5B89\u88C5\u540E\u5199\u5165\u4E16\u754C enable \u6E05\u5355 */\nexport async function enableInstalledPack(opts: {\n bdsRoot: string;\n levelName: string;\n info: PackManifestInfo;\n}): Promise<void> {\n await enablePackInWorld({\n worldsDir: bdsWorldsDir(opts.bdsRoot),\n levelName: opts.levelName,\n kind: opts.info.kind,\n packUuid: opts.info.uuid,\n version: opts.info.version,\n });\n}\n\n/** \u4ECE\u4E16\u754C enable \u6E05\u5355\u79FB\u9664 */\nexport async function disableInstalledPack(opts: {\n bdsRoot: string;\n levelName: string;\n kind: WorldPackKind;\n packUuid: string;\n version: [number, number, number];\n}): Promise<void> {\n await disablePackInWorld({\n worldsDir: bdsWorldsDir(opts.bdsRoot),\n levelName: opts.levelName,\n kind: opts.kind,\n packUuid: opts.packUuid,\n version: opts.version,\n });\n}\n\nexport type UninstallPackResult =\n | { action: \"trashed\"; dest: string }\n | { action: \"deleted\" }\n | { action: \"missing\" };\n\nexport type UninstallPackAction = UninstallPackResult[\"action\"];\n\n/**\n * \u5378\u8F7D\u5DF2\u5B89\u88C5\u4E16\u754C\u5305\uFF1A\u5148 disable enable-list\uFF0C\u518D\u79FB\u5165 trashDir \u6216\u76F4\u63A5\u5220\u9664\u76EE\u5F55\u3002\n * trashDir \u8DE8\u76D8\u7B26\u65F6 fallback \u4E3A copy + rm\u3002\n */\nexport async function uninstallInstalledPack(opts: {\n bdsRoot: string;\n levelName: string;\n pack: InstalledWorldPack;\n /** \u63D0\u4F9B\u5219\u79FB\u5165\u8BE5\u76EE\u5F55\uFF1Bnull/\u7701\u7565\u5219\u76F4\u63A5\u5220\u9664 */\n trashDir?: string | null;\n}): Promise<UninstallPackResult> {\n await disableInstalledPack({\n bdsRoot: opts.bdsRoot,\n levelName: opts.levelName,\n kind: opts.pack.kind,\n packUuid: opts.pack.uuid,\n version: opts.pack.version,\n });\n\n if (!fs.existsSync(opts.pack.dir)) {\n return { action: \"missing\" };\n }\n\n const trashDir = opts.trashDir?.trim() || null;\n if (trashDir) {\n await fs.promises.mkdir(trashDir, { recursive: true });\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n let dest = path.join(trashDir, opts.pack.folderName);\n if (fs.existsSync(dest)) {\n dest = path.join(trashDir, `${opts.pack.folderName}-${stamp}`);\n }\n try {\n await fs.promises.rename(opts.pack.dir, dest);\n } catch {\n await copyDirAsync(opts.pack.dir, dest);\n await fs.promises.rm(opts.pack.dir, { recursive: true, force: true });\n }\n return { action: \"trashed\", dest };\n }\n\n await fs.promises.rm(opts.pack.dir, { recursive: true, force: true });\n return { action: \"deleted\" };\n}\n\nexport function worldPackParentDir(\n bdsRoot: string,\n levelName: string,\n kind: WorldPackKind\n): string {\n return path.join(\n bdsWorldLevelDir(bdsRoot, levelName),\n kind === \"behavior\" ? \"behavior_packs\" : \"resource_packs\"\n );\n}\n\n/** \u4E16\u754C enable-list \u6743\u5A01\u8BFB\u53D6 \u2014 \u59D4\u6258 pack-manager\uFF08\u4F9B doctor \u7B49\uFF0C\u907F\u514D\u786C\u7F16\u7801\u6587\u4EF6\u540D\uFF09 */\nexport function listWorldEnableEntries(\n bdsRoot: string,\n levelName: string,\n kind: WorldPackKind\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return listWorldEnableListResult(bdsRoot, levelName, kind).entries;\n}\n\n/** \u542B parseFail \u4FE1\u53F7\u7684 enable-list \u5FEB\u7167\uFF08doctor \u7528\uFF1B\u4E0D\u66B4\u9732 JSON \u8DEF\u5F84\u6784\u9020\u7EC6\u8282\uFF09 */\nexport function listWorldEnableListResult(\n bdsRoot: string,\n levelName: string,\n kind: WorldPackKind\n): WorldPackListReadResult {\n return readWorldPackListResult(bdsWorldsDir(bdsRoot), levelName, kind);\n}\n\nexport function findInstalledPackById(\n packs: InstalledWorldPack[],\n id: string\n): InstalledWorldPack | null {\n const q = id.trim().toLowerCase();\n return (\n packs.find(\n (p) =>\n p.uuid.toLowerCase() === q ||\n p.folderName.toLowerCase() === q ||\n p.name.toLowerCase() === q ||\n p.folderName.toLowerCase().includes(q) ||\n p.name.toLowerCase().includes(q)\n ) ?? null\n );\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * world-packs.ts \u2014 \u901A\u7528 Minecraft \u57FA\u5CA9\u7248\u4E16\u754C\u884C\u4E3A\u5305\uFF08BP\uFF09\u4E0E\u8D44\u6E90\u5305\uFF08RP\uFF09\u7BA1\u7406\u5DE5\u5177\n *\n * \u6838\u5FC3\u80FD\u529B\uFF1A\n * - \u683C\u5F0F\u4E0E\u547D\u540D\u89C4\u8303\u5316\uFF1A\u8FC7\u6EE4 Minecraft \u989C\u8272\u683C\u5F0F\u7801\uFF0C\u81EA\u52A8\u8865\u5145 `[BP]` / `[RP]` \u524D\u7F00\u53CA\u51B2\u7A81\u907F\u8BA9\n * - \u538B\u7F29\u5305\u9012\u5F52\u89E3\u6784\uFF1A\u652F\u6301 `.zip`\u3001`.mcpack`\u3001`.mcaddon` \u5D4C\u5957\u5305\u89E3\u538B\u5E76\u667A\u80FD\u8BC6\u522B BP \u4E0E RP \u6839\u76EE\u5F55\n * - \u7248\u672C\u9012\u589E\u4E0E\u540C\u6B65\uFF1A\u540C\u6B65\u5347\u7EA7 manifest \u4E2D\u7684\u7248\u672C\u5143\u6570\u636E\u5E76\u5BF9\u9F50\u4E16\u754C\u542F\u7528\u6E05\u5355\u7248\u672C\n * - \u5E42\u7B49\u5B89\u88C5\u4E0E\u56DE\u6EDA\uFF1A\u6309 UUID \u7CBE\u786E\u5339\u914D\u5347\u7EA7\u4E0E\u5B89\u88C5\u8BA1\u5212\uFF0C\u652F\u6301\u5220\u9664\u5907\u4EFD\u81F3\u56DE\u6536\u7AD9\u673A\u5236\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { copyDirAsync, readJsonFile } from \"./fsx.js\";\nimport {\n bdsWorldLevelDir,\n bdsWorldsDir,\n disablePackInWorld,\n enablePackInWorld,\n readPackManifestHeader,\n readWorldPackList,\n readWorldPackListResult,\n type WorldPackListReadResult,\n} from \"./pack-manager.js\";\nimport { extractZipFileToDir } from \"./zipx.js\";\n\nexport type WorldPackKind = \"behavior\" | \"resource\";\n\nexport interface PackManifestInfo {\n name: string;\n uuid: string;\n version: [number, number, number];\n kind: WorldPackKind;\n description?: string;\n}\n\nexport interface InstalledWorldPack {\n kind: WorldPackKind;\n folderName: string;\n dir: string;\n name: string;\n uuid: string;\n version: [number, number, number];\n enabled: boolean;\n}\n\nconst ARCHIVE_EXTS = [\".zip\", \".mcpack\", \".mcaddon\"] as const;\n\n/** \u6EE4\u6389 \u00A7x\uFF08Minecraft \u683C\u5F0F\u7801\uFF09\u3001\u6B8B\u4F59\u538B\u7F29\u540E\u7F00\uFF0C\u52A0 [BP]/[RP] \u524D\u7F00 */\nexport function formatWorldPackFolderName(rawName: string, kind: WorldPackKind): string {\n let s = String(rawName ?? \"\");\n s = s.replace(/\u00A7[0-9a-zA-Z]/g, \"\");\n s = s.replace(/\\.(zip|mcpack|mcaddon)$/i, \"\");\n s = s.replace(/\\s+/g, \" \").trim();\n if (!s) s = \"pack\";\n const prefix = kind === \"resource\" ? \"[RP]\" : \"[BP]\";\n if (s.startsWith(\"[RP]\") || s.startsWith(\"[BP]\")) return s;\n return `${prefix} ${s}`;\n}\n\n/** \u53BB\u6389\u5DF2\u6709 [BP]/[RP] \u524D\u7F00\uFF0C\u5F97\u5230\u6587\u4EF6\u5939\u540D\u4E3B\u5E72 */\nexport function stripWorldPackFolderPrefix(rawName: string): string {\n return String(rawName ?? \"\")\n .replace(/^\\[BP\\]\\s*/i, \"\")\n .replace(/^\\[RP\\]\\s*/i, \"\")\n .replace(/\\.(zip|mcpack|mcaddon)$/i, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * \u5F52\u6863\u5185\u5E38\u89C1\u5360\u4F4D\u76EE\u5F55\u540D\uFF08B / R / BP / RP\uFF09\u8FC7\u77ED\u6216\u8FC7\u6CDB\uFF0C\u4E0D\u80FD\u4F5C\u4E3A\u4E16\u754C\u76EE\u5F55\u540D\uFF0C\n * \u5426\u5219\u4E0D\u540C\u5305\u4F1A\u649E\u5230\u540C\u4E00\u8DEF\u5F84\u5E76\u88AB\u8BEF\u5224\u4E3A\u300C\u8986\u76D6\u300D\u3002\n */\nexport function isGenericPackFolderStem(rawName: string): boolean {\n const s = stripWorldPackFolderPrefix(rawName);\n if (!s) return true;\n if (s.length <= 2) return true;\n return /^(bp|rp|b|r|pack|packs|behavior|behaviours?|resource|resources)$/i.test(s);\n}\n\n/**\n * \u9009\u5B9A\u5B89\u88C5\u6587\u4EF6\u5939\u540D\uFF1Ahint \u8FC7\u6CDB\u65F6\u6539\u7528 manifest.name\uFF1B\u518D\u4E0E\u5DF2\u5360\u7528\u540D\u907F\u8BA9\uFF08\u4E0D\u540C uuid \u4E0D\u4E92\u76F8\u8986\u76D6\uFF09\u3002\n * \u7EAF\u51FD\u6570\uFF1A\u53EA\u4F9D\u8D56 taken \u96C6\u5408\uFF0C\u4FBF\u4E8E\u8868\u9A71\u52A8\u5355\u6D4B\uFF08DRY\uFF1Adecide / choose \u5171\u7528\uFF09\u3002\n */\nexport function allocatePackFolderName(opts: {\n hint?: string;\n info: PackManifestInfo;\n takenFolderNames: Iterable<string>;\n /** \u540C uuid \u66F4\u65B0\u65F6\u5141\u8BB8\u5360\u7528\u7684\u5DF2\u6709\u76EE\u5F55\u540D\uFF08\u4E0D\u89E6\u53D1\u907F\u8BA9\uFF09 */\n allowFolderName?: string;\n}): string {\n const hint = (opts.hint && opts.hint.trim()) || \"\";\n const preferred = isGenericPackFolderStem(hint) ? opts.info.name || hint || \"pack\" : hint;\n let folderName = formatWorldPackFolderName(preferred, opts.info.kind);\n const allow = opts.allowFolderName ? path.basename(opts.allowFolderName) : null;\n if (allow && folderName === allow) return folderName;\n\n const taken = new Set([...opts.takenFolderNames].filter((n) => n !== allow));\n if (!taken.has(folderName)) return folderName;\n\n /* \u540C\u540D\u4E0D\u540C\u5305\uFF1Amanifest \u540D + uuid \u524D\u7F00\uFF1B\u4ECD\u649E\u5219\u9012\u589E */\n const withUuid = formatWorldPackFolderName(\n `${stripWorldPackFolderPrefix(preferred)} ${opts.info.uuid.slice(0, 8)}`,\n opts.info.kind\n );\n if (!taken.has(withUuid)) return withUuid;\n let i = 2;\n while (taken.has(`${withUuid}_${i}`)) i++;\n return `${withUuid}_${i}`;\n}\n\n/**\n * \u9009\u5B9A\u5B89\u88C5\u6587\u4EF6\u5939\u540D\uFF08\u8BFB destParent \u5360\u7528\uFF09\u3002\n * \u51B3\u7B56\u6743\u5A01\u89C1 allocatePackFolderName / decidePackInstallPlan\u3002\n */\nexport function choosePackInstallFolderName(opts: {\n hint?: string;\n info: PackManifestInfo;\n destParent: string;\n allowFolderName?: string;\n}): string {\n const taken = listPackDirsIn(opts.destParent).map((d) => path.basename(d));\n return allocatePackFolderName({\n info: opts.info,\n takenFolderNames: taken,\n ...(opts.hint !== undefined ? { hint: opts.hint } : {}),\n ...(opts.allowFolderName !== undefined ? { allowFolderName: opts.allowFolderName } : {}),\n });\n}\n\n/** \u6839\u636E manifest modules[].type \u5224\u5B9A BP / RP */\nexport function detectPackKindFromManifest(raw: {\n modules?: Array<{ type?: string }>;\n}): WorldPackKind | null {\n const types = (raw.modules ?? []).map((m) => String(m.type ?? \"\").toLowerCase());\n if (types.includes(\"resources\")) return \"resource\";\n if (types.some((t) => t === \"script\" || t === \"data\" || t === \"javascript\")) return \"behavior\";\n return null;\n}\n\nexport function readPackManifestInfo(packDir: string): PackManifestInfo | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = readJsonFile<{\n header?: { name?: string; uuid?: string; version?: number[]; description?: string };\n modules?: Array<{ type?: string }>;\n }>(file);\n const kind = detectPackKindFromManifest(raw);\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n const name = raw.header?.name;\n if (!kind || typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n if (typeof name !== \"string\" || !name) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const description = raw.header?.description;\n return {\n name,\n uuid,\n version,\n kind,\n ...(typeof description === \"string\" ? { description } : {}),\n };\n } catch {\n return null;\n }\n}\n\n/** \u6DF1\u5EA6\u4F18\u5148\u627E\u542B manifest.json \u7684\u5305\u6839\uFF08\u9ED8\u8BA4 maxDepth=2\uFF0Croot \u81EA\u8EAB\u4E3A depth 0\uFF09 */\nexport function discoverPackRoots(root: string, opts?: { maxDepth?: number }): string[] {\n const maxDepth = opts?.maxDepth ?? 2;\n const out: string[] = [];\n const abs = path.resolve(root);\n if (!fs.existsSync(abs)) return out;\n\n function walk(dir: string, depth: number): void {\n const manifest = path.join(dir, \"manifest.json\");\n if (fs.existsSync(manifest) && fs.statSync(manifest).isFile()) {\n out.push(dir);\n return; // \u5305\u6839\u4E0D\u518D\u4E0B\u94BB\n }\n if (depth >= maxDepth) return;\n let entries;\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n if (e.name.startsWith(\".\") || e.name === \"node_modules\") continue;\n walk(path.join(dir, e.name), depth + 1);\n }\n }\n\n const st = fs.statSync(abs);\n if (st.isDirectory()) walk(abs, 0);\n return out;\n}\n\nexport function isPackArchive(filePath: string): boolean {\n const lower = filePath.toLowerCase();\n return ARCHIVE_EXTS.some((ext) => lower.endsWith(ext));\n}\n\n/** \u53BB\u6389 .zip/.mcpack/.mcaddon \u540E\u7F00\u5F97\u5230 stem */\nfunction archiveStem(filePath: string): string {\n const base = path.basename(filePath);\n const lower = base.toLowerCase();\n for (const ext of ARCHIVE_EXTS) {\n if (lower.endsWith(ext)) return base.slice(0, -ext.length);\n }\n return path.parse(base).name;\n}\n\n/** \u5F52\u6863\u89E3\u538B\u76EE\u6807\uFF1A\u540C\u7EA7 stem \u76EE\u5F55\uFF1B\u91CD\u540D\u5219\u52A0 _2/_3\u2026 */\nfunction uniqueSiblingExtractDir(archivePath: string): string {\n const parent = path.dirname(archivePath);\n let dest = path.join(parent, archiveStem(archivePath) || \"pack\");\n if (!fs.existsSync(dest)) return dest;\n let i = 2;\n while (fs.existsSync(`${dest}_${i}`)) i++;\n return `${dest}_${i}`;\n}\n\n/**\n * \u5217\u51FA\u76EE\u5F55\u6811\u5185\u7684\u5305\u5F52\u6863\u6587\u4EF6\u3002\n * \u5DF2\u662F\u5305\u6839\uFF08\u542B manifest.json\uFF09\u7684\u76EE\u5F55\u4E0D\u518D\u4E0B\u94BB\uFF0C\u907F\u514D\u8BEF\u89E3\u538B\u5305\u5185\u8D44\u6E90\u3002\n */\nexport function listPackArchiveFiles(root: string, opts?: { maxDepth?: number }): string[] {\n const maxDepth = opts?.maxDepth ?? 4;\n const out: string[] = [];\n const abs = path.resolve(root);\n if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) return out;\n\n function walk(dir: string, depth: number): void {\n if (fs.existsSync(path.join(dir, \"manifest.json\"))) return;\n let entries;\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (e.name.startsWith(\".\") || e.name === \"node_modules\") continue;\n const full = path.join(dir, e.name);\n if (e.isFile() && isPackArchive(full)) {\n out.push(full);\n continue;\n }\n if (e.isDirectory() && depth < maxDepth) walk(full, depth + 1);\n }\n }\n\n walk(abs, 0);\n return out;\n}\n\n/**\n * \u5728\u4E34\u65F6\u6811\u5185\u539F\u5730\u5C55\u5F00\u5D4C\u5957\u5F52\u6863\uFF1A\u89E3\u538B\u5230\u540C\u7EA7\u76EE\u5F55\u5E76\u5220\u9664\u5F52\u6863\u6587\u4EF6\uFF0C\u591A\u8F6E\u76F4\u81F3\u6CA1\u6709\u65B0\u5F52\u6863\u3002\n * \u4EC5\u5E94\u5BF9\u6211\u4EEC\u81EA\u5DF1\u7684 staging\uFF0C\u7981\u6B62\u7528\u4E8E\u7528\u6237 inbox \u539F\u76EE\u5F55\u3002\n */\nexport async function expandNestedArchivesInPlace(\n workDir: string,\n opts?: { maxRounds?: number; maxScanDepth?: number }\n): Promise<number> {\n const maxRounds = opts?.maxRounds ?? 3;\n const maxScanDepth = opts?.maxScanDepth ?? 4;\n let expanded = 0;\n for (let round = 0; round < maxRounds; round++) {\n const archives = listPackArchiveFiles(workDir, { maxDepth: maxScanDepth });\n if (archives.length === 0) break;\n for (const arch of archives) {\n const dest = uniqueSiblingExtractDir(arch);\n await fs.promises.mkdir(dest, { recursive: true });\n await extractZipFileToDir(arch, dest);\n await fs.promises.unlink(arch);\n expanded++;\n }\n }\n return expanded;\n}\n\nexport type ResolvePackRootsResult = {\n roots: string[];\n /** \u6E05\u7406\u672C\u8F6E\u521B\u5EFA\u7684\u5168\u90E8\u4E34\u65F6\u76EE\u5F55\uFF08\u53EF\u5B89\u5168\u591A\u6B21\u8C03\u7528\uFF09 */\n dispose: () => void;\n};\n\n/**\n * \u7EDF\u4E00\u5305\u6839\u89E3\u6790\uFF1A\u76EE\u5F55 / \u9876\u5C42\u5F52\u6863 / \u5D4C\u5957 .mcpack|.zip|.mcaddon\u3002\n * \u89C4\u5219\uFF1A\u5148\u5C55\u5F00\u5F52\u6863\u4E3A\u76EE\u5F55\u6811\uFF0C\u518D\u53EA\u8BA4\u542B manifest.json \u7684\u76EE\u5F55\u4E3A\u5305\u6839\u3002\n * \u7528\u6237\u76EE\u5F55\u5185\u7684\u5D4C\u5957\u5F52\u6863\u89E3\u5230\u72EC\u7ACB temp\uFF0C\u4E0D\u4FEE\u6539\u539F\u76EE\u5F55\u3002\n */\nexport async function resolvePackRoots(\n src: string,\n opts?: { maxDirDepth?: number; maxArchiveRounds?: number }\n): Promise<ResolvePackRootsResult> {\n const maxDirDepth = opts?.maxDirDepth ?? 4;\n const maxArchiveRounds = opts?.maxArchiveRounds ?? 3;\n const temps: string[] = [];\n const dispose = (): void => {\n for (const d of temps.splice(0, temps.length)) {\n try {\n fs.rmSync(d, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n }\n };\n\n const abs = path.resolve(src);\n if (!fs.existsSync(abs)) return { roots: [], dispose };\n\n try {\n const st = fs.statSync(abs);\n if (st.isFile()) {\n if (!isPackArchive(abs)) return { roots: [], dispose };\n const tmp = await extractArchiveToTemp(abs);\n temps.push(tmp);\n await expandNestedArchivesInPlace(tmp, {\n maxRounds: maxArchiveRounds,\n maxScanDepth: maxDirDepth,\n });\n return { roots: discoverPackRoots(tmp, { maxDepth: maxDirDepth }), dispose };\n }\n\n if (!st.isDirectory()) return { roots: [], dispose };\n\n const nestedArchives = listPackArchiveFiles(abs, { maxDepth: maxDirDepth });\n if (nestedArchives.length === 0) {\n return { roots: discoverPackRoots(abs, { maxDepth: maxDirDepth }), dispose };\n }\n\n /* \u76EE\u5F55\u5305\u6839 + \u5404\u5D4C\u5957\u5F52\u6863\u5404\u81EA\u89E3\u5230 temp\uFF08\u4E0D\u6539\u7528\u6237\u76EE\u5F55\uFF09 */\n const roots = discoverPackRoots(abs, { maxDepth: maxDirDepth });\n const seen = new Set(roots.map((r) => path.resolve(r)));\n for (const arch of nestedArchives) {\n const tmp = await extractArchiveToTemp(arch);\n temps.push(tmp);\n await expandNestedArchivesInPlace(tmp, {\n maxRounds: maxArchiveRounds,\n maxScanDepth: maxDirDepth,\n });\n for (const r of discoverPackRoots(tmp, { maxDepth: maxDirDepth })) {\n const key = path.resolve(r);\n if (seen.has(key)) continue;\n seen.add(key);\n roots.push(r);\n }\n }\n return { roots, dispose };\n } catch (e) {\n dispose();\n throw e;\n }\n}\n\n/** \u89E3\u538B zip/mcpack/mcaddon \u5230\u4E34\u65F6\u76EE\u5F55\uFF0C\u8FD4\u56DE\u8BE5\u76EE\u5F55\uFF08\u7ECF zipx \u9632 zip-slip\uFF09 */\nexport async function extractArchiveToTemp(filePath: string): Promise<string> {\n const tmp = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-pack-\"));\n await extractZipFileToDir(filePath, tmp);\n return tmp;\n}\n\nfunction listPackDirsIn(parent: string): string[] {\n if (!fs.existsSync(parent)) return [];\n const out: string[] = [];\n for (const e of fs.readdirSync(parent, { withFileTypes: true })) {\n if (!e.isDirectory()) continue;\n const dir = path.join(parent, e.name);\n if (fs.existsSync(path.join(dir, \"manifest.json\"))) out.push(dir);\n }\n return out;\n}\n\n/** \u626B\u63CF\u4E16\u754C\u5185\u5DF2\u5B89\u88C5 BP/RP \u76EE\u5F55 */\nexport function listInstalledWorldPacks(bdsRoot: string, levelName: string): InstalledWorldPack[] {\n const worldRoot = bdsWorldLevelDir(bdsRoot, levelName);\n const worldsDir = bdsWorldsDir(bdsRoot);\n const result: InstalledWorldPack[] = [];\n\n for (const kind of [\"behavior\", \"resource\"] as const) {\n const parent = path.join(\n worldRoot,\n kind === \"behavior\" ? \"behavior_packs\" : \"resource_packs\"\n );\n const enabledList = readWorldPackList(worldsDir, levelName, kind);\n const enabledMap = new Map(enabledList.map((e) => [e.pack_id, e.version] as const));\n\n for (const dir of listPackDirsIn(parent)) {\n const info = readPackManifestInfo(dir);\n if (!info || info.kind !== kind) {\n // \u4ECD\u5C1D\u8BD5\u7528 header \u5C55\u793A\uFF08enabled \u4E0E\u6B63\u5E38\u8DEF\u5F84\u540C\u5951\u7EA6\uFF1Aenable-list \u542B uuid \u2192 LSP\uFF09\n const header = readPackManifestHeader(dir);\n if (!header) continue;\n result.push({\n kind,\n folderName: path.basename(dir),\n dir,\n name: path.basename(dir),\n uuid: header.uuid,\n version: header.version,\n enabled: enabledMap.has(header.uuid),\n });\n continue;\n }\n result.push({\n kind: info.kind,\n folderName: path.basename(dir),\n dir,\n name: info.name,\n uuid: info.uuid,\n version: info.version,\n enabled: enabledMap.has(info.uuid),\n });\n }\n }\n return result;\n}\n\n/**\n * \u5C06\u76EE\u6807\u5305 manifest.json \u4E2D\u7684 Patch \u7248\u672C\u53F7\u9012\u589E\uFF08+1\uFF09\u5E76\u6301\u4E45\u5316\u5199\u56DE\u3002\n *\n * @param packDir \u5305\u6839\u76EE\u5F55\u8DEF\u5F84\u3002\n * @returns \u9012\u589E\u540E\u7684\u7248\u672C\u4E09\u5143\u7EC4 `[major, minor, patch]`\u3002\n */\nexport function bumpPackPatchVersion(packDir: string): [number, number, number] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) throw new Error(`manifest.json missing: ${packDir}`);\n const raw = readJsonFile<{\n header?: { version?: number[] };\n modules?: Array<{ version?: number[] }>;\n }>(file);\n const ver = raw.header?.version;\n if (!Array.isArray(ver) || ver.length < 3) throw new Error(`invalid header.version in ${file}`);\n const next: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2]) + 1];\n return writePackHeaderVersion(packDir, next);\n}\n\n/**\n * \u5411\u76EE\u6807\u5305\u7684 manifest.json \u5199\u5165\u65B0\u7684\u7248\u672C\u53F7\uFF0C\u5E76\u540C\u6B65\u66F4\u65B0\u5185\u90E8 modules \u7684 patch \u7248\u672C\u3002\n *\n * @param packDir \u5305\u6839\u76EE\u5F55\u8DEF\u5F84\u3002\n * @param next \u5F85\u5199\u5165\u7684\u7248\u672C\u4E09\u5143\u7EC4\u3002\n * @returns \u5199\u5165\u786E\u8BA4\u7684\u7248\u672C\u4E09\u5143\u7EC4\u3002\n */\nexport function writePackHeaderVersion(\n\n packDir: string,\n next: [number, number, number]\n): [number, number, number] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) throw new Error(`manifest.json missing: ${packDir}`);\n const raw = readJsonFile<{\n header?: { version?: number[] };\n modules?: Array<{ version?: number[] }>;\n }>(file);\n if (!raw.header) raw.header = {};\n raw.header.version = next;\n if (Array.isArray(raw.modules)) {\n for (const m of raw.modules) {\n if (Array.isArray(m.version) && m.version.length >= 3) {\n m.version = [Number(m.version[0]), Number(m.version[1]), next[2]];\n }\n }\n }\n fs.writeFileSync(file, `${JSON.stringify(raw, null, 2)}\\n`, \"utf8\");\n return next;\n}\n\n/** \u8BFB\u53D6 BP manifest \u4E2D\u4F9D\u8D56\u7684\u8D44\u6E90\u5305 uuid\uFF08\u975E @minecraft \u6A21\u5757\uFF09 */\nexport function readPackDependencyUuids(packDir: string): string[] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return [];\n try {\n const raw = readJsonFile<{\n dependencies?: Array<{ uuid?: string; module_name?: string }>;\n }>(file);\n return (raw.dependencies ?? [])\n .map((d) => d.uuid)\n .filter((u): u is string => typeof u === \"string\" && u.length > 0);\n } catch {\n return [];\n }\n}\n\n/** \u6BD4\u8F83 SemVer \u4E09\u5143\u7EC4\uFF1Ba>b \u6B63\uFF0Ca<b \u8D1F\uFF0C\u76F8\u7B49 0 */\nexport function compareSemVer3(\n a: [number, number, number],\n b: [number, number, number]\n): number {\n for (let i = 0; i < 3; i++) {\n const d = a[i]! - b[i]!;\n if (d !== 0) return d;\n }\n return 0;\n}\n\n/** \u53D6\u8F83\u5927\u7684 SemVer \u4E09\u5143\u7EC4 */\nexport function maxSemVer3(\n a: [number, number, number],\n b: [number, number, number]\n): [number, number, number] {\n return compareSemVer3(a, b) >= 0 ? a : b;\n}\n\n/** \u6309 component \u62AC\u4E00\u7EA7 */\nexport function bumpSemVer3(\n v: [number, number, number],\n component: \"patch\" | \"minor\"\n): [number, number, number] {\n return component === \"minor\" ? [v[0], v[1] + 1, 0] : [v[0], v[1], v[2] + 1];\n}\n\n/**\n * \u8FDB\u670D\u542F\u7528\u7248\u672C\uFF1Amax(\u8FDC\u7A0B/\u65B0\u5305, \u65E7\u542F\u7528) \u518D\u62AC\u4E00\u7EA7\u3002\n * \u5355\u4E00\u89C4\u5219\uFF0C\u7981\u6B62 while \u8FFD\u8D76\uFF08\u4F5C\u8005\u4E71\u5199\u9AD8\u7248\u672C\u5982 [1,21,100] \u65F6\u4E5F\u80FD\u4E00\u6B21\u7B97\u5B8C\uFF09\u3002\n */\nexport function nextEnabledVersion(\n remote: [number, number, number],\n previous: [number, number, number],\n component: \"patch\" | \"minor\" = \"patch\"\n): [number, number, number] {\n return bumpSemVer3(maxSemVer3(remote, previous), component);\n}\n\n/**\n * \u5C06\u5305\u76EE\u5F55 manifest \u62AC\u5230 nextEnabledVersion(\u5F53\u524D, previous)\u3002\n * previous \u4E00\u822C\u4E3A\u66F4\u65B0\u524D\u5DF2\u5B89\u88C5 RP / \u4E16\u754C enable \u5217\u8868\u4E2D\u7684\u7248\u672C\u3002\n */\nexport function ensureVersionGreaterThan(\n packDir: string,\n previous: [number, number, number],\n component: \"patch\" | \"minor\" = \"patch\"\n): [number, number, number] {\n const info = readPackManifestInfo(packDir);\n if (!info) throw new Error(`cannot read pack version: ${packDir}`);\n const next = nextEnabledVersion(info.version, previous, component);\n return writePackHeaderVersion(packDir, next);\n}\n\nexport interface InstallPackResult {\n ok: boolean;\n skipped?: boolean;\n reason?: string;\n destDir?: string;\n folderName?: string;\n info?: PackManifestInfo;\n conflict?: { existing: PackManifestInfo & { dir: string }; incoming: PackManifestInfo };\n}\n\n/** \u76EE\u6807\u7236\u76EE\u5F55\u5185\u5DF2\u5360\u7528\u9879\uFF08\u4F9B\u7EAF\u51B3\u7B56\uFF0C\u4E0D\u542B FS \u526F\u4F5C\u7528\uFF09 */\nexport type DestOccupancy = {\n folderName: string;\n dir: string;\n uuid: string | null;\n version: [number, number, number] | null;\n /** \u53EF\u8BFB\u65F6\u7684\u5C55\u793A\u540D\uFF1B\u51B3\u7B56\u4E0D\u4F9D\u8D56\uFF0C\u4EC5\u4F9B conflict UI */\n name?: string;\n /** \u53EF\u8BFB\u65F6\u7684\u5305\u7C7B\u578B\uFF1B\u51B3\u7B56\u5C55\u793A\u4F18\u5148\u7528\u771F\u5B9E kind\uFF0C\u907F\u514D\u4F2A\u9020 incoming.kind\uFF08LSP\uFF09 */\n kind?: WorldPackKind;\n};\n\nexport type PackInstallPlan =\n | { kind: \"fresh\"; folderName: string; incoming: PackManifestInfo }\n | {\n kind: \"overwriteInPlace\";\n folderName: string;\n dir: string;\n incoming: PackManifestInfo;\n existing: PackManifestInfo & { dir: string };\n }\n | {\n kind: \"needConfirm\";\n folderName: string;\n dir: string;\n incoming: PackManifestInfo;\n existing: PackManifestInfo & { dir: string };\n };\n\n/**\n * \u8BFB\u5355\u76EE\u5F55\u5360\u7528\u4E8B\u5B9E\uFF08info \u4F18\u5148\uFF0C\u5426\u5219 header\uFF09\u3002\n * \u89E3\u6790\u5931\u8D25\u8FD4\u56DE null\uFF1B\u4E0D\u629B BOM\uFF08readJsonFile \u5DF2\u5265\u79BB\uFF09\u3002\n */\nexport function readPackDirOccupancy(dir: string): {\n uuid: string;\n version: [number, number, number];\n name?: string;\n kind?: WorldPackKind;\n} | null {\n const info = readPackManifestInfo(dir);\n if (info) {\n return {\n uuid: info.uuid,\n version: info.version,\n name: info.name,\n kind: info.kind,\n };\n }\n const header = readPackManifestHeader(dir);\n if (header) {\n return { uuid: header.uuid, version: header.version };\n }\n return null;\n}\n\n/** \u626B\u63CF destParent \u4E0B\u542B manifest \u7684\u76EE\u5F55\u5360\u7528\uFF08\u5355\u4E00\u4E8B\u5B9E\u6E90\uFF1AreadPackDirOccupancy\uFF09 */\nexport function scanDestOccupancy(destParent: string): DestOccupancy[] {\n const out: DestOccupancy[] = [];\n for (const dir of listPackDirsIn(destParent)) {\n let facts: ReturnType<typeof readPackDirOccupancy> = null;\n try {\n // DRY\uFF1A\u4E0E readPackDirOccupancy \u5171\u7528 info\u2192header \u56DE\u9000\uFF0C\u7981\u6B62\u5185\u8054\u53CC\u8BFB\n facts = readPackDirOccupancy(dir);\n } catch {\n /* manifest \u4E0D\u53EF\u8BFB\u5219\u5360\u4F4D uuid \u4E3A\u7A7A */\n }\n out.push({\n folderName: path.basename(dir),\n dir,\n uuid: facts?.uuid ?? null,\n version: facts?.version ?? null,\n ...(facts?.name ? { name: facts.name } : {}),\n ...(facts?.kind ? { kind: facts.kind } : {}),\n });\n }\n return out;\n}\n\n/**\n * \u7EAF\u51B3\u7B56\uFF1A\u88C5\u5230\u54EA\u3001\u662F\u5426\u9700\u786E\u8BA4\u3001\u662F\u5426\u539F\u5730\u8986\u76D6\u3002\n * \u540C uuid\uFF1Aincoming \u7248\u672C\u4E25\u683C\u66F4\u5927 \u2192 \u9759\u9ED8\u8986\u76D6\uFF1B\u2264 \u5DF2\u6709\u4E14 !force \u2192 needConfirm\uFF1Bforce \u2192 \u539F\u5730\u8986\u76D6\u3002\n */\nexport function decidePackInstallPlan(opts: {\n incoming: PackManifestInfo;\n hint?: string;\n occupancy: readonly DestOccupancy[];\n force?: boolean;\n}): PackInstallPlan {\n const force = Boolean(opts.force);\n const incomingUuid = opts.incoming.uuid.toLowerCase();\n const same = opts.occupancy.find((o) => o.uuid != null && o.uuid.toLowerCase() === incomingUuid);\n\n if (same) {\n const existingVersion: [number, number, number] = same.version ?? [0, 0, 0];\n const existing: PackManifestInfo & { dir: string } = {\n name: same.name ?? same.folderName,\n uuid: same.uuid!,\n version: existingVersion,\n kind: same.kind ?? opts.incoming.kind,\n dir: same.dir,\n };\n\n const newer = compareSemVer3(opts.incoming.version, existing.version) > 0;\n if (force || newer) {\n return {\n kind: \"overwriteInPlace\",\n folderName: same.folderName,\n dir: same.dir,\n incoming: opts.incoming,\n existing,\n };\n }\n return {\n kind: \"needConfirm\",\n folderName: same.folderName,\n dir: same.dir,\n incoming: opts.incoming,\n existing,\n };\n }\n\n const folderName = allocatePackFolderName({\n info: opts.incoming,\n takenFolderNames: opts.occupancy.map((o) => o.folderName),\n ...(opts.hint !== undefined ? { hint: opts.hint } : {}),\n });\n return { kind: \"fresh\", folderName, incoming: opts.incoming };\n}\n\n/** \u843D\u76D8\u540E\u6821\u9A8C\uFF1A\u9632\u6B62\u65C1\u8DEF\u5B89\u88C5 / \u62F7\u8D1D\u5931\u8D25\u4ECD\u62A5\u6210\u529F */\nexport function verifyInstalledPack(\n destDir: string,\n incoming: PackManifestInfo\n): { ok: true; info: PackManifestInfo } | { ok: false; reason: string } {\n const info = readPackManifestInfo(destDir);\n if (!info) return { ok: false, reason: \"verify: dest has no readable manifest\" };\n if (info.uuid.toLowerCase() !== incoming.uuid.toLowerCase()) {\n return { ok: false, reason: `verify: uuid mismatch got=${info.uuid} want=${incoming.uuid}` };\n }\n if (info.kind !== incoming.kind) {\n return { ok: false, reason: `verify: kind mismatch got=${info.kind} want=${incoming.kind}` };\n }\n if (compareSemVer3(info.version, incoming.version) !== 0) {\n return {\n ok: false,\n reason: `verify: version mismatch got=${info.version.join(\".\")} want=${incoming.version.join(\".\")}`,\n };\n }\n return { ok: true, info };\n}\n\n/**\n * \u5C06\u5305\u76EE\u5F55\u5B89\u88C5\u5230 destParent\uFF08behavior_packs \u6216 resource_packs\uFF09\u3002\n * \u7F16\u6392\uFF1Ascan \u2192 decide \u2192 apply \u2192 verify\u3002\u540C uuid \u7248\u672C\u66F4\u9AD8\u65F6\u9759\u9ED8\u539F\u5730\u8986\u76D6\u3002\n */\nexport async function installPackDirectory(opts: {\n srcDir: string;\n destParent: string;\n folderName?: string;\n force?: boolean;\n}): Promise<InstallPackResult> {\n const info = readPackManifestInfo(opts.srcDir);\n if (!info) {\n return { ok: false, reason: \"invalid or unrecognized manifest.json\" };\n }\n\n await fs.promises.mkdir(opts.destParent, { recursive: true });\n\n const occupancy = scanDestOccupancy(opts.destParent);\n const plan = decidePackInstallPlan({\n incoming: info,\n hint: opts.folderName ?? path.basename(opts.srcDir),\n occupancy,\n ...(opts.force !== undefined ? { force: opts.force } : {}),\n });\n\n if (plan.kind === \"needConfirm\") {\n return {\n ok: false,\n skipped: true,\n reason: \"conflict\",\n conflict: {\n existing: plan.existing,\n incoming: info,\n },\n };\n }\n\n const destDir = path.join(opts.destParent, plan.folderName);\n if (plan.kind === \"overwriteInPlace\" && path.resolve(plan.dir) !== path.resolve(destDir)) {\n return {\n ok: false,\n reason: `invariant: overwrite path drift plan.dir=${plan.dir} destDir=${destDir}`,\n };\n }\n\n if (fs.existsSync(destDir)) {\n await fs.promises.rm(destDir, { recursive: true, force: true });\n }\n await copyDirAsync(opts.srcDir, destDir);\n\n const verified = verifyInstalledPack(destDir, info);\n if (!verified.ok) {\n return { ok: false, reason: verified.reason, folderName: plan.folderName, info };\n }\n return { ok: true, destDir, folderName: plan.folderName, info: verified.info };\n}\n\n/** \u5B89\u88C5\u540E\u5199\u5165\u4E16\u754C enable \u6E05\u5355 */\nexport async function enableInstalledPack(opts: {\n bdsRoot: string;\n levelName: string;\n info: PackManifestInfo;\n}): Promise<void> {\n await enablePackInWorld({\n worldsDir: bdsWorldsDir(opts.bdsRoot),\n levelName: opts.levelName,\n kind: opts.info.kind,\n packUuid: opts.info.uuid,\n version: opts.info.version,\n });\n}\n\n/** \u4ECE\u4E16\u754C enable \u6E05\u5355\u79FB\u9664 */\nexport async function disableInstalledPack(opts: {\n bdsRoot: string;\n levelName: string;\n kind: WorldPackKind;\n packUuid: string;\n version: [number, number, number];\n}): Promise<void> {\n await disablePackInWorld({\n worldsDir: bdsWorldsDir(opts.bdsRoot),\n levelName: opts.levelName,\n kind: opts.kind,\n packUuid: opts.packUuid,\n version: opts.version,\n });\n}\n\nexport type UninstallPackResult =\n | { action: \"trashed\"; dest: string }\n | { action: \"deleted\" }\n | { action: \"missing\" };\n\nexport type UninstallPackAction = UninstallPackResult[\"action\"];\n\n/**\n * \u5378\u8F7D\u5DF2\u5B89\u88C5\u4E16\u754C\u5305\uFF1A\u5148 disable enable-list\uFF0C\u518D\u79FB\u5165 trashDir \u6216\u76F4\u63A5\u5220\u9664\u76EE\u5F55\u3002\n * trashDir \u8DE8\u76D8\u7B26\u65F6 fallback \u4E3A copy + rm\u3002\n */\nexport async function uninstallInstalledPack(opts: {\n bdsRoot: string;\n levelName: string;\n pack: InstalledWorldPack;\n /** \u63D0\u4F9B\u5219\u79FB\u5165\u8BE5\u76EE\u5F55\uFF1Bnull/\u7701\u7565\u5219\u76F4\u63A5\u5220\u9664 */\n trashDir?: string | null;\n}): Promise<UninstallPackResult> {\n await disableInstalledPack({\n bdsRoot: opts.bdsRoot,\n levelName: opts.levelName,\n kind: opts.pack.kind,\n packUuid: opts.pack.uuid,\n version: opts.pack.version,\n });\n\n if (!fs.existsSync(opts.pack.dir)) {\n return { action: \"missing\" };\n }\n\n const trashDir = opts.trashDir?.trim() || null;\n if (trashDir) {\n await fs.promises.mkdir(trashDir, { recursive: true });\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n let dest = path.join(trashDir, opts.pack.folderName);\n if (fs.existsSync(dest)) {\n dest = path.join(trashDir, `${opts.pack.folderName}-${stamp}`);\n }\n try {\n await fs.promises.rename(opts.pack.dir, dest);\n } catch {\n await copyDirAsync(opts.pack.dir, dest);\n await fs.promises.rm(opts.pack.dir, { recursive: true, force: true });\n }\n return { action: \"trashed\", dest };\n }\n\n await fs.promises.rm(opts.pack.dir, { recursive: true, force: true });\n return { action: \"deleted\" };\n}\n\nexport function worldPackParentDir(\n bdsRoot: string,\n levelName: string,\n kind: WorldPackKind\n): string {\n return path.join(\n bdsWorldLevelDir(bdsRoot, levelName),\n kind === \"behavior\" ? \"behavior_packs\" : \"resource_packs\"\n );\n}\n\n/** \u4E16\u754C enable-list \u6743\u5A01\u8BFB\u53D6 \u2014 \u59D4\u6258 pack-manager\uFF08\u4F9B doctor \u7B49\uFF0C\u907F\u514D\u786C\u7F16\u7801\u6587\u4EF6\u540D\uFF09 */\nexport function listWorldEnableEntries(\n bdsRoot: string,\n levelName: string,\n kind: WorldPackKind\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return listWorldEnableListResult(bdsRoot, levelName, kind).entries;\n}\n\n/** \u542B parseFail \u4FE1\u53F7\u7684 enable-list \u5FEB\u7167\uFF08doctor \u7528\uFF1B\u4E0D\u66B4\u9732 JSON \u8DEF\u5F84\u6784\u9020\u7EC6\u8282\uFF09 */\nexport function listWorldEnableListResult(\n bdsRoot: string,\n levelName: string,\n kind: WorldPackKind\n): WorldPackListReadResult {\n return readWorldPackListResult(bdsWorldsDir(bdsRoot), levelName, kind);\n}\n\nexport function findInstalledPackById(\n packs: InstalledWorldPack[],\n id: string\n): InstalledWorldPack | null {\n const q = id.trim().toLowerCase();\n return (\n packs.find(\n (p) =>\n p.uuid.toLowerCase() === q ||\n p.folderName.toLowerCase() === q ||\n p.name.toLowerCase() === q ||\n p.folderName.toLowerCase().includes(q) ||\n p.name.toLowerCase().includes(q)\n ) ?? null\n );\n}\n"],
|
|
5
|
+
"mappings": "AAUA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,cAAc,oBAAoB;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,2BAA2B;AAsBpC,MAAM,eAAe,CAAC,QAAQ,WAAW,UAAU;AAG5C,SAAS,0BAA0B,SAAiB,MAA6B;AACtF,MAAI,IAAI,OAAO,WAAW,EAAE;AAC5B,MAAI,EAAE,QAAQ,iBAAiB,EAAE;AACjC,MAAI,EAAE,QAAQ,4BAA4B,EAAE;AAC5C,MAAI,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAChC,MAAI,CAAC,EAAG,KAAI;AACZ,QAAM,SAAS,SAAS,aAAa,SAAS;AAC9C,MAAI,EAAE,WAAW,MAAM,KAAK,EAAE,WAAW,MAAM,EAAG,QAAO;AACzD,SAAO,GAAG,MAAM,IAAI,CAAC;AACvB;AAGO,SAAS,2BAA2B,SAAyB;AAClE,SAAO,OAAO,WAAW,EAAE,EACxB,QAAQ,eAAe,EAAE,EACzB,QAAQ,eAAe,EAAE,EACzB,QAAQ,4BAA4B,EAAE,EACtC,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAMO,SAAS,wBAAwB,SAA0B;AAChE,QAAM,IAAI,2BAA2B,OAAO;AAC5C,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,EAAE,UAAU,EAAG,QAAO;AAC1B,SAAO,oEAAoE,KAAK,CAAC;AACnF;AAMO,SAAS,uBAAuB,MAM5B;AACT,QAAM,OAAQ,KAAK,QAAQ,KAAK,KAAK,KAAK,KAAM;AAChD,QAAM,YAAY,wBAAwB,IAAI,IAAI,KAAK,KAAK,QAAQ,QAAQ,SAAS;AACrF,MAAI,aAAa,0BAA0B,WAAW,KAAK,KAAK,IAAI;AACpE,QAAM,QAAQ,KAAK,kBAAkB,KAAK,SAAS,KAAK,eAAe,IAAI;AAC3E,MAAI,SAAS,eAAe,MAAO,QAAO;AAE1C,QAAM,QAAQ,IAAI,IAAI,CAAC,GAAG,KAAK,gBAAgB,EAAE,OAAO,CAAC,MAAM,MAAM,KAAK,CAAC;AAC3E,MAAI,CAAC,MAAM,IAAI,UAAU,EAAG,QAAO;AAGnC,QAAM,WAAW;AAAA,IACf,GAAG,2BAA2B,SAAS,CAAC,IAAI,KAAK,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC;AAAA,IACtE,KAAK,KAAK;AAAA,EACZ;AACA,MAAI,CAAC,MAAM,IAAI,QAAQ,EAAG,QAAO;AACjC,MAAI,IAAI;AACR,SAAO,MAAM,IAAI,GAAG,QAAQ,IAAI,CAAC,EAAE,EAAG;AACtC,SAAO,GAAG,QAAQ,IAAI,CAAC;AACzB;AAMO,SAAS,4BAA4B,MAKjC;AACT,QAAM,QAAQ,eAAe,KAAK,UAAU,EAAE,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACzE,SAAO,uBAAuB;AAAA,IAC5B,MAAM,KAAK;AAAA,IACX,kBAAkB;AAAA,IAClB,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,IACrD,GAAI,KAAK,oBAAoB,SAAY,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;AAAA,EACxF,CAAC;AACH;AAGO,SAAS,2BAA2B,KAElB;AACvB,QAAM,SAAS,IAAI,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,OAAO,EAAE,QAAQ,EAAE,EAAE,YAAY,CAAC;AAC/E,MAAI,MAAM,SAAS,WAAW,EAAG,QAAO;AACxC,MAAI,MAAM,KAAK,CAAC,MAAM,MAAM,YAAY,MAAM,UAAU,MAAM,YAAY,EAAG,QAAO;AACpF,SAAO;AACT;AAEO,SAAS,qBAAqB,SAA0C;AAC7E,QAAM,OAAO,KAAK,KAAK,SAAS,eAAe;AAC/C,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO;AACjC,MAAI;AACF,UAAM,MAAM,aAGT,IAAI;AACP,UAAM,OAAO,2BAA2B,GAAG;AAC3C,UAAM,OAAO,IAAI,QAAQ;AACzB,UAAM,MAAM,IAAI,QAAQ;AACxB,UAAM,OAAO,IAAI,QAAQ;AACzB,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,SAAS,EAAG,QAAO;AACvF,QAAI,OAAO,SAAS,YAAY,CAAC,KAAM,QAAO;AAC9C,UAAM,UAAoC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC;AACzF,UAAM,cAAc,IAAI,QAAQ;AAChC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,OAAO,gBAAgB,WAAW,EAAE,YAAY,IAAI,CAAC;AAAA,IAC3D;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,kBAAkB,MAAc,MAAwC;AACtF,QAAM,WAAW,MAAM,YAAY;AACnC,QAAM,MAAgB,CAAC;AACvB,QAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG,QAAO;AAEhC,WAAS,KAAK,KAAa,OAAqB;AAC9C,UAAM,WAAW,KAAK,KAAK,KAAK,eAAe;AAC/C,QAAI,GAAG,WAAW,QAAQ,KAAK,GAAG,SAAS,QAAQ,EAAE,OAAO,GAAG;AAC7D,UAAI,KAAK,GAAG;AACZ;AAAA,IACF;AACA,QAAI,SAAS,SAAU;AACvB,QAAI;AACJ,QAAI;AACF,gBAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACvD,QAAQ;AACN;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,EAAE,YAAY,EAAG;AACtB,UAAI,EAAE,KAAK,WAAW,GAAG,KAAK,EAAE,SAAS,eAAgB;AACzD,WAAK,KAAK,KAAK,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,KAAK,GAAG,SAAS,GAAG;AAC1B,MAAI,GAAG,YAAY,EAAG,MAAK,KAAK,CAAC;AACjC,SAAO;AACT;AAEO,SAAS,cAAc,UAA2B;AACvD,QAAM,QAAQ,SAAS,YAAY;AACnC,SAAO,aAAa,KAAK,CAAC,QAAQ,MAAM,SAAS,GAAG,CAAC;AACvD;AAGA,SAAS,YAAY,UAA0B;AAC7C,QAAM,OAAO,KAAK,SAAS,QAAQ;AACnC,QAAM,QAAQ,KAAK,YAAY;AAC/B,aAAW,OAAO,cAAc;AAC9B,QAAI,MAAM,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,CAAC,IAAI,MAAM;AAAA,EAC3D;AACA,SAAO,KAAK,MAAM,IAAI,EAAE;AAC1B;AAGA,SAAS,wBAAwB,aAA6B;AAC5D,QAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,MAAI,OAAO,KAAK,KAAK,QAAQ,YAAY,WAAW,KAAK,MAAM;AAC/D,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO;AACjC,MAAI,IAAI;AACR,SAAO,GAAG,WAAW,GAAG,IAAI,IAAI,CAAC,EAAE,EAAG;AACtC,SAAO,GAAG,IAAI,IAAI,CAAC;AACrB;AAMO,SAAS,qBAAqB,MAAc,MAAwC;AACzF,QAAM,WAAW,MAAM,YAAY;AACnC,QAAM,MAAgB,CAAC;AACvB,QAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,CAAC,GAAG,WAAW,GAAG,KAAK,CAAC,GAAG,SAAS,GAAG,EAAE,YAAY,EAAG,QAAO;AAEnE,WAAS,KAAK,KAAa,OAAqB;AAC9C,QAAI,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,EAAG;AACpD,QAAI;AACJ,QAAI;AACF,gBAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACvD,QAAQ;AACN;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,KAAK,WAAW,GAAG,KAAK,EAAE,SAAS,eAAgB;AACzD,YAAM,OAAO,KAAK,KAAK,KAAK,EAAE,IAAI;AAClC,UAAI,EAAE,OAAO,KAAK,cAAc,IAAI,GAAG;AACrC,YAAI,KAAK,IAAI;AACb;AAAA,MACF;AACA,UAAI,EAAE,YAAY,KAAK,QAAQ,SAAU,MAAK,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,OAAK,KAAK,CAAC;AACX,SAAO;AACT;AAMA,eAAsB,4BACpB,SACA,MACiB;AACjB,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,eAAe,MAAM,gBAAgB;AAC3C,MAAI,WAAW;AACf,WAAS,QAAQ,GAAG,QAAQ,WAAW,SAAS;AAC9C,UAAM,WAAW,qBAAqB,SAAS,EAAE,UAAU,aAAa,CAAC;AACzE,QAAI,SAAS,WAAW,EAAG;AAC3B,eAAW,QAAQ,UAAU;AAC3B,YAAM,OAAO,wBAAwB,IAAI;AACzC,YAAM,GAAG,SAAS,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;AACjD,YAAM,oBAAoB,MAAM,IAAI;AACpC,YAAM,GAAG,SAAS,OAAO,IAAI;AAC7B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAaA,eAAsB,iBACpB,KACA,MACiC;AACjC,QAAM,cAAc,MAAM,eAAe;AACzC,QAAM,mBAAmB,MAAM,oBAAoB;AACnD,QAAM,QAAkB,CAAC;AACzB,QAAM,UAAU,MAAY;AAC1B,eAAW,KAAK,MAAM,OAAO,GAAG,MAAM,MAAM,GAAG;AAC7C,UAAI;AACF,WAAG,OAAO,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,MAC/C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG,QAAO,EAAE,OAAO,CAAC,GAAG,QAAQ;AAErD,MAAI;AACF,UAAM,KAAK,GAAG,SAAS,GAAG;AAC1B,QAAI,GAAG,OAAO,GAAG;AACf,UAAI,CAAC,cAAc,GAAG,EAAG,QAAO,EAAE,OAAO,CAAC,GAAG,QAAQ;AACrD,YAAM,MAAM,MAAM,qBAAqB,GAAG;AAC1C,YAAM,KAAK,GAAG;AACd,YAAM,4BAA4B,KAAK;AAAA,QACrC,WAAW;AAAA,QACX,cAAc;AAAA,MAChB,CAAC;AACD,aAAO,EAAE,OAAO,kBAAkB,KAAK,EAAE,UAAU,YAAY,CAAC,GAAG,QAAQ;AAAA,IAC7E;AAEA,QAAI,CAAC,GAAG,YAAY,EAAG,QAAO,EAAE,OAAO,CAAC,GAAG,QAAQ;AAEnD,UAAM,iBAAiB,qBAAqB,KAAK,EAAE,UAAU,YAAY,CAAC;AAC1E,QAAI,eAAe,WAAW,GAAG;AAC/B,aAAO,EAAE,OAAO,kBAAkB,KAAK,EAAE,UAAU,YAAY,CAAC,GAAG,QAAQ;AAAA,IAC7E;AAGA,UAAM,QAAQ,kBAAkB,KAAK,EAAE,UAAU,YAAY,CAAC;AAC9D,UAAM,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC;AACtD,eAAW,QAAQ,gBAAgB;AACjC,YAAM,MAAM,MAAM,qBAAqB,IAAI;AAC3C,YAAM,KAAK,GAAG;AACd,YAAM,4BAA4B,KAAK;AAAA,QACrC,WAAW;AAAA,QACX,cAAc;AAAA,MAChB,CAAC;AACD,iBAAW,KAAK,kBAAkB,KAAK,EAAE,UAAU,YAAY,CAAC,GAAG;AACjE,cAAM,MAAM,KAAK,QAAQ,CAAC;AAC1B,YAAI,KAAK,IAAI,GAAG,EAAG;AACnB,aAAK,IAAI,GAAG;AACZ,cAAM,KAAK,CAAC;AAAA,MACd;AAAA,IACF;AACA,WAAO,EAAE,OAAO,QAAQ;AAAA,EAC1B,SAAS,GAAG;AACV,YAAQ;AACR,UAAM;AAAA,EACR;AACF;AAGA,eAAsB,qBAAqB,UAAmC;AAC5E,QAAM,MAAM,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,YAAY,CAAC;AAC/D,QAAM,oBAAoB,UAAU,GAAG;AACvC,SAAO;AACT;AAEA,SAAS,eAAe,QAA0B;AAChD,MAAI,CAAC,GAAG,WAAW,MAAM,EAAG,QAAO,CAAC;AACpC,QAAM,MAAgB,CAAC;AACvB,aAAW,KAAK,GAAG,YAAY,QAAQ,EAAE,eAAe,KAAK,CAAC,GAAG;AAC/D,QAAI,CAAC,EAAE,YAAY,EAAG;AACtB,UAAM,MAAM,KAAK,KAAK,QAAQ,EAAE,IAAI;AACpC,QAAI,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,EAAG,KAAI,KAAK,GAAG;AAAA,EAClE;AACA,SAAO;AACT;AAGO,SAAS,wBAAwB,SAAiB,WAAyC;AAChG,QAAM,YAAY,iBAAiB,SAAS,SAAS;AACrD,QAAM,YAAY,aAAa,OAAO;AACtC,QAAM,SAA+B,CAAC;AAEtC,aAAW,QAAQ,CAAC,YAAY,UAAU,GAAY;AACpD,UAAM,SAAS,KAAK;AAAA,MAClB;AAAA,MACA,SAAS,aAAa,mBAAmB;AAAA,IAC3C;AACA,UAAM,cAAc,kBAAkB,WAAW,WAAW,IAAI;AAChE,UAAM,aAAa,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,CAAU,CAAC;AAElF,eAAW,OAAO,eAAe,MAAM,GAAG;AACxC,YAAM,OAAO,qBAAqB,GAAG;AACrC,UAAI,CAAC,QAAQ,KAAK,SAAS,MAAM;AAE/B,cAAM,SAAS,uBAAuB,GAAG;AACzC,YAAI,CAAC,OAAQ;AACb,eAAO,KAAK;AAAA,UACV;AAAA,UACA,YAAY,KAAK,SAAS,GAAG;AAAA,UAC7B;AAAA,UACA,MAAM,KAAK,SAAS,GAAG;AAAA,UACvB,MAAM,OAAO;AAAA,UACb,SAAS,OAAO;AAAA,UAChB,SAAS,WAAW,IAAI,OAAO,IAAI;AAAA,QACrC,CAAC;AACD;AAAA,MACF;AACA,aAAO,KAAK;AAAA,QACV,MAAM,KAAK;AAAA,QACX,YAAY,KAAK,SAAS,GAAG;AAAA,QAC7B;AAAA,QACA,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,SAAS,WAAW,IAAI,KAAK,IAAI;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,qBAAqB,SAA2C;AAC9E,QAAM,OAAO,KAAK,KAAK,SAAS,eAAe;AAC/C,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,OAAM,IAAI,MAAM,0BAA0B,OAAO,EAAE;AAC7E,QAAM,MAAM,aAGT,IAAI;AACP,QAAM,MAAM,IAAI,QAAQ;AACxB,MAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,SAAS,EAAG,OAAM,IAAI,MAAM,6BAA6B,IAAI,EAAE;AAC9F,QAAM,OAAiC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC;AAC1F,SAAO,uBAAuB,SAAS,IAAI;AAC7C;AASO,SAAS,uBAEd,SACA,MAC0B;AAC1B,QAAM,OAAO,KAAK,KAAK,SAAS,eAAe;AAC/C,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,OAAM,IAAI,MAAM,0BAA0B,OAAO,EAAE;AAC7E,QAAM,MAAM,aAGT,IAAI;AACP,MAAI,CAAC,IAAI,OAAQ,KAAI,SAAS,CAAC;AAC/B,MAAI,OAAO,UAAU;AACrB,MAAI,MAAM,QAAQ,IAAI,OAAO,GAAG;AAC9B,eAAW,KAAK,IAAI,SAAS;AAC3B,UAAI,MAAM,QAAQ,EAAE,OAAO,KAAK,EAAE,QAAQ,UAAU,GAAG;AACrD,UAAE,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACA,KAAG,cAAc,MAAM,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AAClE,SAAO;AACT;AAGO,SAAS,wBAAwB,SAA2B;AACjE,QAAM,OAAO,KAAK,KAAK,SAAS,eAAe;AAC/C,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO,CAAC;AAClC,MAAI;AACF,UAAM,MAAM,aAET,IAAI;AACP,YAAQ,IAAI,gBAAgB,CAAC,GAC1B,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,OAAO,CAAC,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,CAAC;AAAA,EACrE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGO,SAAS,eACd,GACA,GACQ;AACR,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,IAAI,EAAE,CAAC,IAAK,EAAE,CAAC;AACrB,QAAI,MAAM,EAAG,QAAO;AAAA,EACtB;AACA,SAAO;AACT;AAGO,SAAS,WACd,GACA,GAC0B;AAC1B,SAAO,eAAe,GAAG,CAAC,KAAK,IAAI,IAAI;AACzC;AAGO,SAAS,YACd,GACA,WAC0B;AAC1B,SAAO,cAAc,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;AAC5E;AAMO,SAAS,mBACd,QACA,UACA,YAA+B,SACL;AAC1B,SAAO,YAAY,WAAW,QAAQ,QAAQ,GAAG,SAAS;AAC5D;AAMO,SAAS,yBACd,SACA,UACA,YAA+B,SACL;AAC1B,QAAM,OAAO,qBAAqB,OAAO;AACzC,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B,OAAO,EAAE;AACjE,QAAM,OAAO,mBAAmB,KAAK,SAAS,UAAU,SAAS;AACjE,SAAO,uBAAuB,SAAS,IAAI;AAC7C;AA6CO,SAAS,qBAAqB,KAK5B;AACP,QAAM,OAAO,qBAAqB,GAAG;AACrC,MAAI,MAAM;AACR,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AACA,QAAM,SAAS,uBAAuB,GAAG;AACzC,MAAI,QAAQ;AACV,WAAO,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ;AAAA,EACtD;AACA,SAAO;AACT;AAGO,SAAS,kBAAkB,YAAqC;AACrE,QAAM,MAAuB,CAAC;AAC9B,aAAW,OAAO,eAAe,UAAU,GAAG;AAC5C,QAAI,QAAiD;AACrD,QAAI;AAEF,cAAQ,qBAAqB,GAAG;AAAA,IAClC,QAAQ;AAAA,IAER;AACA,QAAI,KAAK;AAAA,MACP,YAAY,KAAK,SAAS,GAAG;AAAA,MAC7B;AAAA,MACA,MAAM,OAAO,QAAQ;AAAA,MACrB,SAAS,OAAO,WAAW;AAAA,MAC3B,GAAI,OAAO,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,MAC1C,GAAI,OAAO,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IAC5C,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAMO,SAAS,sBAAsB,MAKlB;AAClB,QAAM,QAAQ,QAAQ,KAAK,KAAK;AAChC,QAAM,eAAe,KAAK,SAAS,KAAK,YAAY;AACpD,QAAM,OAAO,KAAK,UAAU,KAAK,CAAC,MAAM,EAAE,QAAQ,QAAQ,EAAE,KAAK,YAAY,MAAM,YAAY;AAE/F,MAAI,MAAM;AACR,UAAM,kBAA4C,KAAK,WAAW,CAAC,GAAG,GAAG,CAAC;AAC1E,UAAM,WAA+C;AAAA,MACnD,MAAM,KAAK,QAAQ,KAAK;AAAA,MACxB,MAAM,KAAK;AAAA,MACX,SAAS;AAAA,MACT,MAAM,KAAK,QAAQ,KAAK,SAAS;AAAA,MACjC,KAAK,KAAK;AAAA,IACZ;AAEA,UAAM,QAAQ,eAAe,KAAK,SAAS,SAAS,SAAS,OAAO,IAAI;AACxE,QAAI,SAAS,OAAO;AAClB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,KAAK,KAAK;AAAA,QACV,UAAU,KAAK;AAAA,QACf;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,YAAY,KAAK;AAAA,MACjB,KAAK,KAAK;AAAA,MACV,UAAU,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,uBAAuB;AAAA,IACxC,MAAM,KAAK;AAAA,IACX,kBAAkB,KAAK,UAAU,IAAI,CAAC,MAAM,EAAE,UAAU;AAAA,IACxD,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,EACvD,CAAC;AACD,SAAO,EAAE,MAAM,SAAS,YAAY,UAAU,KAAK,SAAS;AAC9D;AAGO,SAAS,oBACd,SACA,UACsE;AACtE,QAAM,OAAO,qBAAqB,OAAO;AACzC,MAAI,CAAC,KAAM,QAAO,EAAE,IAAI,OAAO,QAAQ,wCAAwC;AAC/E,MAAI,KAAK,KAAK,YAAY,MAAM,SAAS,KAAK,YAAY,GAAG;AAC3D,WAAO,EAAE,IAAI,OAAO,QAAQ,6BAA6B,KAAK,IAAI,SAAS,SAAS,IAAI,GAAG;AAAA,EAC7F;AACA,MAAI,KAAK,SAAS,SAAS,MAAM;AAC/B,WAAO,EAAE,IAAI,OAAO,QAAQ,6BAA6B,KAAK,IAAI,SAAS,SAAS,IAAI,GAAG;AAAA,EAC7F;AACA,MAAI,eAAe,KAAK,SAAS,SAAS,OAAO,MAAM,GAAG;AACxD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,gCAAgC,KAAK,QAAQ,KAAK,GAAG,CAAC,SAAS,SAAS,QAAQ,KAAK,GAAG,CAAC;AAAA,IACnG;AAAA,EACF;AACA,SAAO,EAAE,IAAI,MAAM,KAAK;AAC1B;AAMA,eAAsB,qBAAqB,MAKZ;AAC7B,QAAM,OAAO,qBAAqB,KAAK,MAAM;AAC7C,MAAI,CAAC,MAAM;AACT,WAAO,EAAE,IAAI,OAAO,QAAQ,wCAAwC;AAAA,EACtE;AAEA,QAAM,GAAG,SAAS,MAAM,KAAK,YAAY,EAAE,WAAW,KAAK,CAAC;AAE5D,QAAM,YAAY,kBAAkB,KAAK,UAAU;AACnD,QAAM,OAAO,sBAAsB;AAAA,IACjC,UAAU;AAAA,IACV,MAAM,KAAK,cAAc,KAAK,SAAS,KAAK,MAAM;AAAA,IAClD;AAAA,IACA,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,EAC1D,CAAC;AAED,MAAI,KAAK,SAAS,eAAe;AAC/B,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,UAAU;AAAA,QACR,UAAU,KAAK;AAAA,QACf,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,KAAK,KAAK,KAAK,YAAY,KAAK,UAAU;AAC1D,MAAI,KAAK,SAAS,sBAAsB,KAAK,QAAQ,KAAK,GAAG,MAAM,KAAK,QAAQ,OAAO,GAAG;AACxF,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,4CAA4C,KAAK,GAAG,YAAY,OAAO;AAAA,IACjF;AAAA,EACF;AAEA,MAAI,GAAG,WAAW,OAAO,GAAG;AAC1B,UAAM,GAAG,SAAS,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAChE;AACA,QAAM,aAAa,KAAK,QAAQ,OAAO;AAEvC,QAAM,WAAW,oBAAoB,SAAS,IAAI;AAClD,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,EAAE,IAAI,OAAO,QAAQ,SAAS,QAAQ,YAAY,KAAK,YAAY,KAAK;AAAA,EACjF;AACA,SAAO,EAAE,IAAI,MAAM,SAAS,YAAY,KAAK,YAAY,MAAM,SAAS,KAAK;AAC/E;AAGA,eAAsB,oBAAoB,MAIxB;AAChB,QAAM,kBAAkB;AAAA,IACtB,WAAW,aAAa,KAAK,OAAO;AAAA,IACpC,WAAW,KAAK;AAAA,IAChB,MAAM,KAAK,KAAK;AAAA,IAChB,UAAU,KAAK,KAAK;AAAA,IACpB,SAAS,KAAK,KAAK;AAAA,EACrB,CAAC;AACH;AAGA,eAAsB,qBAAqB,MAMzB;AAChB,QAAM,mBAAmB;AAAA,IACvB,WAAW,aAAa,KAAK,OAAO;AAAA,IACpC,WAAW,KAAK;AAAA,IAChB,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,IACf,SAAS,KAAK;AAAA,EAChB,CAAC;AACH;AAaA,eAAsB,uBAAuB,MAMZ;AAC/B,QAAM,qBAAqB;AAAA,IACzB,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,IAChB,MAAM,KAAK,KAAK;AAAA,IAChB,UAAU,KAAK,KAAK;AAAA,IACpB,SAAS,KAAK,KAAK;AAAA,EACrB,CAAC;AAED,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,GAAG,GAAG;AACjC,WAAO,EAAE,QAAQ,UAAU;AAAA,EAC7B;AAEA,QAAM,WAAW,KAAK,UAAU,KAAK,KAAK;AAC1C,MAAI,UAAU;AACZ,UAAM,GAAG,SAAS,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AACrD,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,SAAS,GAAG;AAC3D,QAAI,OAAO,KAAK,KAAK,UAAU,KAAK,KAAK,UAAU;AACnD,QAAI,GAAG,WAAW,IAAI,GAAG;AACvB,aAAO,KAAK,KAAK,UAAU,GAAG,KAAK,KAAK,UAAU,IAAI,KAAK,EAAE;AAAA,IAC/D;AACA,QAAI;AACF,YAAM,GAAG,SAAS,OAAO,KAAK,KAAK,KAAK,IAAI;AAAA,IAC9C,QAAQ;AACN,YAAM,aAAa,KAAK,KAAK,KAAK,IAAI;AACtC,YAAM,GAAG,SAAS,GAAG,KAAK,KAAK,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACtE;AACA,WAAO,EAAE,QAAQ,WAAW,KAAK;AAAA,EACnC;AAEA,QAAM,GAAG,SAAS,GAAG,KAAK,KAAK,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpE,SAAO,EAAE,QAAQ,UAAU;AAC7B;AAEO,SAAS,mBACd,SACA,WACA,MACQ;AACR,SAAO,KAAK;AAAA,IACV,iBAAiB,SAAS,SAAS;AAAA,IACnC,SAAS,aAAa,mBAAmB;AAAA,EAC3C;AACF;AAGO,SAAS,uBACd,SACA,WACA,MAC+D;AAC/D,SAAO,0BAA0B,SAAS,WAAW,IAAI,EAAE;AAC7D;AAGO,SAAS,0BACd,SACA,WACA,MACyB;AACzB,SAAO,wBAAwB,aAAa,OAAO,GAAG,WAAW,IAAI;AACvE;AAEO,SAAS,sBACd,OACA,IAC2B;AAC3B,QAAM,IAAI,GAAG,KAAK,EAAE,YAAY;AAChC,SACE,MAAM;AAAA,IACJ,CAAC,MACC,EAAE,KAAK,YAAY,MAAM,KACzB,EAAE,WAAW,YAAY,MAAM,KAC/B,EAAE,KAAK,YAAY,MAAM,KACzB,EAAE,WAAW,YAAY,EAAE,SAAS,CAAC,KACrC,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC;AAAA,EACnC,KAAK;AAET;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|