"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseRecipeMarkdown = parseRecipeMarkdown; const KNOWN_UNITS = new Set([ 'g', 'kg', 'hg', 'mg', 'ml', 'dl', 'l', 'tl', 'st', 'tsk', 'msk', 'krm', 'matsled', 'tesled', 'pris', 'portion', 'port', 'burk', 'förp', 'paket', 'efter smak', 'klyfta', ]); const H1_RE = /^#\s+/; const H2_RE = /^##\s+/; const INGREDIENT_HEADING_RE = /ingrediens/; const INSTRUCTION_HEADING_RE = /instruktion|tillagning|gör så här|steg|tillväg|metod/; const BULLET_RE = /^[-*]\s+/; const PAREN_NOTE_RE = /\(([^)]+)\)\s*$/; const FRACTION_RE = /^(\d+)?\s*(\d+)\s*\/\s*([\d.]+)\s+(\S+)\s+(.+)$/; const RANGE_RE = /^(?:ca\.?\s+)?(\d+(?:[.,]\d+)?)\s*[-–]\s*(?:ca\.?\s+)?(\d+(?:[.,]\d+)?)\s+(\S+)\s+(.+)$/i; const QTY_UNIT_NAME_RE = /^(\d+(?:[.,]\d+)?)\s+(\S+)\s+(.+)$/; const QTY_NAME_RE = /^(\d+(?:[.,]\d+)?)\s+(.+)$/; const ALTERNATIVES_RE = /\s+eller\s+/i; function parseRecipeMarkdown(markdown) { const lines = markdown.split('\n'); let name = ''; let description = ''; let instructions = ''; const ingredients = []; let currentSection = 'none'; const descriptionLines = []; const instructionLines = []; for (const line of lines) { const trimmed = line.trim(); if (H1_RE.test(trimmed) && !trimmed.startsWith('##')) { name = trimmed.replace(H1_RE, '').trim(); currentSection = 'description'; continue; } if (H2_RE.test(trimmed)) { const heading = trimmed.replace(H2_RE, '').trim().toLowerCase(); if (INGREDIENT_HEADING_RE.test(heading)) { currentSection = 'ingredients'; } else if (INSTRUCTION_HEADING_RE.test(heading)) { currentSection = 'instructions'; } else { currentSection = 'none'; } continue; } switch (currentSection) { case 'description': if (trimmed.length > 0) { descriptionLines.push(trimmed); } break; case 'ingredients': if (BULLET_RE.test(trimmed)) { const ingredientText = trimmed.replace(BULLET_RE, ''); ingredients.push(parseIngredientLine(ingredientText)); } break; case 'instructions': if (trimmed.length > 0) { instructionLines.push(trimmed); } break; } } description = descriptionLines.join('\n'); instructions = instructionLines.join('\n'); return { name, description, instructions, ingredients }; } function parseIngredientLine(text) { const trimmed = text.trim(); const toAlternatives = (rawName) => ALTERNATIVES_RE.test(rawName) ? rawName.split(ALTERNATIVES_RE).map((s) => s.trim()).filter(Boolean) : [rawName]; let note = null; let main = trimmed; const parenMatch = trimmed.match(PAREN_NOTE_RE); if (parenMatch) { note = parenMatch[1].trim(); main = trimmed.slice(0, parenMatch.index).trim(); } const fractionMatch = main.match(FRACTION_RE); if (fractionMatch) { const whole = fractionMatch[1] ? parseFloat(fractionMatch[1]) : 0; const quantity = whole + parseFloat(fractionMatch[2]) / parseFloat(fractionMatch[3]); const candidateUnit = fractionMatch[4].toLowerCase(); if (KNOWN_UNITS.has(candidateUnit)) { const rawName = fractionMatch[5].trim(); return { quantity, unit: candidateUnit, rawName, note, alternatives: toAlternatives(rawName) }; } } const rangeMatch = main.match(RANGE_RE); if (rangeMatch) { const candidateUnit = rangeMatch[3].toLowerCase(); if (KNOWN_UNITS.has(candidateUnit)) { const lo = parseNumber(rangeMatch[1]); const hi = parseNumber(rangeMatch[2]); const rawName = rangeMatch[4].trim(); return { quantity: (lo + hi) / 2, unit: candidateUnit, rawName, note, alternatives: toAlternatives(rawName) }; } } const fullMatch = main.match(QTY_UNIT_NAME_RE); if (fullMatch) { const candidateUnit = fullMatch[2].toLowerCase(); if (KNOWN_UNITS.has(candidateUnit)) { const rawName = fullMatch[3].trim(); return { quantity: parseNumber(fullMatch[1]), unit: candidateUnit, rawName, note, alternatives: toAlternatives(rawName) }; } const rawName = fullMatch[2] + ' ' + fullMatch[3]; return { quantity: parseNumber(fullMatch[1]), unit: 'st', rawName, note, alternatives: toAlternatives(rawName) }; } const noUnitMatch = main.match(QTY_NAME_RE); if (noUnitMatch) { const rawName = noUnitMatch[2].trim(); return { quantity: parseNumber(noUnitMatch[1]), unit: 'st', rawName, note, alternatives: toAlternatives(rawName) }; } return { quantity: 0, unit: '', rawName: main, note, alternatives: toAlternatives(main) }; } function parseNumber(s) { return parseFloat(s.replace(',', '.')); } //# sourceMappingURL=recipe-parser.js.map