import recipeSchema, { Recipe } from "@lib/recipeSchema.ts"; export function parseJsonLdToRecipeSchema(jsonLdContent: string) { try { let data = JSON.parse(jsonLdContent); const image = data.image; // Handle nested data inside `mainEntity` if (data["mainEntity"]) { data = data["mainEntity"]; } // Ensure it's a valid Recipe type if ( typeof data !== "object" || !data["@type"] || data["@type"] !== "Recipe" ) { return; } const recipeInstructions = Array.isArray(data.recipeInstructions) ? data.recipeInstructions.map((instr: unknown) => { if (!instr) return ""; if (typeof instr === "string") return instr; if (typeof instr === "object" && "text" in instr && instr.text) { return instr.text; } return ""; }).filter((instr: string) => instr.trim() !== "") : []; // Parse servings const recipeYield = parseServings(data.recipeYield); // Parse times const totalTime = parseDuration(data.totalTime); // Extract tags const keywords = data.keywords ? Array.isArray(data.keywords) ? data.keywords : data.keywords.split(",").map((tag: string) => tag.trim()) : []; // Build the recipe object const recipe: Recipe = { _type: "Recipe", name: data.name || "Unnamed Recipe", image: pickImage(image || data.image || ""), author: { "_type": "Person", name: Array.isArray(data.author) ? data.author.map((a: { name: string }) => a.name).join(", ") : data.author?.name || "", }, description: data.description || "", recipeIngredient: data.recipeIngredient, recipeInstructions, recipeYield, totalTime, keywords, }; // Validate against the schema return recipeSchema.parse(recipe); } catch (error) { console.log("Invalid JSON-LD content or parsing error:", error); return undefined; } } function pickImage(images: string | string[]): string { if (Array.isArray(images)) { return images[0]; } return images; } function parseServings(servingsData: unknown): number { if (typeof servingsData === "string") { const match = servingsData.match(/\d+/); return match ? parseInt(match[0], 10) : 1; } if (typeof servingsData === "number") { return servingsData; } return 1; } function parseDuration(duration: string | undefined): number { if (!duration) return 0; // Matches ISO 8601 durations (e.g., "PT30M" -> 30 minutes) const match = duration.match(/PT(?:(\d+)H)?(?:(\d+)M)?/); const hours = match?.[1] ? parseInt(match[1], 10) : 0; const minutes = match?.[2] ? parseInt(match[2], 10) : 0; return hours * 60 + minutes; }