@tmlmt/cooklang-parser 2.1.3 → 2.1.4

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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 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 .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).oneOrMore()\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 .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).oneOrMore()\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 .whitespace().zeroOrMore()\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,\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,\n): FixedValue | Range {\n if (value.type === \"fixed\") {\n const newValue = multiplyNumericValue(\n value.value as DecimalValue | FractionValue,\n factor,\n );\n if (\n factor === parseInt(factor.toString()) || // e.g. 2 === int\n 1 / factor === parseInt((1 / 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\";\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.substring(1).trim();\n } else {\n /* v8 ignore else -- @preserve */\n if (!section.isBlank()) {\n this.sections.push(section);\n }\n section = new Section(line.substring(1).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 = newServings / 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.\n * @returns A new Recipe instance with the scaled ingredients.\n */\n scaleBy(factor: number): 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 ? 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 = originalServings * factor;\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(servingsValue * factor);\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(yieldValue * factor);\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(servesValue * factor);\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","i","e","i"]}
1
+ {"version":3,"sources":["../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 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 .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).oneOrMore()\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 .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).oneOrMore()\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 .whitespace().zeroOrMore()\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.substring(1).trim();\n } else {\n /* v8 ignore else -- @preserve */\n if (!section.isBlank()) {\n this.sections.push(section);\n }\n section = new Section(line.substring(1).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","i","e","Big","Big","i"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmlmt/cooklang-parser",
3
- "version": "2.1.3",
3
+ "version": "2.1.4",
4
4
  "description": "Cooklang parsers and utilities",
5
5
  "author": "Thomas Lamant <tom@tmlmt.com>",
6
6
  "type": "module",