refactor: clean up gallery tooling and document the workflow
All checks were successful
Deploy on push / deploy (push) Has been skipped
All checks were successful
Deploy on push / deploy (push) Has been skipped
This commit is contained in:
@@ -99,6 +99,20 @@ function syncEloWithMeals(meals) {
|
||||
return syncedData;
|
||||
}
|
||||
|
||||
function getEloAlignmentReport(meals, eloData) {
|
||||
const mealIds = new Set(meals.map((meal) => meal.id));
|
||||
const eloIds = new Set(eloData.entries.map((entry) => entry.id));
|
||||
|
||||
return {
|
||||
missingEntryIds: meals
|
||||
.map((meal) => meal.id)
|
||||
.filter((mealId) => !eloIds.has(mealId)),
|
||||
unexpectedEntryIds: eloData.entries
|
||||
.map((entry) => entry.id)
|
||||
.filter((entryId) => !mealIds.has(entryId)),
|
||||
};
|
||||
}
|
||||
|
||||
function compareRankedMeals(left, right) {
|
||||
if (right.rating !== left.rating) {
|
||||
return right.rating - left.rating;
|
||||
@@ -132,6 +146,7 @@ function getRankedMeals(meals, eloData) {
|
||||
|
||||
module.exports = {
|
||||
eloPath,
|
||||
getEloAlignmentReport,
|
||||
getRankedMeals,
|
||||
loadEloData,
|
||||
saveEloData,
|
||||
|
||||
@@ -3,6 +3,12 @@ const path = require("path");
|
||||
|
||||
const repoRoot = path.resolve(__dirname, "..", "..");
|
||||
const mealsPath = path.join(repoRoot, "data", "meals.json");
|
||||
const fullsDir = path.join(repoRoot, "images", "fulls");
|
||||
const thumbsDir = path.join(repoRoot, "images", "thumbs");
|
||||
|
||||
function isNonEmptyString(value) {
|
||||
return typeof value === "string" && value.trim().length > 0;
|
||||
}
|
||||
|
||||
function validateThumbnail(meal, index) {
|
||||
if (meal.thumbnail === undefined) {
|
||||
@@ -55,7 +61,7 @@ function validateMeals(meals) {
|
||||
}
|
||||
|
||||
for (const field of ["id", "title", "description"]) {
|
||||
if (typeof meal[field] !== "string" || meal[field].length === 0) {
|
||||
if (!isNonEmptyString(meal[field])) {
|
||||
throw new Error(`Meal ${index} is missing required string field "${field}"`);
|
||||
}
|
||||
}
|
||||
@@ -64,8 +70,8 @@ function validateMeals(meals) {
|
||||
throw new Error(`Meal ${index} has a non-numeric id "${meal.id}"`);
|
||||
}
|
||||
|
||||
if (meal.position !== undefined && typeof meal.position !== "string") {
|
||||
throw new Error(`Meal ${index} has a non-string "position" value`);
|
||||
if (meal.position !== undefined && !isNonEmptyString(meal.position)) {
|
||||
throw new Error(`Meal ${index} has an invalid "position" value`);
|
||||
}
|
||||
|
||||
if (ids.has(meal.id)) {
|
||||
@@ -91,6 +97,49 @@ function saveMeals(meals) {
|
||||
fs.writeFileSync(mealsPath, `${JSON.stringify(meals, null, 2)}\n`);
|
||||
}
|
||||
|
||||
function getMealImagePaths(mealOrId) {
|
||||
const mealId =
|
||||
typeof mealOrId === "string" ? mealOrId : mealOrId && typeof mealOrId.id === "string" ? mealOrId.id : null;
|
||||
|
||||
if (!mealId) {
|
||||
throw new Error("Expected a meal object or meal id string");
|
||||
}
|
||||
|
||||
return {
|
||||
fullPath: path.join(fullsDir, `${mealId}.jpg`),
|
||||
thumbPath: path.join(thumbsDir, `${mealId}.jpg`),
|
||||
};
|
||||
}
|
||||
|
||||
function validateMealAssets(meals, options = {}) {
|
||||
const settings = {
|
||||
requireFull: true,
|
||||
requireThumb: true,
|
||||
...options,
|
||||
};
|
||||
const missingAssets = [];
|
||||
|
||||
for (const meal of meals) {
|
||||
const { fullPath, thumbPath } = getMealImagePaths(meal);
|
||||
|
||||
if (settings.requireFull && !fs.existsSync(fullPath)) {
|
||||
missingAssets.push(
|
||||
`Meal ${meal.id} is missing full-size image: ${path.relative(repoRoot, fullPath)}`
|
||||
);
|
||||
}
|
||||
|
||||
if (settings.requireThumb && !fs.existsSync(thumbPath)) {
|
||||
missingAssets.push(
|
||||
`Meal ${meal.id} is missing thumbnail image: ${path.relative(repoRoot, thumbPath)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingAssets.length > 0) {
|
||||
throw new Error(`Missing image assets:\n${missingAssets.join("\n")}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getNextMealId(meals) {
|
||||
if (meals.length === 0) {
|
||||
return "01";
|
||||
@@ -108,9 +157,13 @@ function getNextMealId(meals) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fullsDir,
|
||||
getNextMealId,
|
||||
getMealImagePaths,
|
||||
loadMeals,
|
||||
mealsPath,
|
||||
repoRoot,
|
||||
saveMeals,
|
||||
thumbsDir,
|
||||
validateMealAssets,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user