import { parseIngredient, unitsOfMeasure as _unitsOfMeasure, } from "https://esm.sh/parse-ingredient@1.2.1"; import { Ingredient, IngredientGroup } from "@lib/recipeSchema.ts"; import { removeMarkdownFormatting } from "@lib/string.ts"; const customUnits = { tableSpoon: { short: "EL", plural: "Table Spoons", alternates: ["el", "EL", "Tbsp", "tbsp"], }, dose: { short: "Dose", plural: "Dosen", alternates: ["Dose", "dose", "Dose(n)"], }, pound: { short: "lb", plural: "pounds", alternates: ["lb", "lbs", "pound", "pounds"], }, teaSpoon: { short: "TL", plural: "Tea Spoon", alternates: ["tl", "TL", "Tsp", "tsp", "teaspoon"], }, litre: { short: "L", plural: "liters", alternates: ["L", "l"], }, paket: { short: "Paket", plural: "Pakets", alternates: ["Paket", "paket"], }, }; export const unitsOfMeasure = { ..._unitsOfMeasure, ...customUnits, } as const; export function parseIngredients( text: string, ): (Ingredient | IngredientGroup)[] { const cleanText = removeMarkdownFormatting(text) .split("\n") .map((line) => line.trim().replace(/^-/, "")) .join("\n"); const ingredients = parseIngredient(cleanText, { normalizeUOM: true, additionalUOMs: customUnits, }); const results: (Ingredient | IngredientGroup)[] = []; let currentGroup: IngredientGroup | undefined; for (const ing of ingredients) { if (ing.isGroupHeader) { if (currentGroup) { results.push(currentGroup); } currentGroup = { name: ing.description.replace(/:$/, ""), items: [], }; } else { const ingredient = { name: ing.description.replace(/^\s?-/, "").trim(), unit: ing.unitOfMeasure || "", quantity: ing.quantity?.toString() || ing.quantity2?.toString() || "", note: "", }; const unit = ingredient.unit.toLowerCase() as keyof typeof unitsOfMeasure; if (unit in unitsOfMeasure && unit !== "cup") { ingredient.unit = unitsOfMeasure[unit].short; } if (!currentGroup) { results.push(ingredient); } else { currentGroup.items.push(ingredient); } } } if (currentGroup) { results.push(currentGroup); } return results; }