Skip to content

Commit

Permalink
Merge pull request #18 from jakeboone02/ignore-uoms
Browse files Browse the repository at this point in the history
Add `ignoreUOMs` option
  • Loading branch information
jakeboone02 committed Jan 19, 2024
2 parents 01b89ad + 7244758 commit b02b367
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 41 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

<!-- Release comparison links -->

[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
Expand Down
61 changes: 35 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ In the browser, all exports including the `parseIngredient` function are availab
```html
<script src="https://unpkg.com/parse-ingredient"></script>
<script>
console.log(ParseIngredient.parseIngredient('1 1/2 cups sugar'));
ParseIngredient.parseIngredient('1 1/2 cups sugar');
// [
// {
// quantity: 1.5,
Expand All @@ -83,7 +83,7 @@ In the browser, all exports including the `parseIngredient` function are availab
```js
import { parseIngredient } from 'parse-ingredient';

console.log(parseIngredient('1-2 pears'));
parseIngredient('1-2 pears');
// [
// {
// quantity: 1,
Expand All @@ -94,11 +94,10 @@ console.log(parseIngredient('1-2 pears'));
// isGroupHeader: false,
// }
// ]
console.log(
parseIngredient(
`2/3 cup flour

parseIngredient(
`2/3 cup flour
1 tsp baking powder`
)
);
// [
// {
Expand All @@ -118,7 +117,7 @@ console.log(
// isGroupHeader: false,
// },
// ]
console.log(parseIngredient('For cake:'));
parseIngredient('For cake:');
// [
// {
// quantity: null,
Expand All @@ -129,7 +128,7 @@ console.log(parseIngredient('For cake:'));
// isGroupHeader: true,
// }
// ]
console.log(parseIngredient('Ripe tomato x2'));
parseIngredient('Ripe tomato x2');
// [
// {
// quantity: 2,
Expand All @@ -148,10 +147,8 @@ console.log(parseIngredient('Ripe tomato x2'));

Pass `true` to convert units of measure to their long, singular form, e.g. "ml" becomes "milliliter" and "cups" becomes "cup". This can help normalize the units of measure for processing. In most cases, this option will make `unitOfMeasure` equivalent to `unitOfMeasureID`.

Example:

```js
console.log(parseIngredient('1 c sugar', { normalizeUOM: true }));
parseIngredient('1 c sugar', { normalizeUOM: true });
// [
// {
// quantity: 1,
Expand All @@ -168,20 +165,16 @@ console.log(parseIngredient('1 c sugar', { normalizeUOM: true }));

Pass an object that matches the format of the exported `unitsOfMeasure` object. Keys that match any in the exported object will be used instead of the default, and any others will be added to the list of known units of measure when parsing ingredients.

Example:

```js
console.log(
parseIngredient('2 buckets of widgets', {
additionalUOMs: {
bucket: {
short: 'bkt',
plural: 'buckets',
versions: ['bk'],
},
parseIngredient('2 buckets of widgets', {
additionalUOMs: {
bucket: {
short: 'bkt',
plural: 'buckets',
versions: ['bk'],
},
})
);
},
});
// [
// {
// quantity: 2,
Expand All @@ -198,10 +191,8 @@ console.log(

When `true`, ingredient descriptions that start with "of " will not be modified. (By default, a leading "of " will be removed from all descriptions.)

Example:

```js
console.log(parseIngredient('1 cup of sugar', { allowLeadingOf: true }));
parseIngredient('1 cup of sugar', { allowLeadingOf: true });
// [
// {
// quantity: 1,
Expand All @@ -214,6 +205,24 @@ console.log(parseIngredient('1 cup of sugar', { allowLeadingOf: true }));
// ]
```

### `ignoreUOMs`

An array of strings to ignore as units of measure when parsing ingredients.

```js
parseIngredient('2 large eggs', { ignoreUOMs: ['large'] });
// [
// {
// quantity: 2,
// quantity2: null,
// unitOfMeasure: null,
// unitOfMeasureID: null,
// description: 'large eggs',
// isGroupHeader: false,
// }
// ]
```

## Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
Expand Down
6 changes: 0 additions & 6 deletions babel.config.json

This file was deleted.

1 change: 1 addition & 0 deletions ci/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ <h1>parse-ingredient CI</h1>
<div>allowLeadingOf</div>
<div>normalizeUOM</div>
<div>additionalUOMs</div>
<div>ignoreUOMs</div>
</div>
<script src="src/index.ts"></script>
</body>
Expand Down
2 changes: 2 additions & 0 deletions ci/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const additionalUOMs = {
alternates: ['ounce'],
},
} as const;
const ignoreUOMs = ['cup', 'cups'] as const;

for (const ex of examples) {
const run = [
Expand All @@ -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 => `<div>${JSON.stringify(e, null, 2)}</div>`));
Expand Down
8 changes: 4 additions & 4 deletions ci/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
7 changes: 6 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand Down Expand Up @@ -45,6 +45,11 @@ <h4>Ingredient List</h4>
Allow leading "of "
</label>
<br />
<label>
Ignore UOMs
<input type="text" id="ignore-uoms" />
</label>
<br />
<button type="button" id="parse">Parse</button>
<h4>Results</h4>
<pre id="results" class="language-json">(Click "Parse" to see results.)</pre>
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const defaultOptions = {
additionalUOMs: {},
allowLeadingOf: false,
normalizeUOM: false,
ignoreUOMs: [],
} as const satisfies Required<ParseIngredientOptions>;

/**
Expand Down
4 changes: 4 additions & 0 deletions src/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions src/parseIngredient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand Down
22 changes: 22 additions & 0 deletions src/parseIngredientTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'] },
],
};
24 changes: 24 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
Expand Down

0 comments on commit b02b367

Please sign in to comment.