diff --git a/CHANGELOG.md b/CHANGELOG.md index 014aa0d..fa6f498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - N/A +## [v1.2.0] - 2024-01-18 + +### Added + +- [#18] New option `ignoreUOMs`, an array of strings that will _not_ be considered units of measure. + ## [v1.1.1] - 2024-01-15 ### Fixed @@ -143,10 +149,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. [#7]: https://github.com/jakeboone02/parse-ingredient/pull/7 [#8]: https://github.com/jakeboone02/parse-ingredient/pull/8 [#14]: https://github.com/jakeboone02/parse-ingredient/pull/14 +[#18]: https://github.com/jakeboone02/parse-ingredient/pull/18 -[unreleased]: https://github.com/jakeboone02/parse-ingredient/compare/v1.1.0...HEAD +[unreleased]: https://github.com/jakeboone02/parse-ingredient/compare/v1.2.0...HEAD +[v1.2.0]: https://github.com/jakeboone02/parse-ingredient/compare/v1.1.1...v1.2.0 +[v1.1.1]: https://github.com/jakeboone02/parse-ingredient/compare/v1.1.0...v1.1.1 [v1.1.0]: https://github.com/jakeboone02/parse-ingredient/compare/v1.0.1...v1.1.0 [v1.0.1]: https://github.com/jakeboone02/parse-ingredient/compare/v1.0.0...v1.0.1 [v1.0.0]: https://github.com/jakeboone02/parse-ingredient/compare/v0.6.0...v1.0.0 diff --git a/README.md b/README.md index a0221ae..590b210 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ In the browser, all exports including the `parseIngredient` function are availab ```html diff --git a/ci/src/index.ts b/ci/src/index.ts index ab22bec..ae5e0e4 100755 --- a/ci/src/index.ts +++ b/ci/src/index.ts @@ -20,6 +20,7 @@ const additionalUOMs = { alternates: ['ounce'], }, } as const; +const ignoreUOMs = ['cup', 'cups'] as const; for (const ex of examples) { const run = [ @@ -28,6 +29,7 @@ for (const ex of examples) { parseIngredient(ex, { allowLeadingOf }), parseIngredient(ex, { normalizeUOM }), parseIngredient(ex, { additionalUOMs }), + parseIngredient(ex, { ignoreUOMs }), ]; gridInnerHTML.push(...run.map(e => `
${JSON.stringify(e, null, 2)}
`)); diff --git a/ci/src/styles.css b/ci/src/styles.css index 2a5ec77..a377e6a 100755 --- a/ci/src/styles.css +++ b/ci/src/styles.css @@ -5,22 +5,22 @@ body { #grid { display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; column-gap: 1rem; row-gap: 0.4rem; } -#grid > *:nth-child(n + 5) { +#grid > *:nth-child(n + 6) { border-bottom: 1px solid #dddddd; } -#grid > *:nth-child(-n + 5) { +#grid > *:nth-child(-n + 6) { border-bottom: 1px solid gray; font-weight: bold; text-align: center; } -#grid > *:nth-child(5n + 1):nth-child(n + 5) { +#grid > *:nth-child(6n + 1):nth-child(n + 6) { font-weight: bold; text-align: right; } diff --git a/index.html b/index.html index 60149b0..cba2c21 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + @@ -45,6 +45,11 @@

Ingredient List

Allow leading "of "
+ +

Results

(Click "Parse" to see results.)
diff --git a/src/constants.ts b/src/constants.ts index 966b7a2..7be2b1e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -8,6 +8,7 @@ export const defaultOptions = { additionalUOMs: {}, allowLeadingOf: false, normalizeUOM: false, + ignoreUOMs: [], } as const satisfies Required; /** diff --git a/src/dev.ts b/src/dev.ts index f296aed..25e8ed6 100644 --- a/src/dev.ts +++ b/src/dev.ts @@ -26,10 +26,14 @@ document.getElementById('ingredient-list')!.innerHTML = seed; document.getElementById('parse')!.addEventListener('click', () => { const normalizeUOM = (document.getElementById('normalize-uom') as HTMLInputElement).checked; const allowLeadingOf = (document.getElementById('allow-leading-of') as HTMLInputElement).checked; + const ignoreUOMs = ((document.getElementById('ignore-uoms') as HTMLInputElement).value ?? '') + .split(',') + .map(s => s.trim()); document.getElementById('results')!.innerHTML = JSON.stringify( parseIngredient((document.getElementById('ingredient-list') as HTMLInputElement).value, { normalizeUOM, allowLeadingOf, + ignoreUOMs, }), null, 2 diff --git a/src/parseIngredient.ts b/src/parseIngredient.ts index c2d4d11..66a855c 100644 --- a/src/parseIngredient.ts +++ b/src/parseIngredient.ts @@ -52,8 +52,11 @@ export const parseIngredient = ( // The first character is not numeric. First check for trailing quantity/uom. const trailingQtyResult = trailingQuantityRegEx.exec(line); - if (trailingQtyResult) { - // Trailing quantity detected. + if (trailingQtyResult && opts.ignoreUOMs.includes(trailingQtyResult.at(-1) ?? '')) { + // Trailing quantity detected, but bailing out since the UOM should be ignored. + oIng.description = line; + } else if (trailingQtyResult) { + // Trailing quantity detected with missing or non-ignored UOM. // Remove the quantity and unit of measure from the description. oIng.description = line.replace(trailingQuantityRegEx, '').trim(); @@ -153,7 +156,9 @@ export const parseIngredient = ( while (++i < uomArrayLength && !uom) { const { alternates, id, short, plural } = uomArray[i]; - const versions = [...alternates, id, short, plural]; + const versions = [...alternates, id, short, plural].filter( + unit => !opts.ignoreUOMs.includes(unit) + ); if (versions.includes(firstWord)) { uom = firstWord; uomID = id; diff --git a/src/parseIngredientTests.ts b/src/parseIngredientTests.ts index b0c393b..34d6caf 100644 --- a/src/parseIngredientTests.ts +++ b/src/parseIngredientTests.ts @@ -526,4 +526,26 @@ export const parseIngredientTests: Record< }, ], ], + 'ignores units of measure': [ + '1 cup stuff\nstuff x 2 cups', + [ + { + quantity: 1, + quantity2: null, + unitOfMeasureID: null, + unitOfMeasure: null, + description: 'cup stuff', + isGroupHeader: false, + }, + { + quantity: null, + quantity2: null, + unitOfMeasureID: null, + unitOfMeasure: null, + description: 'stuff x 2 cups', + isGroupHeader: false, + }, + ], + { ignoreUOMs: ['cup', 'cups'] }, + ], }; diff --git a/src/types.ts b/src/types.ts index 993e4fe..9276db2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -69,6 +69,30 @@ export interface ParseIngredientOptions { * @default {} */ additionalUOMs?: UnitOfMeasureDefinitions; + /** + * An array of strings to ignore as units of measure when parsing ingredients. + * + * @example + * + * ```ts + * parseIngredient('2 small eggs', { + * ignoreUOMs: ['small', 'medium', 'large'] + * }) + * // [ + * // { + * // quantity: 2, + * // quantity2: null, + * // unitOfMeasure: null, + * // unitOfMeasureID: null, + * // description: 'small eggs', + * // isGroupHeader: false, + * // } + * // ] + * ``` + * + * @default [] + */ + ignoreUOMs?: string[]; /** * If `true`, ingredient descriptions that start with "of " will not be * modified. (By default, a leading "of " will be removed from all descriptions.)