@tmlmt/cooklang-parser 2.1.7 → 3.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/classes/category_config.ts","../src/classes/section.ts","../node_modules/.pnpm/human-regex@2.1.5_patch_hash=6d6bd9e233f99785a7c2187fd464edc114b76d47001dbb4eb6b5d72168de7460/node_modules/human-regex/src/human-regex.ts","../src/regex.ts","../src/units.ts","../src/errors.ts","../src/parser_helpers.ts","../src/classes/recipe.ts","../src/classes/shopping_list.ts"],"sourcesContent":["import { CategoryConfig } from \"./classes/category_config\";\nimport { Recipe } from \"./classes/recipe\";\nimport { ShoppingList } from \"./classes/shopping_list\";\nimport { Section } from \"./classes/section\";\n\nimport type {\n Metadata,\n Ingredient,\n IngredientFlag,\n IngredientExtras,\n FixedValue,\n Range,\n DecimalValue,\n FractionValue,\n TextValue,\n Timer,\n TextItem,\n IngredientItem,\n CookwareItem,\n TimerItem,\n Item,\n Step,\n Note,\n Cookware,\n CookwareFlag,\n CategorizedIngredients,\n AddedRecipe,\n RecipeWithFactor,\n RecipeWithServings,\n CategoryIngredient,\n Category,\n QuantityPart,\n} from \"./types\";\n\nexport {\n Recipe,\n ShoppingList,\n CategoryConfig,\n Metadata,\n Ingredient,\n IngredientFlag,\n IngredientExtras,\n FixedValue,\n Range,\n DecimalValue,\n FractionValue,\n TextValue,\n Timer,\n TextItem,\n IngredientItem,\n CookwareItem,\n TimerItem,\n Item,\n Step,\n Note,\n Cookware,\n CookwareFlag,\n CategorizedIngredients,\n AddedRecipe,\n RecipeWithFactor,\n RecipeWithServings,\n CategoryIngredient,\n Category,\n Section,\n QuantityPart,\n};\n","import type { Category, CategoryIngredient } from \"../types\";\n\n/**\n * Parser for category configurations specified à-la-cooklang.\n *\n * ## Usage\n *\n * You can either directly provide the category configuration string when creating the instance\n * e.g. `const categoryConfig = new CategoryConfig(<...>)`, or create it first and then pass\n * the category configuration string to the {@link CategoryConfig.parse | parse()} method.\n *\n * The initialized `CategoryConfig` can then be fed to a {@link ShoppingList}\n *\n * @example\n * ```typescript\n * import { CategoryConfig } from @tmlmt/cooklang-parser;\n *\n * const categoryConfigString = `\n * [Dairy]\n * milk\n * butter\n *\n * [Bakery]\n * flour\n * sugar`;\n *\n * const categoryConfig = new CategoryConfig(categoryConfigString);\n * ```\n *\n * @see [Category Configuration](https://cooklang.org/docs/spec/#shopping-lists) section of the cooklang specs\n *\n * @category Classes\n */\nexport class CategoryConfig {\n /**\n * The parsed categories of ingredients.\n */\n categories: Category[] = [];\n\n /**\n * Creates a new CategoryConfig instance.\n * @param config - The category configuration to parse.\n */\n constructor(config?: string) {\n if (config) {\n this.parse(config);\n }\n }\n\n /**\n * Parses a category configuration from a string into property\n * {@link CategoryConfig.categories | categories}\n * @param config - The category configuration to parse.\n */\n parse(config: string) {\n let currentCategory: Category | null = null;\n const categoryNames = new Set<string>();\n const ingredientNames = new Set<string>();\n\n for (const line of config.split(\"\\n\")) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n if (trimmedLine.startsWith(\"[\") && trimmedLine.endsWith(\"]\")) {\n const categoryName = trimmedLine\n .substring(1, trimmedLine.length - 1)\n .trim();\n\n if (categoryNames.has(categoryName)) {\n throw new Error(`Duplicate category found: ${categoryName}`);\n }\n categoryNames.add(categoryName);\n\n currentCategory = { name: categoryName, ingredients: [] };\n this.categories.push(currentCategory);\n } else {\n if (currentCategory === null) {\n throw new Error(\n `Ingredient found without a category: ${trimmedLine}`,\n );\n }\n\n const aliases = trimmedLine.split(\"|\").map((s) => s.trim());\n for (const alias of aliases) {\n if (ingredientNames.has(alias)) {\n throw new Error(`Duplicate ingredient/alias found: ${alias}`);\n }\n ingredientNames.add(alias);\n }\n\n const ingredient: CategoryIngredient = {\n name: aliases[0]!, // We know this exists because trimmedLine is not empty\n aliases: aliases,\n };\n currentCategory.ingredients.push(ingredient);\n }\n }\n }\n}\n","import type { Step, Note } from \"../types\";\n\n/**\n * Represents a recipe section\n *\n * Wrapped as a _Class_ and not defined as a simple _Type_ to expose some useful helper\n * classes (e.g. {@link Section.isBlank | isBlank()})\n *\n * @category Types\n */\nexport class Section {\n /**\n * The name of the section. Can be an empty string for the default (first) section.\n * @defaultValue `\"\"`\n */\n name: string;\n /** An array of steps and notes that make up the content of the section. */\n content: (Step | Note)[] = [];\n\n /**\n * Creates an instance of Section.\n * @param name - The name of the section. Defaults to an empty string.\n */\n constructor(name: string = \"\") {\n this.name = name;\n }\n\n /**\n * Checks if the section is blank (has no name and no content).\n * Used during recipe parsing\n * @returns `true` if the section is blank, otherwise `false`.\n */\n isBlank(): boolean {\n return this.name === \"\" && this.content.length === 0;\n }\n}\n","type PartialBut<T, K extends keyof T> = Partial<T> & Pick<T, K>;\n\nconst escapeCache = new Map<string, string>();\n\nconst Flags = {\n GLOBAL: \"g\",\n NON_SENSITIVE: \"i\",\n MULTILINE: \"m\",\n DOT_ALL: \"s\",\n UNICODE: \"u\",\n STICKY: \"y\",\n} as const;\n\nconst Ranges = Object.freeze({\n digit: \"0-9\",\n lowercaseLetter: \"a-z\",\n uppercaseLetter: \"A-Z\",\n letter: \"a-zA-Z\",\n alphanumeric: \"a-zA-Z0-9\",\n anyCharacter: \".\",\n});\n\ntype RangeKeys = keyof typeof Ranges;\n\nconst Quantifiers = Object.freeze({\n zeroOrMore: \"*\",\n oneOrMore: \"+\",\n optional: \"?\",\n});\n\ntype Quantifiers =\n | \"exactly\"\n | \"atLeast\"\n | \"atMost\"\n | \"between\"\n | \"oneOrMore\"\n | \"zeroOrMore\"\n | \"repeat\";\ntype QuantifierMethods = Quantifiers | \"optional\" | \"lazy\";\n\ntype WithLazy = HumanRegex;\ntype Base = Omit<HumanRegex, \"lazy\">;\ntype AtStart = Omit<Base, QuantifierMethods | \"endGroup\">;\ntype AfterAnchor = Omit<Base, QuantifierMethods | \"or\">;\ntype SimpleQuantifier = Omit<Base, Quantifiers>;\ntype LazyQuantifier = Omit<WithLazy, Quantifiers>;\n\nclass HumanRegex {\n private parts: string[];\n private flags: Set<string>;\n\n constructor() {\n this.parts = [];\n this.flags = new Set<string>();\n }\n\n digit(): Base {\n return this.add(\"\\\\d\");\n }\n\n special(): Base {\n return this.add(\"(?=.*[!@#$%^&*])\");\n }\n\n word(): Base {\n return this.add(\"\\\\w\");\n }\n\n whitespace(): Base {\n return this.add(\"\\\\s\");\n }\n\n nonWhitespace(): Base {\n return this.add(\"\\\\S\");\n }\n\n literal(text: string): this {\n return this.add(escapeLiteral(text));\n }\n\n or(): AfterAnchor {\n return this.add(\"|\");\n }\n\n range(name: RangeKeys): Base {\n const range = Ranges[name];\n if (!range) throw new Error(`Unknown range: ${name}`);\n return this.add(`[${range}]`);\n }\n\n notRange(name: RangeKeys): Base {\n const range = Ranges[name];\n if (!range) throw new Error(`Unknown range: ${name}`);\n return this.add(`[^${range}]`);\n }\n\n anyOf(chars: string): Base {\n return this.add(`[${chars}]`);\n }\n\n notAnyOf(chars: string): Base {\n return this.add(`[^${chars}]`);\n }\n\n lazy(): Base {\n const lastPart = this.parts.pop();\n if (!lastPart) throw new Error(\"No quantifier to make lazy\");\n return this.add(`${lastPart}?`);\n }\n\n letter(): Base {\n return this.add(\"[a-zA-Z]\");\n }\n\n anyCharacter(): Base {\n return this.add(\".\");\n }\n\n newline(): Base {\n return this.add(\"(?:\\\\r\\\\n|\\\\r|\\\\n)\"); // Windows: \\r\\n, Unix: \\n, Old Macs: \\r\n }\n\n negativeLookahead(pattern: string): Base {\n return this.add(`(?!${pattern})`);\n }\n\n positiveLookahead(pattern: string): Base {\n return this.add(`(?=${pattern})`);\n }\n\n positiveLookbehind(pattern: string): Base {\n return this.add(`(?<=${pattern})`);\n }\n\n negativeLookbehind(pattern: string): Base {\n return this.add(`(?<!${pattern})`);\n }\n\n hasSpecialCharacter(): Base {\n return this.add(\"(?=.*[!@#$%^&*])\");\n }\n\n hasDigit(): Base {\n return this.add(\"(?=.*\\\\d)\");\n }\n\n hasLetter(): Base {\n return this.add(\"(?=.*[a-zA-Z])\");\n }\n\n optional(): SimpleQuantifier {\n return this.add(Quantifiers.optional);\n }\n\n exactly(n: number): SimpleQuantifier {\n return this.add(`{${n}}`);\n }\n\n atLeast(n: number): LazyQuantifier {\n return this.add(`{${n},}`);\n }\n\n atMost(n: number): LazyQuantifier {\n return this.add(`{0,${n}}`);\n }\n\n between(min: number, max: number): LazyQuantifier {\n return this.add(`{${min},${max}}`);\n }\n\n oneOrMore(): LazyQuantifier {\n return this.add(Quantifiers.oneOrMore);\n }\n\n zeroOrMore(): LazyQuantifier {\n return this.add(Quantifiers.zeroOrMore);\n }\n\n startNamedGroup(name: string): AfterAnchor {\n return this.add(`(?<${name}>`);\n }\n\n startGroup(): AfterAnchor {\n return this.add(\"(?:\");\n }\n\n startCaptureGroup(): AfterAnchor {\n return this.add(\"(\");\n }\n\n wordBoundary(): Base {\n return this.add(\"\\\\b\");\n }\n\n nonWordBoundary(): Base {\n return this.add(\"\\\\B\");\n }\n\n endGroup(): Base {\n return this.add(\")\");\n }\n\n startAnchor(): AfterAnchor {\n return this.add(\"^\");\n }\n\n endAnchor(): AfterAnchor {\n return this.add(\"$\");\n }\n\n global(): this {\n this.flags.add(Flags.GLOBAL);\n return this;\n }\n\n nonSensitive(): this {\n this.flags.add(Flags.NON_SENSITIVE);\n return this;\n }\n\n multiline(): this {\n this.flags.add(Flags.MULTILINE);\n return this;\n }\n\n dotAll(): this {\n this.flags.add(Flags.DOT_ALL);\n return this;\n }\n\n sticky(): this {\n this.flags.add(Flags.STICKY);\n return this;\n }\n\n unicodeChar(variant?: \"u\" | \"l\" | \"t\" | \"m\" | \"o\"): Base {\n this.flags.add(Flags.UNICODE);\n const validVariants = new Set([\"u\", \"l\", \"t\", \"m\", \"o\"] as const);\n\n if (variant !== undefined && !validVariants.has(variant)) {\n throw new Error(`Invalid Unicode letter variant: ${variant}`);\n }\n\n return this.add(`\\\\p{L${variant ?? \"\"}}`);\n }\n\n unicodeDigit(): Base {\n this.flags.add(Flags.UNICODE);\n return this.add(\"\\\\p{N}\");\n }\n\n unicodePunctuation(): Base {\n this.flags.add(Flags.UNICODE);\n return this.add(\"\\\\p{P}\");\n }\n\n unicodeSymbol(): Base {\n this.flags.add(Flags.UNICODE);\n return this.add(\"\\\\p{S}\");\n }\n\n repeat(count: number): Base {\n if (this.parts.length === 0) {\n throw new Error(\"No pattern to repeat\");\n }\n\n const lastPart = this.parts.pop();\n this.parts.push(`(${lastPart}){${count}}`);\n return this;\n }\n\n ipv4Octet(): Base {\n return this.add(\"(25[0-5]|2[0-4]\\\\d|1\\\\d\\\\d|[1-9]\\\\d|\\\\d)\");\n }\n\n protocol(): Base {\n return this.add(\"https?://\");\n }\n\n www(): Base {\n return this.add(\"(www\\\\.)?\");\n }\n\n tld(): Base {\n return this.add(\"(com|org|net)\");\n }\n\n path(): Base {\n return this.add(\"(/\\\\w+)*\");\n }\n\n private add(part: string): this {\n this.parts.push(part);\n return this;\n }\n\n toString(): string {\n return this.parts.join(\"\");\n }\n\n toRegExp(): RegExp {\n return new RegExp(this.toString(), [...this.flags].join(\"\"));\n }\n}\n\nfunction escapeLiteral(text: string): string {\n if (!escapeCache.has(text)) {\n escapeCache.set(text, text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"));\n }\n return escapeCache.get(text)!;\n}\n\nconst createRegex = (): AtStart => new HumanRegex();\n\nconst Patterns = (() => {\n const createCachedPattern = (\n builder: () => PartialBut<HumanRegex, \"toRegExp\">\n ) => {\n const regex = builder().toRegExp();\n return () => new RegExp(regex.source, regex.flags);\n };\n\n return {\n email: createCachedPattern(() =>\n createRegex()\n .startAnchor()\n .word()\n .oneOrMore()\n .literal(\"@\")\n .word()\n .oneOrMore()\n .startGroup()\n .literal(\".\")\n .word()\n .oneOrMore()\n .endGroup()\n .zeroOrMore()\n .literal(\".\")\n .letter()\n .atLeast(2)\n .endAnchor()\n ),\n url: createCachedPattern(() =>\n createRegex()\n .startAnchor()\n .protocol()\n .www()\n .word()\n .oneOrMore()\n .literal(\".\")\n .tld()\n .path()\n .endAnchor()\n ),\n phoneInternational: createCachedPattern(() =>\n createRegex()\n .startAnchor()\n .literal(\"+\")\n .digit()\n .between(1, 3)\n .literal(\"-\")\n .digit()\n .between(3, 14)\n .endAnchor()\n ),\n };\n})();\n\nexport { createRegex, Patterns, Flags, Ranges, Quantifiers };\n","import { createRegex } from \"human-regex\";\n\nexport const metadataRegex = createRegex()\n .literal(\"---\").newline()\n .startCaptureGroup().anyCharacter().zeroOrMore().optional().endGroup()\n .newline().literal(\"---\")\n .dotAll().toRegExp();\n\nexport const scalingMetaValueRegex = (varName: string): RegExp => createRegex()\n .startAnchor()\n .literal(varName)\n .literal(\":\")\n .anyOf(\"\\\\t \").zeroOrMore()\n .startCaptureGroup()\n .startCaptureGroup()\n .notAnyOf(\",\\\\n\").oneOrMore()\n .endGroup()\n .startGroup()\n .literal(\",\")\n .whitespace().zeroOrMore()\n .startCaptureGroup()\n .anyCharacter().oneOrMore()\n .endGroup()\n .endGroup().optional()\n .endGroup()\n .endAnchor()\n .multiline()\n .toRegExp()\n\nconst nonWordChar = \"\\\\s@#~\\\\[\\\\]{(,;:!?\"\n\nconst multiwordIngredient = createRegex()\n .literal(\"@\")\n .startNamedGroup(\"mIngredientModifiers\")\n .anyOf(\"@\\\\-&?\").zeroOrMore()\n .endGroup().optional()\n .startNamedGroup(\"mIngredientRecipeAnchor\")\n .literal(\"./\")\n .endGroup().optional()\n .startNamedGroup(\"mIngredientName\")\n .notAnyOf(nonWordChar).oneOrMore()\n .startGroup()\n .whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore()\n .endGroup().oneOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup()\n .positiveLookahead(\"\\\\s*(?:\\\\{[^\\\\}]*\\\\}|\\\\([^)]*\\\\))\")\n .startGroup()\n .literal(\"{\")\n .startNamedGroup(\"mIngredientQuantityModifier\")\n .literal(\"=\").exactly(1)\n .endGroup().optional()\n .startNamedGroup(\"mIngredientQuantity\")\n .notAnyOf(\"}%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .startNamedGroup(\"mIngredientUnit\")\n .notAnyOf(\"}\").oneOrMore().lazy()\n .endGroup()\n .endGroup().optional()\n .literal(\"}\")\n .endGroup().optional()\n .startGroup()\n .literal(\"(\")\n .startNamedGroup(\"mIngredientPreparation\")\n .notAnyOf(\")\").oneOrMore().lazy()\n .endGroup()\n .literal(\")\")\n .endGroup().optional()\n .toRegExp();\n\nconst singleWordIngredient = createRegex()\n .literal(\"@\")\n .startNamedGroup(\"sIngredientModifiers\")\n .anyOf(\"@\\\\-&?\").zeroOrMore()\n .endGroup().optional()\n .startNamedGroup(\"sIngredientRecipeAnchor\")\n .literal(\"./\")\n .endGroup().optional()\n .startNamedGroup(\"sIngredientName\")\n .notAnyOf(nonWordChar).zeroOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup()\n .startGroup()\n .literal(\"{\")\n .startNamedGroup(\"sIngredientQuantityModifier\")\n .literal(\"=\").exactly(1)\n .endGroup().optional()\n .startNamedGroup(\"sIngredientQuantity\")\n .notAnyOf(\"}%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .startNamedGroup(\"sIngredientUnit\")\n .notAnyOf(\"}\").oneOrMore().lazy()\n .endGroup()\n .endGroup().optional()\n .literal(\"}\")\n .endGroup().optional()\n .startGroup()\n .literal(\"(\")\n .startNamedGroup(\"sIngredientPreparation\")\n .notAnyOf(\")\").oneOrMore().lazy()\n .endGroup()\n .literal(\")\")\n .endGroup().optional()\n .toRegExp();\n\nexport const ingredientAliasRegex = createRegex()\n .startAnchor()\n .startNamedGroup(\"ingredientListName\")\n .notAnyOf(\"|\").oneOrMore()\n .endGroup()\n .literal(\"|\")\n .startNamedGroup(\"ingredientDisplayName\")\n .notAnyOf(\"|\").oneOrMore()\n .endGroup()\n .endAnchor()\n .toRegExp();\n\nconst multiwordCookware = createRegex()\n .literal(\"#\")\n .startNamedGroup(\"mCookwareModifiers\")\n .anyOf(\"\\\\-&?\").zeroOrMore()\n .endGroup()\n .startNamedGroup(\"mCookwareName\")\n .notAnyOf(nonWordChar).oneOrMore()\n .startGroup()\n .whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore()\n .endGroup().oneOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup().positiveLookahead(\"\\\\s*(?:\\\\{[^\\\\}]*\\\\})\")\n .literal(\"{\")\n .startNamedGroup(\"mCookwareQuantity\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .literal(\"}\")\n .toRegExp();\n\nconst singleWordCookware = createRegex()\n .literal(\"#\")\n .startNamedGroup(\"sCookwareModifiers\")\n .anyOf(\"\\\\-&?\").zeroOrMore()\n .endGroup()\n .startNamedGroup(\"sCookwareName\")\n .notAnyOf(nonWordChar).zeroOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup()\n .startGroup()\n .literal(\"{\")\n .startNamedGroup(\"sCookwareQuantity\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .literal(\"}\")\n .endGroup().optional()\n .toRegExp();\n\nconst timer = createRegex()\n .literal(\"~\")\n .startNamedGroup(\"timerName\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .literal(\"{\")\n .startNamedGroup(\"timerQuantity\")\n .anyCharacter().oneOrMore().lazy()\n .endGroup()\n .startGroup()\n .literal(\"%\")\n .startNamedGroup(\"timerUnit\")\n .anyCharacter().oneOrMore().lazy()\n .endGroup()\n .endGroup().optional()\n .literal(\"}\")\n .toRegExp()\n\nexport const tokensRegex = new RegExp(\n [\n multiwordIngredient,\n singleWordIngredient,\n multiwordCookware,\n singleWordCookware,\n timer,\n ]\n .map((r) => r.source)\n .join(\"|\"),\n \"gu\",\n);\n\nexport const commentRegex = createRegex()\n .literal(\"--\")\n .anyCharacter().zeroOrMore()\n .global()\n .toRegExp();\n\nexport const blockCommentRegex = createRegex()\n .literal(\"[-\")\n .anyCharacter().zeroOrMore().lazy()\n .literal(\"-]\")\n .whitespace().zeroOrMore()\n .global()\n .toRegExp();\n\nexport const shoppingListRegex = createRegex()\n .literal(\"[\")\n .startNamedGroup(\"name\")\n .anyCharacter().oneOrMore()\n .endGroup()\n .literal(\"]\")\n .newline()\n .startNamedGroup(\"items\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .startGroup()\n .newline().newline()\n .or()\n .endAnchor()\n .endGroup()\n .global()\n .toRegExp()\n\nexport const rangeRegex = createRegex()\n .startAnchor()\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".,/\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .literal(\"-\")\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".,/\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .endAnchor()\n .toRegExp()\n\nexport const numberLikeRegex = createRegex()\n .startAnchor()\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".,/\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .endAnchor()\n .toRegExp()\n\nexport const floatRegex = createRegex()\n .startAnchor()\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .endAnchor()\n .toRegExp()","import type { FixedValue, Range, DecimalValue, FractionValue } from \"./types\";\nimport Big from \"big.js\";\nexport type UnitType = \"mass\" | \"volume\" | \"count\";\nexport type UnitSystem = \"metric\" | \"imperial\";\n\nexport interface UnitDefinition {\n name: string; // canonical name, e.g. 'g'\n type: UnitType;\n system: UnitSystem;\n aliases: string[]; // e.g. ['gram', 'grams']\n toBase: number; // conversion factor to the base unit of its type\n}\n\nexport interface Quantity {\n value: FixedValue | Range;\n unit?: string;\n}\n\n// Base units: mass -> gram (g), volume -> milliliter (ml)\nconst units: UnitDefinition[] = [\n // Mass (Metric)\n {\n name: \"g\",\n type: \"mass\",\n system: \"metric\",\n aliases: [\"gram\", \"grams\", \"grammes\"],\n toBase: 1,\n },\n {\n name: \"kg\",\n type: \"mass\",\n system: \"metric\",\n aliases: [\"kilogram\", \"kilograms\", \"kilogrammes\", \"kilos\", \"kilo\"],\n toBase: 1000,\n },\n // Mass (Imperial)\n {\n name: \"oz\",\n type: \"mass\",\n system: \"imperial\",\n aliases: [\"ounce\", \"ounces\"],\n toBase: 28.3495,\n },\n {\n name: \"lb\",\n type: \"mass\",\n system: \"imperial\",\n aliases: [\"pound\", \"pounds\"],\n toBase: 453.592,\n },\n\n // Volume (Metric)\n {\n name: \"ml\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"milliliter\", \"milliliters\", \"millilitre\", \"millilitres\", \"cc\"],\n toBase: 1,\n },\n {\n name: \"cl\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"centiliter\", \"centiliters\", \"centilitre\", \"centilitres\"],\n toBase: 10,\n },\n {\n name: \"dl\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"deciliter\", \"deciliters\", \"decilitre\", \"decilitres\"],\n toBase: 100,\n },\n {\n name: \"l\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"liter\", \"liters\", \"litre\", \"litres\"],\n toBase: 1000,\n },\n {\n name: \"tsp\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"teaspoon\", \"teaspoons\"],\n toBase: 5,\n },\n {\n name: \"tbsp\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"tablespoon\", \"tablespoons\"],\n toBase: 15,\n },\n\n // Volume (Imperial)\n {\n name: \"fl-oz\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"fluid ounce\", \"fluid ounces\"],\n toBase: 29.5735,\n },\n {\n name: \"cup\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"cups\"],\n toBase: 236.588,\n },\n {\n name: \"pint\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"pints\"],\n toBase: 473.176,\n },\n {\n name: \"quart\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"quarts\"],\n toBase: 946.353,\n },\n {\n name: \"gallon\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"gallons\"],\n toBase: 3785.41,\n },\n\n // Count units (no conversion, but recognized as a type)\n {\n name: \"piece\",\n type: \"count\",\n system: \"metric\",\n aliases: [\"pieces\", \"pc\"],\n toBase: 1,\n },\n];\n\nconst unitMap = new Map<string, UnitDefinition>();\nfor (const unit of units) {\n unitMap.set(unit.name.toLowerCase(), unit);\n for (const alias of unit.aliases) {\n unitMap.set(alias.toLowerCase(), unit);\n }\n}\n\nexport function normalizeUnit(unit: string = \"\"): UnitDefinition | undefined {\n return unitMap.get(unit.toLowerCase().trim());\n}\n\nexport class CannotAddTextValueError extends Error {\n constructor() {\n super(\"Cannot add a quantity with a text value.\");\n this.name = \"CannotAddTextValueError\";\n }\n}\n\nexport class IncompatibleUnitsError extends Error {\n constructor(unit1: string, unit2: string) {\n super(\n `Cannot add quantities with incompatible or unknown units: ${unit1} and ${unit2}`,\n );\n this.name = \"IncompatibleUnitsError\";\n }\n}\n\nfunction gcd(a: number, b: number): number {\n return b === 0 ? a : gcd(b, a % b);\n}\n\nexport function simplifyFraction(\n num: number,\n den: number,\n): DecimalValue | FractionValue {\n if (den === 0) {\n throw new Error(\"Denominator cannot be zero.\");\n }\n\n const commonDivisor = gcd(Math.abs(num), Math.abs(den));\n let simplifiedNum = num / commonDivisor;\n let simplifiedDen = den / commonDivisor;\n if (simplifiedDen < 0) {\n simplifiedNum = -simplifiedNum;\n simplifiedDen = -simplifiedDen;\n }\n\n if (simplifiedDen === 1) {\n return { type: \"decimal\", value: simplifiedNum };\n } else {\n return { type: \"fraction\", num: simplifiedNum, den: simplifiedDen };\n }\n}\n\nexport function multiplyNumericValue(\n v: DecimalValue | FractionValue,\n factor: number | Big,\n): DecimalValue | FractionValue {\n if (v.type === \"decimal\") {\n return { type: \"decimal\", value: Big(v.value).times(factor).toNumber() };\n }\n return simplifyFraction(Big(v.num).times(factor).toNumber(), v.den);\n}\n\nexport function addNumericValues(\n val1: DecimalValue | FractionValue,\n val2: DecimalValue | FractionValue,\n): DecimalValue | FractionValue {\n let num1: number;\n let den1: number;\n let num2: number;\n let den2: number;\n\n if (val1.type === \"decimal\") {\n num1 = val1.value;\n den1 = 1;\n } else {\n num1 = val1.num;\n den1 = val1.den;\n }\n\n if (val2.type === \"decimal\") {\n num2 = val2.value;\n den2 = 1;\n } else {\n num2 = val2.num;\n den2 = val2.den;\n }\n\n // Return 0 if both values are 0\n if (num1 === 0 && num2 === 0) {\n return { type: \"decimal\", value: 0 };\n }\n\n // We only return a fraction where both input values are fractions themselves or only one while the other is 0\n if (\n (val1.type === \"fraction\" && val2.type === \"fraction\") ||\n (val1.type === \"fraction\" && val2.type === \"decimal\" && val2.value === 0) ||\n (val2.type === \"fraction\" && val1.type === \"decimal\" && val1.value === 0)\n ) {\n const commonDen = den1 * den2;\n const sumNum = num1 * den2 + num2 * den1;\n return simplifyFraction(sumNum, commonDen);\n } else {\n return {\n type: \"decimal\",\n value: Big(num1).div(den1).add(Big(num2).div(den2)).toNumber(),\n };\n }\n}\n\nconst toRoundedDecimal = (v: DecimalValue | FractionValue): DecimalValue => {\n const value = v.type === \"decimal\" ? v.value : v.num / v.den;\n return { type: \"decimal\", value: Math.floor(value * 100) / 100 };\n};\n\nexport function multiplyQuantityValue(\n value: FixedValue | Range,\n factor: number | Big,\n): FixedValue | Range {\n if (value.type === \"fixed\") {\n const newValue = multiplyNumericValue(\n value.value as DecimalValue | FractionValue,\n Big(factor),\n );\n if (\n factor === parseInt(factor.toString()) || // e.g. 2 === int\n Big(1).div(factor).toNumber() === parseInt(Big(1).div(factor).toString()) // e.g. 0.25 => 4 === int\n ) {\n // Preserve fractions\n return {\n type: \"fixed\",\n value: newValue,\n };\n }\n // We might multiply with big decimal number so rounding into decimal value\n return {\n type: \"fixed\",\n value: toRoundedDecimal(newValue),\n };\n }\n\n return {\n type: \"range\",\n min: multiplyNumericValue(value.min, factor),\n max: multiplyNumericValue(value.max, factor),\n };\n}\n\nconst convertQuantityValue = (\n value: FixedValue | Range,\n def: UnitDefinition,\n targetDef: UnitDefinition,\n): FixedValue | Range => {\n if (def.name === targetDef.name) return value;\n\n const factor = def.toBase / targetDef.toBase;\n\n return multiplyQuantityValue(value, factor);\n};\n\n/**\n * Get the default / neutral quantity which can be provided to addQuantity\n * for it to return the other value as result\n *\n * @return zero\n */\nexport function getDefaultQuantityValue(): FixedValue {\n return { type: \"fixed\", value: { type: \"decimal\", value: 0 } };\n}\n\n/**\n * Adds two quantity values together.\n *\n * - Adding two {@link FixedValue}s returns a new {@link FixedValue}.\n * - Adding a {@link Range} to any value returns a {@link Range}.\n *\n * @param v1 - The first quantity value.\n * @param v2 - The second quantity value.\n * @returns A new quantity value representing the sum.\n */\nexport function addQuantityValues(v1: FixedValue, v2: FixedValue): FixedValue;\nexport function addQuantityValues(\n v1: FixedValue | Range,\n v2: FixedValue | Range,\n): Range;\n\nexport function addQuantityValues(\n v1: FixedValue | Range,\n v2: FixedValue | Range,\n): FixedValue | Range {\n if (\n (v1.type === \"fixed\" && v1.value.type === \"text\") ||\n (v2.type === \"fixed\" && v2.value.type === \"text\")\n ) {\n throw new CannotAddTextValueError();\n }\n\n if (v1.type === \"fixed\" && v2.type === \"fixed\") {\n const res = addNumericValues(\n v1.value as DecimalValue | FractionValue,\n v2.value as DecimalValue | FractionValue,\n );\n return { type: \"fixed\", value: res };\n }\n const r1 =\n v1.type === \"range\" ? v1 : { type: \"range\", min: v1.value, max: v1.value };\n const r2 =\n v2.type === \"range\" ? v2 : { type: \"range\", min: v2.value, max: v2.value };\n const newMin = addNumericValues(\n r1.min as DecimalValue | FractionValue,\n r2.min as DecimalValue | FractionValue,\n );\n const newMax = addNumericValues(\n r1.max as DecimalValue | FractionValue,\n r2.max as DecimalValue | FractionValue,\n );\n return { type: \"range\", min: newMin, max: newMax };\n}\n\n/**\n * Adds two quantities, returning the result in the most appropriate unit.\n */\nexport function addQuantities(q1: Quantity, q2: Quantity): Quantity {\n const v1 = q1.value;\n const v2 = q2.value;\n\n // Case 1: one of the two values is a text, we throw an error we can catch on the other end\n if (\n (v1.type === \"fixed\" && v1.value.type === \"text\") ||\n (v2.type === \"fixed\" && v2.value.type === \"text\")\n ) {\n throw new CannotAddTextValueError();\n }\n\n const unit1Def = normalizeUnit(q1.unit);\n const unit2Def = normalizeUnit(q2.unit);\n\n const addQuantityValuesAndSetUnit = (\n val1: FixedValue | Range,\n val2: FixedValue | Range,\n unit: string | undefined,\n ): Quantity => ({ value: addQuantityValues(val1, val2), unit });\n\n // Case 2: one of the two values doesn't have a unit, we preserve its value and consider its unit to be that of the other one\n // If at least one of the two units is \"\", this preserves it versus setting the resulting unit as undefined\n if ((q1.unit === \"\" || q1.unit === undefined) && q2.unit !== undefined) {\n return addQuantityValuesAndSetUnit(v1, v2, q2.unit); // Prefer q2's unit\n }\n if ((q2.unit === \"\" || q2.unit === undefined) && q1.unit !== undefined) {\n return addQuantityValuesAndSetUnit(v1, v2, q1.unit); // Prefer q1's unit\n }\n\n // Case 3: the two quantities have the exact same unit\n if (\n (!q1.unit && !q2.unit) ||\n (q1.unit && q2.unit && q1.unit.toLowerCase() === q2.unit.toLowerCase())\n ) {\n return addQuantityValuesAndSetUnit(v1, v2, q1.unit);\n }\n\n // Case 4: the two quantities have different units of known type\n if (unit1Def && unit2Def) {\n // Case 4.1: different unit type => we can't add quantities\n\n if (unit1Def.type !== unit2Def.type) {\n throw new IncompatibleUnitsError(\n `${unit1Def.type} (${q1.unit})`,\n `${unit2Def.type} (${q2.unit})`,\n );\n }\n\n let targetUnitDef: UnitDefinition;\n\n // Case 4.2: same unit type but different system => we convert to metric\n if (unit1Def.system !== unit2Def.system) {\n const metricUnitDef = unit1Def.system === \"metric\" ? unit1Def : unit2Def;\n targetUnitDef = units\n .filter((u) => u.type === metricUnitDef.type && u.system === \"metric\")\n .reduce((prev, current) =>\n prev.toBase > current.toBase ? prev : current,\n );\n }\n // Case 4.3: same unit type, same system but different unit => we use the biggest unit of the two\n else {\n targetUnitDef = unit1Def.toBase >= unit2Def.toBase ? unit1Def : unit2Def;\n }\n const convertedV1 = convertQuantityValue(v1, unit1Def, targetUnitDef);\n const convertedV2 = convertQuantityValue(v2, unit2Def, targetUnitDef);\n\n return addQuantityValuesAndSetUnit(\n convertedV1,\n convertedV2,\n targetUnitDef.name,\n );\n }\n\n // Case 5: the two quantities have different units of unknown type\n throw new IncompatibleUnitsError(q1.unit!, q2.unit!);\n}\n","import { IngredientFlag, CookwareFlag } from \"./types\";\n\nexport class ReferencedItemCannotBeRedefinedError extends Error {\n constructor(\n item_type: \"ingredient\" | \"cookware\",\n item_name: string,\n new_modifier: IngredientFlag | CookwareFlag,\n ) {\n super(\n `The referenced ${item_type} \"${item_name}\" cannot be redefined as ${new_modifier}.\nYou can either remove the reference to create a new ${item_type} defined as ${new_modifier} or add the ${new_modifier} flag to the original definition of the ${item_type}`,\n );\n this.name = \"ReferencedItemCannotBeRedefinedError\";\n }\n}\n","import type {\n MetadataExtract,\n Metadata,\n FixedValue,\n Range,\n TextValue,\n DecimalValue,\n FractionValue,\n} from \"./types\";\nimport {\n metadataRegex,\n rangeRegex,\n numberLikeRegex,\n scalingMetaValueRegex,\n} from \"./regex\";\nimport { Section as SectionObject } from \"./classes/section\";\nimport type { Ingredient, Note, Step, Cookware } from \"./types\";\nimport {\n addQuantities,\n getDefaultQuantityValue,\n CannotAddTextValueError,\n IncompatibleUnitsError,\n Quantity,\n addQuantityValues,\n} from \"./units\";\nimport { ReferencedItemCannotBeRedefinedError } from \"./errors\";\n\n/**\n * Pushes a pending note to the section content if it's not empty.\n * @param section - The current section object.\n * @param note - The note content.\n * @returns An empty string if the note was pushed, otherwise the original note.\n */\nexport function flushPendingNote(\n section: SectionObject,\n note: Note[\"note\"],\n): Note[\"note\"] {\n if (note.length > 0) {\n section.content.push({ type: \"note\", note });\n return \"\";\n }\n return note;\n}\n\n/**\n * Pushes pending step items and a pending note to the section content.\n * @param section - The current section object.\n * @param items - The list of step items. This array will be cleared.\n * @returns true if the items were pushed, otherwise false.\n */\nexport function flushPendingItems(\n section: SectionObject,\n items: Step[\"items\"],\n): boolean {\n if (items.length > 0) {\n section.content.push({ type: \"step\", items: [...items] });\n items.length = 0;\n return true;\n }\n return false;\n}\n\n/**\n * Finds an ingredient in the list (case-insensitively) and updates it, or adds it if not present.\n * This function mutates the `ingredients` array.\n * @param ingredients - The list of ingredients.\n * @param newIngredient - The ingredient to find or add.\n * @param isReference - Whether this is a reference ingredient (`&` modifier).\n * @returns The index of the ingredient in the list.\n * @returns An object containing the index of the ingredient and its quantity part in the list.\n */\nexport function findAndUpsertIngredient(\n ingredients: Ingredient[],\n newIngredient: Ingredient,\n isReference: boolean,\n): {\n ingredientIndex: number;\n quantityPartIndex: number | undefined;\n} {\n const { name, quantity, unit } = newIngredient;\n\n // New ingredient\n if (isReference) {\n const indexFind = ingredients.findIndex(\n (i) => i.name.toLowerCase() === name.toLowerCase(),\n );\n\n if (indexFind === -1) {\n throw new Error(\n `Referenced ingredient \"${name}\" not found. A referenced ingredient must be declared before being referenced with '&'.`,\n );\n }\n\n // Ingredient already exists, update it\n const existingIngredient = ingredients[indexFind]!;\n\n // Checking whether any provided flags are the same as the original ingredient\n for (const flag of newIngredient.flags!) {\n /* v8 ignore else -- @preserve */\n if (!existingIngredient.flags!.includes(flag)) {\n throw new ReferencedItemCannotBeRedefinedError(\n \"ingredient\",\n existingIngredient.name,\n flag,\n );\n }\n }\n\n let quantityPartIndex = undefined;\n if (quantity !== undefined) {\n const currentQuantity: Quantity = {\n value: existingIngredient.quantity ?? getDefaultQuantityValue(),\n unit: existingIngredient.unit ?? \"\",\n };\n const newQuantity = { value: quantity, unit: unit ?? \"\" };\n try {\n const total = addQuantities(currentQuantity, newQuantity);\n existingIngredient.quantity = total.value;\n existingIngredient.unit = total.unit || undefined;\n if (existingIngredient.quantityParts) {\n existingIngredient.quantityParts.push(\n ...newIngredient.quantityParts!,\n );\n } else {\n existingIngredient.quantityParts = newIngredient.quantityParts;\n }\n quantityPartIndex = existingIngredient.quantityParts!.length - 1;\n } catch (e) {\n /* v8 ignore else -- expliciting error types -- @preserve */\n if (\n e instanceof IncompatibleUnitsError ||\n e instanceof CannotAddTextValueError\n ) {\n // Addition not possible, so add as a new ingredient.\n return {\n ingredientIndex: ingredients.push(newIngredient) - 1,\n quantityPartIndex: 0,\n };\n }\n }\n }\n return {\n ingredientIndex: indexFind,\n quantityPartIndex,\n };\n }\n\n // Not a reference, so add as a new ingredient.\n return {\n ingredientIndex: ingredients.push(newIngredient) - 1,\n quantityPartIndex: newIngredient.quantity ? 0 : undefined,\n };\n}\n\nexport function findAndUpsertCookware(\n cookware: Cookware[],\n newCookware: Cookware,\n isReference: boolean,\n): {\n cookwareIndex: number;\n quantityPartIndex: number | undefined;\n} {\n const { name, quantity } = newCookware;\n\n if (isReference) {\n const index = cookware.findIndex(\n (i) => i.name.toLowerCase() === name.toLowerCase(),\n );\n\n if (index === -1) {\n throw new Error(\n `Referenced cookware \"${name}\" not found. A referenced cookware must be declared before being referenced with '&'.`,\n );\n }\n\n const existingCookware = cookware[index]!;\n\n // Checking whether any provided flags are the same as the original cookware\n for (const flag of newCookware.flags) {\n /* v8 ignore else -- @preserve */\n if (!existingCookware.flags.includes(flag)) {\n throw new ReferencedItemCannotBeRedefinedError(\n \"cookware\",\n existingCookware.name,\n flag,\n );\n }\n }\n\n let quantityPartIndex = undefined;\n if (quantity !== undefined) {\n if (!existingCookware.quantity) {\n existingCookware.quantity = quantity;\n existingCookware.quantityParts = newCookware.quantityParts;\n quantityPartIndex = 0;\n } else {\n try {\n existingCookware.quantity = addQuantityValues(\n existingCookware.quantity,\n quantity,\n );\n if (!existingCookware.quantityParts) {\n existingCookware.quantityParts = newCookware.quantityParts;\n quantityPartIndex = 0;\n } else {\n quantityPartIndex =\n existingCookware.quantityParts.push(\n ...newCookware.quantityParts!,\n ) - 1;\n }\n } catch (e) {\n /* v8 ignore else -- expliciting error type -- @preserve */\n if (e instanceof CannotAddTextValueError) {\n return {\n cookwareIndex: cookware.push(newCookware) - 1,\n quantityPartIndex: 0,\n };\n }\n }\n }\n }\n return {\n cookwareIndex: index,\n quantityPartIndex,\n };\n }\n\n return {\n cookwareIndex: cookware.push(newCookware) - 1,\n quantityPartIndex: quantity ? 0 : undefined,\n };\n}\n\n// Parser when we know the input is either a number-like value\nexport const parseFixedValue = (\n input_str: string,\n): TextValue | DecimalValue | FractionValue => {\n if (!numberLikeRegex.test(input_str)) {\n return { type: \"text\", value: input_str };\n }\n\n // After this we know that s is either a fraction or a decimal value\n const s = input_str.trim().replace(\",\", \".\");\n\n // fraction\n if (s.includes(\"/\")) {\n const parts = s.split(\"/\");\n\n const num = Number(parts[0]);\n const den = Number(parts[1]);\n\n return { type: \"fraction\", num, den };\n }\n\n // decimal\n return { type: \"decimal\", value: Number(s) };\n};\n\nexport function parseQuantityInput(input_str: string): FixedValue | Range {\n const clean_str = String(input_str).trim();\n\n if (rangeRegex.test(clean_str)) {\n const range_parts = clean_str.split(\"-\");\n // As we've tested for it, we know that we have Number-like Quantities to parse\n const min = parseFixedValue(range_parts[0]!.trim()) as\n | DecimalValue\n | FractionValue;\n const max = parseFixedValue(range_parts[1]!.trim()) as\n | DecimalValue\n | FractionValue;\n return { type: \"range\", min, max };\n }\n\n return { type: \"fixed\", value: parseFixedValue(clean_str) };\n}\n\nexport function parseSimpleMetaVar(content: string, varName: string) {\n const varMatch = content.match(\n new RegExp(`^${varName}:\\\\s*(.*(?:\\\\r?\\\\n\\\\s+.*)*)+`, \"m\"),\n );\n return varMatch\n ? varMatch[1]?.trim().replace(/\\s*\\r?\\n\\s+/g, \" \")\n : undefined;\n}\n\nexport function parseScalingMetaVar(\n content: string,\n varName: string,\n): [number, string] | undefined {\n const varMatch = content.match(scalingMetaValueRegex(varName));\n if (!varMatch) return undefined;\n if (isNaN(Number(varMatch[2]?.trim()))) {\n throw new Error(\"Scaling variables should be numbers\");\n }\n return [Number(varMatch[2]?.trim()), varMatch[1]!.trim()];\n}\n\nexport function parseListMetaVar(content: string, varName: string) {\n // Handle both inline and YAML-style tags\n const listMatch = content.match(\n new RegExp(\n `^${varName}:\\\\s*(?:\\\\[([^\\\\]]*)\\\\]|((?:\\\\r?\\\\n\\\\s*-\\\\s*.+)+))`,\n \"m\",\n ),\n );\n if (!listMatch) return undefined;\n\n /* v8 ignore else -- @preserve */\n if (listMatch[1] !== undefined) {\n // Inline list: tags: [one, two, three]\n return listMatch[1].split(\",\").map((tag) => tag.trim());\n } else if (listMatch[2]) {\n // YAML list:\n // tags:\n // - one\n // - two\n return listMatch[2]\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\")\n .map((line) => line.replace(/^\\s*-\\s*/, \"\").trim());\n }\n}\n\nexport function extractMetadata(content: string): MetadataExtract {\n const metadata: Metadata = {};\n let servings: number | undefined = undefined;\n\n // Is there front-matter at all?\n const metadataContent = content.match(metadataRegex)?.[1];\n if (!metadataContent) {\n return { metadata };\n }\n\n // String metadata variables\n for (const metaVar of [\n \"title\",\n \"source\",\n \"source.name\",\n \"source.url\",\n \"author\",\n \"source.author\",\n \"prep time\",\n \"time.prep\",\n \"cook time\",\n \"time.cook\",\n \"time required\",\n \"time\",\n \"duration\",\n \"locale\",\n \"introduction\",\n \"description\",\n \"course\",\n \"category\",\n \"diet\",\n \"cuisine\",\n \"difficulty\",\n \"image\",\n \"picture\",\n ] as (keyof Pick<\n Metadata,\n | \"title\"\n | \"source\"\n | \"source.name\"\n | \"source.url\"\n | \"author\"\n | \"source.author\"\n | \"prep time\"\n | \"time.prep\"\n | \"cook time\"\n | \"time.cook\"\n | \"time required\"\n | \"time\"\n | \"duration\"\n | \"locale\"\n | \"introduction\"\n | \"description\"\n | \"course\"\n | \"category\"\n | \"diet\"\n | \"cuisine\"\n | \"difficulty\"\n | \"image\"\n | \"picture\"\n >)[]) {\n const stringMetaValue = parseSimpleMetaVar(metadataContent, metaVar);\n if (stringMetaValue) metadata[metaVar] = stringMetaValue;\n }\n\n // String metadata variables\n for (const metaVar of [\"serves\", \"yield\", \"servings\"] as (keyof Pick<\n Metadata,\n \"servings\" | \"yield\" | \"serves\"\n >)[]) {\n const scalingMetaValue = parseScalingMetaVar(metadataContent, metaVar);\n if (scalingMetaValue && scalingMetaValue[1]) {\n metadata[metaVar] = scalingMetaValue[1];\n servings = scalingMetaValue[0];\n }\n }\n\n // List metadata variables\n for (const metaVar of [\"tags\", \"images\", \"pictures\"] as (keyof Pick<\n Metadata,\n \"tags\" | \"images\" | \"pictures\"\n >)[]) {\n const listMetaValue = parseListMetaVar(metadataContent, metaVar);\n if (listMetaValue) metadata[metaVar] = listMetaValue;\n }\n\n return { metadata, servings };\n}\n","import type {\n Metadata,\n Ingredient,\n IngredientExtras,\n IngredientItem,\n Timer,\n Step,\n Note,\n Cookware,\n MetadataExtract,\n CookwareItem,\n IngredientFlag,\n CookwareFlag,\n} from \"../types\";\nimport { Section } from \"./section\";\nimport {\n tokensRegex,\n commentRegex,\n blockCommentRegex,\n metadataRegex,\n ingredientAliasRegex,\n floatRegex,\n} from \"../regex\";\nimport {\n flushPendingItems,\n flushPendingNote,\n findAndUpsertIngredient,\n findAndUpsertCookware,\n parseQuantityInput,\n extractMetadata,\n} from \"../parser_helpers\";\nimport {\n addQuantities,\n getDefaultQuantityValue,\n multiplyQuantityValue,\n type Quantity,\n} from \"../units\";\nimport Big from \"big.js\";\n\n/**\n * Recipe parser.\n *\n * ## Usage\n *\n * You can either directly provide the recipe string when creating the instance\n * e.g. `const recipe = new Recipe('Add @eggs{3}')`, or create it first and then pass\n * the recipe string to the {@link Recipe.parse | parse()} method.\n *\n * Look at the [properties](#properties) to see how the recipe's properties are parsed.\n *\n * @category Classes\n *\n * @example\n * ```typescript\n * import { Recipe } from \"@tmlmt/cooklang-parser\";\n *\n * const recipeString = `\n * ---\n * title: Pancakes\n * tags: [breakfast, easy]\n * ---\n * Crack the @eggs{3} with @flour{100%g} and @milk{200%mL}\n *\n * Melt some @butter{50%g} in a #pan on medium heat.\n *\n * Cook for ~{5%minutes} on each side.\n * `\n * const recipe = new Recipe(recipeString);\n * ```\n */\nexport class Recipe {\n /**\n * The parsed recipe metadata.\n */\n metadata: Metadata = {};\n /**\n * The parsed recipe ingredients.\n */\n ingredients: Ingredient[] = [];\n /**\n * The parsed recipe sections.\n */\n sections: Section[] = [];\n /**\n * The parsed recipe cookware.\n */\n cookware: Cookware[] = [];\n /**\n * The parsed recipe timers.\n */\n timers: Timer[] = [];\n /**\n * The parsed recipe servings. Used for scaling. Parsed from one of\n * {@link Metadata.servings}, {@link Metadata.yield} or {@link Metadata.serves}\n * metadata fields.\n *\n * @see {@link Recipe.scaleBy | scaleBy()} and {@link Recipe.scaleTo | scaleTo()} methods\n */\n servings?: number;\n\n /**\n * Creates a new Recipe instance.\n * @param content - The recipe content to parse.\n */\n constructor(content?: string) {\n if (content) {\n this.parse(content);\n }\n }\n\n /**\n * Parses a recipe from a string.\n * @param content - The recipe content to parse.\n */\n parse(content: string) {\n const cleanContent = content\n .replace(metadataRegex, \"\")\n .replace(commentRegex, \"\")\n .replace(blockCommentRegex, \"\")\n .trim()\n .split(/\\r\\n?|\\n/);\n\n const { metadata, servings }: MetadataExtract = extractMetadata(content);\n this.metadata = metadata;\n this.servings = servings;\n\n let blankLineBefore = true;\n let section: Section = new Section();\n const items: Step[\"items\"] = [];\n let note: Note[\"note\"] = \"\";\n let inNote = false;\n\n for (const line of cleanContent) {\n if (line.trim().length === 0) {\n flushPendingItems(section, items);\n note = flushPendingNote(section, note);\n blankLineBefore = true;\n inNote = false;\n continue;\n }\n\n if (line.startsWith(\"=\")) {\n flushPendingItems(section, items);\n note = flushPendingNote(section, note);\n\n if (this.sections.length === 0 && section.isBlank()) {\n section.name = line.replace(/^=+|=+$/g, \"\").trim();\n } else {\n /* v8 ignore else -- @preserve */\n if (!section.isBlank()) {\n this.sections.push(section);\n }\n section = new Section(line.replace(/^=+|=+$/g, \"\").trim());\n }\n blankLineBefore = true;\n inNote = false;\n continue;\n }\n\n if (blankLineBefore && line.startsWith(\">\")) {\n flushPendingItems(section, items);\n note = flushPendingNote(section, note);\n note += line.substring(1).trim();\n inNote = true;\n blankLineBefore = false;\n continue;\n }\n\n if (inNote) {\n if (line.startsWith(\">\")) {\n note += \" \" + line.substring(1).trim();\n } else {\n note += \" \" + line.trim();\n }\n blankLineBefore = false;\n continue;\n }\n\n note = flushPendingNote(section, note);\n\n let cursor = 0;\n for (const match of line.matchAll(tokensRegex)) {\n const idx = match.index;\n /* v8 ignore else -- @preserve */\n if (idx > cursor) {\n items.push({ type: \"text\", value: line.slice(cursor, idx) });\n }\n\n const groups = match.groups!;\n\n if (groups.mIngredientName || groups.sIngredientName) {\n let name = (groups.mIngredientName || groups.sIngredientName)!;\n const scalableQuantity =\n (groups.mIngredientQuantityModifier ||\n groups.sIngredientQuantityModifier) !== \"=\";\n const quantityRaw =\n groups.mIngredientQuantity || groups.sIngredientQuantity;\n const unit = groups.mIngredientUnit || groups.sIngredientUnit;\n const preparation =\n groups.mIngredientPreparation || groups.sIngredientPreparation;\n const modifiers =\n groups.mIngredientModifiers || groups.sIngredientModifiers;\n const reference = modifiers !== undefined && modifiers.includes(\"&\");\n const flags: IngredientFlag[] = [];\n if (modifiers !== undefined && modifiers.includes(\"?\")) {\n flags.push(\"optional\");\n }\n if (modifiers !== undefined && modifiers.includes(\"-\")) {\n flags.push(\"hidden\");\n }\n if (\n (modifiers !== undefined && modifiers.includes(\"@\")) ||\n groups.mIngredientRecipeAnchor ||\n groups.sIngredientRecipeAnchor\n ) {\n flags.push(\"recipe\");\n }\n\n let extras: IngredientExtras | undefined = undefined;\n // If the ingredient is a recipe, we need to extract the name from the path given\n if (flags.includes(\"recipe\")) {\n extras = { path: `${name}.cook` };\n name = name.substring(name.lastIndexOf(\"/\") + 1);\n }\n\n const quantity = quantityRaw\n ? parseQuantityInput(quantityRaw)\n : undefined;\n const aliasMatch = name.match(ingredientAliasRegex);\n let listName, displayName: string;\n if (\n aliasMatch &&\n aliasMatch.groups!.ingredientListName!.trim().length > 0 &&\n aliasMatch.groups!.ingredientDisplayName!.trim().length > 0\n ) {\n listName = aliasMatch.groups!.ingredientListName!.trim();\n displayName = aliasMatch.groups!.ingredientDisplayName!.trim();\n } else {\n listName = name;\n displayName = name;\n }\n\n const newIngredient: Ingredient = {\n name: listName,\n quantity,\n quantityParts: quantity\n ? [\n {\n value: quantity,\n unit,\n scalable: scalableQuantity,\n },\n ]\n : undefined,\n unit,\n preparation,\n flags,\n };\n\n if (extras) {\n newIngredient.extras = extras;\n }\n\n const idxsInList = findAndUpsertIngredient(\n this.ingredients,\n newIngredient,\n reference,\n );\n\n const newItem: IngredientItem = {\n type: \"ingredient\",\n index: idxsInList.ingredientIndex,\n displayName,\n };\n if (idxsInList.quantityPartIndex !== undefined) {\n newItem.quantityPartIndex = idxsInList.quantityPartIndex;\n }\n items.push(newItem);\n } else if (groups.mCookwareName || groups.sCookwareName) {\n const name = (groups.mCookwareName || groups.sCookwareName)!;\n const modifiers =\n groups.mCookwareModifiers || groups.sCookwareModifiers;\n const quantityRaw =\n groups.mCookwareQuantity || groups.sCookwareQuantity;\n const reference = modifiers !== undefined && modifiers.includes(\"&\");\n const flags: CookwareFlag[] = [];\n if (modifiers !== undefined && modifiers.includes(\"?\")) {\n flags.push(\"optional\");\n }\n if (modifiers !== undefined && modifiers.includes(\"-\")) {\n flags.push(\"hidden\");\n }\n const quantity = quantityRaw\n ? parseQuantityInput(quantityRaw)\n : undefined;\n\n const idxsInList = findAndUpsertCookware(\n this.cookware,\n {\n name,\n quantity,\n quantityParts: quantity ? [quantity] : undefined,\n flags,\n },\n reference,\n );\n items.push({\n type: \"cookware\",\n index: idxsInList.cookwareIndex,\n quantityPartIndex: idxsInList.quantityPartIndex,\n } as CookwareItem);\n }\n // Then it's necessarily a timer which was matched\n else {\n const durationStr = groups.timerQuantity!.trim();\n const unit = (groups.timerUnit || \"\").trim();\n if (!unit) {\n throw new Error(\"Timer missing unit\");\n }\n const name = groups.timerName || undefined;\n const duration = parseQuantityInput(durationStr);\n const timerObj: Timer = {\n name,\n duration,\n unit,\n };\n items.push({ type: \"timer\", index: this.timers.push(timerObj) - 1 });\n }\n\n cursor = idx + match[0].length;\n }\n\n if (cursor < line.length) {\n items.push({ type: \"text\", value: line.slice(cursor) });\n }\n\n blankLineBefore = false;\n }\n\n // End of content reached: pushing all temporarily saved elements\n flushPendingItems(section, items);\n note = flushPendingNote(section, note);\n if (!section.isBlank()) {\n this.sections.push(section);\n }\n }\n\n /**\n * Scales the recipe to a new number of servings. In practice, it calls\n * {@link Recipe.scaleBy | scaleBy} with a factor corresponding to the ratio between `newServings`\n * and the recipe's {@link Recipe.servings | servings} value.\n * @param newServings - The new number of servings.\n * @returns A new Recipe instance with the scaled ingredients.\n * @throws `Error` if the recipe does not contains an initial {@link Recipe.servings | servings} value\n */\n scaleTo(newServings: number): Recipe {\n const originalServings = this.getServings();\n\n if (originalServings === undefined || originalServings === 0) {\n throw new Error(\"Error scaling recipe: no initial servings value set\");\n }\n\n const factor = Big(newServings).div(originalServings);\n return this.scaleBy(factor);\n }\n\n /**\n * Scales the recipe by a factor.\n * @param factor - The factor to scale the recipe by. While integers can be passed as-is, it is recommended to pass fractions as\n * [Big](https://github.com/MikeMcl/big.js/) values, e.g. `Big(num).div(den)` in order to avoid undesirable floating point operation inaccuracies.\n * @returns A new Recipe instance with the scaled ingredients.\n */\n scaleBy(factor: number | Big): Recipe {\n const newRecipe = this.clone();\n\n const originalServings = newRecipe.getServings();\n\n if (originalServings === undefined || originalServings === 0) {\n throw new Error(\"Error scaling recipe: no initial servings value set\");\n }\n\n newRecipe.ingredients = newRecipe.ingredients\n .map((ingredient) => {\n // Scale first individual parts of total quantity depending on whether they are scalable or not\n if (ingredient.quantityParts) {\n ingredient.quantityParts = ingredient.quantityParts.map(\n (quantityPart) => {\n if (\n quantityPart.value.type === \"fixed\" &&\n quantityPart.value.value.type === \"text\"\n ) {\n return quantityPart;\n }\n return {\n ...quantityPart,\n value: multiplyQuantityValue(\n quantityPart.value,\n quantityPart.scalable ? Big(factor) : 1,\n ),\n };\n },\n );\n // Recalculate total quantity from quantity parts\n if (ingredient.quantityParts.length === 1) {\n ingredient.quantity = ingredient.quantityParts[0]!.value;\n ingredient.unit = ingredient.quantityParts[0]!.unit;\n } else {\n const totalQuantity = ingredient.quantityParts.reduce(\n (acc, val) =>\n addQuantities(acc, { value: val.value, unit: val.unit }),\n { value: getDefaultQuantityValue() } as Quantity,\n );\n ingredient.quantity = totalQuantity.value;\n ingredient.unit = totalQuantity.unit;\n }\n }\n return ingredient;\n })\n .filter((ingredient) => ingredient.quantity !== null);\n\n newRecipe.servings = Big(originalServings).times(factor).toNumber();\n\n /* v8 ignore else -- @preserve */\n if (newRecipe.metadata.servings && this.metadata.servings) {\n if (\n floatRegex.test(String(this.metadata.servings).replace(\",\", \".\").trim())\n ) {\n const servingsValue = parseFloat(\n String(this.metadata.servings).replace(\",\", \".\"),\n );\n newRecipe.metadata.servings = String(\n Big(servingsValue).times(factor).toNumber(),\n );\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (newRecipe.metadata.yield && this.metadata.yield) {\n if (\n floatRegex.test(String(this.metadata.yield).replace(\",\", \".\").trim())\n ) {\n const yieldValue = parseFloat(\n String(this.metadata.yield).replace(\",\", \".\"),\n );\n newRecipe.metadata.yield = String(\n Big(yieldValue).times(factor).toNumber(),\n );\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (newRecipe.metadata.serves && this.metadata.serves) {\n if (\n floatRegex.test(String(this.metadata.serves).replace(\",\", \".\").trim())\n ) {\n const servesValue = parseFloat(\n String(this.metadata.serves).replace(\",\", \".\"),\n );\n newRecipe.metadata.serves = String(\n Big(servesValue).times(factor).toNumber(),\n );\n }\n }\n\n return newRecipe;\n }\n\n /**\n * Gets the number of servings for the recipe.\n * @private\n * @returns The number of servings, or undefined if not set.\n */\n private getServings(): number | undefined {\n if (this.servings) {\n return this.servings;\n }\n return undefined;\n }\n\n /**\n * Clones the recipe.\n * @returns A new Recipe instance with the same properties.\n */\n clone(): Recipe {\n const newRecipe = new Recipe();\n // deep copy\n newRecipe.metadata = JSON.parse(JSON.stringify(this.metadata)) as Metadata;\n newRecipe.ingredients = JSON.parse(\n JSON.stringify(this.ingredients),\n ) as Ingredient[];\n newRecipe.sections = JSON.parse(JSON.stringify(this.sections)) as Section[];\n newRecipe.cookware = JSON.parse(\n JSON.stringify(this.cookware),\n ) as Cookware[];\n newRecipe.timers = JSON.parse(JSON.stringify(this.timers)) as Timer[];\n newRecipe.servings = this.servings;\n return newRecipe;\n }\n}\n","import { CategoryConfig } from \"./category_config\";\nimport { Recipe } from \"./recipe\";\nimport type {\n Ingredient,\n CategorizedIngredients,\n AddedRecipe,\n AddedIngredient,\n} from \"../types\";\nimport { addQuantities, type Quantity } from \"../units\";\n\n/**\n * Shopping List generator.\n *\n * ## Usage\n *\n * - Create a new ShoppingList instance with an optional category configuration (see {@link ShoppingList.\"constructor\" | constructor})\n * - Add recipes, scaling them as needed (see {@link ShoppingList.add_recipe | add_recipe()})\n * - Categorize the ingredients (see {@link ShoppingList.categorize | categorize()})\n *\n * @example\n *\n * ```typescript\n * import * as fs from \"fs\";\n * import { ShoppingList } from @tmlmt/cooklang-parser;\n *\n * const categoryConfig = fs.readFileSync(\"./myconfig.txt\", \"utf-8\")\n * const recipe1 = new Recipe(fs.readFileSync(\"./myrecipe.cook\", \"utf-8\"));\n * const shoppingList = new ShoppingList();\n * shoppingList.set_category_config(categoryConfig);\n * // Quantities are automatically calculated and ingredients categorized\n * // when adding a recipe\n * shoppingList.add_recipe(recipe1);\n * ```\n *\n * @category Classes\n */\nexport class ShoppingList {\n /**\n * The ingredients in the shopping list.\n */\n ingredients: Ingredient[] = [];\n /**\n * The recipes in the shopping list.\n */\n recipes: AddedRecipe[] = [];\n /**\n * The category configuration for the shopping list.\n */\n category_config?: CategoryConfig;\n /**\n * The categorized ingredients in the shopping list.\n */\n categories?: CategorizedIngredients;\n\n /**\n * Creates a new ShoppingList instance\n * @param category_config_str - The category configuration to parse.\n */\n constructor(category_config_str?: string | CategoryConfig) {\n if (category_config_str) {\n this.set_category_config(category_config_str);\n }\n }\n\n private calculate_ingredients() {\n this.ingredients = [];\n for (const addedRecipe of this.recipes) {\n let scaledRecipe: Recipe;\n if (\"factor\" in addedRecipe) {\n const { recipe, factor } = addedRecipe;\n scaledRecipe = factor === 1 ? recipe : recipe.scaleBy(factor);\n } else {\n scaledRecipe = addedRecipe.recipe.scaleTo(addedRecipe.servings);\n }\n\n for (const ingredient of scaledRecipe.ingredients) {\n // Do not add hidden ingredients to the shopping list\n if (ingredient.flags && ingredient.flags.includes(\"hidden\")) {\n continue;\n }\n\n const existingIngredient = this.ingredients.find(\n (i) => i.name === ingredient.name,\n );\n\n let addSeparate = false;\n try {\n if (existingIngredient && ingredient.quantity) {\n if (existingIngredient.quantity) {\n const newQuantity: Quantity = addQuantities(\n {\n value: existingIngredient.quantity,\n unit: existingIngredient.unit ?? \"\",\n },\n {\n value: ingredient.quantity,\n unit: ingredient.unit ?? \"\",\n },\n );\n existingIngredient.quantity = newQuantity.value;\n if (newQuantity.unit) {\n existingIngredient.unit = newQuantity.unit;\n }\n } else {\n existingIngredient.quantity = ingredient.quantity;\n\n /* v8 ignore else -- only set unit if it is given -- @preserve */\n if (ingredient.unit) {\n existingIngredient.unit = ingredient.unit;\n }\n }\n }\n } catch {\n // Cannot add quantities, adding as separate ingredients\n addSeparate = true;\n }\n\n if (!existingIngredient || addSeparate) {\n const newIngredient: AddedIngredient = { name: ingredient.name };\n if (ingredient.quantity) {\n newIngredient.quantity = ingredient.quantity;\n }\n if (ingredient.unit) {\n newIngredient.unit = ingredient.unit;\n }\n this.ingredients.push(newIngredient);\n }\n }\n }\n }\n\n /**\n * Adds a recipe to the shopping list, then automatically\n * recalculates the quantities and recategorize the ingredients.\n * @param recipe - The recipe to add.\n * @param scaling - The scaling option for the recipe. Can be either a factor or a number of servings\n */\n add_recipe(\n recipe: Recipe,\n scaling?: { factor: number } | { servings: number },\n ): void;\n /**\n * Adds a recipe to the shopping list, then automatically\n * recalculates the quantities and recategorize the ingredients.\n * @param recipe - The recipe to add.\n * @param factor - The factor to scale the recipe by.\n * @deprecated since v2.0.3. Use the other call signature with `scaling` instead. Will be removed in v3\n */\n add_recipe(recipe: Recipe, factor?: number): void;\n add_recipe(\n recipe: Recipe,\n scaling?: { factor: number } | { servings: number } | number,\n ): void {\n if (typeof scaling === \"number\" || scaling === undefined) {\n this.recipes.push({ recipe, factor: scaling ?? 1 });\n } else {\n if (\"factor\" in scaling) {\n this.recipes.push({ recipe, factor: scaling.factor });\n } else {\n this.recipes.push({ recipe, servings: scaling.servings });\n }\n }\n this.calculate_ingredients();\n this.categorize();\n }\n\n /**\n * Removes a recipe from the shopping list, then automatically\n * recalculates the quantities and recategorize the ingredients.s\n * @param index - The index of the recipe to remove.\n */\n remove_recipe(index: number) {\n if (index < 0 || index >= this.recipes.length) {\n throw new Error(\"Index out of bounds\");\n }\n this.recipes.splice(index, 1);\n this.calculate_ingredients();\n this.categorize();\n }\n\n /**\n * Sets the category configuration for the shopping list\n * and automatically categorize current ingredients from the list.\n * @param config - The category configuration to parse.\n */\n set_category_config(config: string | CategoryConfig) {\n if (typeof config === \"string\")\n this.category_config = new CategoryConfig(config);\n else if (config instanceof CategoryConfig) this.category_config = config;\n else throw new Error(\"Invalid category configuration\");\n this.categorize();\n }\n\n /**\n * Categorizes the ingredients in the shopping list\n * Will use the category config if any, otherwise all ingredients will be placed in the \"other\" category\n */\n categorize() {\n if (!this.category_config) {\n this.categories = { other: this.ingredients };\n return;\n }\n\n const categories: CategorizedIngredients = { other: [] };\n for (const category of this.category_config.categories) {\n categories[category.name] = [];\n }\n\n for (const ingredient of this.ingredients) {\n let found = false;\n for (const category of this.category_config.categories) {\n for (const categoryIngredient of category.ingredients) {\n if (categoryIngredient.aliases.includes(ingredient.name)) {\n categories[category.name]!.push(ingredient);\n found = true;\n break;\n }\n }\n if (found) {\n break;\n }\n }\n if (!found) {\n categories.other!.push(ingredient);\n }\n }\n\n this.categories = categories;\n }\n}\n"],"mappings":"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","names":["escapeCache","Map","Flags","GLOBAL","NON_SENSITIVE","MULTILINE","DOT_ALL","UNICODE","STICKY","Ranges","Object","freeze","digit","lowercaseLetter","uppercaseLetter","letter","alphanumeric","anyCharacter","Quantifiers","zeroOrMore","oneOrMore","optional","HumanRegex","constructor","this","parts","flags","Set","add","special","word","whitespace","nonWhitespace","text","has","set","replace","get","or","name","range","Error","chars","lazy","lastPart","pop","newline","pattern","hasSpecialCharacter","hasDigit","hasLetter","n","min","max","startGroup","startCaptureGroup","wordBoundary","nonWordBoundary","endGroup","startAnchor","endAnchor","global","nonSensitive","multiline","dotAll","sticky","variant","validVariants","unicodeDigit","unicodePunctuation","unicodeSymbol","count","length","push","ipv4Octet","protocol","www","tld","path","part","toString","join","toRegExp","RegExp","createRegex","Patterns","createCachedPattern","builder","regex","source","email","literal","atLeast","url","phoneInternational","between","r","a","Big","i","e","import_big","Big","i"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/classes/category_config.ts","../src/classes/product_catalog.ts","../node_modules/.pnpm/human-regex@2.2.0/node_modules/human-regex/src/human-regex.ts","../src/regex.ts","../src/units/definitions.ts","../src/quantities/numeric.ts","../src/errors.ts","../src/utils/type_guards.ts","../src/quantities/mutations.ts","../src/utils/parser_helpers.ts","../src/classes/section.ts","../src/quantities/alternatives.ts","../src/units/conversion.ts","../src/units/lookup.ts","../src/utils/general.ts","../src/classes/recipe.ts","../src/classes/shopping_list.ts","../src/classes/shopping_cart.ts","../src/utils/render_helpers.ts"],"sourcesContent":["// Classes\n\nimport { CategoryConfig } from \"./classes/category_config\";\nimport { ProductCatalog } from \"./classes/product_catalog\";\nimport { Recipe } from \"./classes/recipe\";\nimport { ShoppingList } from \"./classes/shopping_list\";\nimport {\n ShoppingCart,\n type ShoppingCartOptions,\n type ShoppingCartSummary,\n} from \"./classes/shopping_cart\";\nimport { Section } from \"./classes/section\";\n\nexport {\n CategoryConfig,\n ProductCatalog,\n Recipe,\n ShoppingList,\n ShoppingCart,\n Section,\n};\n\n// Helpers\n\nimport {\n isAlternativeSelected,\n isGroupedItem,\n formatNumericValue,\n formatSingleValue,\n formatQuantity,\n formatUnit,\n formatQuantityWithUnit,\n formatExtendedQuantity,\n formatItemQuantity,\n} from \"./utils/render_helpers\";\nimport {\n isAndGroup,\n isSimpleGroup,\n hasAlternatives,\n} from \"./utils/type_guards\";\n\nexport {\n isAlternativeSelected,\n isGroupedItem,\n formatNumericValue,\n formatSingleValue,\n formatQuantity,\n formatUnit,\n formatQuantityWithUnit,\n formatExtendedQuantity,\n formatItemQuantity,\n isAndGroup,\n isSimpleGroup,\n hasAlternatives,\n};\n\n// Types\n\nimport type {\n Metadata,\n Ingredient,\n IngredientFlag,\n IngredientExtras,\n FixedValue,\n Range,\n DecimalValue,\n FractionValue,\n TextValue,\n FixedNumericValue,\n Timer,\n TextItem,\n IngredientItem,\n IngredientItemQuantity,\n IngredientAlternative,\n CookwareItem,\n TimerItem,\n ArbitraryScalable,\n ArbitraryScalableItem,\n StepItem,\n Step,\n Note,\n NoteItem,\n Cookware,\n CookwareFlag,\n CategorizedIngredients,\n AddedRecipe,\n AddedRecipeOptions,\n AddedIngredient,\n RecipeWithFactor,\n RecipeWithServings,\n CategoryIngredient,\n Category,\n ProductOptionBase,\n ProductOptionCore,\n ProductOption,\n ProductSize,\n ProductSelection,\n CartContent,\n ProductMatch,\n CartMatch,\n ProductMisMatch,\n CartMisMatch,\n NoProductMatchErrorCode,\n QuantityBase,\n QuantityWithPlainUnit,\n QuantityWithExtendedUnit,\n QuantityWithUnitDef,\n QuantityWithUnitLike,\n Unit,\n UnitSystem,\n UnitType,\n UnitDefinition,\n UnitDefinitionLike,\n AndGroup,\n OrGroup,\n Group,\n FlatAndGroup,\n FlatOrGroup,\n FlatGroup,\n MaybeNestedGroup,\n MaybeNestedAndGroup,\n MaybeNestedOrGroup,\n IngredientQuantityGroup,\n IngredientQuantityAndGroup,\n AlternativeIngredientRef,\n RecipeChoices,\n RecipeAlternatives,\n GetIngredientQuantitiesOptions,\n} from \"./types\";\n\nexport {\n ShoppingCartOptions,\n ShoppingCartSummary,\n Metadata,\n Ingredient,\n IngredientFlag,\n IngredientExtras,\n FixedValue,\n Range,\n DecimalValue,\n FractionValue,\n TextValue,\n FixedNumericValue,\n Timer,\n TextItem,\n IngredientItem,\n IngredientItemQuantity,\n IngredientAlternative,\n CookwareItem,\n TimerItem,\n ArbitraryScalable,\n ArbitraryScalableItem,\n StepItem,\n Step,\n Note,\n NoteItem,\n Cookware,\n CookwareFlag,\n CategorizedIngredients,\n AddedRecipe,\n AddedRecipeOptions,\n AddedIngredient,\n RecipeWithFactor,\n RecipeWithServings,\n CategoryIngredient,\n Category,\n ProductOptionBase,\n ProductOptionCore,\n ProductOption,\n ProductSize,\n ProductSelection,\n CartContent,\n ProductMatch,\n CartMatch,\n ProductMisMatch,\n CartMisMatch,\n NoProductMatchErrorCode,\n QuantityBase,\n QuantityWithPlainUnit,\n QuantityWithExtendedUnit,\n QuantityWithUnitDef,\n QuantityWithUnitLike,\n Unit,\n UnitSystem,\n UnitType,\n UnitDefinition,\n UnitDefinitionLike,\n AndGroup,\n OrGroup,\n Group,\n FlatAndGroup,\n FlatOrGroup,\n FlatGroup,\n MaybeNestedGroup,\n MaybeNestedAndGroup,\n MaybeNestedOrGroup,\n IngredientQuantityGroup,\n IngredientQuantityAndGroup,\n AlternativeIngredientRef,\n RecipeChoices,\n RecipeAlternatives,\n GetIngredientQuantitiesOptions,\n};\n\n// Errors\n\nimport {\n NoProductCatalogForCartError,\n NoShoppingListForCartError,\n} from \"./errors\";\n\nexport { NoProductCatalogForCartError, NoShoppingListForCartError };\n","import type { Category, CategoryIngredient } from \"../types\";\n\n/**\n * Parser for category configurations specified à-la-cooklang.\n *\n * ## Usage\n *\n * You can either directly provide the category configuration string when creating the instance\n * e.g. `const categoryConfig = new CategoryConfig(<...>)`, or create it first and then pass\n * the category configuration string to the {@link CategoryConfig.parse | parse()} method.\n *\n * The initialized `CategoryConfig` can then be fed to a {@link ShoppingList}\n *\n * @example\n * ```typescript\n * import { CategoryConfig } from @tmlmt/cooklang-parser;\n *\n * const categoryConfigString = `\n * [Dairy]\n * milk\n * butter\n *\n * [Bakery]\n * flour\n * sugar`;\n *\n * const categoryConfig = new CategoryConfig(categoryConfigString);\n * ```\n *\n * @see [Category Configuration](https://cooklang.org/docs/spec/#shopping-lists) section of the cooklang specs\n *\n * @category Classes\n */\nexport class CategoryConfig {\n /**\n * The parsed categories of ingredients.\n */\n categories: Category[] = [];\n\n /**\n * Creates a new CategoryConfig instance.\n * @param config - The category configuration to parse.\n */\n constructor(config?: string) {\n if (config) {\n this.parse(config);\n }\n }\n\n /**\n * Parses a category configuration from a string into property\n * {@link CategoryConfig.categories | categories}\n * @param config - The category configuration to parse.\n */\n parse(config: string) {\n let currentCategory: Category | null = null;\n const categoryNames = new Set<string>();\n const ingredientNames = new Set<string>();\n\n for (const line of config.split(\"\\n\")) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n if (trimmedLine.startsWith(\"[\") && trimmedLine.endsWith(\"]\")) {\n const categoryName = trimmedLine\n .substring(1, trimmedLine.length - 1)\n .trim();\n\n if (categoryNames.has(categoryName)) {\n throw new Error(`Duplicate category found: ${categoryName}`);\n }\n categoryNames.add(categoryName);\n\n currentCategory = { name: categoryName, ingredients: [] };\n this.categories.push(currentCategory);\n } else {\n if (currentCategory === null) {\n throw new Error(\n `Ingredient found without a category: ${trimmedLine}`,\n );\n }\n\n const aliases = trimmedLine.split(\"|\").map((s) => s.trim());\n for (const alias of aliases) {\n if (ingredientNames.has(alias)) {\n throw new Error(`Duplicate ingredient/alias found: ${alias}`);\n }\n ingredientNames.add(alias);\n }\n\n const ingredient: CategoryIngredient = {\n name: aliases[0]!, // We know this exists because trimmedLine is not empty\n aliases: aliases,\n };\n currentCategory.ingredients.push(ingredient);\n }\n }\n }\n}\n","import TOML from \"smol-toml\";\nimport type {\n FixedNumericValue,\n ProductOption,\n ProductOptionToml,\n ProductSize,\n} from \"../types\";\nimport type { TomlTable } from \"smol-toml\";\nimport {\n isPositiveIntegerString,\n parseQuantityInput,\n stringifyQuantityValue,\n} from \"../utils/parser_helpers\";\nimport { InvalidProductCatalogFormat } from \"../errors\";\n\n/**\n * Product Catalog Manager: used in conjunction with {@link ShoppingCart}\n *\n * ## Usage\n *\n * You can either directly populate the products by feeding the {@link ProductCatalog.products | products} property. Alternatively,\n * you can provide a catalog in TOML format to either the constructor itself or to the {@link ProductCatalog.parse | parse()} method.\n *\n * @category Classes\n *\n * @example\n * ```typescript\n * import { ProductCatalog } from \"@tmlmt/cooklang-parser\";\n *\n * const catalog = `\n * [eggs]\n * aliases = [\"oeuf\", \"huevo\"]\n * 01123 = { name = \"Single Egg\", size = \"1\", price = 2 }\n * 11244 = { name = \"Pack of 6 eggs\", size = \"6\", price = 10 }\n *\n * [flour]\n * aliases = [\"farine\", \"Mehl\"]\n * 01124 = { name = \"Small pack\", size = \"100%g\", price = 1.5 }\n * 14141 = { name = \"Big pack\", size = \"6%kg\", price = 10 }\n * `\n * const catalog = new ProductCatalog(catalog);\n * const eggs = catalog.find(\"oeuf\");\n * ```\n */\nexport class ProductCatalog {\n public products: ProductOption[] = [];\n\n constructor(tomlContent?: string) {\n if (tomlContent) this.parse(tomlContent);\n }\n\n /**\n * Parses a TOML string into a list of product options.\n * @param tomlContent - The TOML string to parse.\n * @returns A parsed list of `ProductOption`.\n */\n public parse(tomlContent: string): ProductOption[] {\n const catalogRaw = TOML.parse(tomlContent);\n\n // Reset internal state\n this.products = [];\n\n if (!this.isValidTomlContent(catalogRaw)) {\n throw new InvalidProductCatalogFormat();\n }\n\n for (const [ingredientName, ingredientData] of Object.entries(catalogRaw)) {\n const ingredientTable = ingredientData as TomlTable;\n const aliases = ingredientTable.aliases as string[] | undefined;\n\n for (const [key, productData] of Object.entries(ingredientTable)) {\n if (key === \"aliases\") {\n continue;\n }\n\n const productId = key;\n const { name, size, price, ...rest } =\n productData as unknown as ProductOptionToml;\n\n // Handle size as string or string[]\n const sizeStrings = Array.isArray(size) ? size : [size];\n const sizes: ProductSize[] = sizeStrings.map((sizeStr) => {\n const sizeAndUnitRaw = sizeStr.split(\"%\");\n const sizeParsed = parseQuantityInput(\n sizeAndUnitRaw[0]!,\n ) as FixedNumericValue;\n const productSize: ProductSize = { size: sizeParsed };\n if (sizeAndUnitRaw.length > 1) {\n productSize.unit = sizeAndUnitRaw[1]!;\n }\n return productSize;\n });\n\n const productOption: ProductOption = {\n id: productId,\n productName: name,\n ingredientName: ingredientName,\n price: price,\n sizes,\n ...rest,\n };\n if (aliases) {\n productOption.ingredientAliases = aliases;\n }\n\n this.products.push(productOption);\n }\n }\n\n return this.products;\n }\n\n /**\n * Stringifies the catalog to a TOML string.\n * @returns The TOML string representation of the catalog.\n */\n public stringify(): string {\n const grouped: Record<string, TomlTable> = {};\n\n for (const product of this.products) {\n const {\n id,\n ingredientName,\n ingredientAliases,\n sizes,\n productName,\n ...rest\n } = product;\n if (!grouped[ingredientName]) {\n grouped[ingredientName] = {};\n }\n if (ingredientAliases && !grouped[ingredientName].aliases) {\n grouped[ingredientName].aliases = ingredientAliases;\n }\n\n // Stringify each size as \"value%unit\" or just \"value\"\n const sizeStrings = sizes.map((s) =>\n s.unit\n ? `${stringifyQuantityValue(s.size)}%${s.unit}`\n : stringifyQuantityValue(s.size),\n );\n\n grouped[ingredientName][id] = {\n ...rest,\n name: productName,\n // Use array if multiple sizes, otherwise single string\n size: sizeStrings.length === 1 ? sizeStrings[0]! : sizeStrings,\n };\n }\n\n return TOML.stringify(grouped);\n }\n\n /**\n * Adds a product to the catalog.\n * @param productOption - The product to add.\n */\n public add(productOption: ProductOption): void {\n this.products.push(productOption);\n }\n\n /**\n * Removes a product from the catalog by its ID.\n * @param productId - The ID of the product to remove.\n */\n public remove(productId: string): void {\n this.products = this.products.filter((product) => product.id !== productId);\n }\n\n private isValidTomlContent(catalog: TomlTable): boolean {\n for (const productsRaw of Object.values(catalog)) {\n if (typeof productsRaw !== \"object\" || productsRaw === null) {\n return false;\n }\n\n for (const [id, obj] of Object.entries(productsRaw)) {\n if (id === \"aliases\") {\n if (!Array.isArray(obj)) {\n return false;\n }\n } else {\n if (!isPositiveIntegerString(id)) {\n return false;\n }\n if (typeof obj !== \"object\" || obj === null) {\n return false;\n }\n\n const record = obj as Record<string, unknown>;\n const keys = Object.keys(record);\n\n const mandatoryKeys = [\"name\", \"size\", \"price\"];\n\n if (mandatoryKeys.some((key) => !keys.includes(key))) {\n return false;\n }\n\n const hasProductName = typeof record.name === \"string\";\n // Size can be a string or an array of strings\n const hasSize =\n typeof record.size === \"string\" ||\n (Array.isArray(record.size) &&\n record.size.every((s) => typeof s === \"string\"));\n const hasPrice = typeof record.price === \"number\";\n\n if (!(hasProductName && hasSize && hasPrice)) {\n return false;\n }\n }\n }\n }\n\n return true;\n }\n}\n","type PartialBut<T, K extends keyof T> = Partial<T> & Pick<T, K>;\n\nconst escapeCache = new Map<string, string>();\n\nconst Flags = {\n GLOBAL: \"g\",\n NON_SENSITIVE: \"i\",\n MULTILINE: \"m\",\n DOT_ALL: \"s\",\n UNICODE: \"u\",\n STICKY: \"y\",\n} as const;\n\nconst Ranges = Object.freeze({\n digit: \"0-9\",\n lowercaseLetter: \"a-z\",\n uppercaseLetter: \"A-Z\",\n letter: \"a-zA-Z\",\n alphanumeric: \"a-zA-Z0-9\",\n anyCharacter: \".\",\n});\n\ntype RangeKeys = keyof typeof Ranges;\n\nconst Quantifiers = Object.freeze({\n zeroOrMore: \"*\",\n oneOrMore: \"+\",\n optional: \"?\",\n});\n\ntype Quantifiers =\n | \"exactly\"\n | \"atLeast\"\n | \"atMost\"\n | \"between\"\n | \"oneOrMore\"\n | \"zeroOrMore\"\n | \"repeat\";\ntype QuantifierMethods = Quantifiers | \"optional\" | \"lazy\";\n\ntype WithLazy = HumanRegex;\ntype Base = Omit<HumanRegex, \"lazy\">;\ntype AtStart = Omit<Base, QuantifierMethods | \"endGroup\">;\ntype AfterAnchor = Omit<Base, QuantifierMethods | \"or\">;\ntype SimpleQuantifier = Omit<Base, Quantifiers>;\ntype LazyQuantifier = Omit<WithLazy, Quantifiers>;\n\nclass HumanRegex {\n private parts: string[];\n private flags: Set<string>;\n\n constructor() {\n this.parts = [];\n this.flags = new Set<string>();\n }\n\n digit(): Base {\n return this.add(\"\\\\d\");\n }\n\n special(): Base {\n return this.add(\"(?=.*[!@#$%^&*])\");\n }\n\n word(): Base {\n return this.add(\"\\\\w\");\n }\n\n whitespace(): Base {\n return this.add(\"\\\\s\");\n }\n\n nonWhitespace(): Base {\n return this.add(\"\\\\S\");\n }\n\n literal(text: string): this {\n return this.add(escapeLiteral(text));\n }\n\n or(): AfterAnchor {\n return this.add(\"|\");\n }\n\n range(name: RangeKeys): Base {\n const range = Ranges[name];\n if (!range) throw new Error(`Unknown range: ${name}`);\n return this.add(`[${range}]`);\n }\n\n notRange(name: RangeKeys): Base {\n const range = Ranges[name];\n if (!range) throw new Error(`Unknown range: ${name}`);\n return this.add(`[^${range}]`);\n }\n\n anyOf(chars: string): Base {\n return this.add(`[${chars}]`);\n }\n\n notAnyOf(chars: string): Base {\n return this.add(`[^${chars}]`);\n }\n\n lazy(): Base {\n const lastPart = this.parts.pop();\n if (!lastPart) throw new Error(\"No quantifier to make lazy\");\n return this.add(`${lastPart}?`);\n }\n\n letter(): Base {\n return this.add(\"[a-zA-Z]\");\n }\n\n anyCharacter(): Base {\n return this.add(\".\");\n }\n\n newline(): Base {\n return this.add(\"(\\\\r\\\\n|\\\\r|\\\\n)\"); // Windows: \\r\\n, Unix: \\n, Old Macs: \\r\n }\n\n negativeLookahead(pattern: string): Base {\n return this.add(`(?!${pattern})`);\n }\n\n positiveLookahead(pattern: string): Base {\n return this.add(`(?=${pattern})`);\n }\n\n positiveLookbehind(pattern: string): Base {\n return this.add(`(?<=${pattern})`);\n }\n\n negativeLookbehind(pattern: string): Base {\n return this.add(`(?<!${pattern})`);\n }\n\n hasSpecialCharacter(): Base {\n return this.add(\"(?=.*[!@#$%^&*])\");\n }\n\n hasDigit(): Base {\n return this.add(\"(?=.*\\\\d)\");\n }\n\n hasLetter(): Base {\n return this.add(\"(?=.*[a-zA-Z])\");\n }\n\n optional(): SimpleQuantifier {\n return this.add(Quantifiers.optional);\n }\n\n exactly(n: number): SimpleQuantifier {\n return this.add(`{${n}}`);\n }\n\n atLeast(n: number): LazyQuantifier {\n return this.add(`{${n},}`);\n }\n\n atMost(n: number): LazyQuantifier {\n return this.add(`{0,${n}}`);\n }\n\n between(min: number, max: number): LazyQuantifier {\n return this.add(`{${min},${max}}`);\n }\n\n oneOrMore(): LazyQuantifier {\n return this.add(Quantifiers.oneOrMore);\n }\n\n zeroOrMore(): LazyQuantifier {\n return this.add(Quantifiers.zeroOrMore);\n }\n\n startNamedGroup(name: string): AfterAnchor {\n return this.add(`(?<${name}>`);\n }\n\n startGroup(): AfterAnchor {\n return this.add(\"(?:\");\n }\n\n startCaptureGroup(): AfterAnchor {\n return this.add(\"(\");\n }\n\n wordBoundary(): Base {\n return this.add(\"\\\\b\");\n }\n\n nonWordBoundary(): Base {\n return this.add(\"\\\\B\");\n }\n\n endGroup(): Base {\n return this.add(\")\");\n }\n\n startAnchor(): AfterAnchor {\n return this.add(\"^\");\n }\n\n endAnchor(): AfterAnchor {\n return this.add(\"$\");\n }\n\n global(): this {\n this.flags.add(Flags.GLOBAL);\n return this;\n }\n\n nonSensitive(): this {\n this.flags.add(Flags.NON_SENSITIVE);\n return this;\n }\n\n multiline(): this {\n this.flags.add(Flags.MULTILINE);\n return this;\n }\n\n dotAll(): this {\n this.flags.add(Flags.DOT_ALL);\n return this;\n }\n\n sticky(): this {\n this.flags.add(Flags.STICKY);\n return this;\n }\n\n unicodeChar(variant?: \"u\" | \"l\" | \"t\" | \"m\" | \"o\"): Base {\n this.flags.add(Flags.UNICODE);\n const validVariants = new Set([\"u\", \"l\", \"t\", \"m\", \"o\"] as const);\n\n if (variant !== undefined && !validVariants.has(variant)) {\n throw new Error(`Invalid Unicode letter variant: ${variant}`);\n }\n\n return this.add(`\\\\p{L${variant ?? \"\"}}`);\n }\n\n unicodeDigit(): Base {\n this.flags.add(Flags.UNICODE);\n return this.add(\"\\\\p{N}\");\n }\n\n unicodePunctuation(): Base {\n this.flags.add(Flags.UNICODE);\n return this.add(\"\\\\p{P}\");\n }\n\n unicodeSymbol(): Base {\n this.flags.add(Flags.UNICODE);\n return this.add(\"\\\\p{S}\");\n }\n\n repeat(count: number): Base {\n if (this.parts.length === 0) {\n throw new Error(\"No pattern to repeat\");\n }\n\n const lastPart = this.parts.pop();\n this.parts.push(`(${lastPart}){${count}}`);\n return this;\n }\n\n ipv4Octet(): Base {\n return this.add(\"(25[0-5]|2[0-4]\\\\d|1\\\\d\\\\d|[1-9]\\\\d|\\\\d)\");\n }\n\n protocol(): Base {\n return this.add(\"https?://\");\n }\n\n www(): Base {\n return this.add(\"(www\\\\.)?\");\n }\n\n tld(): Base {\n return this.add(\"(com|org|net)\");\n }\n\n path(): Base {\n return this.add(\"(/\\\\w+)*\");\n }\n\n private add(part: string): this {\n this.parts.push(part);\n return this;\n }\n\n toString(): string {\n return this.parts.join(\"\");\n }\n\n toRegExp(): RegExp {\n return new RegExp(this.toString(), [...this.flags].join(\"\"));\n }\n}\n\nfunction escapeLiteral(text: string): string {\n if (!escapeCache.has(text)) {\n escapeCache.set(text, text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"));\n }\n return escapeCache.get(text)!;\n}\n\nconst createRegex = (): AtStart => new HumanRegex();\n\nconst Patterns = (() => {\n const createCachedPattern = (\n builder: () => PartialBut<HumanRegex, \"toRegExp\">\n ) => {\n const regex = builder().toRegExp();\n return () => new RegExp(regex.source, regex.flags);\n };\n\n return {\n email: createCachedPattern(() =>\n createRegex()\n .startAnchor()\n .word()\n .oneOrMore()\n .literal(\"@\")\n .word()\n .oneOrMore()\n .startGroup()\n .literal(\".\")\n .word()\n .oneOrMore()\n .endGroup()\n .zeroOrMore()\n .literal(\".\")\n .letter()\n .atLeast(2)\n .endAnchor()\n ),\n url: createCachedPattern(() =>\n createRegex()\n .startAnchor()\n .protocol()\n .www()\n .word()\n .oneOrMore()\n .literal(\".\")\n .tld()\n .path()\n .endAnchor()\n ),\n phoneInternational: createCachedPattern(() =>\n createRegex()\n .startAnchor()\n .literal(\"+\")\n .digit()\n .between(1, 3)\n .literal(\"-\")\n .digit()\n .between(3, 14)\n .endAnchor()\n ),\n };\n})();\n\nexport { createRegex, Patterns, Flags, Ranges, Quantifiers };\n","import { createRegex } from \"human-regex\";\n\nexport const metadataRegex = createRegex()\n .literal(\"---\").newline()\n .startCaptureGroup().anyCharacter().zeroOrMore().optional().endGroup()\n .newline().literal(\"---\")\n .dotAll().toRegExp();\n\nexport const scalingMetaValueRegex = (varName: string): RegExp => createRegex()\n .startAnchor()\n .literal(varName)\n .literal(\":\")\n .anyOf(\"\\\\t \").zeroOrMore()\n .startCaptureGroup()\n .startCaptureGroup()\n .notAnyOf(\",\\\\n\").oneOrMore()\n .endGroup()\n .startGroup()\n .literal(\",\")\n .whitespace().zeroOrMore()\n .startCaptureGroup()\n .anyCharacter().oneOrMore()\n .endGroup()\n .endGroup().optional()\n .endGroup()\n .endAnchor()\n .multiline()\n .toRegExp()\n\nconst nonWordChar = \"\\\\s@#~\\\\[\\\\]{(,;:!?\"\nconst nonWordCharStrict = \"\\\\s@#~\\\\[\\\\]{(,;:!?|\"\n\nexport const ingredientWithAlternativeRegex = createRegex()\n .literal(\"@\")\n .startNamedGroup(\"ingredientModifiers\")\n .anyOf(\"@\\\\-&?\").zeroOrMore()\n .endGroup().optional()\n .startNamedGroup(\"ingredientRecipeAnchor\")\n .literal(\"./\")\n .endGroup().optional()\n .startGroup()\n .startGroup()\n .startNamedGroup(\"mIngredientName\")\n .notAnyOf(nonWordChar).oneOrMore()\n .startGroup()\n .whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore()\n .endGroup().oneOrMore()\n .endGroup()\n .positiveLookahead(\"\\\\s*(?:\\\\{[^\\\\}]*\\\\}|\\\\([^)]*\\\\))\")\n .endGroup()\n .or()\n .startNamedGroup(\"sIngredientName\")\n .notAnyOf(nonWordChar).zeroOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup()\n .endGroup()\n .startGroup()\n .literal(\"{\")\n .startNamedGroup(\"ingredientQuantityModifier\")\n .literal(\"=\").exactly(1)\n .endGroup().optional()\n .startNamedGroup(\"ingredientQuantity\")\n .startGroup()\n .notAnyOf(\"}|%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .notAnyOf(\"|}\").oneOrMore().lazy()\n .endGroup().optional()\n .startGroup()\n .literal(\"|\")\n .notAnyOf(\"}\").oneOrMore().lazy()\n .endGroup().zeroOrMore()\n .endGroup()\n .literal(\"}\")\n .endGroup().optional()\n .startGroup()\n .literal(\"(\")\n .startNamedGroup(\"ingredientPreparation\")\n .notAnyOf(\")\").oneOrMore().lazy()\n .endGroup()\n .literal(\")\")\n .endGroup().optional()\n .startGroup()\n .literal(\"[\")\n .startNamedGroup(\"ingredientNote\")\n .notAnyOf(\"\\\\]\").oneOrMore().lazy()\n .endGroup()\n .literal(\"]\")\n .endGroup().optional()\n .startNamedGroup(\"ingredientAlternative\")\n .startGroup()\n .literal(\"|\")\n .startGroup()\n .anyOf(\"@\\\\-&?\").zeroOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"./\")\n .endGroup().optional()\n .startGroup()\n .startGroup()\n .startGroup()\n .notAnyOf(nonWordChar).oneOrMore()\n .startGroup()\n .whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore()\n .endGroup().oneOrMore()\n .endGroup()\n .positiveLookahead(\"\\\\s*(?:\\\\{[^\\\\}]*\\\\}|\\\\([^)]*\\\\))\")\n .endGroup()\n .or()\n .startGroup()\n .notAnyOf(nonWordChar).oneOrMore()\n .endGroup()\n .endGroup()\n .startGroup()\n .literal(\"{\")\n .startGroup()\n .literal(\"=\").exactly(1)\n .endGroup().optional()\n .startGroup()\n .notAnyOf(\"}%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .startGroup()\n .notAnyOf(\"}\").oneOrMore().lazy()\n .endGroup()\n .endGroup().optional()\n .literal(\"}\")\n .endGroup().optional()\n .startGroup()\n .literal(\"(\")\n .startGroup()\n .notAnyOf(\")\").oneOrMore().lazy()\n .endGroup()\n .literal(\")\")\n .endGroup().optional()\n .startGroup()\n .literal(\"[\")\n .startGroup()\n .notAnyOf(\"\\\\]\").oneOrMore().lazy()\n .endGroup()\n .literal(\"]\")\n .endGroup().optional()\n .endGroup().zeroOrMore()\n .endGroup()\n .toRegExp();\n\nexport const inlineIngredientAlternativesRegex = new RegExp(\"\\\\|\" + ingredientWithAlternativeRegex.source.slice(1))\n\nexport const quantityAlternativeRegex = createRegex()\n .startNamedGroup(\"quantity\")\n .notAnyOf(\"}|%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .startNamedGroup(\"unit\")\n .notAnyOf(\"|}\").oneOrMore()\n .endGroup()\n .endGroup().optional()\n .startGroup()\n .literal(\"|\")\n .startNamedGroup(\"alternative\")\n .startGroup()\n .notAnyOf(\"}\").oneOrMore()\n .endGroup().zeroOrMore()\n .endGroup()\n .endGroup().optional()\n .toRegExp()\n \nexport const ingredientWithGroupKeyRegex = createRegex()\n .literal(\"@|\")\n .startNamedGroup(\"gIngredientGroupKey\")\n .notAnyOf(nonWordCharStrict).oneOrMore()\n .endGroup()\n .literal(\"|\")\n .startNamedGroup(\"gIngredientModifiers\")\n .anyOf(\"@\\\\-&?\").zeroOrMore()\n .endGroup().optional()\n .startNamedGroup(\"gIngredientRecipeAnchor\")\n .literal(\"./\")\n .endGroup().optional()\n .startGroup()\n .startGroup()\n .startNamedGroup(\"gmIngredientName\")\n .notAnyOf(nonWordChar).oneOrMore()\n .startGroup()\n .whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore()\n .endGroup().oneOrMore()\n .endGroup()\n .positiveLookahead(\"\\\\s*(?:\\\\{[^\\\\}]*\\\\}|\\\\([^)]*\\\\))\")\n .endGroup()\n .or()\n .startNamedGroup(\"gsIngredientName\")\n .notAnyOf(nonWordChar).zeroOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup()\n .endGroup()\n .startGroup()\n .literal(\"{\")\n .startNamedGroup(\"gIngredientQuantityModifier\")\n .literal(\"=\").exactly(1)\n .endGroup().optional()\n .startNamedGroup(\"gIngredientQuantity\")\n .startGroup()\n .notAnyOf(\"}|%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .notAnyOf(\"|}\").oneOrMore().lazy()\n .endGroup().optional()\n .startGroup()\n .literal(\"|\")\n .notAnyOf(\"}\").oneOrMore().lazy()\n .endGroup().zeroOrMore()\n .endGroup()\n .literal(\"}\")\n .endGroup().optional()\n .startGroup()\n .literal(\"(\")\n .startNamedGroup(\"gIngredientPreparation\")\n .notAnyOf(\")\").oneOrMore().lazy()\n .endGroup()\n .literal(\")\")\n .endGroup().optional()\n .toRegExp()\n\nexport const ingredientAliasRegex = createRegex()\n .startAnchor()\n .startNamedGroup(\"ingredientListName\")\n .notAnyOf(\"|\").oneOrMore()\n .endGroup()\n .literal(\"|\")\n .startNamedGroup(\"ingredientDisplayName\")\n .notAnyOf(\"|\").oneOrMore()\n .endGroup()\n .endAnchor()\n .toRegExp();\n\nexport const cookwareRegex = createRegex()\n .literal(\"#\")\n .startNamedGroup(\"cookwareModifiers\")\n .anyOf(\"\\\\-&?\").zeroOrMore()\n .endGroup()\n .startGroup()\n .startGroup()\n .startNamedGroup(\"mCookwareName\")\n .notAnyOf(nonWordChar).oneOrMore()\n .startGroup()\n .whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore()\n .endGroup().oneOrMore()\n .endGroup().positiveLookahead(\"\\\\s*(?:\\\\{[^\\\\}]*\\\\})\")\n .endGroup()\n .or()\n .startNamedGroup(\"sCookwareName\")\n .notAnyOf(nonWordChar).zeroOrMore()\n .notAnyOf(\"\\\\.\"+nonWordChar)\n .endGroup()\n .endGroup()\n .startGroup()\n .literal(\"{\")\n .startNamedGroup(\"cookwareQuantity\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .literal(\"}\")\n .endGroup().optional()\n .toRegExp();\n\nconst timerRegex = createRegex()\n .literal(\"~\")\n .startNamedGroup(\"timerName\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .literal(\"{\")\n .startNamedGroup(\"timerQuantity\")\n .anyCharacter().oneOrMore().lazy()\n .endGroup()\n .startGroup()\n .literal(\"%\")\n .startNamedGroup(\"timerUnit\")\n .anyCharacter().oneOrMore().lazy()\n .endGroup()\n .endGroup().optional()\n .literal(\"}\")\n .toRegExp()\n\nexport const arbitraryScalableRegex = createRegex()\n .literal(\"{{\")\n .startGroup()\n .startNamedGroup(\"arbitraryName\")\n .notAnyOf(\"}:%\").oneOrMore()\n .endGroup()\n .literal(\":\")\n .endGroup().optional()\n .startNamedGroup(\"arbitraryQuantity\")\n .startGroup()\n .notAnyOf(\"}|%\").oneOrMore()\n .endGroup().optional()\n .startGroup()\n .literal(\"%\")\n .notAnyOf(\"|}\").oneOrMore().lazy()\n .endGroup().optional()\n .startGroup()\n .literal(\"|\")\n .notAnyOf(\"}\").oneOrMore().lazy()\n .endGroup().zeroOrMore()\n .endGroup()\n .literal(\"}}\")\n .toRegExp();\n\nexport const tokensRegex = new RegExp(\n [\n ingredientWithGroupKeyRegex,\n ingredientWithAlternativeRegex,\n cookwareRegex,\n timerRegex,\n arbitraryScalableRegex\n ]\n .map((r) => r.source)\n .join(\"|\"),\n \"gu\",\n);\n\nexport const commentRegex = createRegex()\n .literal(\"--\")\n .anyCharacter().zeroOrMore()\n .global()\n .toRegExp();\n\nexport const blockCommentRegex = createRegex()\n .literal(\"[-\")\n .anyCharacter().zeroOrMore().lazy()\n .literal(\"-]\")\n .whitespace().zeroOrMore()\n .global()\n .toRegExp();\n\nexport const shoppingListRegex = createRegex()\n .literal(\"[\")\n .startNamedGroup(\"name\")\n .anyCharacter().oneOrMore()\n .endGroup()\n .literal(\"]\")\n .newline()\n .startNamedGroup(\"items\")\n .anyCharacter().zeroOrMore().lazy()\n .endGroup()\n .startGroup()\n .newline().newline()\n .or()\n .endAnchor()\n .endGroup()\n .global()\n .toRegExp()\n\nexport const rangeRegex = createRegex()\n .startAnchor()\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".,/\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .literal(\"-\")\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".,/\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .endAnchor()\n .toRegExp()\n\nexport const numberLikeRegex = createRegex()\n .startAnchor()\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".,/\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .endAnchor()\n .toRegExp()\n\nexport const floatRegex = createRegex()\n .startAnchor()\n .digit().oneOrMore()\n .startGroup()\n .anyOf(\".\").exactly(1)\n .digit().oneOrMore()\n .endGroup().optional()\n .endAnchor()\n .toRegExp()","import type { UnitDefinition, UnitDefinitionLike } from \"../types\";\n\n// Base units: mass -> gram (g), volume -> milliliter (ml)\nexport const units: UnitDefinition[] = [\n // Mass (Metric)\n {\n name: \"g\",\n type: \"mass\",\n system: \"metric\",\n aliases: [\"gram\", \"grams\", \"grammes\"],\n toBase: 1,\n },\n {\n name: \"kg\",\n type: \"mass\",\n system: \"metric\",\n aliases: [\"kilogram\", \"kilograms\", \"kilogrammes\", \"kilos\", \"kilo\"],\n toBase: 1000,\n },\n // Mass (Imperial)\n {\n name: \"oz\",\n type: \"mass\",\n system: \"imperial\",\n aliases: [\"ounce\", \"ounces\"],\n toBase: 28.3495,\n },\n {\n name: \"lb\",\n type: \"mass\",\n system: \"imperial\",\n aliases: [\"pound\", \"pounds\"],\n toBase: 453.592,\n },\n\n // Volume (Metric)\n {\n name: \"ml\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"milliliter\", \"milliliters\", \"millilitre\", \"millilitres\", \"cc\"],\n toBase: 1,\n },\n {\n name: \"cl\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"centiliter\", \"centiliters\", \"centilitre\", \"centilitres\"],\n toBase: 10,\n },\n {\n name: \"dl\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"deciliter\", \"deciliters\", \"decilitre\", \"decilitres\"],\n toBase: 100,\n },\n {\n name: \"l\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"liter\", \"liters\", \"litre\", \"litres\"],\n toBase: 1000,\n },\n {\n name: \"tsp\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"teaspoon\", \"teaspoons\"],\n toBase: 5,\n },\n {\n name: \"tbsp\",\n type: \"volume\",\n system: \"metric\",\n aliases: [\"tablespoon\", \"tablespoons\"],\n toBase: 15,\n },\n\n // Volume (Imperial)\n {\n name: \"fl-oz\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"fluid ounce\", \"fluid ounces\"],\n toBase: 29.5735,\n },\n {\n name: \"cup\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"cups\"],\n toBase: 236.588,\n },\n {\n name: \"pint\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"pints\"],\n toBase: 473.176,\n },\n {\n name: \"quart\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"quarts\"],\n toBase: 946.353,\n },\n {\n name: \"gallon\",\n type: \"volume\",\n system: \"imperial\",\n aliases: [\"gallons\"],\n toBase: 3785.41,\n },\n\n // Count units (no conversion, but recognized as a type)\n {\n name: \"piece\",\n type: \"count\",\n system: \"metric\",\n aliases: [\"pieces\", \"pc\"],\n toBase: 1,\n },\n];\n\nconst unitMap = new Map<string, UnitDefinition>();\nfor (const unit of units) {\n unitMap.set(unit.name.toLowerCase(), unit);\n for (const alias of unit.aliases) {\n unitMap.set(alias.toLowerCase(), unit);\n }\n}\n\nexport function normalizeUnit(unit: string = \"\"): UnitDefinition | undefined {\n return unitMap.get(unit.toLowerCase().trim());\n}\n\nexport const NO_UNIT = \"__no-unit__\";\n\nexport function resolveUnit(\n name: string = NO_UNIT,\n integerProtected: boolean = false,\n): UnitDefinitionLike {\n const normalizedUnit = normalizeUnit(name);\n const resolvedUnit: UnitDefinitionLike = normalizedUnit\n ? { ...normalizedUnit, name }\n : { name, type: \"other\", system: \"none\" };\n return integerProtected\n ? { ...resolvedUnit, integerProtected: true }\n : resolvedUnit;\n}\n\nexport function isNoUnit(unit?: UnitDefinitionLike): boolean {\n if (!unit) return true;\n return resolveUnit(unit.name).name === NO_UNIT;\n}\n","import Big from \"big.js\";\nimport type { DecimalValue, FractionValue, FixedValue, Range } from \"../types\";\n\nfunction gcd(a: number, b: number): number {\n return b === 0 ? a : gcd(b, a % b);\n}\n\nexport function simplifyFraction(\n num: number,\n den: number,\n): DecimalValue | FractionValue {\n if (den === 0) {\n throw new Error(\"Denominator cannot be zero.\");\n }\n\n const commonDivisor = gcd(Math.abs(num), Math.abs(den));\n let simplifiedNum = num / commonDivisor;\n let simplifiedDen = den / commonDivisor;\n if (simplifiedDen < 0) {\n simplifiedNum = -simplifiedNum;\n simplifiedDen = -simplifiedDen;\n }\n\n if (simplifiedDen === 1) {\n return { type: \"decimal\", decimal: simplifiedNum };\n } else {\n return { type: \"fraction\", num: simplifiedNum, den: simplifiedDen };\n }\n}\n\nexport function getNumericValue(v: DecimalValue | FractionValue): number {\n if (v.type === \"decimal\") {\n return v.decimal;\n }\n return v.num / v.den;\n}\n\nexport function multiplyNumericValue(\n v: DecimalValue | FractionValue,\n factor: number | Big,\n): DecimalValue | FractionValue {\n if (v.type === \"decimal\") {\n return {\n type: \"decimal\",\n decimal: Big(v.decimal).times(factor).toNumber(),\n };\n }\n return simplifyFraction(Big(v.num).times(factor).toNumber(), v.den);\n}\n\nexport function addNumericValues(\n val1: DecimalValue | FractionValue,\n val2: DecimalValue | FractionValue,\n): DecimalValue | FractionValue {\n let num1: number;\n let den1: number;\n let num2: number;\n let den2: number;\n\n if (val1.type === \"decimal\") {\n num1 = val1.decimal;\n den1 = 1;\n } else {\n num1 = val1.num;\n den1 = val1.den;\n }\n\n if (val2.type === \"decimal\") {\n num2 = val2.decimal;\n den2 = 1;\n } else {\n num2 = val2.num;\n den2 = val2.den;\n }\n\n // Return 0 if both values are 0\n if (num1 === 0 && num2 === 0) {\n return { type: \"decimal\", decimal: 0 };\n }\n\n // We only return a fraction where both input values are fractions themselves or only one while the other is 0\n if (\n (val1.type === \"fraction\" && val2.type === \"fraction\") ||\n (val1.type === \"fraction\" &&\n val2.type === \"decimal\" &&\n val2.decimal === 0) ||\n (val2.type === \"fraction\" && val1.type === \"decimal\" && val1.decimal === 0)\n ) {\n const commonDen = den1 * den2;\n const sumNum = num1 * den2 + num2 * den1;\n return simplifyFraction(sumNum, commonDen);\n } else {\n return {\n type: \"decimal\",\n decimal: Big(num1).div(den1).add(Big(num2).div(den2)).toNumber(),\n };\n }\n}\n\nexport const toRoundedDecimal = (\n v: DecimalValue | FractionValue,\n): DecimalValue => {\n const value = v.type === \"decimal\" ? v.decimal : v.num / v.den;\n return { type: \"decimal\", decimal: Math.round(value * 1000) / 1000 };\n};\n\nexport function multiplyQuantityValue(\n value: FixedValue | Range,\n factor: number | Big,\n): FixedValue | Range {\n if (value.type === \"fixed\") {\n const newValue = multiplyNumericValue(\n value.value as DecimalValue | FractionValue,\n Big(factor),\n );\n if (\n newValue.type === \"fraction\" &&\n (Big(factor).toNumber() === parseInt(Big(factor).toString()) || // e.g. 2 === int\n Big(1).div(factor).toNumber() ===\n parseInt(Big(1).div(factor).toString())) // e.g. 0.25 => 4 === int\n ) {\n // Preserve fractions\n return {\n type: \"fixed\",\n value: newValue,\n };\n }\n // We might multiply with big decimal number so rounding into decimal value\n return {\n type: \"fixed\",\n value: toRoundedDecimal(newValue),\n };\n }\n\n return {\n type: \"range\",\n min: multiplyNumericValue(value.min, factor),\n max: multiplyNumericValue(value.max, factor),\n };\n}\n\nexport function getAverageValue(q: FixedValue | Range): string | number {\n if (q.type === \"fixed\") {\n return q.value.type === \"text\" ? q.value.text : getNumericValue(q.value);\n } else {\n return (getNumericValue(q.min) + getNumericValue(q.max)) / 2;\n }\n}\n","import { IngredientFlag, CookwareFlag, NoProductMatchErrorCode } from \"./types\";\n\nexport class ReferencedItemCannotBeRedefinedError extends Error {\n constructor(\n item_type: \"ingredient\" | \"cookware\",\n item_name: string,\n new_modifier: IngredientFlag | CookwareFlag,\n ) {\n super(\n `The referenced ${item_type} \"${item_name}\" cannot be redefined as ${new_modifier}.\nYou can either remove the reference to create a new ${item_type} defined as ${new_modifier} or add the ${new_modifier} flag to the original definition of the ${item_type}`,\n );\n this.name = \"ReferencedItemCannotBeRedefinedError\";\n }\n}\n\n/**\n * Error thrown when trying to build a shopping cart without a product catalog\n * @category Errors\n */\nexport class NoProductCatalogForCartError extends Error {\n constructor() {\n super(\n `Cannot build a cart without a product catalog. Please set one using setProductCatalog()`,\n );\n this.name = \"NoProductCatalogForCartError\";\n }\n}\n\n/**\n * Error thrown when trying to build a shopping cart without a shopping list\n * @category Errors\n */\nexport class NoShoppingListForCartError extends Error {\n constructor() {\n super(\n `Cannot build a cart without a shopping list. Please set one using setShoppingList()`,\n );\n this.name = \"NoShoppingListForCartError\";\n }\n}\n\nexport class NoProductMatchError extends Error {\n code: NoProductMatchErrorCode;\n\n constructor(item_name: string, code: NoProductMatchErrorCode) {\n const messageMap: Record<NoProductMatchErrorCode, string> = {\n incompatibleUnits: `The units of the products in the catalogue are incompatible with ingredient ${item_name} in the shopping list.`,\n noProduct:\n \"No product was found linked to ingredient name ${item_name} in the shopping list\",\n textValue: `Ingredient ${item_name} has a text value as quantity and can therefore not be matched with any product in the catalogue.`,\n noQuantity: `Ingredient ${item_name} has no quantity and can therefore not be matched with any product in the catalogue.`,\n textValue_incompatibleUnits: `Multiple alternative quantities were provided for ingredient ${item_name} in the shopping list but they were either text values or no product in catalog were found to have compatible units`,\n };\n super(messageMap[code]);\n this.code = code;\n this.name = \"NoProductMatchError\";\n }\n}\n\nexport class InvalidProductCatalogFormat extends Error {\n constructor() {\n super(\"Invalid product catalog format.\");\n this.name = \"InvalidProductCatalogFormat\";\n }\n}\n\nexport class CannotAddTextValueError extends Error {\n constructor() {\n super(\"Cannot add a quantity with a text value.\");\n this.name = \"CannotAddTextValueError\";\n }\n}\n\nexport class IncompatibleUnitsError extends Error {\n constructor(unit1: string, unit2: string) {\n super(\n `Cannot add quantities with incompatible or unknown units: ${unit1} and ${unit2}`,\n );\n this.name = \"IncompatibleUnitsError\";\n }\n}\n\nexport class InvalidQuantityFormat extends Error {\n constructor(value: string, extra?: string) {\n super(\n `Invalid quantity format found in: ${value}${extra ? ` (${extra})` : \"\"}`,\n );\n this.name = \"InvalidQuantityFormat\";\n }\n}\n","import type {\n Group,\n OrGroup,\n AndGroup,\n QuantityWithUnitLike,\n DecimalValue,\n FractionValue,\n FixedValue,\n Range,\n IngredientQuantityGroup,\n IngredientQuantityAndGroup,\n AlternativeIngredientRef,\n} from \"../types\";\n\n// Helper type-checks (as before)\nexport function isGroup(x: QuantityWithUnitLike | Group): x is Group {\n return \"and\" in x || \"or\" in x;\n}\nexport function isOrGroup(x: QuantityWithUnitLike | Group): x is OrGroup {\n return isGroup(x) && \"or\" in x;\n}\n/**\n * Type guard to check if an ingredient quantity-like object is an AND group.\n * *\n * @param x - The quantity-like entry to check\n * @returns true if this is an AND group (has `and` property)\n * @category Helpers\n *\n * @example\n * ```typescript\n * for (const entry of ingredient.quantities) {\n * if (isAndGroup(entry)) {\n * // entry.and contains the list of quantities in the AND group\n * }\n * }\n * ```\n */\nexport function isAndGroup(\n x: IngredientQuantityGroup | IngredientQuantityAndGroup,\n): x is IngredientQuantityAndGroup;\nexport function isAndGroup(x: QuantityWithUnitLike | Group): x is AndGroup;\nexport function isAndGroup(\n x:\n | QuantityWithUnitLike\n | Group\n | IngredientQuantityGroup\n | IngredientQuantityAndGroup,\n): boolean {\n return \"and\" in x;\n}\nexport function isQuantity(\n x: QuantityWithUnitLike | Group,\n): x is QuantityWithUnitLike {\n return x && typeof x === \"object\" && \"quantity\" in x;\n}\n\n/**\n * Type guard to check if an ingredient quantity entry is a simple group.\n *\n * Simple groups have a single quantity with optional unit and equivalents.\n *\n * @param entry - The quantity entry to check\n * @returns true if this is a simple group (has `quantity` property)\n * @category Helpers\n *\n * @example\n * ```typescript\n * for (const entry of ingredient.quantities) {\n * if (isSimpleGroup(entry)) {\n * // entry.quantity is available\n * // entry.unit is available\n * }\n * }\n * ```\n */\nexport function isSimpleGroup(\n entry: IngredientQuantityGroup | IngredientQuantityAndGroup,\n): entry is IngredientQuantityGroup {\n return \"quantity\" in entry;\n}\n\nfunction isNumericValueIntegerLike(v: DecimalValue | FractionValue): boolean {\n if (v.type === \"decimal\") return Number.isInteger(v.decimal);\n // fraction: integer-like when numerator divisible by denominator\n return v.num % v.den === 0;\n}\n\nexport function isValueIntegerLike(q: FixedValue | Range): boolean {\n if (q.type === \"fixed\") {\n if (q.value.type === \"text\") return false;\n return isNumericValueIntegerLike(q.value);\n }\n // Range: integer-like when both min and max are integer-like\n return isNumericValueIntegerLike(q.min) && isNumericValueIntegerLike(q.max);\n}\n\n/**\n * Type guard to check if an ingredient quantity entry has alternatives.\n *\n * @param entry - The quantity entry to check\n * @returns true if this entry has alternatives\n * @category Helpers\n *\n * @example\n * ```typescript\n * for (const entry of ingredient.quantities) {\n * if (hasAlternatives(entry)) {\n * // entry.alternatives is available and non-empty\n * for (const alt of entry.alternatives) {\n * console.log(`Alternative ingredient index: ${alt.index}`);\n * }\n * }\n * }\n * ```\n */\nexport function hasAlternatives(\n entry: IngredientQuantityGroup | IngredientQuantityAndGroup,\n): entry is (IngredientQuantityGroup | IngredientQuantityAndGroup) & {\n alternatives: AlternativeIngredientRef[];\n} {\n return (\n \"alternatives\" in entry &&\n Array.isArray(entry.alternatives) &&\n entry.alternatives.length > 0\n );\n}\n","import type {\n FixedValue,\n Range,\n DecimalValue,\n FractionValue,\n Unit,\n UnitDefinition,\n QuantityWithPlainUnit,\n QuantityWithExtendedUnit,\n QuantityWithUnitDef,\n MaybeNestedGroup,\n MaybeNestedAndGroup,\n} from \"../types\";\nimport {\n units,\n normalizeUnit,\n resolveUnit,\n isNoUnit,\n} from \"../units/definitions\";\nimport { addNumericValues, multiplyQuantityValue } from \"./numeric\";\nimport { CannotAddTextValueError, IncompatibleUnitsError } from \"../errors\";\nimport { isAndGroup, isOrGroup, isQuantity } from \"../utils/type_guards\";\n\n// `deNormalizeQuantity` is provided by `./math` and re-exported below.\n\nexport function extendAllUnits(\n q: QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit>,\n): QuantityWithExtendedUnit | MaybeNestedGroup<QuantityWithExtendedUnit> {\n if (isAndGroup(q)) {\n return { and: q.and.map(extendAllUnits) };\n } else if (isOrGroup(q)) {\n return { or: q.or.map(extendAllUnits) };\n } else {\n const newQ: QuantityWithExtendedUnit = {\n quantity: q.quantity,\n };\n if (q.unit) {\n newQ.unit = { name: q.unit };\n }\n return newQ;\n }\n}\n\nexport function normalizeAllUnits(\n q: QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit>,\n): QuantityWithUnitDef | MaybeNestedGroup<QuantityWithUnitDef> {\n if (isAndGroup(q)) {\n return { and: q.and.map(normalizeAllUnits) };\n } else if (isOrGroup(q)) {\n return { or: q.or.map(normalizeAllUnits) };\n } else {\n const newQ: QuantityWithUnitDef = {\n quantity: q.quantity,\n unit: resolveUnit(q.unit),\n };\n // If the quantity has equivalents, convert them to an OR group\n if (q.equivalents && q.equivalents.length > 0) {\n const equivalentsNormalized = q.equivalents.map((eq) =>\n normalizeAllUnits(eq),\n );\n return {\n or: [newQ, ...equivalentsNormalized] as QuantityWithUnitDef[],\n };\n }\n return newQ;\n }\n}\n\nexport const convertQuantityValue = (\n value: FixedValue | Range,\n def: UnitDefinition,\n targetDef: UnitDefinition,\n): FixedValue | Range => {\n if (def.name === targetDef.name) return value;\n\n const factor = def.toBase / targetDef.toBase;\n\n return multiplyQuantityValue(value, factor);\n};\n\n/**\n * Get the default / neutral quantity which can be provided to addQuantity\n * for it to return the other value as result\n *\n * @return zero\n */\nexport function getDefaultQuantityValue(): FixedValue {\n return { type: \"fixed\", value: { type: \"decimal\", decimal: 0 } };\n}\n\n/**\n * Adds two quantity values together.\n *\n * - Adding two {@link FixedValue}s returns a new {@link FixedValue}.\n * - Adding a {@link Range} to any value returns a {@link Range}.\n *\n * @param v1 - The first quantity value.\n * @param v2 - The second quantity value.\n * @returns A new quantity value representing the sum.\n */\nexport function addQuantityValues(v1: FixedValue, v2: FixedValue): FixedValue;\nexport function addQuantityValues(\n v1: FixedValue | Range,\n v2: FixedValue | Range,\n): Range;\n\nexport function addQuantityValues(\n v1: FixedValue | Range,\n v2: FixedValue | Range,\n): FixedValue | Range {\n if (\n (v1.type === \"fixed\" && v1.value.type === \"text\") ||\n (v2.type === \"fixed\" && v2.value.type === \"text\")\n ) {\n throw new CannotAddTextValueError();\n }\n\n if (v1.type === \"fixed\" && v2.type === \"fixed\") {\n const res = addNumericValues(\n v1.value as DecimalValue | FractionValue,\n v2.value as DecimalValue | FractionValue,\n );\n return { type: \"fixed\", value: res };\n }\n const r1 =\n v1.type === \"range\" ? v1 : { type: \"range\", min: v1.value, max: v1.value };\n const r2 =\n v2.type === \"range\" ? v2 : { type: \"range\", min: v2.value, max: v2.value };\n const newMin = addNumericValues(\n r1.min as DecimalValue | FractionValue,\n r2.min as DecimalValue | FractionValue,\n );\n const newMax = addNumericValues(\n r1.max as DecimalValue | FractionValue,\n r2.max as DecimalValue | FractionValue,\n );\n return { type: \"range\", min: newMin, max: newMax };\n}\n\n/**\n * Adds two quantities, returning the result in the most appropriate unit.\n */\nexport function addQuantities(\n q1: QuantityWithExtendedUnit,\n q2: QuantityWithExtendedUnit,\n): QuantityWithExtendedUnit {\n const v1 = q1.quantity;\n const v2 = q2.quantity;\n // Case 1: one of the two values is a text, we throw an error we can catch on the other end\n if (\n (v1.type === \"fixed\" && v1.value.type === \"text\") ||\n (v2.type === \"fixed\" && v2.value.type === \"text\")\n ) {\n throw new CannotAddTextValueError();\n }\n\n const unit1Def = normalizeUnit(q1.unit?.name);\n const unit2Def = normalizeUnit(q2.unit?.name);\n\n const addQuantityValuesAndSetUnit = (\n val1: FixedValue | Range,\n val2: FixedValue | Range,\n unit?: Unit,\n ): QuantityWithExtendedUnit => ({\n quantity: addQuantityValues(val1, val2),\n unit,\n });\n\n // Case 2: one of the two values doesn't have a unit, we preserve its value and consider its unit to be that of the other one\n // If at least one of the two units is \"\", this preserves it versus setting the resulting unit as undefined\n if (\n (q1.unit?.name === \"\" || q1.unit === undefined) &&\n q2.unit !== undefined\n ) {\n return addQuantityValuesAndSetUnit(v1, v2, q2.unit); // Prefer q2's unit\n }\n if (\n (q2.unit?.name === \"\" || q2.unit === undefined) &&\n q1.unit !== undefined\n ) {\n return addQuantityValuesAndSetUnit(v1, v2, q1.unit); // Prefer q1's unit\n }\n\n // Case 3: the two quantities have the exact same unit\n if (\n (!q1.unit && !q2.unit) ||\n (q1.unit &&\n q2.unit &&\n q1.unit.name.toLowerCase() === q2.unit.name.toLowerCase())\n ) {\n return addQuantityValuesAndSetUnit(v1, v2, q1.unit);\n }\n\n // Case 4: the two quantities have different units of known type\n if (unit1Def && unit2Def) {\n // Case 4.1: different unit type => we can't add quantities\n if (unit1Def.type !== unit2Def.type) {\n throw new IncompatibleUnitsError(\n `${unit1Def.type} (${q1.unit?.name})`,\n `${unit2Def.type} (${q2.unit?.name})`,\n );\n }\n\n let targetUnitDef: UnitDefinition;\n\n // Case 4.2: same unit type but different system => we convert to metric\n if (unit1Def.system !== unit2Def.system) {\n const metricUnitDef = unit1Def.system === \"metric\" ? unit1Def : unit2Def;\n targetUnitDef = units\n .filter((u) => u.type === metricUnitDef.type && u.system === \"metric\")\n .reduce((prev, current) =>\n prev.toBase > current.toBase ? prev : current,\n );\n }\n // Case 4.3: same unit type, same system but different unit => we use the biggest unit of the two\n else {\n targetUnitDef = unit1Def.toBase >= unit2Def.toBase ? unit1Def : unit2Def;\n }\n const convertedV1 = convertQuantityValue(v1, unit1Def, targetUnitDef);\n const convertedV2 = convertQuantityValue(v2, unit2Def, targetUnitDef);\n const targetUnit: Unit = { name: targetUnitDef.name };\n\n return addQuantityValuesAndSetUnit(convertedV1, convertedV2, targetUnit);\n }\n\n // Case 5: the two quantities have different units of unknown type\n throw new IncompatibleUnitsError(\n q1.unit?.name as string,\n q2.unit?.name as string,\n );\n}\n\nexport function toPlainUnit(\n quantity:\n | QuantityWithExtendedUnit\n | MaybeNestedGroup<QuantityWithExtendedUnit>,\n): QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit> {\n if (isQuantity(quantity))\n return quantity.unit\n ? { ...quantity, unit: quantity.unit.name }\n : (quantity as QuantityWithPlainUnit);\n else if (isOrGroup(quantity)) {\n return {\n or: quantity.or.map(toPlainUnit),\n } as MaybeNestedGroup<QuantityWithPlainUnit>;\n } else {\n return {\n and: quantity.and.map(toPlainUnit),\n } as MaybeNestedGroup<QuantityWithPlainUnit>;\n }\n}\n\n// Convert plain unit to extended unit format for addEquivalentsAndSimplify\n// Overloads for precise return types\nexport function toExtendedUnit(\n q: QuantityWithPlainUnit,\n): QuantityWithExtendedUnit;\nexport function toExtendedUnit(\n q: MaybeNestedGroup<QuantityWithPlainUnit>,\n): MaybeNestedGroup<QuantityWithExtendedUnit>;\nexport function toExtendedUnit(\n q: QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit>,\n): QuantityWithExtendedUnit | MaybeNestedGroup<QuantityWithExtendedUnit>;\nexport function toExtendedUnit(\n q: QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit>,\n): QuantityWithExtendedUnit | MaybeNestedGroup<QuantityWithExtendedUnit> {\n if (isQuantity(q)) {\n return q.unit\n ? { ...q, unit: { name: q.unit } }\n : (q as QuantityWithExtendedUnit);\n } else if (isOrGroup(q)) {\n return { or: q.or.map(toExtendedUnit) };\n } else {\n return { and: q.and.map(toExtendedUnit) };\n }\n}\n\nexport function deNormalizeQuantity(\n q: QuantityWithUnitDef,\n): QuantityWithExtendedUnit {\n const result: QuantityWithExtendedUnit = {\n quantity: q.quantity,\n };\n if (!isNoUnit(q.unit)) {\n result.unit = { name: q.unit.name };\n }\n return result;\n}\n\n// Helper function to convert addEquivalentsAndSimplify result to Ingredient.quantities format\n// Returns either a QuantityWithPlainUnit (for simple/OR groups) or an IngredientQuantityAndGroup (for AND groups)\nexport const flattenPlainUnitGroup = (\n summed: QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit>,\n): (\n | QuantityWithPlainUnit\n | {\n and: QuantityWithPlainUnit[];\n equivalents?: QuantityWithPlainUnit[];\n }\n)[] => {\n if (isOrGroup(summed)) {\n // OR group: check if first entry is an AND group (nested OR-with-AND case from addEquivalentsAndSimplify)\n // This happens when we have incompatible integer-protected primaries with compatible equivalents\n // e.g., { or: [{ and: [large, small] }, cup] }\n const entries = summed.or;\n const andGroupEntry = entries.find(\n (e): e is MaybeNestedGroup<QuantityWithPlainUnit> => isAndGroup(e),\n );\n\n if (andGroupEntry) {\n // Nested OR-with-AND case: AND group of primaries + equivalents\n const andEntries: QuantityWithPlainUnit[] = [];\n // Double casting due to:\n // - Nested ORs are flattened already\n // - Double nesting is not possible in this context\n const addGroupEntryContent = (\n andGroupEntry as MaybeNestedAndGroup<QuantityWithPlainUnit>\n ).and as QuantityWithPlainUnit[];\n for (const entry of addGroupEntryContent) {\n andEntries.push({\n quantity: entry.quantity,\n ...(entry.unit && { unit: entry.unit }),\n });\n }\n\n // The other entries in the OR group are the equivalents\n const equivalentsList: QuantityWithPlainUnit[] = entries\n .filter((e): e is QuantityWithPlainUnit => isQuantity(e))\n .map((e) => ({ quantity: e.quantity, unit: e.unit }));\n\n if (equivalentsList.length > 0) {\n return [\n {\n and: andEntries,\n equivalents: equivalentsList,\n },\n ];\n } else {\n // No equivalents: flatten to separate entries (shouldn't happen in this branch, but handle it)\n return andEntries;\n }\n }\n\n // Simple OR group: first entry is primary, rest are equivalents\n const simpleEntries = entries.filter((e): e is QuantityWithPlainUnit =>\n isQuantity(e),\n );\n /* v8 ignore else -- @preserve */\n if (simpleEntries.length > 0) {\n const result: QuantityWithPlainUnit = {\n quantity: simpleEntries[0]!.quantity,\n unit: simpleEntries[0]!.unit,\n };\n if (simpleEntries.length > 1) {\n result.equivalents = simpleEntries.slice(1);\n }\n return [result];\n }\n // Fallback: use first entry regardless\n else {\n const first = entries[0] as QuantityWithPlainUnit;\n return [{ quantity: first.quantity, unit: first.unit }];\n }\n } else if (isAndGroup(summed)) {\n // AND group: check if entries have OR groups (equivalents that can be extracted)\n const andEntries: QuantityWithPlainUnit[] = [];\n const equivalentsList: QuantityWithPlainUnit[] = [];\n for (const entry of summed.and) {\n // Double-nesting is not possible in this context\n // v8 ignore else -- @preserve\n if (isOrGroup(entry)) {\n // This entry has equivalents: first is primary, rest are equivalents\n const orEntries = entry.or as QuantityWithPlainUnit[];\n andEntries.push({\n quantity: orEntries[0]!.quantity,\n ...(orEntries[0]!.unit && { unit: orEntries[0]!.unit }),\n });\n // Collect equivalents for later merging\n equivalentsList.push(...orEntries.slice(1));\n } else if (isQuantity(entry)) {\n // Simple quantity, no equivalents\n andEntries.push({\n quantity: entry.quantity,\n ...(entry.unit && { unit: entry.unit }),\n });\n }\n }\n\n // Build the AND group result\n // If there are no equivalents, flatten to separate groupQuantity entries (water case)\n // If there are equivalents, return an AND group with the summed equivalents (carrots case)\n if (equivalentsList.length === 0) {\n // No equivalents: flatten to separate entries\n return andEntries;\n }\n\n const result: {\n and: QuantityWithPlainUnit[];\n equivalents?: QuantityWithPlainUnit[];\n } = {\n and: andEntries,\n equivalents: equivalentsList,\n };\n\n return [result];\n } else {\n // Simple QuantityWithPlainUnit\n return [\n { quantity: summed.quantity, ...(summed.unit && { unit: summed.unit }) },\n ];\n }\n};\n","import type {\n MetadataExtract,\n Metadata,\n FixedValue,\n Range,\n TextValue,\n DecimalValue,\n FractionValue,\n NoteItem,\n} from \"../types\";\nimport {\n metadataRegex,\n rangeRegex,\n numberLikeRegex,\n scalingMetaValueRegex,\n} from \"../regex\";\nimport { Section as SectionObject } from \"../classes/section\";\nimport type { Ingredient, Step, Cookware } from \"../types\";\nimport { addQuantityValues } from \"../quantities/mutations\";\nimport {\n CannotAddTextValueError,\n ReferencedItemCannotBeRedefinedError,\n} from \"../errors\";\n\n/**\n * Pushes a pending note to the section content if it has items.\n * @param section - The current section object.\n * @param noteItems - The note items array.\n * @returns An empty array if the note was pushed, otherwise the original items.\n */\nexport function flushPendingNote(\n section: SectionObject,\n noteItems: NoteItem[],\n): NoteItem[] {\n if (noteItems.length > 0) {\n section.content.push({ type: \"note\", items: [...noteItems] });\n return [];\n }\n return noteItems;\n}\n\n/**\n * Pushes pending step items and a pending note to the section content.\n * @param section - The current section object.\n * @param items - The list of step items. This array will be cleared.\n * @returns true if the items were pushed, otherwise false.\n */\nexport function flushPendingItems(\n section: SectionObject,\n items: Step[\"items\"],\n): boolean {\n if (items.length > 0) {\n section.content.push({ type: \"step\", items: [...items] });\n items.length = 0;\n return true;\n }\n return false;\n}\n\n/**\n * Finds an ingredient in the list (case-insensitively) and updates it, or adds it if not present.\n * This function mutates the `ingredients` array.\n * @param ingredients - The list of ingredients.\n * @param newIngredient - The ingredient to find or add.\n * @param isReference - Whether this is a reference ingredient (`&` modifier).\n * @returns The index of the ingredient in the list.\n * @returns An object containing the index of the ingredient and its quantity part in the list.\n */\nexport function findAndUpsertIngredient(\n ingredients: Ingredient[],\n newIngredient: Ingredient,\n isReference: boolean,\n): number {\n const { name } = newIngredient;\n\n if (isReference) {\n const indexFind = ingredients.findIndex(\n (i) => i.name.toLowerCase() === name.toLowerCase(),\n );\n\n if (indexFind === -1) {\n throw new Error(\n `Referenced ingredient \"${name}\" not found. A referenced ingredient must be declared before being referenced with '&'.`,\n );\n }\n\n // Ingredient already exists\n const existingIngredient = ingredients[indexFind]!;\n\n // Checking whether any provided flags are the same as the original ingredient\n // TODO: backport fix (check on array length) to v2\n if (!newIngredient.flags) {\n if (\n Array.isArray(existingIngredient.flags) &&\n existingIngredient.flags.length > 0\n ) {\n throw new ReferencedItemCannotBeRedefinedError(\n \"ingredient\",\n existingIngredient.name,\n existingIngredient.flags[0]!,\n );\n }\n } else {\n for (const flag of newIngredient.flags) {\n /* v8 ignore else -- @preserve */\n if (\n existingIngredient.flags === undefined ||\n !existingIngredient.flags.includes(flag)\n ) {\n throw new ReferencedItemCannotBeRedefinedError(\n \"ingredient\",\n existingIngredient.name,\n flag,\n );\n }\n }\n }\n\n return indexFind;\n }\n\n // Not a reference, so add as a new ingredient.\n return ingredients.push(newIngredient) - 1;\n}\n\nexport function findAndUpsertCookware(\n cookware: Cookware[],\n newCookware: Cookware,\n isReference: boolean,\n): number {\n const { name, quantity } = newCookware;\n\n if (isReference) {\n const index = cookware.findIndex(\n (i) => i.name.toLowerCase() === name.toLowerCase(),\n );\n\n if (index === -1) {\n throw new Error(\n `Referenced cookware \"${name}\" not found. A referenced cookware must be declared before being referenced with '&'.`,\n );\n }\n\n const existingCookware = cookware[index]!;\n\n // Checking whether any provided flags are the same as the original cookware\n // TODO: backport fix (if/else) + check on array length to v2\n if (!newCookware.flags) {\n if (\n Array.isArray(existingCookware.flags) &&\n existingCookware.flags.length > 0\n ) {\n throw new ReferencedItemCannotBeRedefinedError(\n \"cookware\",\n existingCookware.name,\n existingCookware.flags[0]!,\n );\n }\n } else {\n for (const flag of newCookware.flags) {\n /* v8 ignore else -- @preserve */\n if (\n existingCookware.flags === undefined ||\n !existingCookware.flags.includes(flag)\n ) {\n throw new ReferencedItemCannotBeRedefinedError(\n \"cookware\",\n existingCookware.name,\n flag,\n );\n }\n }\n }\n\n if (quantity !== undefined) {\n if (!existingCookware.quantity) {\n existingCookware.quantity = quantity;\n } else {\n try {\n existingCookware.quantity = addQuantityValues(\n existingCookware.quantity,\n quantity,\n );\n } catch (e) {\n /* v8 ignore else -- expliciting error type -- @preserve */\n if (e instanceof CannotAddTextValueError) {\n return cookware.push(newCookware) - 1;\n }\n }\n }\n }\n return index;\n }\n\n return cookware.push(newCookware) - 1;\n}\n\n// Parser when we know the input is either a number-like value\nexport const parseFixedValue = (\n input_str: string,\n): TextValue | DecimalValue | FractionValue => {\n if (!numberLikeRegex.test(input_str)) {\n return { type: \"text\", text: input_str };\n }\n\n // After this we know that s is either a fraction or a decimal value\n const s = input_str.trim().replace(\",\", \".\");\n\n // fraction\n if (s.includes(\"/\")) {\n const parts = s.split(\"/\");\n\n const num = Number(parts[0]);\n const den = Number(parts[1]);\n\n return { type: \"fraction\", num, den };\n }\n\n // decimal\n return { type: \"decimal\", decimal: Number(s) };\n};\n\nexport function stringifyQuantityValue(quantity: FixedValue | Range): string {\n if (quantity.type === \"fixed\") {\n return stringifyFixedValue(quantity);\n } else {\n return `${stringifyFixedValue({ type: \"fixed\", value: quantity.min })}-${stringifyFixedValue({ type: \"fixed\", value: quantity.max })}`;\n }\n}\n\nfunction stringifyFixedValue(quantity: FixedValue): string {\n if (quantity.value.type === \"fraction\")\n return `${quantity.value.num}/${quantity.value.den}`;\n else if (quantity.value.type === \"decimal\")\n return String(quantity.value.decimal);\n else return quantity.value.text;\n}\n\n// TODO: rename to parseQuantityValue\nexport function parseQuantityInput(input_str: string): FixedValue | Range {\n const clean_str = String(input_str).trim();\n\n if (rangeRegex.test(clean_str)) {\n const range_parts = clean_str.split(\"-\");\n // As we've tested for it, we know that we have Number-like Quantities to parse\n const min = parseFixedValue(range_parts[0]!.trim()) as\n | DecimalValue\n | FractionValue;\n const max = parseFixedValue(range_parts[1]!.trim()) as\n | DecimalValue\n | FractionValue;\n return { type: \"range\", min, max };\n }\n\n return { type: \"fixed\", value: parseFixedValue(clean_str) };\n}\n\nexport function parseSimpleMetaVar(content: string, varName: string) {\n const varMatch = content.match(\n new RegExp(`^${varName}:\\\\s*(.*(?:\\\\r?\\\\n\\\\s+.*)*)+`, \"m\"),\n );\n return varMatch\n ? varMatch[1]?.trim().replace(/\\s*\\r?\\n\\s+/g, \" \")\n : undefined;\n}\n\nexport function parseScalingMetaVar(\n content: string,\n varName: string,\n): [number, string] | undefined {\n const varMatch = content.match(scalingMetaValueRegex(varName));\n if (!varMatch) return undefined;\n if (isNaN(Number(varMatch[2]?.trim()))) {\n throw new Error(\"Scaling variables should be numbers\");\n }\n return [Number(varMatch[2]?.trim()), varMatch[1]!.trim()];\n}\n\nexport function parseListMetaVar(content: string, varName: string) {\n // Handle both inline and YAML-style tags\n const listMatch = content.match(\n new RegExp(\n `^${varName}:\\\\s*(?:\\\\[([^\\\\]]*)\\\\]|((?:\\\\r?\\\\n\\\\s*-\\\\s*.+)+))`,\n \"m\",\n ),\n );\n if (!listMatch) return undefined;\n\n /* v8 ignore else -- @preserve */\n if (listMatch[1] !== undefined) {\n // Inline list: tags: [one, two, three]\n return listMatch[1].split(\",\").map((tag) => tag.trim());\n } else if (listMatch[2]) {\n // YAML list:\n // tags:\n // - one\n // - two\n return listMatch[2]\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\")\n .map((line) => line.replace(/^\\s*-\\s*/, \"\").trim());\n }\n}\n\nexport function extractMetadata(content: string): MetadataExtract {\n const metadata: Metadata = {};\n let servings: number | undefined = undefined;\n\n // Is there front-matter at all?\n const metadataContent = content.match(metadataRegex)?.[2];\n if (!metadataContent) {\n return { metadata };\n }\n\n // String metadata variables\n for (const metaVar of [\n \"title\",\n \"source\",\n \"source.name\",\n \"source.url\",\n \"author\",\n \"source.author\",\n \"prep time\",\n \"time.prep\",\n \"cook time\",\n \"time.cook\",\n \"time required\",\n \"time\",\n \"duration\",\n \"locale\",\n \"introduction\",\n \"description\",\n \"course\",\n \"category\",\n \"diet\",\n \"cuisine\",\n \"difficulty\",\n \"image\",\n \"picture\",\n ] as (keyof Pick<\n Metadata,\n | \"title\"\n | \"source\"\n | \"source.name\"\n | \"source.url\"\n | \"author\"\n | \"source.author\"\n | \"prep time\"\n | \"time.prep\"\n | \"cook time\"\n | \"time.cook\"\n | \"time required\"\n | \"time\"\n | \"duration\"\n | \"locale\"\n | \"introduction\"\n | \"description\"\n | \"course\"\n | \"category\"\n | \"diet\"\n | \"cuisine\"\n | \"difficulty\"\n | \"image\"\n | \"picture\"\n >)[]) {\n const stringMetaValue = parseSimpleMetaVar(metadataContent, metaVar);\n if (stringMetaValue) metadata[metaVar] = stringMetaValue;\n }\n\n // String metadata variables\n for (const metaVar of [\"serves\", \"yield\", \"servings\"] as (keyof Pick<\n Metadata,\n \"servings\" | \"yield\" | \"serves\"\n >)[]) {\n const scalingMetaValue = parseScalingMetaVar(metadataContent, metaVar);\n if (scalingMetaValue && scalingMetaValue[1]) {\n metadata[metaVar] = scalingMetaValue[1];\n servings = scalingMetaValue[0];\n }\n }\n\n // List metadata variables\n for (const metaVar of [\"tags\", \"images\", \"pictures\"] as (keyof Pick<\n Metadata,\n \"tags\" | \"images\" | \"pictures\"\n >)[]) {\n const listMetaValue = parseListMetaVar(metadataContent, metaVar);\n if (listMetaValue) metadata[metaVar] = listMetaValue;\n }\n\n return { metadata, servings };\n}\n\nexport function isPositiveIntegerString(str: string): boolean {\n return /^\\d+$/.test(str);\n}\n\nexport function unionOfSets<T>(s1: Set<T>, s2: Set<T>): Set<T> {\n const result = new Set(s1);\n for (const item of s2) {\n result.add(item);\n }\n return result;\n}\n\n/**\n * Returns a canonical string key from sorted alternative indices for grouping quantities.\n * Used to determine if two ingredient items have the same alternatives and can be summed together.\n * @param alternatives - Array of alternative ingredient references\n * @returns A string of sorted indices (e.g., \"0,2,5\") or null if no alternatives\n */\nexport function getAlternativeSignature(\n alternatives: { index: number }[] | undefined,\n): string | null {\n if (!alternatives || alternatives.length === 0) return null;\n return alternatives\n .map((a) => a.index)\n .sort((a, b) => a - b)\n .join(\",\");\n}\n","import type { Step, Note } from \"../types\";\n\n/**\n * Represents a recipe section\n *\n * Wrapped as a _Class_ and not defined as a simple _Type_ to expose some useful helper\n * classes (e.g. {@link Section.isBlank | isBlank()})\n *\n * @category Types\n */\nexport class Section {\n /**\n * The name of the section. Can be an empty string for the default (first) section.\n * @defaultValue `\"\"`\n */\n name: string;\n /** An array of steps and notes that make up the content of the section. */\n content: (Step | Note)[] = [];\n\n /**\n * Creates an instance of Section.\n * @param name - The name of the section. Defaults to an empty string.\n */\n constructor(name: string = \"\") {\n this.name = name;\n }\n\n /**\n * Checks if the section is blank (has no name and no content).\n * Used during recipe parsing\n * @returns `true` if the section is blank, otherwise `false`.\n */\n isBlank(): boolean {\n return this.name === \"\" && this.content.length === 0;\n }\n}\n","import { isNoUnit } from \"../units/definitions\";\nimport type {\n QuantityWithPlainUnit,\n QuantityWithExtendedUnit,\n QuantityWithUnitDef,\n UnitDefinitionLike,\n FlatOrGroup,\n MaybeNestedOrGroup,\n FlatAndGroup,\n MaybeNestedGroup,\n} from \"../types\";\nimport { resolveUnit } from \"../units/definitions\";\nimport { multiplyQuantityValue, getAverageValue } from \"./numeric\";\nimport Big from \"big.js\";\nimport {\n isAndGroup,\n isOrGroup,\n isQuantity,\n isValueIntegerLike,\n} from \"../utils/type_guards\";\nimport {\n getDefaultQuantityValue,\n addQuantities,\n deNormalizeQuantity,\n toPlainUnit,\n} from \"./mutations\";\nimport { getUnitRatio, getBaseUnitRatio } from \"../units/conversion\";\nimport {\n areUnitsCompatible,\n findCompatibleQuantityWithinList,\n findListWithCompatibleQuantity,\n} from \"../units/lookup\";\nimport { deepClone } from \"../utils/general\";\n\nexport function getEquivalentUnitsLists(\n ...quantities: (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[]\n): QuantityWithUnitDef[][] {\n const quantitiesCopy = deepClone(quantities);\n\n const OrGroups = (\n quantitiesCopy.filter(isOrGroup) as FlatOrGroup<QuantityWithExtendedUnit>[]\n ).filter((q) => q.or.length > 1);\n\n const unitLists: QuantityWithUnitDef[][] = [];\n const normalizeOrGroup = (og: FlatOrGroup<QuantityWithExtendedUnit>) => ({\n ...og,\n or: og.or.map((q) => ({\n ...q,\n unit: resolveUnit(q.unit?.name, q.unit?.integerProtected),\n })),\n });\n\n function findLinkIndexForUnits(\n lists: QuantityWithUnitDef[][],\n unitsToCheck: (UnitDefinitionLike | undefined)[],\n ) {\n return lists.findIndex((l) => {\n const listItem = l.map((q) => resolveUnit(q.unit?.name));\n return unitsToCheck.some((u) =>\n listItem.some(\n (lu) =>\n lu.name === u?.name ||\n (lu.system === u?.system &&\n lu.type === u?.type &&\n lu.type !== \"other\"),\n ),\n );\n });\n }\n\n function mergeOrGroupIntoList(\n lists: QuantityWithUnitDef[][],\n idx: number,\n og: ReturnType<typeof normalizeOrGroup>,\n ) {\n let unitRatio: Big | undefined;\n const commonUnitList = lists[idx]!.reduce((acc, v) => {\n const normalizedV: QuantityWithUnitDef = {\n ...v,\n unit: resolveUnit(v.unit?.name, v.unit?.integerProtected),\n };\n\n const commonQuantity = og.or.find(\n (q) => isQuantity(q) && areUnitsCompatible(q.unit, normalizedV.unit),\n );\n if (commonQuantity) {\n acc.push(normalizedV);\n unitRatio = getUnitRatio(normalizedV, commonQuantity);\n }\n return acc;\n }, [] as QuantityWithUnitDef[]);\n\n for (const newQ of og.or) {\n if (commonUnitList.some((q) => areUnitsCompatible(q.unit, newQ.unit))) {\n continue;\n } else {\n const scaledQuantity = multiplyQuantityValue(newQ.quantity, unitRatio!);\n lists[idx]!.push({ ...newQ, quantity: scaledQuantity });\n }\n }\n }\n\n for (const orGroup of OrGroups) {\n const orGroupModified = normalizeOrGroup(orGroup);\n const units = orGroupModified.or.map((q) => q.unit);\n const linkIndex = findLinkIndexForUnits(unitLists, units);\n if (linkIndex === -1) {\n unitLists.push(orGroupModified.or);\n } else {\n mergeOrGroupIntoList(unitLists, linkIndex, orGroupModified);\n }\n }\n\n return unitLists;\n}\n\n/**\n * List sorting helper for equivalent units\n * @param list - list of quantities to sort\n * @returns sorted list of quantities with integerProtected units first, then no-unit, then the rest alphabetically\n */\nexport function sortUnitList(list: QuantityWithUnitDef[]) {\n if (!list || list.length <= 1) return list;\n const priorityList: QuantityWithUnitDef[] = [];\n const nonPriorityList: QuantityWithUnitDef[] = [];\n for (const q of list) {\n if (q.unit.integerProtected || q.unit.system === \"none\") {\n priorityList.push(q);\n } else {\n nonPriorityList.push(q);\n }\n }\n\n return priorityList\n .sort((a, b) => {\n const prefixA = a.unit.integerProtected ? \"___\" : \"\";\n const prefixB = b.unit.integerProtected ? \"___\" : \"\";\n return (prefixA + a.unit.name).localeCompare(prefixB + b.unit.name, \"en\");\n })\n .concat(nonPriorityList);\n}\n\nexport function reduceOrsToFirstEquivalent(\n unitList: QuantityWithUnitDef[][],\n quantities: (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[],\n): QuantityWithExtendedUnit[] {\n function reduceToQuantity(firstQuantity: QuantityWithExtendedUnit) {\n // Look for the global list of equivalent for this quantity unit;\n const equivalentList = sortUnitList(\n findListWithCompatibleQuantity(unitList, firstQuantity)!,\n );\n if (!equivalentList) return firstQuantity;\n // Find that first quantity in the OR\n const firstQuantityInList = findCompatibleQuantityWithinList(\n equivalentList,\n firstQuantity,\n )!;\n // Normalize the first quantity's unit\n const normalizedFirstQuantity: QuantityWithUnitDef = {\n ...firstQuantity,\n unit: resolveUnit(firstQuantity.unit?.name),\n };\n // Priority 1: the first quantity has an integer-protected unit\n if (firstQuantityInList.unit.integerProtected) {\n const resultQuantity: QuantityWithExtendedUnit = {\n quantity: firstQuantity.quantity,\n };\n /* v8 ignore else -- @preserve */\n if (!isNoUnit(normalizedFirstQuantity.unit)) {\n resultQuantity.unit = { name: normalizedFirstQuantity.unit.name };\n }\n return resultQuantity;\n } else {\n // Priority 2: the next integer-protected units in the equivalent list\n let nextProtected: number | undefined;\n const equivalentListTemp = [...equivalentList];\n while (nextProtected !== -1) {\n nextProtected = equivalentListTemp.findIndex(\n (eq) => eq.unit?.integerProtected,\n );\n // Ratio between the values in the OR group vs the ones used in the equivalent unit list\n if (nextProtected !== -1) {\n const unitRatio = getUnitRatio(\n equivalentListTemp[nextProtected]!,\n firstQuantityInList,\n );\n const nextProtectedQuantityValue = multiplyQuantityValue(\n firstQuantity.quantity,\n unitRatio,\n );\n if (isValueIntegerLike(nextProtectedQuantityValue)) {\n const nextProtectedQuantity: QuantityWithExtendedUnit = {\n quantity: nextProtectedQuantityValue,\n };\n /* v8 ignore else -- @preserve */\n if (!isNoUnit(equivalentListTemp[nextProtected]!.unit)) {\n nextProtectedQuantity.unit = {\n name: equivalentListTemp[nextProtected]!.unit.name,\n };\n }\n\n return nextProtectedQuantity;\n } else {\n equivalentListTemp.splice(nextProtected, 1);\n }\n }\n }\n\n // Priority 3: the first non-integer-Protected value of the list\n const firstNonIntegerProtected = equivalentListTemp.filter(\n (q) => !q.unit.integerProtected,\n )[0]!;\n const unitRatio = getUnitRatio(\n firstNonIntegerProtected,\n firstQuantityInList,\n ).times(getBaseUnitRatio(normalizedFirstQuantity, firstQuantityInList));\n const firstEqQuantity: QuantityWithExtendedUnit = {\n quantity:\n firstNonIntegerProtected.unit.name === firstQuantity.unit!.name\n ? firstQuantity.quantity\n : multiplyQuantityValue(firstQuantity.quantity, unitRatio),\n };\n if (!isNoUnit(firstNonIntegerProtected.unit)) {\n firstEqQuantity.unit = { name: firstNonIntegerProtected.unit.name };\n }\n return firstEqQuantity;\n }\n }\n return quantities.map((q) => {\n if (isQuantity(q)) return reduceToQuantity(q);\n // Now, q is necessarily an OR group\n // We normalize units and sort them to get integerProtected elements first, then no units, then the rest\n const qListModified = sortUnitList(\n q.or.map((qq) => ({\n ...qq,\n unit: resolveUnit(qq.unit?.name, qq.unit?.integerProtected),\n })),\n );\n // We can simply use the first element\n return reduceToQuantity(qListModified[0]!);\n });\n}\n\nexport function addQuantitiesOrGroups(\n ...quantities: (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[]\n): {\n sum: QuantityWithUnitDef | FlatAndGroup<QuantityWithUnitDef>;\n unitsLists: QuantityWithUnitDef[][];\n} {\n if (quantities.length === 0)\n return {\n sum: {\n quantity: getDefaultQuantityValue(),\n unit: resolveUnit(),\n },\n unitsLists: [],\n };\n // This is purely theoretical and won't really happen in practice\n if (quantities.length === 1) {\n if (isQuantity(quantities[0]!))\n return {\n sum: {\n ...quantities[0],\n unit: resolveUnit(quantities[0].unit?.name),\n },\n unitsLists: [],\n };\n }\n // Step 1: find equivalents units\n const unitsLists = getEquivalentUnitsLists(...quantities);\n // Step 2: reduce the OR group to Quantities\n const reducedQuantities = reduceOrsToFirstEquivalent(unitsLists, quantities);\n // Step 3: calculate the sum\n const sum: QuantityWithUnitDef[] = [];\n for (const nextQ of reducedQuantities) {\n const existingQ = findCompatibleQuantityWithinList(sum, nextQ);\n if (existingQ === undefined) {\n sum.push({\n ...nextQ,\n unit: resolveUnit(nextQ.unit?.name),\n });\n } else {\n const sumQ = addQuantities(existingQ, nextQ);\n existingQ.quantity = sumQ.quantity;\n existingQ.unit = resolveUnit(sumQ.unit?.name);\n }\n }\n if (sum.length === 1) {\n return { sum: sum[0]!, unitsLists };\n }\n return { sum: { and: sum }, unitsLists };\n}\n\nexport function regroupQuantitiesAndExpandEquivalents(\n sum: QuantityWithUnitDef | FlatAndGroup<QuantityWithUnitDef>,\n unitsLists: QuantityWithUnitDef[][],\n): (QuantityWithExtendedUnit | MaybeNestedOrGroup<QuantityWithExtendedUnit>)[] {\n const sumQuantities = isAndGroup(sum) ? sum.and : [sum];\n const result: (\n | QuantityWithExtendedUnit\n | MaybeNestedOrGroup<QuantityWithExtendedUnit>\n )[] = [];\n const processedQuantities = new Set<QuantityWithUnitDef>();\n\n for (const list of unitsLists) {\n const listCopy = deepClone(list);\n const main: QuantityWithUnitDef[] = [];\n const mainCandidates = sumQuantities.filter(\n (q) => !processedQuantities.has(q),\n );\n if (mainCandidates.length === 0) continue;\n\n mainCandidates.forEach((q) => {\n // If the sum contain a value from the unit list, we push it to the mains and remove it from the list\n const mainInList = findCompatibleQuantityWithinList(listCopy, q);\n /* v8 ignore else -- @preserve */\n if (mainInList !== undefined) {\n processedQuantities.add(q);\n main.push(q);\n listCopy.splice(listCopy.indexOf(mainInList), 1);\n }\n });\n\n // We sort the equivalent units and calculate the equivalent value for each of them\n const equivalents = sortUnitList(listCopy).map((equiv) => {\n const initialValue: QuantityWithExtendedUnit = {\n quantity: getDefaultQuantityValue(),\n };\n /* v8 ignore else -- @preserve */\n if (equiv.unit) {\n initialValue.unit = { name: equiv.unit.name };\n }\n return main.reduce((acc, v) => {\n const mainInList = findCompatibleQuantityWithinList(list, v)!;\n const newValue: QuantityWithExtendedUnit = {\n quantity: multiplyQuantityValue(\n v.quantity,\n Big(getAverageValue(equiv.quantity)).div(\n getAverageValue(mainInList.quantity),\n ),\n ),\n };\n if (equiv.unit && !isNoUnit(equiv.unit)) {\n newValue.unit = { name: equiv.unit.name };\n }\n return addQuantities(acc, newValue);\n }, initialValue);\n });\n\n if (main.length + equivalents.length > 1) {\n const resultMain:\n | QuantityWithExtendedUnit\n | FlatAndGroup<QuantityWithExtendedUnit> =\n main.length > 1\n ? {\n and: main.map(deNormalizeQuantity),\n }\n : deNormalizeQuantity(main[0]!);\n result.push({\n or: [resultMain, ...equivalents],\n });\n }\n // Processing a UnitList with only 1 quantity is purely theoretical and won't happen in practice\n else {\n result.push(deNormalizeQuantity(main[0]!));\n }\n }\n\n // We add at the end the lone quantities\n sumQuantities\n .filter((q) => !processedQuantities.has(q))\n .forEach((q) => result.push(deNormalizeQuantity(q)));\n\n return result;\n}\n\nexport function addEquivalentsAndSimplify(\n ...quantities: (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[]\n): QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit> {\n if (quantities.length === 1) {\n return toPlainUnit(quantities[0]!);\n }\n // Step 1+2+3: find equivalents, reduce groups and add quantities\n const { sum, unitsLists } = addQuantitiesOrGroups(...quantities);\n // Step 4: regroup and expand equivalents per group\n const regrouped = regroupQuantitiesAndExpandEquivalents(sum, unitsLists);\n if (regrouped.length === 1) {\n return toPlainUnit(regrouped[0]!);\n } else {\n return { and: regrouped.map(toPlainUnit) };\n }\n}\n","import Big from \"big.js\";\nimport type { QuantityWithUnitDef } from \"../types\";\nimport { getAverageValue } from \"../quantities/numeric\";\n\nexport function getUnitRatio(q1: QuantityWithUnitDef, q2: QuantityWithUnitDef) {\n const q1Value = getAverageValue(q1.quantity);\n const q2Value = getAverageValue(q2.quantity);\n const factor =\n \"toBase\" in q1.unit && \"toBase\" in q2.unit\n ? q1.unit.toBase / q2.unit.toBase\n : 1;\n\n if (typeof q1Value !== \"number\" || typeof q2Value !== \"number\") {\n throw Error(\n \"One of both values is not a number, so a ratio cannot be computed\",\n );\n }\n return Big(q1Value).times(factor).div(q2Value);\n}\n\nexport function getBaseUnitRatio(\n q: QuantityWithUnitDef,\n qRef: QuantityWithUnitDef,\n) {\n if (\"toBase\" in q.unit && \"toBase\" in qRef.unit) {\n return q.unit.toBase / qRef.unit.toBase;\n } else {\n return 1;\n }\n}\n","import type {\n QuantityWithExtendedUnit,\n QuantityWithUnitDef,\n UnitDefinitionLike,\n} from \"../types\";\nimport { resolveUnit } from \"./definitions\";\n\nexport function areUnitsCompatible(\n u1: UnitDefinitionLike,\n u2: UnitDefinitionLike,\n): boolean {\n if (u1.name === u2.name) {\n return true;\n }\n if (u1.type !== \"other\" && u1.type === u2.type && u1.system === u2.system) {\n return true;\n }\n return false;\n}\n\nexport function findListWithCompatibleQuantity(\n list: QuantityWithUnitDef[][],\n quantity: QuantityWithExtendedUnit,\n) {\n const quantityWithUnitDef = {\n ...quantity,\n unit: resolveUnit(quantity.unit?.name),\n };\n return list.find((l) =>\n l.some((lq) => areUnitsCompatible(lq.unit, quantityWithUnitDef.unit)),\n );\n}\n\nexport function findCompatibleQuantityWithinList(\n list: QuantityWithUnitDef[],\n quantity: QuantityWithExtendedUnit,\n): QuantityWithUnitDef | undefined {\n const quantityWithUnitDef = {\n ...quantity,\n unit: resolveUnit(quantity.unit?.name),\n };\n return list.find(\n (q) =>\n q.unit.name === quantityWithUnitDef.unit.name ||\n (q.unit.type === quantityWithUnitDef.unit.type &&\n q.unit.type !== \"other\"),\n );\n}\n","const legacyDeepClone = <T>(v: T): T => {\n if (v === null || typeof v !== \"object\") {\n return v;\n }\n if (v instanceof Map) {\n return new Map(\n Array.from(v.entries()).map(([k, val]) => [\n legacyDeepClone(k),\n legacyDeepClone(val),\n ])\n ) as T;\n }\n if (v instanceof Set) {\n return new Set(Array.from(v).map((val: unknown) => legacyDeepClone(val))) as T;\n }\n if (v instanceof Date) {\n return new Date(v.getTime()) as T;\n }\n if (Array.isArray(v)) {\n return v.map((item: unknown) => legacyDeepClone(item)) as T;\n }\n const cloned = {} as Record<string, unknown>;\n for (const key of Object.keys(v)) {\n cloned[key] = legacyDeepClone((v as Record<string, unknown>)[key]);\n }\n return cloned as T;\n};\n\nexport const deepClone = <T>(v: T): T =>\n typeof structuredClone === \"function\"\n ? structuredClone(v)\n : legacyDeepClone(v);\n","import type {\n Metadata,\n Ingredient,\n IngredientExtras,\n IngredientItem,\n IngredientItemQuantity,\n Timer,\n Step,\n NoteItem,\n Cookware,\n MetadataExtract,\n CookwareItem,\n IngredientFlag,\n CookwareFlag,\n RecipeAlternatives,\n IngredientAlternative,\n FlatOrGroup,\n QuantityWithExtendedUnit,\n AlternativeIngredientRef,\n QuantityWithPlainUnit,\n IngredientQuantityGroup,\n IngredientQuantityAndGroup,\n ArbitraryScalable,\n FixedNumericValue,\n StepItem,\n GetIngredientQuantitiesOptions,\n} from \"../types\";\nimport { Section } from \"./section\";\nimport {\n tokensRegex,\n commentRegex,\n blockCommentRegex,\n metadataRegex,\n ingredientWithAlternativeRegex,\n ingredientWithGroupKeyRegex,\n ingredientAliasRegex,\n floatRegex,\n quantityAlternativeRegex,\n inlineIngredientAlternativesRegex,\n arbitraryScalableRegex,\n} from \"../regex\";\nimport {\n flushPendingItems,\n flushPendingNote,\n findAndUpsertIngredient,\n findAndUpsertCookware,\n parseQuantityInput,\n extractMetadata,\n unionOfSets,\n getAlternativeSignature,\n} from \"../utils/parser_helpers\";\nimport { addEquivalentsAndSimplify } from \"../quantities/alternatives\";\nimport { multiplyQuantityValue } from \"../quantities/numeric\";\nimport {\n toPlainUnit,\n toExtendedUnit,\n flattenPlainUnitGroup,\n} from \"../quantities/mutations\";\nimport { resolveUnit } from \"../units/definitions\";\nimport Big from \"big.js\";\nimport { deepClone } from \"../utils/general\";\nimport { InvalidQuantityFormat } from \"../errors\";\n\n/**\n * Recipe parser.\n *\n * ## Usage\n *\n * You can either directly provide the recipe string when creating the instance\n * e.g. `const recipe = new Recipe('Add @eggs{3}')`, or create it first and then pass\n * the recipe string to the {@link Recipe.parse | parse()} method.\n *\n * Look at the [properties](#properties) to see how the recipe's properties are parsed.\n *\n * @category Classes\n *\n * @example\n * ```typescript\n * import { Recipe } from \"@tmlmt/cooklang-parser\";\n *\n * const recipeString = `\n * ---\n * title: Pancakes\n * tags: [breakfast, easy]\n * ---\n * Crack the @eggs{3} with @flour{100%g} and @milk{200%mL}\n *\n * Melt some @butter{50%g} in a #pan on medium heat.\n *\n * Cook for ~{5%minutes} on each side.\n * `\n * const recipe = new Recipe(recipeString);\n * ```\n */\nexport class Recipe {\n /**\n * The parsed recipe metadata.\n */\n metadata: Metadata = {};\n /**\n * The possible choices of alternative ingredients for this recipe.\n */\n choices: RecipeAlternatives = {\n ingredientItems: new Map(),\n ingredientGroups: new Map(),\n };\n /**\n * The parsed recipe ingredients.\n */\n ingredients: Ingredient[] = [];\n /**\n * The parsed recipe sections.\n */\n sections: Section[] = [];\n /**\n * The parsed recipe cookware.\n */\n cookware: Cookware[] = [];\n /**\n * The parsed recipe timers.\n */\n timers: Timer[] = [];\n /**\n * The parsed arbitrary quantities.\n */\n arbitraries: ArbitraryScalable[] = [];\n /**\n * The parsed recipe servings. Used for scaling. Parsed from one of\n * {@link Metadata.servings}, {@link Metadata.yield} or {@link Metadata.serves}\n * metadata fields.\n *\n * @see {@link Recipe.scaleBy | scaleBy()} and {@link Recipe.scaleTo | scaleTo()} methods\n */\n servings?: number;\n\n /**\n * External storage for item count (not a property on instances).\n * Used for giving ID numbers to items during parsing.\n */\n private static itemCounts = new WeakMap<Recipe, number>();\n\n /**\n * Gets the current item count for this recipe.\n */\n private getItemCount(): number {\n return Recipe.itemCounts.get(this)!;\n }\n\n /**\n * Gets the current item count and increments it.\n */\n private getAndIncrementItemCount(): number {\n const current = this.getItemCount();\n Recipe.itemCounts.set(this, current + 1);\n return current;\n }\n\n /**\n * Creates a new Recipe instance.\n * @param content - The recipe content to parse.\n */\n constructor(content?: string) {\n Recipe.itemCounts.set(this, 0);\n if (content) {\n this.parse(content);\n }\n }\n\n /**\n * Parses a matched arbitrary scalable quantity and adds it to the given array.\n * @private\n * @param regexMatchGroups - The regex match groups from arbitrary scalable regex.\n * @param intoArray - The array to push the parsed arbitrary scalable item into.\n */\n private _parseArbitraryScalable(\n regexMatchGroups: RegExpMatchArray[\"groups\"],\n intoArray: Array<NoteItem | StepItem>,\n ): void {\n // Type-guard to ensure regexMatchGroups is defined, which it is when calling this function\n // v8 ignore if -- @preserve\n if (!regexMatchGroups || !regexMatchGroups.arbitraryQuantity) return;\n const quantityMatch = regexMatchGroups.arbitraryQuantity\n ?.trim()\n .match(quantityAlternativeRegex);\n // Type-guard to ensure quantityMatch.groups is defined, which we know when calling this function\n // v8 ignore else -- @preserve\n if (quantityMatch?.groups) {\n const value = parseQuantityInput(quantityMatch.groups.quantity!);\n const unit = quantityMatch.groups.unit;\n const name = regexMatchGroups.arbitraryName || undefined;\n if (!value || (value.type === \"fixed\" && value.value.type === \"text\")) {\n throw new InvalidQuantityFormat(\n regexMatchGroups.arbitraryQuantity?.trim(),\n \"Arbitrary quantities must have a numerical value\",\n );\n }\n const arbitrary: ArbitraryScalable = {\n quantity: value as FixedNumericValue,\n };\n if (name) arbitrary.name = name;\n if (unit) arbitrary.unit = unit;\n intoArray.push({\n type: \"arbitrary\",\n index: this.arbitraries.push(arbitrary) - 1,\n });\n }\n }\n\n /**\n * Parses text for arbitrary scalables and returns NoteItem array.\n * @param text - The text to parse for arbitrary scalables.\n * @returns Array of NoteItem (text and arbitrary scalable items).\n */\n private _parseNoteText(text: string): NoteItem[] {\n const noteItems: NoteItem[] = [];\n let cursor = 0;\n const globalRegex = new RegExp(arbitraryScalableRegex.source, \"g\");\n\n for (const match of text.matchAll(globalRegex)) {\n const idx = match.index;\n /* v8 ignore else -- @preserve */\n if (idx > cursor) {\n noteItems.push({ type: \"text\", value: text.slice(cursor, idx) });\n }\n\n this._parseArbitraryScalable(match.groups, noteItems);\n cursor = idx + match[0].length;\n }\n\n if (cursor < text.length) {\n noteItems.push({ type: \"text\", value: text.slice(cursor) });\n }\n\n return noteItems;\n }\n\n private _parseQuantityRecursive(\n quantityRaw: string,\n ): QuantityWithExtendedUnit[] {\n let quantityMatch = quantityRaw.match(quantityAlternativeRegex);\n const quantities: QuantityWithExtendedUnit[] = [];\n while (quantityMatch?.groups) {\n const value = quantityMatch.groups.quantity\n ? parseQuantityInput(quantityMatch.groups.quantity)\n : undefined;\n const unit = quantityMatch.groups.unit;\n if (value) {\n const newQuantity: QuantityWithExtendedUnit = { quantity: value };\n if (unit) {\n if (unit.startsWith(\"=\")) {\n newQuantity.unit = {\n name: unit.substring(1),\n integerProtected: true,\n };\n } else {\n newQuantity.unit = { name: unit };\n }\n }\n quantities.push(newQuantity);\n } else {\n throw new InvalidQuantityFormat(quantityRaw);\n }\n quantityMatch = quantityMatch.groups.alternative\n ? quantityMatch.groups.alternative.match(quantityAlternativeRegex)\n : null;\n }\n return quantities;\n }\n\n private _parseIngredientWithAlternativeRecursive(\n ingredientMatchString: string,\n items: Step[\"items\"],\n ): void {\n const alternatives: IngredientAlternative[] = [];\n let testString = ingredientMatchString;\n while (true) {\n const match = testString.match(\n alternatives.length > 0\n ? inlineIngredientAlternativesRegex\n : ingredientWithAlternativeRegex,\n );\n if (!match?.groups) break;\n const groups = match.groups;\n\n // Use variables for readability\n // @<modifiers><name>{quantity%unit|altQuantities}(preparation)[note]|<altIngredients>\n let name = (groups.mIngredientName || groups.sIngredientName)!;\n\n // 1. We build up the different parts of the Ingredient object\n // Preparation\n const preparation = groups.ingredientPreparation;\n // Flags\n const modifiers = groups.ingredientModifiers;\n const reference = modifiers !== undefined && modifiers.includes(\"&\");\n const flags: IngredientFlag[] = [];\n if (modifiers !== undefined && modifiers.includes(\"?\")) {\n flags.push(\"optional\");\n }\n if (modifiers !== undefined && modifiers.includes(\"-\")) {\n flags.push(\"hidden\");\n }\n if (\n (modifiers !== undefined && modifiers.includes(\"@\")) ||\n groups.ingredientRecipeAnchor\n ) {\n flags.push(\"recipe\");\n }\n // Extras\n let extras: IngredientExtras | undefined = undefined;\n // -- if the ingredient is a recipe, we need to extract the name from the path given\n if (flags.includes(\"recipe\")) {\n extras = { path: `${name}.cook` };\n name = name.substring(name.lastIndexOf(\"/\") + 1);\n }\n // Distinguish name from display name / name alias\n const aliasMatch = name.match(ingredientAliasRegex);\n let listName, displayName: string;\n if (\n aliasMatch &&\n aliasMatch.groups!.ingredientListName!.trim().length > 0 &&\n aliasMatch.groups!.ingredientDisplayName!.trim().length > 0\n ) {\n listName = aliasMatch.groups!.ingredientListName!.trim();\n displayName = aliasMatch.groups!.ingredientDisplayName!.trim();\n } else {\n listName = name;\n displayName = name;\n }\n\n const newIngredient: Ingredient = {\n name: listName,\n };\n // Only add parameters if they are non null / non empty\n if (preparation) {\n newIngredient.preparation = preparation;\n }\n if (flags.length > 0) {\n newIngredient.flags = flags;\n }\n if (extras) {\n newIngredient.extras = extras;\n }\n\n const idxInList = findAndUpsertIngredient(\n this.ingredients,\n newIngredient,\n reference,\n );\n\n // 2. We build up the ingredient item\n // -- alternative quantities\n let itemQuantity: IngredientItemQuantity | undefined = undefined;\n if (groups.ingredientQuantity) {\n const parsedQuantities = this._parseQuantityRecursive(\n groups.ingredientQuantity,\n );\n const [primary, ...rest] = parsedQuantities;\n if (primary) {\n itemQuantity = {\n ...primary,\n scalable: groups.ingredientQuantityModifier !== \"=\",\n };\n if (rest.length > 0) {\n itemQuantity.equivalents = rest;\n }\n }\n }\n\n const alternative: IngredientAlternative = {\n index: idxInList,\n displayName,\n };\n // Only add itemQuantity and note if they exist\n const note = groups.ingredientNote?.trim();\n if (note) {\n alternative.note = note;\n }\n if (itemQuantity) {\n alternative.itemQuantity = itemQuantity;\n }\n alternatives.push(alternative);\n testString = groups.ingredientAlternative || \"\";\n }\n\n // Update alternatives list of all processed ingredients\n if (alternatives.length > 1) {\n const alternativesIndexes = alternatives.map((alt) => alt.index);\n for (const ingredientIndex of alternativesIndexes) {\n const ingredient = this.ingredients[ingredientIndex];\n // In practice, the ingredient will always be found\n /* v8 ignore else -- @preserve */\n if (ingredient) {\n if (!ingredient.alternatives) {\n ingredient.alternatives = new Set(\n alternativesIndexes.filter((index) => index !== ingredientIndex),\n );\n } else {\n ingredient.alternatives = unionOfSets(\n ingredient.alternatives,\n new Set(\n alternativesIndexes.filter(\n (index) => index !== ingredientIndex,\n ),\n ),\n );\n }\n }\n }\n }\n\n const id = `ingredient-item-${this.getAndIncrementItemCount()}`;\n\n // Finalize item\n const newItem: IngredientItem = {\n type: \"ingredient\",\n id,\n alternatives,\n };\n items.push(newItem);\n\n if (alternatives.length > 1) {\n this.choices.ingredientItems.set(id, alternatives);\n }\n }\n\n private _parseIngredientWithGroupKey(\n ingredientMatchString: string,\n items: Step[\"items\"],\n ): void {\n const match = ingredientMatchString.match(ingredientWithGroupKeyRegex);\n // This is a type guard to ensure match and match.groups are defined\n /* v8 ignore if -- @preserve */\n if (!match?.groups) return;\n const groups = match.groups;\n\n // Use variables for readability\n // @|<groupKey|<modifiers><name>{quantity%unit|altQuantities}(preparation)[note]\n const groupKey = groups.gIngredientGroupKey!;\n let name = (groups.gmIngredientName || groups.gsIngredientName)!;\n\n // 1. We build up the different parts of the Ingredient object\n // Preparation\n const preparation = groups.gIngredientPreparation;\n // Flags\n const modifiers = groups.gIngredientModifiers;\n const reference = modifiers !== undefined && modifiers.includes(\"&\");\n const flags: IngredientFlag[] = [];\n if (modifiers !== undefined && modifiers.includes(\"?\")) {\n flags.push(\"optional\");\n }\n if (modifiers !== undefined && modifiers.includes(\"-\")) {\n flags.push(\"hidden\");\n }\n if (\n (modifiers !== undefined && modifiers.includes(\"@\")) ||\n groups.gIngredientRecipeAnchor\n ) {\n flags.push(\"recipe\");\n }\n // Extras\n let extras: IngredientExtras | undefined = undefined;\n // -- if the ingredient is a recipe, we need to extract the name from the path given\n if (flags.includes(\"recipe\")) {\n extras = { path: `${name}.cook` };\n name = name.substring(name.lastIndexOf(\"/\") + 1);\n }\n // Distinguish name from display name / name alias\n const aliasMatch = name.match(ingredientAliasRegex);\n let listName, displayName: string;\n if (\n aliasMatch &&\n aliasMatch.groups!.ingredientListName!.trim().length > 0 &&\n aliasMatch.groups!.ingredientDisplayName!.trim().length > 0\n ) {\n listName = aliasMatch.groups!.ingredientListName!.trim();\n displayName = aliasMatch.groups!.ingredientDisplayName!.trim();\n } else {\n listName = name;\n displayName = name;\n }\n\n const newIngredient: Ingredient = {\n name: listName,\n };\n // Only add parameters if they are non null / non empty\n if (preparation) {\n newIngredient.preparation = preparation;\n }\n if (flags.length > 0) {\n newIngredient.flags = flags;\n }\n if (extras) {\n newIngredient.extras = extras;\n }\n\n const idxInList = findAndUpsertIngredient(\n this.ingredients,\n newIngredient,\n reference,\n );\n\n // 2. We build up the ingredient item\n // -- alternative quantities\n let itemQuantity: IngredientItemQuantity | undefined = undefined;\n if (groups.gIngredientQuantity) {\n const parsedQuantities = this._parseQuantityRecursive(\n groups.gIngredientQuantity,\n );\n const [primary, ...rest] = parsedQuantities;\n itemQuantity = {\n ...primary!, // there's necessarily a primary quantity as the match group was detected\n scalable: groups.gIngredientQuantityModifier !== \"=\",\n };\n if (rest.length > 0) {\n itemQuantity.equivalents = rest;\n }\n }\n\n const alternative: IngredientAlternative = {\n index: idxInList,\n displayName,\n };\n // Only add itemQuantity if it exists\n if (itemQuantity) {\n alternative.itemQuantity = itemQuantity;\n }\n\n const existingAlternatives = this.choices.ingredientGroups.get(groupKey);\n // For all alternative ingredients already processed for this group, add the new ingredient as alternative\n function upsertAlternativeToIngredient(\n ingredients: Ingredient[],\n ingredientIdx: number,\n newAlternativeIdx: number,\n ) {\n const ingredient = ingredients[ingredientIdx];\n // In practice, the ingredient will always be found\n /* v8 ignore else -- @preserve */\n if (ingredient) {\n if (ingredient.alternatives === undefined) {\n ingredient.alternatives = new Set([newAlternativeIdx]);\n } else {\n ingredient.alternatives.add(newAlternativeIdx);\n }\n }\n }\n if (existingAlternatives) {\n for (const alt of existingAlternatives) {\n upsertAlternativeToIngredient(this.ingredients, alt.index, idxInList);\n upsertAlternativeToIngredient(this.ingredients, idxInList, alt.index);\n }\n }\n const id = `ingredient-item-${this.getAndIncrementItemCount()}`;\n\n // Finalize item\n const newItem: IngredientItem = {\n type: \"ingredient\",\n id,\n group: groupKey,\n alternatives: [alternative],\n };\n items.push(newItem);\n\n // Populate or update choices\n const choiceAlternative = deepClone(alternative);\n choiceAlternative.itemId = id;\n const existingChoice = this.choices.ingredientGroups.get(groupKey);\n if (!existingChoice) {\n this.choices.ingredientGroups.set(groupKey, [choiceAlternative]);\n } else {\n existingChoice.push(choiceAlternative);\n }\n }\n\n /**\n * Populates the `quantities` property for each ingredient based on\n * how they appear in the recipe preparation. Only primary ingredients\n * get quantities populated. Primary ingredients get `usedAsPrimary: true` flag.\n *\n * For inline alternatives (e.g. `\\@a|b|c`), the first alternative is primary.\n * For grouped alternatives (e.g. `\\@|group|a`, `\\@|group|b`), the first item in the group is primary.\n *\n * Quantities are grouped by their alternative signature and summed using addEquivalentsAndSimplify.\n * @internal\n */\n private _populate_ingredient_quantities(): void {\n // Reset quantities and usedAsPrimary flag\n for (const ing of this.ingredients) {\n delete ing.quantities;\n delete ing.usedAsPrimary;\n }\n\n // Get ingredients with quantities using default (no explicit choice = primary with alternatives)\n const ingredientsWithQuantities = this.getIngredientQuantities();\n\n // Track which indices have been matched (for handling duplicate names)\n const matchedIndices = new Set<number>();\n\n // Copy quantities and usedAsPrimary to this.ingredients\n // Match by finding the first ingredient with same name that hasn't been matched yet\n for (const computed of ingredientsWithQuantities) {\n const idx = this.ingredients.findIndex(\n (ing, i) => ing.name === computed.name && !matchedIndices.has(i),\n );\n matchedIndices.add(idx);\n const ing = this.ingredients[idx]!;\n if (computed.quantities) {\n ing.quantities = computed.quantities;\n }\n if (computed.usedAsPrimary) {\n ing.usedAsPrimary = true;\n }\n }\n }\n\n /**\n * Gets ingredients with their quantities populated, optionally filtered by section/step\n * and respecting user choices for alternatives.\n *\n * When no options are provided, returns all recipe ingredients with quantities\n * calculated using primary alternatives (same as after parsing).\n *\n * @param options - Options for filtering and choice selection:\n * - `section`: Filter to a specific section (Section object or 0-based index)\n * - `step`: Filter to a specific step (Step object or 0-based index)\n * - `choices`: Choices for alternative ingredients (defaults to primary)\n * @returns Array of Ingredient objects with quantities populated\n *\n * @example\n * ```typescript\n * // Get all ingredients with primary alternatives\n * const ingredients = recipe.getIngredientQuantities();\n *\n * // Get ingredients for a specific section\n * const sectionIngredients = recipe.getIngredientQuantities({ section: 0 });\n *\n * // Get ingredients with specific choices applied\n * const withChoices = recipe.getIngredientQuantities({\n * choices: { ingredientItems: new Map([['ingredient-item-2', 1]]) }\n * });\n * ```\n */\n getIngredientQuantities(\n options?: GetIngredientQuantitiesOptions,\n ): Ingredient[] {\n const { section, step, choices } = options || {};\n\n // Determine sections to process\n const sectionsToProcess =\n section !== undefined\n ? (() => {\n const idx =\n typeof section === \"number\"\n ? section\n : this.sections.indexOf(section);\n return idx >= 0 && idx < this.sections.length\n ? [this.sections[idx]!]\n : [];\n })()\n : this.sections;\n\n // Type for accumulated quantities\n type QuantityAccumulator = {\n quantities: (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[];\n alternativeQuantities: Map<\n number,\n (QuantityWithExtendedUnit | FlatOrGroup<QuantityWithExtendedUnit>)[]\n >;\n };\n\n // Map: ingredientIndex -> alternativeSignature -> accumulated data\n const ingredientGroups = new Map<\n number,\n Map<string | null, QuantityAccumulator>\n >();\n\n // Track selected ingredients (get quantities + usedAsPrimary) and all referenced ingredients\n const selectedIndices = new Set<number>();\n const referencedIndices = new Set<number>();\n\n for (const currentSection of sectionsToProcess) {\n const allSteps = currentSection.content.filter(\n (item): item is Step => item.type === \"step\",\n );\n\n // Determine steps to process\n const stepsToProcess =\n step === undefined\n ? allSteps\n : typeof step === \"number\"\n ? step >= 0 && step < allSteps.length\n ? [allSteps[step]!]\n : []\n : allSteps.includes(step)\n ? [step]\n : [];\n\n for (const currentStep of stepsToProcess) {\n for (const item of currentStep.items.filter(\n (item): item is IngredientItem => item.type === \"ingredient\",\n )) {\n const isGrouped = \"group\" in item && item.group !== undefined;\n const groupAlternatives = isGrouped\n ? this.choices.ingredientGroups.get(item.group!)\n : undefined;\n\n // Determine selection state\n let selectedAltIndex = 0;\n let isSelected = false;\n let hasExplicitChoice = false;\n\n if (isGrouped) {\n const groupChoice = choices?.ingredientGroups?.get(item.group!);\n hasExplicitChoice = groupChoice !== undefined;\n const targetIndex = groupChoice ?? 0;\n isSelected = groupAlternatives?.[targetIndex]?.itemId === item.id;\n } else {\n const itemChoice = choices?.ingredientItems?.get(item.id);\n hasExplicitChoice = itemChoice !== undefined;\n selectedAltIndex = itemChoice ?? 0;\n isSelected = true;\n }\n\n const alternative = item.alternatives[selectedAltIndex];\n if (!alternative || !isSelected) continue;\n\n selectedIndices.add(alternative.index);\n\n // Add all alternatives to referenced set (so indices remain valid in result)\n const allAlts = isGrouped ? groupAlternatives! : item.alternatives;\n for (const alt of allAlts) {\n referencedIndices.add(alt.index);\n }\n\n if (!alternative.itemQuantity) continue;\n\n // Build quantity entry with equivalents\n const baseQty: QuantityWithExtendedUnit = {\n quantity: alternative.itemQuantity.quantity,\n ...(alternative.itemQuantity.unit && {\n unit: alternative.itemQuantity.unit,\n }),\n };\n const quantityEntry = alternative.itemQuantity.equivalents?.length\n ? { or: [baseQty, ...alternative.itemQuantity.equivalents] }\n : baseQty;\n\n // Build alternative refs (only when no explicit choice)\n let alternativeRefs: AlternativeIngredientRef[] | undefined;\n if (!hasExplicitChoice && allAlts.length > 1) {\n alternativeRefs = allAlts\n .filter((alt) =>\n isGrouped\n ? alt.itemId !== item.id\n : alt.index !== alternative.index,\n )\n .map((otherAlt) => {\n const ref: AlternativeIngredientRef = { index: otherAlt.index };\n if (otherAlt.itemQuantity) {\n const altQty: QuantityWithPlainUnit = {\n quantity: otherAlt.itemQuantity.quantity,\n ...(otherAlt.itemQuantity.unit && {\n unit: otherAlt.itemQuantity.unit.name,\n }),\n ...(otherAlt.itemQuantity.equivalents && {\n equivalents: otherAlt.itemQuantity.equivalents.map(\n (eq) => toPlainUnit(eq) as QuantityWithPlainUnit,\n ),\n }),\n };\n ref.quantities = [altQty];\n }\n return ref;\n });\n }\n\n // Get or create accumulator for this ingredient/signature\n // Use unit type+system for signature only when there are alternatives,\n // so compatible units (g/kg) group together but incompatible (cup/g) stay separate\n const altIndices = getAlternativeSignature(alternativeRefs) ?? \"\";\n let signature: string | null;\n if (isGrouped) {\n const resolvedUnit = resolveUnit(\n alternative.itemQuantity.unit?.name,\n );\n signature = `group:${item.group}|${altIndices}|${resolvedUnit.type}`;\n } else if (altIndices) {\n // Has alternatives: include unit type to keep incompatible units separate\n const resolvedUnit = resolveUnit(\n alternative.itemQuantity.unit?.name,\n );\n signature = `${altIndices}|${resolvedUnit.type}}`;\n } else {\n // No alternatives: use null to allow normal summing behavior\n signature = null;\n }\n\n if (!ingredientGroups.has(alternative.index)) {\n ingredientGroups.set(alternative.index, new Map());\n }\n const groupsForIng = ingredientGroups.get(alternative.index)!;\n if (!groupsForIng.has(signature)) {\n groupsForIng.set(signature, {\n quantities: [],\n alternativeQuantities: new Map(),\n });\n }\n const group = groupsForIng.get(signature)!;\n\n group.quantities.push(quantityEntry);\n\n // Accumulate alternative quantities\n for (const ref of alternativeRefs ?? []) {\n if (!group.alternativeQuantities.has(ref.index)) {\n group.alternativeQuantities.set(ref.index, []);\n }\n for (const altQty of ref.quantities ?? []) {\n const extended = toExtendedUnit({\n quantity: altQty.quantity,\n unit: altQty.unit,\n });\n if (altQty.equivalents?.length) {\n const eqEntries: QuantityWithExtendedUnit[] = [\n extended,\n ...altQty.equivalents.map((eq) => toExtendedUnit(eq)),\n ];\n group.alternativeQuantities\n .get(ref.index)!\n .push({ or: eqEntries });\n } else {\n group.alternativeQuantities.get(ref.index)!.push(extended);\n }\n }\n }\n }\n }\n }\n\n // Build result\n const result: Ingredient[] = [];\n\n for (let index = 0; index < this.ingredients.length; index++) {\n if (!referencedIndices.has(index)) continue;\n\n const orig = this.ingredients[index]!;\n const ing: Ingredient = {\n name: orig.name,\n ...(orig.preparation && { preparation: orig.preparation }),\n ...(orig.flags && { flags: orig.flags }),\n ...(orig.extras && { extras: orig.extras }),\n };\n\n if (selectedIndices.has(index)) {\n ing.usedAsPrimary = true;\n\n const groupsForIng = ingredientGroups.get(index);\n if (groupsForIng) {\n const quantityGroups: (\n | IngredientQuantityGroup\n | IngredientQuantityAndGroup\n )[] = [];\n\n for (const [, group] of groupsForIng) {\n const summed = addEquivalentsAndSimplify(...group.quantities);\n const flattened = flattenPlainUnitGroup(summed);\n\n // Build alternatives from accumulated quantities\n const alternatives: AlternativeIngredientRef[] | undefined =\n group.alternativeQuantities.size > 0\n ? [...group.alternativeQuantities].map(([altIdx, altQtys]) => ({\n index: altIdx,\n ...(altQtys.length > 0 && {\n quantities: flattenPlainUnitGroup(\n addEquivalentsAndSimplify(...altQtys),\n ).flatMap(\n /* v8 ignore next -- item.and branch requires complex nested AND-with-equivalents structure */\n (item) => (\"quantity\" in item ? [item] : item.and),\n ),\n }),\n }))\n : undefined;\n\n for (const gq of flattened) {\n if (\"and\" in gq) {\n quantityGroups.push({\n and: gq.and,\n ...(gq.equivalents?.length && {\n equivalents: gq.equivalents,\n }),\n ...(alternatives?.length && { alternatives }),\n });\n } else {\n quantityGroups.push({\n ...(gq as IngredientQuantityGroup),\n ...(alternatives?.length && { alternatives }),\n });\n }\n }\n }\n\n // v8 ignore else -- @preserve\n if (quantityGroups.length > 0) {\n ing.quantities = quantityGroups;\n }\n }\n }\n\n result.push(ing);\n }\n\n return result;\n }\n\n /**\n * Parses a recipe from a string.\n * @param content - The recipe content to parse.\n */\n parse(content: string) {\n // Remove noise\n const cleanContent = content\n .replace(metadataRegex, \"\")\n .replace(commentRegex, \"\")\n .replace(blockCommentRegex, \"\")\n .trim()\n .split(/\\r\\n?|\\n/);\n\n // Metadata\n const { metadata, servings }: MetadataExtract = extractMetadata(content);\n this.metadata = metadata;\n this.servings = servings;\n\n // Initializing utility variables and property bearers\n let blankLineBefore = true;\n let section: Section = new Section();\n const items: Step[\"items\"] = [];\n let noteText = \"\";\n let inNote = false;\n\n // We parse content line by line\n for (const line of cleanContent) {\n // A blank line triggers flushing pending stuff\n if (line.trim().length === 0) {\n flushPendingItems(section, items);\n flushPendingNote(\n section,\n noteText ? this._parseNoteText(noteText) : [],\n );\n noteText = \"\";\n blankLineBefore = true;\n inNote = false;\n continue;\n }\n\n // New section\n if (line.startsWith(\"=\")) {\n flushPendingItems(section, items);\n flushPendingNote(\n section,\n noteText ? this._parseNoteText(noteText) : [],\n );\n noteText = \"\";\n\n if (this.sections.length === 0 && section.isBlank()) {\n section.name = line.replace(/^=+|=+$/g, \"\").trim();\n } else {\n /* v8 ignore else -- @preserve */\n if (!section.isBlank()) {\n this.sections.push(section);\n }\n section = new Section(line.replace(/^=+|=+$/g, \"\").trim());\n }\n blankLineBefore = true;\n inNote = false;\n continue;\n }\n\n // New note\n if (blankLineBefore && line.startsWith(\">\")) {\n flushPendingItems(section, items);\n noteText = line.substring(1).trim();\n inNote = true;\n blankLineBefore = false;\n continue;\n }\n\n // Continue note\n if (inNote) {\n if (line.startsWith(\">\")) {\n noteText += \" \" + line.substring(1).trim();\n } else {\n noteText += \" \" + line.trim();\n }\n blankLineBefore = false;\n continue;\n }\n\n // Detecting items\n let cursor = 0;\n for (const match of line.matchAll(tokensRegex)) {\n const idx = match.index;\n /* v8 ignore else -- @preserve */\n if (idx > cursor) {\n items.push({ type: \"text\", value: line.slice(cursor, idx) });\n }\n\n const groups = match.groups!;\n\n // Ingredient items with potential in-line alternatives\n if (groups.mIngredientName || groups.sIngredientName) {\n this._parseIngredientWithAlternativeRecursive(match[0], items);\n }\n // Ingredient items part of a group of alternative ingredients\n else if (groups.gmIngredientName || groups.gsIngredientName) {\n this._parseIngredientWithGroupKey(match[0], items);\n }\n // Cookware items\n else if (groups.mCookwareName || groups.sCookwareName) {\n const name = (groups.mCookwareName || groups.sCookwareName)!;\n const modifiers = groups.cookwareModifiers;\n const quantityRaw = groups.cookwareQuantity;\n const reference = modifiers !== undefined && modifiers.includes(\"&\");\n const flags: CookwareFlag[] = [];\n if (modifiers !== undefined && modifiers.includes(\"?\")) {\n flags.push(\"optional\");\n }\n if (modifiers !== undefined && modifiers.includes(\"-\")) {\n flags.push(\"hidden\");\n }\n const quantity = quantityRaw\n ? parseQuantityInput(quantityRaw)\n : undefined;\n const newCookware: Cookware = {\n name,\n };\n if (quantity) {\n newCookware.quantity = quantity;\n }\n if (flags.length > 0) {\n newCookware.flags = flags;\n }\n\n // Add cookware in cookware list\n const idxInList = findAndUpsertCookware(\n this.cookware,\n newCookware,\n reference,\n );\n\n // Adding the item itself in the preparation\n const newItem: CookwareItem = {\n type: \"cookware\",\n index: idxInList,\n };\n if (quantity) {\n newItem.quantity = quantity;\n }\n items.push(newItem);\n }\n // Arbitrary scalable quantities\n else if (groups.arbitraryQuantity) {\n this._parseArbitraryScalable(groups, items);\n }\n // Then it's necessarily a timer which was matched\n else {\n const durationStr = groups.timerQuantity!.trim();\n const unit = (groups.timerUnit || \"\").trim();\n if (!unit) {\n throw new Error(\"Timer missing unit\");\n }\n const name = groups.timerName || undefined;\n const duration = parseQuantityInput(durationStr);\n const timerObj: Timer = {\n name,\n duration,\n unit,\n };\n items.push({ type: \"timer\", index: this.timers.push(timerObj) - 1 });\n }\n\n cursor = idx + match[0].length;\n }\n\n if (cursor < line.length) {\n items.push({ type: \"text\", value: line.slice(cursor) });\n }\n\n blankLineBefore = false;\n }\n\n // End of content reached: pushing all temporarily saved elements\n flushPendingItems(section, items);\n flushPendingNote(section, noteText ? this._parseNoteText(noteText) : []);\n if (!section.isBlank()) {\n this.sections.push(section);\n }\n\n this._populate_ingredient_quantities();\n }\n\n /**\n * Scales the recipe to a new number of servings. In practice, it calls\n * {@link Recipe.scaleBy | scaleBy} with a factor corresponding to the ratio between `newServings`\n * and the recipe's {@link Recipe.servings | servings} value.\n * @param newServings - The new number of servings.\n * @returns A new Recipe instance with the scaled ingredients.\n * @throws `Error` if the recipe does not contains an initial {@link Recipe.servings | servings} value\n */\n scaleTo(newServings: number): Recipe {\n let originalServings = this.getServings();\n\n // Default to 1 if no servings defined\n if (originalServings === undefined || originalServings === 0) {\n originalServings = 1;\n }\n\n const factor = Big(newServings).div(originalServings);\n return this.scaleBy(factor);\n }\n\n /**\n * Scales the recipe by a factor.\n * @param factor - The factor to scale the recipe by. While integers can be passed as-is, it is recommended to pass fractions as\n * [Big](https://github.com/MikeMcl/big.js/) values, e.g. `Big(num).div(den)` in order to avoid undesirable floating point operation inaccuracies.\n * @returns A new Recipe instance with the scaled ingredients.\n */\n scaleBy(factor: number | Big): Recipe {\n const newRecipe = this.clone();\n\n let originalServings = newRecipe.getServings();\n\n // Default to 1 if no servings defined\n if (originalServings === undefined || originalServings === 0) {\n originalServings = 1;\n }\n\n function scaleAlternativesBy(\n alternatives: IngredientAlternative[],\n factor: number | Big,\n ) {\n for (const alternative of alternatives) {\n if (alternative.itemQuantity) {\n const scaleFactor = alternative.itemQuantity.scalable\n ? Big(factor)\n : 1;\n // Scale the primary quantity\n if (\n alternative.itemQuantity.quantity.type !== \"fixed\" ||\n alternative.itemQuantity.quantity.value.type !== \"text\"\n ) {\n alternative.itemQuantity.quantity = multiplyQuantityValue(\n alternative.itemQuantity.quantity,\n scaleFactor,\n );\n }\n // Scale equivalents if any\n if (alternative.itemQuantity.equivalents) {\n alternative.itemQuantity.equivalents =\n alternative.itemQuantity.equivalents.map(\n (altQuantity: QuantityWithExtendedUnit) => {\n if (\n altQuantity.quantity.type === \"fixed\" &&\n altQuantity.quantity.value.type === \"text\"\n ) {\n return altQuantity;\n } else {\n return {\n ...altQuantity,\n quantity: multiplyQuantityValue(\n altQuantity.quantity,\n scaleFactor,\n ),\n };\n }\n },\n );\n }\n }\n }\n }\n\n // Scale IngredientItems\n for (const section of newRecipe.sections) {\n for (const step of section.content.filter(\n (item) => item.type === \"step\",\n )) {\n for (const item of step.items.filter(\n (item) => item.type === \"ingredient\",\n )) {\n scaleAlternativesBy(item.alternatives, factor);\n }\n }\n }\n\n // Scale Choices\n for (const alternatives of newRecipe.choices.ingredientGroups.values()) {\n scaleAlternativesBy(alternatives, factor);\n }\n for (const alternatives of newRecipe.choices.ingredientItems.values()) {\n scaleAlternativesBy(alternatives, factor);\n }\n\n // Scale Arbitraries\n for (const arbitrary of newRecipe.arbitraries) {\n arbitrary.quantity = multiplyQuantityValue(\n arbitrary.quantity,\n factor,\n ) as FixedNumericValue;\n }\n\n newRecipe._populate_ingredient_quantities();\n\n newRecipe.servings = Big(originalServings).times(factor).toNumber();\n\n /* v8 ignore else -- @preserve */\n if (newRecipe.metadata.servings && this.metadata.servings) {\n if (\n floatRegex.test(String(this.metadata.servings).replace(\",\", \".\").trim())\n ) {\n const servingsValue = parseFloat(\n String(this.metadata.servings).replace(\",\", \".\"),\n );\n newRecipe.metadata.servings = String(\n Big(servingsValue).times(factor).toNumber(),\n );\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (newRecipe.metadata.yield && this.metadata.yield) {\n if (\n floatRegex.test(String(this.metadata.yield).replace(\",\", \".\").trim())\n ) {\n const yieldValue = parseFloat(\n String(this.metadata.yield).replace(\",\", \".\"),\n );\n newRecipe.metadata.yield = String(\n Big(yieldValue).times(factor).toNumber(),\n );\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (newRecipe.metadata.serves && this.metadata.serves) {\n if (\n floatRegex.test(String(this.metadata.serves).replace(\",\", \".\").trim())\n ) {\n const servesValue = parseFloat(\n String(this.metadata.serves).replace(\",\", \".\"),\n );\n newRecipe.metadata.serves = String(\n Big(servesValue).times(factor).toNumber(),\n );\n }\n }\n\n return newRecipe;\n }\n\n /**\n * Gets the number of servings for the recipe.\n * @private\n * @returns The number of servings, or undefined if not set.\n */\n private getServings(): number | undefined {\n if (this.servings) {\n return this.servings;\n }\n return undefined;\n }\n\n /**\n * Clones the recipe.\n * @returns A new Recipe instance with the same properties.\n */\n clone(): Recipe {\n const newRecipe = new Recipe();\n newRecipe.choices = deepClone(this.choices);\n Recipe.itemCounts.set(newRecipe, this.getItemCount());\n // deep copy\n newRecipe.metadata = deepClone(this.metadata);\n newRecipe.ingredients = deepClone(this.ingredients);\n newRecipe.sections = this.sections.map((section) => {\n const newSection = new Section(section.name);\n newSection.content = deepClone(section.content);\n return newSection;\n });\n newRecipe.cookware = deepClone(this.cookware);\n newRecipe.timers = deepClone(this.timers);\n newRecipe.arbitraries = deepClone(this.arbitraries);\n newRecipe.servings = this.servings;\n return newRecipe;\n }\n}\n","import { CategoryConfig } from \"./category_config\";\nimport { Recipe } from \"./recipe\";\nimport type {\n CategorizedIngredients,\n AddedRecipe,\n AddedIngredient,\n QuantityWithExtendedUnit,\n QuantityWithPlainUnit,\n MaybeNestedGroup,\n FlatOrGroup,\n AddedRecipeOptions,\n} from \"../types\";\nimport { addEquivalentsAndSimplify } from \"../quantities/alternatives\";\nimport { extendAllUnits } from \"../quantities/mutations\";\nimport { isAndGroup } from \"../utils/type_guards\";\n\n/**\n * Shopping List generator.\n *\n * ## Usage\n *\n * - Create a new ShoppingList instance with an optional category configuration (see {@link ShoppingList.\"constructor\" | constructor})\n * - Add recipes, scaling them as needed (see {@link ShoppingList.add_recipe | add_recipe()})\n * - Categorize the ingredients (see {@link ShoppingList.categorize | categorize()})\n *\n * @example\n *\n * ```typescript\n * import * as fs from \"fs\";\n * import { ShoppingList } from @tmlmt/cooklang-parser;\n *\n * const categoryConfig = fs.readFileSync(\"./myconfig.txt\", \"utf-8\")\n * const recipe1 = new Recipe(fs.readFileSync(\"./myrecipe.cook\", \"utf-8\"));\n * const shoppingList = new ShoppingList();\n * shoppingList.set_category_config(categoryConfig);\n * // Quantities are automatically calculated and ingredients categorized\n * // when adding a recipe\n * shoppingList.add_recipe(recipe1);\n * ```\n *\n * @category Classes\n */\nexport class ShoppingList {\n // TODO: backport type change\n /**\n * The ingredients in the shopping list.\n */\n ingredients: AddedIngredient[] = [];\n /**\n * The recipes in the shopping list.\n */\n recipes: AddedRecipe[] = [];\n /**\n * The category configuration for the shopping list.\n */\n category_config?: CategoryConfig;\n /**\n * The categorized ingredients in the shopping list.\n */\n categories?: CategorizedIngredients;\n\n /**\n * Creates a new ShoppingList instance\n * @param category_config_str - The category configuration to parse.\n */\n constructor(category_config_str?: string | CategoryConfig) {\n if (category_config_str) {\n this.set_category_config(category_config_str);\n }\n }\n\n private calculate_ingredients() {\n this.ingredients = [];\n\n const addIngredientQuantity = (\n name: string,\n quantityTotal:\n | QuantityWithPlainUnit\n | MaybeNestedGroup<QuantityWithPlainUnit>,\n ) => {\n const quantityTotalExtended = extendAllUnits(quantityTotal);\n const newQuantities = (\n isAndGroup(quantityTotalExtended)\n ? quantityTotalExtended.and\n : [quantityTotalExtended]\n ) as (QuantityWithExtendedUnit | FlatOrGroup<QuantityWithExtendedUnit>)[];\n const existing = this.ingredients.find((i) => i.name === name);\n\n if (existing) {\n if (!existing.quantityTotal) {\n existing.quantityTotal = quantityTotal;\n return;\n }\n try {\n const existingQuantityTotalExtended = extendAllUnits(\n existing.quantityTotal,\n );\n const existingQuantities = (\n isAndGroup(existingQuantityTotalExtended)\n ? existingQuantityTotalExtended.and\n : [existingQuantityTotalExtended]\n ) as (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[];\n existing.quantityTotal = addEquivalentsAndSimplify(\n ...existingQuantities,\n ...newQuantities,\n );\n return;\n } catch {\n // Incompatible\n }\n }\n\n this.ingredients.push({\n name,\n quantityTotal,\n });\n };\n\n for (const addedRecipe of this.recipes) {\n let scaledRecipe: Recipe;\n if (\"factor\" in addedRecipe) {\n const { recipe, factor } = addedRecipe;\n scaledRecipe = factor === 1 ? recipe : recipe.scaleBy(factor);\n } else {\n scaledRecipe = addedRecipe.recipe.scaleTo(addedRecipe.servings);\n }\n\n // Get computed ingredients with total quantities based on choices (or default)\n const ingredients = scaledRecipe.getIngredientQuantities({\n choices: addedRecipe.choices,\n });\n\n for (const ingredient of ingredients) {\n // Do not add hidden ingredients to the shopping list\n if (ingredient.flags && ingredient.flags.includes(\"hidden\")) {\n continue;\n }\n\n // Only add ingredients that were selected (have usedAsPrimary flag)\n // This filters out alternative ingredients that weren't chosen\n if (!ingredient.usedAsPrimary) {\n continue;\n }\n\n // Sum up quantities from the ingredient's quantity groups\n if (ingredient.quantities && ingredient.quantities.length > 0) {\n // Extract all quantities (converting to plain units for summing)\n const allQuantities: (\n | QuantityWithPlainUnit\n | MaybeNestedGroup<QuantityWithPlainUnit>\n )[] = [];\n for (const qGroup of ingredient.quantities) {\n if (\"and\" in qGroup) {\n // AndGroup - add each quantity separately\n for (const qty of qGroup.and) {\n allQuantities.push(qty);\n }\n } else {\n // Simple quantity (strip alternatives - choices already applied)\n const plainQty: QuantityWithPlainUnit = {\n quantity: qGroup.quantity,\n };\n if (qGroup.unit) plainQty.unit = qGroup.unit;\n if (qGroup.equivalents) plainQty.equivalents = qGroup.equivalents;\n allQuantities.push(plainQty);\n }\n }\n if (allQuantities.length === 1) {\n addIngredientQuantity(ingredient.name, allQuantities[0]!);\n } else {\n // allQuantities.length > 1\n // Sum up using addEquivalentsAndSimplify\n const extendedQuantities = allQuantities.map((q) =>\n extendAllUnits(q),\n );\n const totalQuantity = addEquivalentsAndSimplify(\n ...(extendedQuantities as (\n | QuantityWithExtendedUnit\n | FlatOrGroup<QuantityWithExtendedUnit>\n )[]),\n );\n // addEquivalentsAndSimplify already returns plain units\n addIngredientQuantity(ingredient.name, totalQuantity);\n }\n } else if (!this.ingredients.some((i) => i.name === ingredient.name)) {\n this.ingredients.push({ name: ingredient.name });\n }\n }\n }\n }\n\n /**\n * Adds a recipe to the shopping list, then automatically\n * recalculates the quantities and recategorize the ingredients.\n * @param recipe - The recipe to add.\n * @param options - Options for adding the recipe.\n * @throws Error if the recipe has alternatives without corresponding choices.\n */\n add_recipe(recipe: Recipe, options: AddedRecipeOptions = {}): void {\n // Validate that choices are provided for all alternatives\n const errorMessage = this.getUnresolvedAlternativesError(\n recipe,\n options.choices,\n );\n if (errorMessage) {\n throw new Error(errorMessage);\n }\n\n if (!options.scaling) {\n this.recipes.push({\n recipe,\n factor: options.scaling ?? 1,\n choices: options.choices,\n });\n } else {\n if (\"factor\" in options.scaling) {\n this.recipes.push({\n recipe,\n factor: options.scaling.factor,\n choices: options.choices,\n });\n } else {\n this.recipes.push({\n recipe,\n servings: options.scaling.servings,\n choices: options.choices,\n });\n }\n }\n this.calculate_ingredients();\n this.categorize();\n }\n\n /**\n * Checks if a recipe has unresolved alternatives (alternatives without provided choices).\n * @param recipe - The recipe to check.\n * @param choices - The choices provided for the recipe.\n * @returns An error message if there are unresolved alternatives, undefined otherwise.\n */\n private getUnresolvedAlternativesError(\n recipe: Recipe,\n choices?: import(\"../types\").RecipeChoices,\n ): string | undefined {\n const missingItems: string[] = [];\n const missingGroups: string[] = [];\n\n // Check for inline alternatives without choices\n for (const itemId of recipe.choices.ingredientItems.keys()) {\n if (!choices?.ingredientItems?.has(itemId)) {\n missingItems.push(itemId);\n }\n }\n\n // Check for grouped alternatives without choices\n for (const groupId of recipe.choices.ingredientGroups.keys()) {\n if (!choices?.ingredientGroups?.has(groupId)) {\n missingGroups.push(groupId);\n }\n }\n\n if (missingItems.length === 0 && missingGroups.length === 0) {\n return undefined;\n }\n\n const parts: string[] = [];\n if (missingItems.length > 0) {\n parts.push(\n `ingredientItems: [${missingItems.map((i) => `'${i}'`).join(\", \")}]`,\n );\n }\n if (missingGroups.length > 0) {\n parts.push(\n `ingredientGroups: [${missingGroups.map((g) => `'${g}'`).join(\", \")}]`,\n );\n }\n return `Recipe has unresolved alternatives. Missing choices for: ${parts.join(\", \")}`;\n }\n\n /**\n * Removes a recipe from the shopping list, then automatically\n * recalculates the quantities and recategorize the ingredients.s\n * @param index - The index of the recipe to remove.\n */\n remove_recipe(index: number) {\n if (index < 0 || index >= this.recipes.length) {\n throw new Error(\"Index out of bounds\");\n }\n this.recipes.splice(index, 1);\n this.calculate_ingredients();\n this.categorize();\n }\n\n /**\n * Sets the category configuration for the shopping list\n * and automatically categorize current ingredients from the list.\n * @param config - The category configuration to parse.\n */\n set_category_config(config: string | CategoryConfig) {\n if (typeof config === \"string\")\n this.category_config = new CategoryConfig(config);\n else if (config instanceof CategoryConfig) this.category_config = config;\n else throw new Error(\"Invalid category configuration\");\n this.categorize();\n }\n\n /**\n * Categorizes the ingredients in the shopping list\n * Will use the category config if any, otherwise all ingredients will be placed in the \"other\" category\n */\n categorize() {\n if (!this.category_config) {\n this.categories = { other: this.ingredients };\n return;\n }\n\n const categories: CategorizedIngredients = { other: [] };\n for (const category of this.category_config.categories) {\n categories[category.name] = [];\n }\n\n for (const ingredient of this.ingredients) {\n let found = false;\n for (const category of this.category_config.categories) {\n for (const categoryIngredient of category.ingredients) {\n if (categoryIngredient.aliases.includes(ingredient.name)) {\n categories[category.name]!.push(ingredient);\n found = true;\n break;\n }\n }\n if (found) {\n break;\n }\n }\n if (!found) {\n categories.other!.push(ingredient);\n }\n }\n\n this.categories = categories;\n }\n}\n","import type {\n ProductOption,\n ProductSelection,\n AddedIngredient,\n CartContent,\n CartMatch,\n CartMisMatch,\n FixedNumericValue,\n Range,\n ProductOptionNormalized,\n ProductSizeNormalized,\n NoProductMatchErrorCode,\n FlatOrGroup,\n MaybeNestedGroup,\n QuantityWithUnitDef,\n} from \"../types\";\nimport { ProductCatalog } from \"./product_catalog\";\nimport { ShoppingList } from \"./shopping_list\";\nimport {\n NoProductCatalogForCartError,\n NoShoppingListForCartError,\n NoProductMatchError,\n} from \"../errors\";\nimport { resolveUnit } from \"../units/definitions\";\nimport { normalizeAllUnits } from \"../quantities/mutations\";\nimport { getNumericValue, multiplyQuantityValue } from \"../quantities/numeric\";\nimport { isAndGroup, isOrGroup } from \"../utils/type_guards\";\nimport { areUnitsCompatible } from \"../units/lookup\";\nimport { solve, type Model } from \"yalps\";\n\n/**\n * Options for the {@link ShoppingCart} constructor\n * @category Types\n */\nexport interface ShoppingCartOptions {\n /**\n * A product catalog to connect to the cart\n */\n catalog?: ProductCatalog;\n /**\n * A shopping list to connect to the cart\n */\n list?: ShoppingList;\n}\n\n/**\n * Key information about the {@link ShoppingCart}\n * @category Types\n */\nexport interface ShoppingCartSummary {\n /**\n * The total price of the cart\n */\n totalPrice: number;\n /**\n * The total number of items in the cart\n */\n totalItems: number;\n}\n\n/**\n * Shopping Cart Manager: a tool to find the best combination of products to buy (defined in a {@link ProductCatalog}) to satisfy a {@link ShoppingList}.\n *\n * @example\n * ```ts\n * const shoppingList = new ShoppingList();\n * const recipe = new Recipe(\"@flour{600%g}\");\n * shoppingList.add_recipe(recipe);\n *\n * const catalog = new ProductCatalog();\n * catalog.products = [\n * {\n * id: \"flour-1kg\",\n * productName: \"Flour (1kg)\",\n * ingredientName: \"flour\",\n * price: 10,\n * size: { type: \"fixed\", value: { type: \"decimal\", value: 1000 } },\n * unit: \"g\",\n * },\n * {\n * id: \"flour-500g\",\n * productName: \"Flour (500g)\",\n * ingredientName: \"flour\",\n * price: 6,\n * size: { type: \"fixed\", value: { type: \"decimal\", value: 500 } },\n * unit: \"g\",\n * },\n * ];\n *\n * const shoppingCart = new ShoppingCart({list: shoppingList, catalog}))\n * shoppingCart.buildCart();\n * ```\n *\n * @category Classes\n */\nexport class ShoppingCart {\n /**\n * The product catalog to use for matching products\n */\n productCatalog?: ProductCatalog;\n /**\n * The shopping list to build the cart from\n */\n shoppingList?: ShoppingList;\n /**\n * The content of the cart\n */\n cart: CartContent = [];\n /**\n * The ingredients that were successfully matched with products\n */\n match: CartMatch = [];\n /**\n * The ingredients that could not be matched with products\n */\n misMatch: CartMisMatch = [];\n /**\n * Key information about the shopping cart\n */\n summary: ShoppingCartSummary;\n\n /**\n * Creates a new ShoppingCart instance\n * @param options - {@link ShoppingCartOptions | Options} for the constructor\n */\n constructor(options?: ShoppingCartOptions) {\n if (options?.catalog) this.productCatalog = options.catalog;\n if (options?.list) this.shoppingList = options.list;\n this.summary = { totalPrice: 0, totalItems: 0 };\n }\n\n /**\n * Sets the product catalog to use for matching products\n * To use if a catalog was not provided at the creation of the instance\n * @param catalog - The {@link ProductCatalog} to set\n */\n setProductCatalog(catalog: ProductCatalog) {\n this.productCatalog = catalog;\n }\n\n // TODO: harmonize recipe name to use underscores\n /**\n * Sets the shopping list to build the cart from.\n * To use if a shopping list was not provided at the creation of the instance\n * @param list - The {@link ShoppingList} to set\n */\n setShoppingList(list: ShoppingList) {\n this.shoppingList = list;\n }\n\n /**\n * Builds the cart from the shopping list and product catalog\n * @remarks\n * - If a combination of product(s) is successfully found for a given ingredient, the latter will be listed in the {@link ShoppingCart.match | match} array\n * in addition to that combination being added to the {@link ShoppingCart.cart | cart}.\n * - Otherwise, the latter will be listed in the {@link ShoppingCart.misMatch | misMatch} array. Possible causes can be:\n * - No product is listed in the catalog for that ingredient\n * - The ingredient has no quantity, a text quantity\n * - The ingredient's quantity unit is incompatible with the units of the candidate products listed in the catalog\n * @throws {@link NoProductCatalogForCartError} if no product catalog is set\n * @throws {@link NoShoppingListForCartError} if no shopping list is set\n * @returns `true` if all ingredients in the shopping list have been matched to products in the catalog, or `false` otherwise\n */\n buildCart(): boolean {\n this.resetCart();\n\n if (this.productCatalog === undefined) {\n throw new NoProductCatalogForCartError();\n } else if (this.shoppingList === undefined) {\n throw new NoShoppingListForCartError();\n }\n\n for (const ingredient of this.shoppingList.ingredients) {\n const productOptions = this.getProductOptions(ingredient);\n try {\n const optimumMatch = this.getOptimumMatch(ingredient, productOptions);\n this.cart.push(...optimumMatch);\n this.match.push({ ingredient, selection: optimumMatch });\n } catch (error) {\n /* v8 ignore else -- @preserve */\n if (error instanceof NoProductMatchError) {\n this.misMatch.push({ ingredient, reason: error.code });\n }\n }\n }\n\n this.summarize();\n\n return this.misMatch.length > 0;\n }\n\n /**\n * Gets the product options for a given ingredient\n * @param ingredient - The ingredient to get the product options for\n * @returns An array of {@link ProductOption}\n */\n private getProductOptions(ingredient: AddedIngredient): ProductOption[] {\n // this function is only called in buildCart() which starts by checking that a product catalog is present\n return this.productCatalog!.products.filter(\n (product) =>\n product.ingredientName === ingredient.name ||\n product.ingredientAliases?.includes(ingredient.name),\n );\n }\n\n /**\n * Gets the optimum match for a given ingredient and product option\n * @param ingredient - The ingredient to match\n * @param options - The product options to choose from\n * @returns An array of {@link ProductSelection}\n * @throws {@link NoProductMatchError} if no match can be found\n */\n private getOptimumMatch(\n ingredient: AddedIngredient,\n options: ProductOption[],\n ): ProductSelection[] {\n // If there's no product option, return an empty match\n if (options.length === 0)\n throw new NoProductMatchError(ingredient.name, \"noProduct\");\n // If the ingredient has no quantity, we can't match any product\n if (!ingredient.quantityTotal)\n throw new NoProductMatchError(ingredient.name, \"noQuantity\");\n\n // Normalize options units and scale size to base\n const normalizedOptions: ProductOptionNormalized[] = options.map(\n (option) => ({\n ...option,\n sizes: option.sizes.map((s): ProductSizeNormalized => {\n const resolvedUnit = resolveUnit(s.unit);\n return {\n size:\n resolvedUnit && \"toBase\" in resolvedUnit\n ? (multiplyQuantityValue(\n s.size,\n resolvedUnit.toBase,\n ) as FixedNumericValue)\n : s.size,\n unit: resolvedUnit,\n };\n }),\n }),\n );\n const normalizedQuantityTotal = normalizeAllUnits(ingredient.quantityTotal);\n\n function getOptimumMatchForQuantityParts(\n normalizedQuantities:\n | QuantityWithUnitDef\n | MaybeNestedGroup<QuantityWithUnitDef>,\n normalizedOptions: ProductOptionNormalized[],\n selection: ProductSelection[] = [],\n ): ProductSelection[] {\n if (isAndGroup(normalizedQuantities)) {\n for (const q of normalizedQuantities.and) {\n const result = getOptimumMatchForQuantityParts(\n q,\n normalizedOptions,\n selection,\n );\n selection.push(...result);\n }\n } else {\n const alternativeUnitsOfQuantity = isOrGroup(normalizedQuantities)\n ? (normalizedQuantities as FlatOrGroup<QuantityWithUnitDef>).or\n : [normalizedQuantities];\n const solutions: ProductSelection[][] = [];\n const errors = new Set<NoProductMatchErrorCode>();\n for (const alternative of alternativeUnitsOfQuantity) {\n // At this stage, we're treating individual Quantities we should try to match\n if (\n alternative.quantity.type === \"fixed\" &&\n alternative.quantity.value.type === \"text\"\n ) {\n errors.add(\"textValue\");\n continue;\n }\n // At this stage, we know there is a numerical quantity\n // So we scale it to base in order to calculate the correct quantity\n const scaledQuantity = multiplyQuantityValue(\n alternative.quantity,\n \"toBase\" in alternative.unit ? alternative.unit.toBase : 1,\n ) as FixedNumericValue | Range;\n alternative.quantity = scaledQuantity;\n // Are there compatible product options for that specific unit alternative?\n // A product is compatible if ANY of its sizes has a compatible unit\n const matchOptions = normalizedOptions.filter((option) =>\n option.sizes.some((s) =>\n areUnitsCompatible(alternative.unit, s.unit),\n ),\n );\n if (matchOptions.length > 0) {\n // Helper to find the compatible size for a product option\n const findCompatibleSize = (\n option: ProductOptionNormalized,\n ): ProductSizeNormalized =>\n option.sizes.find((s) =>\n areUnitsCompatible(alternative.unit, s.unit),\n )!;\n\n // Simple minimization exercise if only one product option\n if (matchOptions.length == 1) {\n const matchedOption = matchOptions[0]!;\n const compatibleSize = findCompatibleSize(matchedOption);\n const product = options.find(\n (opt) => opt.id === matchedOption.id,\n )!;\n // FixedValue\n const targetQuantity =\n scaledQuantity.type === \"fixed\"\n ? scaledQuantity.value\n : scaledQuantity.min;\n const resQuantity = Math.ceil(\n getNumericValue(targetQuantity) /\n getNumericValue(compatibleSize.size.value),\n );\n solutions.push([\n {\n product,\n quantity: resQuantity,\n totalPrice: resQuantity * matchedOption.price,\n },\n ]);\n continue;\n }\n\n // More complex problem if there are several options\n const model: Model = {\n direction: \"minimize\",\n objective: \"price\",\n integers: true,\n constraints: {\n size: {\n min:\n scaledQuantity.type === \"fixed\"\n ? getNumericValue(scaledQuantity.value)\n : getNumericValue(scaledQuantity.min),\n },\n },\n variables: matchOptions.reduce(\n (acc, option) => {\n const compatibleSize = findCompatibleSize(option);\n acc[option.id] = {\n price: option.price,\n size: getNumericValue(compatibleSize.size.value),\n };\n return acc;\n },\n {} as Record<string, { price: number; size: number }>,\n ),\n };\n\n const solution = solve(model);\n solutions.push(\n solution.variables.map((variable) => {\n const resProductSelection = {\n product: options.find((option) => option.id === variable[0])!,\n quantity: variable[1],\n };\n return {\n ...resProductSelection,\n totalPrice:\n resProductSelection.quantity *\n resProductSelection.product.price,\n };\n }),\n );\n } else {\n errors.add(\"incompatibleUnits\");\n }\n }\n // All alternatives were checked\n if (solutions.length === 0) {\n throw new NoProductMatchError(\n ingredient.name,\n errors.size === 1\n ? (errors.values().next().value as NoProductMatchErrorCode)\n : \"textValue_incompatibleUnits\",\n );\n } else {\n // We return the cheapest solution among those found\n return solutions.sort(\n (a, b) =>\n a.reduce((acc, item) => acc + item.totalPrice, 0) -\n b.reduce((acc, item) => acc + item.totalPrice, 0),\n )[0]!;\n }\n }\n return selection;\n }\n\n return getOptimumMatchForQuantityParts(\n normalizedQuantityTotal,\n normalizedOptions,\n );\n }\n\n /**\n * Reset the cart's properties\n */\n private resetCart() {\n this.cart = [];\n this.match = [];\n this.misMatch = [];\n this.summary = { totalPrice: 0, totalItems: 0 };\n }\n\n /**\n * Calculate the cart's key info and store it in the cart's {@link ShoppingCart.summary | summary} property.\n * This function is automatically invoked by {@link ShoppingCart.buildCart | buildCart() } method.\n * @returns the total price and number of items in the cart\n */\n summarize(): ShoppingCartSummary {\n this.summary.totalPrice = this.cart.reduce(\n (acc, item) => acc + item.totalPrice,\n 0,\n );\n this.summary.totalItems = this.cart.length;\n return this.summary;\n }\n}\n","import type {\n IngredientItem,\n RecipeChoices,\n FixedValue,\n Range,\n TextValue,\n DecimalValue,\n FractionValue,\n Unit,\n QuantityWithExtendedUnit,\n IngredientItemQuantity,\n} from \"../types\";\nimport { Recipe } from \"../classes/recipe\";\n\n// ============================================================================\n// Quantity Formatting Helpers\n// ============================================================================\n\n/**\n * Format a numeric value (decimal or fraction) to a string.\n *\n * @param value - The decimal or fraction value to format\n * @returns The formatted string representation\n * @category Helpers\n *\n * @example\n * ```typescript\n * formatNumericValue({ type: \"decimal\", decimal: 1.5 }); // \"1.5\"\n * formatNumericValue({ type: \"fraction\", num: 1, den: 2 }); // \"1/2\"\n * ```\n */\nexport function formatNumericValue(\n value: DecimalValue | FractionValue,\n): string {\n if (value.type === \"decimal\") {\n return String(value.decimal);\n }\n return `${value.num}/${value.den}`;\n}\n\n/**\n * Format a single value (text, decimal, or fraction) to a string.\n *\n * @param value - The value to format\n * @returns The formatted string representation\n * @category Helpers\n *\n * @example\n * ```typescript\n * formatSingleValue({ type: \"text\", text: \"a pinch\" }); // \"a pinch\"\n * formatSingleValue({ type: \"decimal\", decimal: 2 }); // \"2\"\n * formatSingleValue({ type: \"fraction\", num: 3, den: 4 }); // \"3/4\"\n * ```\n */\nexport function formatSingleValue(\n value: TextValue | DecimalValue | FractionValue,\n): string {\n if (value.type === \"text\") {\n return value.text;\n }\n return formatNumericValue(value);\n}\n\n/**\n * Format a quantity (fixed value or range) to a string.\n *\n * @param quantity - The quantity to format\n * @returns The formatted string representation\n * @category Helpers\n *\n * @example\n * ```typescript\n * formatQuantity({ type: \"fixed\", value: { type: \"decimal\", decimal: 100 } }); // \"100\"\n * formatQuantity({ type: \"range\", min: { type: \"decimal\", decimal: 1 }, max: { type: \"decimal\", decimal: 2 } }); // \"1-2\"\n * ```\n */\nexport function formatQuantity(quantity: FixedValue | Range): string {\n if (quantity.type === \"fixed\") {\n return formatSingleValue(quantity.value);\n }\n // Range\n const minStr = formatNumericValue(quantity.min);\n const maxStr = formatNumericValue(quantity.max);\n return `${minStr}-${maxStr}`;\n}\n\n/**\n * Format a unit to a string. Handles both plain string units and Unit objects.\n *\n * @param unit - The unit to format (string, Unit object, or undefined)\n * @returns The formatted unit string, or empty string if undefined\n * @category Helpers\n *\n * @example\n * ```typescript\n * formatUnit(\"g\"); // \"g\"\n * formatUnit({ name: \"grams\" }); // \"grams\"\n * formatUnit(undefined); // \"\"\n * ```\n */\nexport function formatUnit(unit: string | Unit | undefined): string {\n if (!unit) return \"\";\n if (typeof unit === \"string\") return unit;\n return unit.name;\n}\n\n/**\n * Format a quantity with its unit to a string.\n *\n * @param quantity - The quantity to format\n * @param unit - The unit to append (string, Unit object, or undefined)\n * @returns The formatted string with quantity and unit\n * @category Helpers\n *\n * @example\n * ```typescript\n * formatQuantityWithUnit({ type: \"fixed\", value: { type: \"decimal\", decimal: 100 } }, \"g\"); // \"100 g\"\n * formatQuantityWithUnit({ type: \"fixed\", value: { type: \"decimal\", decimal: 2 } }, undefined); // \"2\"\n * ```\n */\nexport function formatQuantityWithUnit(\n quantity: FixedValue | Range | undefined,\n unit: string | Unit | undefined,\n): string {\n if (!quantity) return \"\";\n const qty = formatQuantity(quantity);\n const unitStr = formatUnit(unit);\n return unitStr ? `${qty} ${unitStr}` : qty;\n}\n\n/**\n * Format a QuantityWithExtendedUnit to a string.\n *\n * @param item - The quantity with extended unit to format\n * @returns The formatted string\n * @category Helpers\n */\nexport function formatExtendedQuantity(item: QuantityWithExtendedUnit): string {\n return formatQuantityWithUnit(item.quantity, item.unit);\n}\n\n/**\n * Format an IngredientItemQuantity with all its equivalents to a string.\n *\n * @param itemQuantity - The ingredient item quantity to format\n * @param separator - The separator between primary and equivalent quantities (default: \" | \")\n * @returns The formatted string with all quantities\n * @category Helpers\n *\n * @example\n * ```typescript\n * // For an ingredient like @flour{100%g|3.5%oz}\n * formatItemQuantity(itemQuantity); // \"100 g | 3.5 oz\"\n * formatItemQuantity(itemQuantity, \" / \"); // \"100 g / 3.5 oz\"\n * ```\n */\nexport function formatItemQuantity(\n itemQuantity: IngredientItemQuantity,\n separator: string = \" | \",\n): string {\n const parts: string[] = [];\n\n // Primary quantity\n parts.push(formatExtendedQuantity(itemQuantity));\n\n // Equivalents\n if (itemQuantity.equivalents) {\n for (const eq of itemQuantity.equivalents) {\n parts.push(formatExtendedQuantity(eq));\n }\n }\n\n return parts.join(separator);\n}\n\n// ============================================================================\n// Ingredient Item Helpers\n// ============================================================================\n\n/**\n * Check if an ingredient item is a grouped alternative (vs inline alternative).\n *\n * Grouped alternatives are ingredients that share a group key (e.g., `@|milk|...`)\n * and are distributed across multiple tokens in the recipe.\n *\n * @param item - The ingredient item to check\n * @returns true if this is a grouped alternative\n * @category Helpers\n *\n * @example\n * ```typescript\n * for (const item of step.items) {\n * if (item.type === 'ingredient') {\n * if (isGroupedItem(item)) {\n * // Handle grouped alternative (e.g., show with strikethrough if not selected)\n * } else {\n * // Handle inline alternative (e.g., hide if not selected)\n * }\n * }\n * }\n * ```\n */\nexport function isGroupedItem(item: IngredientItem): boolean {\n return item.group !== undefined;\n}\n\n// ============================================================================\n// Alternative Selection Helpers\n// ============================================================================\n\n/**\n * Determines if a specific alternative in an IngredientItem is selected\n * based on the applied choices.\n *\n * Use this in renderers to determine how an ingredient alternative should be displayed.\n *\n * @param recipe - The Recipe instance containing choices\n * @param choices - The choices that have been made\n * @param item - The IngredientItem to check\n * @param alternativeIndex - The index within item.alternatives to check (for inline alternatives only)\n * @returns true if this alternative is the selected one\n * @category Helpers\n *\n * @example\n * ```typescript\n * const recipe = new Recipe(cooklangText);\n * for (const item of step.items) {\n * if (item.type === 'ingredient') {\n * item.alternatives.forEach((alt, idx) => {\n * const isSelected = isAlternativeSelected(item, idx, recipe, choices);\n * // Render differently based on isSelected\n * });\n * }\n * }\n * ```\n */\nexport function isAlternativeSelected(\n recipe: Recipe,\n choices: RecipeChoices,\n item: IngredientItem,\n alternativeIndex?: number,\n): boolean {\n // Grouped alternatives: check ingredientGroups map\n if (item.group) {\n // Get the selected index in the group\n const selectedIndex = choices?.ingredientGroups?.get(item.group);\n // Get the alternatives array for this group\n const groupAlternatives = recipe.choices.ingredientGroups.get(item.group);\n if (\n groupAlternatives &&\n selectedIndex !== undefined &&\n selectedIndex < groupAlternatives.length\n ) {\n // Check if the selected alternative's itemId matches this item's id\n const selectedItemId = groupAlternatives[selectedIndex]?.itemId;\n return selectedItemId === item.id;\n }\n return false;\n }\n\n // Inline alternatives: check ingredientItems map\n const selectedIndex = choices?.ingredientItems?.get(item.id);\n return alternativeIndex === selectedIndex;\n}\n"],"mappings":"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","names":["escapeCache","Map","Flags","GLOBAL","NON_SENSITIVE","MULTILINE","DOT_ALL","UNICODE","STICKY","Ranges","Object","freeze","digit","lowercaseLetter","uppercaseLetter","letter","alphanumeric","anyCharacter","Quantifiers","zeroOrMore","oneOrMore","optional","HumanRegex","constructor","this","parts","flags","Set","add","special","word","whitespace","nonWhitespace","text","has","set","replace","get","or","name","range","Error","chars","lazy","lastPart","pop","newline","pattern","hasSpecialCharacter","hasDigit","hasLetter","n","min","max","startGroup","startCaptureGroup","wordBoundary","nonWordBoundary","endGroup","startAnchor","endAnchor","global","nonSensitive","multiline","dotAll","sticky","variant","validVariants","unicodeDigit","unicodePunctuation","unicodeSymbol","count","length","push","ipv4Octet","protocol","www","tld","path","part","toString","join","toRegExp","RegExp","createRegex","Patterns","createCachedPattern","builder","regex","source","email","literal","atLeast","url","phoneInternational","between","r","a","Big","e","i","e","a","TOML","import_big","import_big","Big","units","a","unitRatio","Big","import_big","ing","i","item","Big","factor","i","normalizedOptions","a","selectedIndex"]}