UNPKG

parse-ingredient

Version:

Recipe ingredient parser with support for mixed numbers and vulgar fractions

1 lines 19.7 kB
{"version":3,"sources":["../src/parseIngredient.ts","../src/constants.ts"],"sourcesContent":["import { numericQuantity } from 'numeric-quantity';\nimport {\n defaultOptions,\n firstWordRegEx,\n forsRegEx,\n fromRegEx,\n ofRegEx,\n rangeSeparatorRegEx,\n trailingQuantityRegEx,\n unitsOfMeasure,\n} from './constants';\nimport type { Ingredient, ParseIngredientOptions, UnitOfMeasure } from './types';\n\nconst newLineRegExp = /\\r?\\n/;\n\nconst addIdToUomDefinition = ([uom, def]: [string, UnitOfMeasure]) => ({ id: uom, ...def });\n\n/**\n * Parses a string into an array of recipe ingredient objects\n */\nexport const parseIngredient = (\n /**\n * The ingredient list, as plain text.\n */\n ingredientText: string,\n /**\n * Configuration options. Defaults to {@link defaultOptions}.\n */\n options: ParseIngredientOptions = defaultOptions\n): Ingredient[] => {\n const opts = { ...defaultOptions, ...options };\n const mergedUOMs = { ...unitsOfMeasure, ...opts.additionalUOMs };\n const uomArray = Object.entries(mergedUOMs).map(addIdToUomDefinition);\n const uomArrayLength = uomArray.length;\n\n const ingredientArray = ingredientText\n .split(newLineRegExp)\n .map(line => line.trim())\n .filter(Boolean);\n\n return ingredientArray.map(line => {\n const oIng: Ingredient = {\n quantity: null,\n quantity2: null,\n unitOfMeasureID: null,\n unitOfMeasure: null,\n description: '',\n isGroupHeader: false,\n };\n\n // Check if the first character is numeric.\n if (isNaN(numericQuantity(line[0]))) {\n // The first character is not numeric. First check for trailing quantity/uom.\n const trailingQtyResult = trailingQuantityRegEx.exec(line);\n\n if (trailingQtyResult && opts.ignoreUOMs.includes(trailingQtyResult.at(-1) ?? '')) {\n // Trailing quantity detected, but bailing out since the UOM should be ignored.\n oIng.description = line;\n } else if (trailingQtyResult) {\n // Trailing quantity detected with missing or non-ignored UOM.\n // Remove the quantity and unit of measure from the description.\n oIng.description = line.replace(trailingQuantityRegEx, '').trim();\n\n // Trailing quantity/range.\n const firstQty = trailingQtyResult[3];\n const secondQty = trailingQtyResult[12];\n if (!firstQty) {\n oIng.quantity = numericQuantity(secondQty);\n } else {\n oIng.quantity = numericQuantity(firstQty);\n oIng.quantity2 = numericQuantity(secondQty);\n }\n\n // Trailing unit of measure.\n const uomRaw = trailingQtyResult.at(-1);\n if (uomRaw) {\n let uom = '';\n let uomID = '';\n let i = -1;\n\n while (++i < uomArrayLength && !uom) {\n const { alternates, id, short, plural } = uomArray[i];\n const versions = [...alternates, id, short, plural];\n if (versions.includes(uomRaw)) {\n uom = uomRaw;\n uomID = id;\n }\n }\n\n if (uom) {\n oIng.unitOfMeasureID = uomID;\n oIng.unitOfMeasure = opts.normalizeUOM ? uomID : uom;\n } else if (oIng.description.match(fromRegEx)) {\n oIng.description += ` ${uomRaw}`;\n }\n }\n } else {\n // The first character is not numeric, and no trailing quantity was detected,\n // so the entire line is the description.\n oIng.description = line;\n\n // If the line ends with \":\" or starts with \"For \", then it is assumed to be a group header.\n if (oIng.description.endsWith(':') || forsRegEx.test(oIng.description)) {\n oIng.isGroupHeader = true;\n }\n }\n } else {\n // The first character is numeric. See how many of the first seven\n // constitute a single value. This will be `quantity`.\n let lenNum = 6;\n let nqResult = NaN;\n\n while (lenNum > 0 && isNaN(nqResult)) {\n nqResult = numericQuantity(line.substring(0, lenNum).trim());\n\n if (nqResult > -1) {\n oIng.quantity = nqResult;\n oIng.description = line.substring(lenNum).trim();\n }\n\n lenNum--;\n }\n }\n\n // Now check the description for a `quantity2` at the beginning.\n // First we look for a dash, emdash, endash, \"to \", or \"or \" to\n // indicate a range, then process the next seven characters just\n // like we did for `quantity`.\n const q2reMatch = rangeSeparatorRegEx.exec(oIng.description);\n if (q2reMatch) {\n const q2reMatchLen = q2reMatch[1].length;\n const nqResultFirstChar = numericQuantity(oIng.description.substring(q2reMatchLen).trim()[0]);\n\n if (!isNaN(nqResultFirstChar)) {\n let lenNum = 7;\n let nqResult = NaN;\n\n while (--lenNum > 0 && isNaN(nqResult)) {\n nqResult = numericQuantity(oIng.description.substring(q2reMatchLen, lenNum));\n\n if (!isNaN(nqResult)) {\n oIng.quantity2 = nqResult;\n oIng.description = oIng.description.substring(lenNum).trim();\n }\n }\n }\n }\n\n // Check for a known unit of measure\n const firstWordREMatches = firstWordRegEx.exec(oIng.description);\n\n if (firstWordREMatches) {\n const firstWord = firstWordREMatches[1].replace(/\\s+/g, ' ');\n const remainingDesc = (firstWordREMatches[2] ?? '').trim();\n if (remainingDesc) {\n let uom = '';\n let uomID = '';\n let i = -1;\n\n while (++i < uomArrayLength && !uom) {\n const { alternates, id, short, plural } = uomArray[i];\n const versions = [...alternates, id, short, plural].filter(\n unit => !opts.ignoreUOMs.includes(unit)\n );\n if (versions.includes(firstWord)) {\n uom = firstWord;\n uomID = id;\n }\n }\n\n if (uom) {\n oIng.unitOfMeasureID = uomID;\n oIng.unitOfMeasure = opts.normalizeUOM ? uomID : uom;\n oIng.description = remainingDesc;\n }\n }\n }\n\n if (!opts.allowLeadingOf && oIng.description.match(ofRegEx)) {\n oIng.description = oIng.description.replace(ofRegEx, '');\n }\n\n return oIng;\n });\n};\n","import { numericRegex } from 'numeric-quantity';\nimport { ParseIngredientOptions, UnitOfMeasureDefinitions } from './types';\n\n/**\n * Default options for {@link parseIngredient}.\n */\nexport const defaultOptions: Required<ParseIngredientOptions> = {\n additionalUOMs: {},\n allowLeadingOf: false,\n normalizeUOM: false,\n ignoreUOMs: [],\n} as const;\n\n/**\n * List of \"for\" equivalents (for upcoming i18n support).\n */\nexport const fors = ['For'] as const;\n/**\n * Regex to capture \"for\" equivalents (for upcoming i18n support).\n */\nexport const forsRegEx: RegExp = new RegExp(`^(?:${fors.join('|')})\\\\s`, 'i');\n\n/**\n * List of range separators (for upcoming i18n support).\n */\nexport const rangeSeparatorWords = ['or', 'to'] as const;\nconst rangeSeparatorRegExSource = `(-|–|—|(?:${rangeSeparatorWords.join('|')})\\\\s)`;\n/**\n * Regex to capture range separators (for upcoming i18n support).\n */\nexport const rangeSeparatorRegEx: RegExp = new RegExp(`^${rangeSeparatorRegExSource}`, 'i');\n\n/**\n * Regex to capture the first word of a description, to see if it's a unit of measure.\n */\nexport const firstWordRegEx: RegExp = /^(fl(?:uid)?(?:\\s+|-)(?:oz|ounces?)|\\w+[-.]?)(.+)?/;\n\nconst numericRegexAnywhere = numericRegex.source.replace(/^\\^/, '').replace(/\\$$/, '');\n\n/**\n * Regex to capture trailing quantity and unit of measure.\n */\nexport const trailingQuantityRegEx: RegExp = new RegExp(\n `(,|:|-|–|—|x|⨯)?\\\\s*((${numericRegexAnywhere})\\\\s*(${rangeSeparatorRegExSource}))?\\\\s*(${numericRegexAnywhere})\\\\s*(fl(?:uid)?(?:\\\\s+|-)(?:oz|ounces?)|\\\\w+)?$`,\n 'i'\n);\n\n/**\n * List of \"of\" equivalents (for upcoming i18n support).\n */\nexport const ofs = ['of'] as const;\n/**\n * Regex to capture \"of\" equivalents at the beginning of a string (for upcoming i18n support).\n */\nexport const ofRegEx: RegExp = new RegExp(`^(?:${ofs.join('|')})\\\\s+`, 'i');\n\n/**\n * List of \"from\" equivalents (for upcoming i18n support).\n */\nexport const froms = ['from', 'of'] as const;\n/**\n * Regex to capture \"from\" equivalents at the end of a string (for upcoming i18n support).\n */\nexport const fromRegEx: RegExp = new RegExp(`\\\\s+(?:${froms.join('|')})$`, 'i');\n\n/**\n * Default unit of measure specifications.\n */\nexport const unitsOfMeasure: UnitOfMeasureDefinitions = {\n bag: {\n short: 'bag',\n plural: 'bags',\n alternates: [] satisfies string[],\n },\n box: {\n short: 'box',\n plural: 'boxes',\n alternates: [] satisfies string[],\n },\n bunch: {\n short: 'bunch',\n plural: 'bunches',\n alternates: [] satisfies string[],\n },\n can: {\n short: 'can',\n plural: 'cans',\n alternates: [] satisfies string[],\n },\n carton: {\n short: 'carton',\n plural: 'cartons',\n alternates: [] satisfies string[],\n },\n centimeter: {\n short: 'cm',\n plural: 'centimeters',\n alternates: ['cm.'] satisfies string[],\n },\n clove: {\n short: 'clove',\n plural: 'cloves',\n alternates: [] satisfies string[],\n },\n container: {\n short: 'container',\n plural: 'containers',\n alternates: [] satisfies string[],\n },\n cup: {\n short: 'c',\n plural: 'cups',\n alternates: ['c.', 'C'] satisfies string[],\n },\n dash: {\n short: 'dash',\n plural: 'dashes',\n alternates: [] satisfies string[],\n },\n drop: {\n short: 'drop',\n plural: 'drops',\n alternates: [] satisfies string[],\n },\n ear: {\n short: 'ear',\n plural: 'ears',\n alternates: [] satisfies string[],\n },\n 'fluid ounce': {\n short: 'fl oz',\n plural: 'fluid ounces',\n alternates: [\n 'fluidounce',\n 'floz',\n 'fl-oz',\n 'fluid-ounce',\n 'fluid-ounces',\n 'fluidounces',\n 'fl ounce',\n 'fl ounces',\n 'fl-ounce',\n 'fl-ounces',\n 'fluid oz',\n 'fluid-oz',\n ] satisfies string[],\n },\n foot: {\n short: 'ft',\n plural: 'feet',\n alternates: ['ft.'] satisfies string[],\n },\n gallon: {\n short: 'gal',\n plural: 'gallons',\n alternates: ['gal.'] satisfies string[],\n },\n gram: {\n short: 'g',\n plural: 'grams',\n alternates: ['g.'] satisfies string[],\n },\n head: {\n short: 'head',\n plural: 'heads',\n alternates: [] satisfies string[],\n },\n inch: {\n short: 'in',\n plural: 'inches',\n alternates: ['in.'] satisfies string[],\n },\n kilogram: {\n short: 'kg',\n plural: 'kilograms',\n alternates: ['kg.'] satisfies string[],\n },\n large: {\n short: 'lg',\n plural: 'large',\n alternates: ['lg', 'lg.'] satisfies string[],\n },\n liter: {\n short: 'l',\n plural: 'liters',\n alternates: ['l.'] satisfies string[],\n },\n medium: {\n short: 'md',\n plural: 'medium',\n alternates: ['med', 'med.', 'md.'] satisfies string[],\n },\n meter: {\n short: 'm',\n plural: 'meters',\n alternates: ['m.'] satisfies string[],\n },\n milligram: {\n short: 'mg',\n plural: 'milligrams',\n alternates: ['mg.'] satisfies string[],\n },\n milliliter: {\n short: 'ml',\n plural: 'milliliters',\n alternates: ['mL', 'ml.', 'mL.'] satisfies string[],\n },\n millimeter: {\n short: 'mm',\n plural: 'millimeters',\n alternates: ['mm.'] satisfies string[],\n },\n ounce: {\n short: 'oz',\n plural: 'ounces',\n alternates: ['oz.'] satisfies string[],\n },\n pack: {\n short: 'pack',\n plural: 'packs',\n alternates: [] satisfies string[],\n },\n package: {\n short: 'pkg',\n plural: 'packages',\n alternates: ['pkg.', 'pkgs', 'pkgs.'] satisfies string[],\n },\n piece: {\n short: 'piece',\n plural: 'pieces',\n alternates: ['pc', 'pc.', 'pcs', 'pcs.'] satisfies string[],\n },\n pinch: {\n short: 'pinch',\n plural: 'pinches',\n alternates: [] satisfies string[],\n },\n pint: {\n short: 'pt',\n plural: 'pints',\n alternates: ['pt.'] satisfies string[],\n },\n pound: {\n short: 'lb',\n plural: 'pounds',\n alternates: ['lb.', 'lbs', 'lbs.'] satisfies string[],\n },\n quart: {\n short: 'qt',\n plural: 'quarts',\n alternates: ['qt.', 'qts', 'qts.'] satisfies string[],\n },\n small: {\n short: 'sm',\n plural: 'small',\n alternates: ['sm.'] satisfies string[],\n },\n sprig: {\n short: 'sprig',\n plural: 'sprigs',\n alternates: [] satisfies string[],\n },\n stick: {\n short: 'stick',\n plural: 'sticks',\n alternates: [] satisfies string[],\n },\n tablespoon: {\n short: 'tbsp',\n plural: 'tablespoons',\n alternates: ['tbsp.', 'T', 'Tbsp.', 'Tbsp'] satisfies string[],\n },\n teaspoon: {\n short: 'tsp',\n plural: 'teaspoons',\n alternates: ['tsp.', 't'] satisfies string[],\n },\n yard: {\n short: 'yd',\n plural: 'yards',\n alternates: ['yd.', 'yds.'] satisfies string[],\n },\n} as const;\n"],"mappings":"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","names":["numericQuantity","numericRegex","defaultOptions","fors","forsRegEx","rangeSeparatorWords","rangeSeparatorRegExSource","rangeSeparatorRegEx","firstWordRegEx","numericRegexAnywhere","trailingQuantityRegEx","ofs","ofRegEx","froms","fromRegEx","unitsOfMeasure","newLineRegExp","addIdToUomDefinition","uom","def","parseIngredient","ingredientText","options","defaultOptions","opts","mergedUOMs","unitsOfMeasure","uomArray","uomArrayLength","line","oIng","numericQuantity","trailingQtyResult","trailingQuantityRegEx","firstQty","secondQty","uomRaw","uomID","i","alternates","id","short","plural","fromRegEx","forsRegEx","lenNum","nqResult","q2reMatch","rangeSeparatorRegEx","q2reMatchLen","nqResultFirstChar","firstWordREMatches","firstWordRegEx","firstWord","remainingDesc","unit","ofRegEx"]}