refactoring

This commit is contained in:
2026-03-07 05:17:50 -08:00
parent 68e19d864c
commit 3c07a13547
34 changed files with 11653 additions and 9078 deletions

View File

@@ -8,6 +8,7 @@ const ignoredFolderNames = new Set(["template", "templates", "example", "example
const tarotSuits = ["wands", "cups", "swords", "disks"];
const majorTrumpNumbers = Array.from({ length: 22 }, (_, index) => index);
const expectedMinorCardCount = 56;
const cardBackCandidateExtensions = ["webp", "png", "jpg", "jpeg", "avif", "gif"];
function isPlainObject(value) {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -29,6 +30,10 @@ function asNonEmptyString(value) {
return normalized || null;
}
function isRemoteAssetPath(value) {
return /^(https?:)?\/\//i.test(String(value || "").trim());
}
function toTitleCase(value) {
const normalized = String(value || "").trim().toLowerCase();
if (!normalized) {
@@ -241,6 +246,10 @@ function validateDeckManifest(manifest) {
errors.push("majorNameOverridesByTrump must be an object when provided");
}
if (manifest.cardBack != null && !asNonEmptyString(manifest.cardBack)) {
errors.push("cardBack must be a non-empty string when provided");
}
return errors;
}
@@ -358,6 +367,15 @@ function getReferencedMinorFiles(manifest) {
return [];
}
function getReferencedCardBackFiles(manifest) {
const cardBack = asNonEmptyString(manifest?.cardBack);
if (!cardBack || isRemoteAssetPath(cardBack)) {
return [];
}
return [cardBack];
}
function summarizeMissingFiles(fileList) {
const maxPreview = 8;
const preview = fileList.slice(0, maxPreview).join(", ");
@@ -368,11 +386,30 @@ function summarizeMissingFiles(fileList) {
return `${preview}, ... (+${fileList.length - maxPreview} more)`;
}
function detectDeckCardBackRelativePath(folderName, manifest) {
const explicitCardBack = asNonEmptyString(manifest?.cardBack);
if (explicitCardBack) {
return explicitCardBack;
}
const deckFolderPath = path.join(decksRoot, folderName);
for (let index = 0; index < cardBackCandidateExtensions.length; index += 1) {
const extension = cardBackCandidateExtensions[index];
const candidateName = `back.${extension}`;
if (fs.existsSync(path.join(deckFolderPath, candidateName))) {
return candidateName;
}
}
return null;
}
function auditDeckFiles(folderName, manifest) {
const deckFolderPath = path.join(decksRoot, folderName);
const referencedFiles = [
...getReferencedMajorFiles(manifest),
...getReferencedMinorFiles(manifest)
...getReferencedMinorFiles(manifest),
...getReferencedCardBackFiles(manifest)
]
.map((relativePath) => String(relativePath || "").trim())
.filter(Boolean);
@@ -453,6 +490,7 @@ function compileDeckRegistry() {
const id = (idFromManifest || fallbackId).toLowerCase();
const label = labelFromManifest || folderName;
const basePath = `asset/tarot deck/${folderName}`;
const cardBackPath = detectDeckCardBackRelativePath(folderName, manifest);
if (seenIds.has(id)) {
warnings.push(`Skipped '${folderName}': duplicate deck id '${id}'`);
@@ -465,7 +503,8 @@ function compileDeckRegistry() {
id,
label,
basePath,
manifestPath: `${basePath}/deck.json`
manifestPath: `${basePath}/deck.json`,
...(cardBackPath ? { cardBackPath } : {})
});
});