Files
gallery/scripts/lib/meals.js
Ryan Chou 3439fc834f
All checks were successful
Deploy on push / deploy (push) Has been skipped
add: script to generate thumbnails
2026-03-22 19:54:53 -07:00

82 lines
2.0 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const repoRoot = path.resolve(__dirname, "..", "..");
const mealsPath = path.join(repoRoot, "data", "meals.json");
function validateThumbnail(meal, index) {
if (meal.thumbnail === undefined) {
return;
}
if (
!meal.thumbnail ||
typeof meal.thumbnail !== "object" ||
Array.isArray(meal.thumbnail)
) {
throw new Error(`Meal ${index} has an invalid "thumbnail" object`);
}
if (meal.thumbnail.focus === undefined) {
return;
}
const { focus } = meal.thumbnail;
if (!focus || typeof focus !== "object" || Array.isArray(focus)) {
throw new Error(`Meal ${index} has an invalid "thumbnail.focus" object`);
}
for (const axis of ["x", "y"]) {
if (typeof focus[axis] !== "number" || !Number.isFinite(focus[axis])) {
throw new Error(
`Meal ${index} has a non-numeric thumbnail focus value for "${axis}"`
);
}
if (focus[axis] < 0 || focus[axis] > 1) {
throw new Error(
`Meal ${index} thumbnail focus "${axis}" must be between 0 and 1`
);
}
}
}
function validateMeals(meals) {
if (!Array.isArray(meals)) {
throw new Error("data/meals.json must contain an array");
}
for (const [index, meal] of meals.entries()) {
if (!meal || typeof meal !== "object") {
throw new Error(`Meal at index ${index} must be an object`);
}
for (const field of ["id", "title", "description"]) {
if (typeof meal[field] !== "string" || meal[field].length === 0) {
throw new Error(`Meal ${index} is missing required string field "${field}"`);
}
}
if (meal.position !== undefined && typeof meal.position !== "string") {
throw new Error(`Meal ${index} has a non-string "position" value`);
}
validateThumbnail(meal, index);
}
}
function loadMeals() {
const meals = JSON.parse(fs.readFileSync(mealsPath, "utf8"));
validateMeals(meals);
return meals;
}
module.exports = {
loadMeals,
mealsPath,
repoRoot,
};