function flattenInstructions(instructions) { return instructions.flatMap((instruction) => { if (typeof instruction === "string") return [instruction]; if (Array.isArray(instruction?.itemListElement)) return flattenInstructions(instruction.itemListElement); return instruction?.text ? [instruction.text] : []; }); } function normalizeProgress(progress = {}) { return { completedIngredients: [...new Set((progress.completedIngredients || []).filter(Number.isInteger))], completedSteps: [...new Set((progress.completedSteps || []).filter(Number.isInteger))] }; } function updateProgress(recipe, progress, { kind, index, completed }) { if (!recipe || !["ingredient", "step"].includes(kind) || !Number.isInteger(index) || typeof completed !== "boolean") { throw new Error("Invalid progress update"); } const limit = kind === "ingredient" ? (recipe.recipeIngredient || []).length : flattenInstructions(recipe.recipeInstructions || []).length; if (index < 0 || index >= limit) throw new Error("Progress item does not exist"); const key = kind === "ingredient" ? "completedIngredients" : "completedSteps"; const next = normalizeProgress(progress); const items = new Set(next[key]); if (completed) items.add(index); else items.delete(index); next[key] = [...items].sort((left, right) => left - right); return next; } module.exports = { flattenInstructions, normalizeProgress, updateProgress };