@jclind/ingredient-parser 1.3.0 → 1.3.2

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/README.md CHANGED
@@ -1,211 +1,250 @@
1
- # @jclind/ingredient-parser
2
-
3
- [![npm version](https://img.shields.io/npm/v/@jclind/ingredient-parser)](https://www.npmjs.com/package/@jclind/ingredient-parser)
4
- [![license](https://img.shields.io/npm/l/@jclind/ingredient-parser)](https://github.com/jclind/ingredient-parser/blob/main/LICENSE)
5
-
6
- A TypeScript package for parsing ingredient strings and retrieving structured ingredient data from the Spoonacular API.
7
-
8
- Built on top of [recipe-ingredient-parser-v3](https://www.npmjs.com/package/recipe-ingredient-parser-v3). If you only need ingredient parsing without ingredient metadata, nutrition, or API lookups, you may prefer using that package directly.
9
-
10
- ## Installation
11
-
12
- ```sh
13
- npm install @jclind/ingredient-parser
14
- ```
15
-
16
- ## Quick Start
17
-
18
- ```ts
19
- import { parseIngredient } from '@jclind/ingredient-parser'
20
-
21
- const ingredientString = '1 cup rice, washed'
22
- const apiKey = 'YOUR_API_KEY'
23
-
24
- const result = await parseIngredient(ingredientString, apiKey, {
25
- returnNutritionData: true,
26
- })
27
-
28
- console.log(result)
29
- ```
30
-
31
- ## API
32
-
33
- ### `parseIngredient(ingredientString, SPOONACULAR_API_KEY, options?)`
34
-
35
- Parses an ingredient string and returns both the parsed ingredient data and ingredient metadata retrieved from Spoonacular.
36
-
37
- ```ts
38
- import { parseIngredient } from '@jclind/ingredient-parser'
39
-
40
- parseIngredient(
41
- ingredientString: string,
42
- SPOONACULAR_API_KEY: string,
43
- options?: {
44
- returnNutritionData?: boolean
45
- }
46
- ): Promise<IngredientResponseType>
47
- ```
48
-
49
- | Parameter | Type | Required | Description |
50
- | --------------------- | -------- | -------- | ------------------------------------------------------- |
51
- | `ingredientString` | `string` | Yes | Ingredient string formatted like `2 cups onions, diced` |
52
- | `SPOONACULAR_API_KEY` | `string` | Yes | Your Spoonacular API key |
53
- | `options` | `object` | No | Additional parsing options |
54
-
55
- ### Options
56
-
57
- | Option | Type | Default | Description |
58
- | --------------------- | --------- | ------- | ------------------------------------------------------- |
59
- | `returnNutritionData` | `boolean` | `false` | Includes Spoonacular nutrition data in `ingredientData` |
60
-
61
- ---
62
-
63
- ## Response Structure
64
-
65
- Returns an object with the following shape:
66
-
67
- ```ts
68
- {
69
- id: string
70
- parsedIngredient: ParsedIngredientType
71
- ingredientData: IngredientDataType | null
72
- error?: {
73
- message: string
74
- }
75
- }
76
- ```
77
-
78
- ---
79
-
80
- ### `parsedIngredient`
81
-
82
- ```ts
83
- {
84
- quantity: 1,
85
- unit: 'cup',
86
- unitPlural: 'cups',
87
- symbol: 'c',
88
- ingredient: 'rice',
89
- originalIngredientString: '1 cup rice, washed',
90
- minQty: 1,
91
- maxQty: 1,
92
- comment: 'washed'
93
- }
94
- ```
95
-
96
- ---
97
-
98
- ### `ingredientData`
99
-
100
- ```ts
101
- {
102
- _id: '63caeabf4762c87be39c3795',
103
- ingredientId: 20444,
104
- originalName: 'rice',
105
- name: 'rice',
106
- amount: 1,
107
- possibleUnits: ['g', 'oz', 'cup'],
108
- consistency: 'solid',
109
- shoppingListUnits: ['ounces', 'pounds'],
110
- aisle: 'Pasta and Rice',
111
- image: 'uncooked-white-rice.png',
112
- imagePath: 'https://spoonacular.com/cdn/ingredients_100x100/uncooked-white-rice.png',
113
- nutrition?: {
114
- nutrients: [Array],
115
- properties: [Array],
116
- flavonoids: [Array],
117
- caloricBreakdown: [Object],
118
- weightPerServing: [Object]
119
- },
120
- dateAdded: 1674242751000,
121
- totalPriceUSACents: 75.71
122
- }
123
- ```
124
-
125
- ## Error Handling
126
-
127
- If the ingredient cannot be identified or the API key is invalid, the function returns an error object while still including the parsed ingredient structure.
128
-
129
- ### Unknown Ingredient
130
-
131
- ```ts
132
- parseIngredient('Invalid Text', YOUR_API_KEY)
133
-
134
- /*
135
- {
136
- error: { message: 'No Data Found, unknown ingredient: invalid text' },
137
- ingredientData: null,
138
- parsedIngredient: {
139
- quantity: 0,
140
- unit: 'q.b.',
141
- unitPlural: 'q.b.',
142
- symbol: null,
143
- ingredient: 'Invalid Text',
144
- originalIngredientString: 'Invalid Text',
145
- minQty: 0,
146
- maxQty: 0,
147
- comment: null
148
- }
149
- }
150
- */
151
- ```
152
-
153
- ### Invalid API Key
154
-
155
- ```ts
156
- parseIngredient('1 cup rice', INVALID_API_KEY)
157
-
158
- /*
159
- {
160
- error: { message: 'API Key Not Valid' },
161
- ingredientData: null,
162
- parsedIngredient: {
163
- quantity: 1,
164
- unit: 'cup',
165
- unitPlural: 'cups',
166
- symbol: 'c',
167
- ingredient: 'rice',
168
- originalIngredientString: '1 cup rice',
169
- minQty: 1,
170
- maxQty: 1,
171
- comment: null
172
- }
173
- }
174
- */
175
- ```
176
-
177
- ## TypeScript
178
-
179
- This package ships with full TypeScript definitions. No additional `@types` package required.
180
-
181
- ```ts
182
- import {
183
- parseIngredient,
184
- ParsedIngredientType,
185
- IngredientDataType,
186
- IngredientResponseType,
187
- } from '@jclind/ingredient-parser'
188
-
189
- const ingredientString: string = '1 cup rice, washed'
190
- const apiKey: string = 'YOUR_API_KEY'
191
-
192
- const parsed: IngredientResponseType = await parseIngredient(
193
- ingredientString,
194
- apiKey,
195
- )
196
-
197
- const parsedIngredient: ParsedIngredientType = parsed.parsedIngredient
198
-
199
- const ingredientData: IngredientDataType | null = parsed.ingredientData
200
- ```
201
-
202
- ## Notes
203
-
204
- - A valid Spoonacular API key is required for ingredient lookups.
205
- - Ingredient parsing is powered by `recipe-ingredient-parser-v3`.
206
- - Nutrition data is optional and disabled by default to reduce API usage.
207
- - Parsed ingredient results are returned even when ingredient lookup fails.
208
-
209
- ## Issues & Contributing
210
-
211
- Found a bug or have a feature request? [Open an issue](https://github.com/jclind/ingredient-parser/issues) on GitHub. PRs are welcome.
1
+ # @jclind/ingredient-parser
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@jclind/ingredient-parser)](https://www.npmjs.com/package/@jclind/ingredient-parser)
4
+ [![license](https://img.shields.io/npm/l/@jclind/ingredient-parser)](https://github.com/jclind/ingredient-parser/blob/main/LICENSE)
5
+
6
+ A TypeScript package for parsing ingredient strings and retrieving structured ingredient data from the Spoonacular API.
7
+
8
+ Built on top of [recipe-ingredient-parser-v3](https://www.npmjs.com/package/recipe-ingredient-parser-v3). If you only need ingredient parsing without ingredient metadata, nutrition, or API lookups, you may prefer using that package directly.
9
+
10
+ ## Installation
11
+
12
+ ```sh
13
+ npm install @jclind/ingredient-parser
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```ts
19
+ import { ingredientParser } from '@jclind/ingredient-parser'
20
+
21
+ const result = await ingredientParser('1 cup rice, washed', 'YOUR_API_KEY', {
22
+ returnNutritionData: true,
23
+ })
24
+
25
+ console.log(result)
26
+ ```
27
+
28
+ ## API
29
+
30
+ ### `ingredientParser(ingredientString, apiKey, options?)`
31
+
32
+ Parses an ingredient string and returns both the parsed ingredient data and ingredient metadata retrieved from Spoonacular.
33
+
34
+ ```ts
35
+ import { ingredientParser } from '@jclind/ingredient-parser'
36
+
37
+ ingredientParser(
38
+ ingredientString: string,
39
+ apiKey: string,
40
+ options?: {
41
+ returnNutritionData?: boolean
42
+ imageSize?: '100x100' | '250x250' | '500x500'
43
+ serverUrl?: string
44
+ }
45
+ ): Promise<IngredientResponse>
46
+ ```
47
+
48
+ | Parameter | Type | Required | Description |
49
+ | ------------------ | -------- | -------- | ------------------------------------------------------- |
50
+ | `ingredientString` | `string` | Yes | Ingredient string formatted like `2 cups onions, diced` |
51
+ | `apiKey` | `string` | Yes | Your Spoonacular API key |
52
+ | `options` | `object` | No | Additional parsing options |
53
+
54
+ #### Options
55
+
56
+ | Option | Type | Default | Description |
57
+ | --------------------- | --------------------------------------- | ----------- | ------------------------------------------------------------- |
58
+ | `returnNutritionData` | `boolean` | `false` | Includes Spoonacular nutrition data in `ingredientData` |
59
+ | `imageSize` | `'100x100' \| '250x250' \| '500x500'` | `'100x100'` | Size of the ingredient image returned in `imagePath` |
60
+ | `serverUrl` | `string` | — | Override the default proxy server URL used to call Spoonacular |
61
+
62
+ ---
63
+
64
+ ### `parseIngredientString(ingredientString)`
65
+
66
+ Parses an ingredient string locally without any network calls. Use this when you only need quantity, unit, and ingredient name extraction.
67
+
68
+ ```ts
69
+ import { parseIngredientString } from '@jclind/ingredient-parser'
70
+
71
+ parseIngredientString(ingredientString: string): ParsedIngredient
72
+ ```
73
+
74
+ ```ts
75
+ parseIngredientString('1 cup rice, washed')
76
+ // {
77
+ // quantity: 1,
78
+ // unit: 'cup',
79
+ // unitPlural: 'cups',
80
+ // symbol: 'c',
81
+ // ingredient: 'rice',
82
+ // originalIngredientString: '1 cup rice, washed',
83
+ // minQty: 1,
84
+ // maxQty: 1,
85
+ // comment: 'washed'
86
+ // }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Response Structure
92
+
93
+ `ingredientParser` returns a discriminated union. On success, `ingredientData` is always present. On error, `error` is present and `ingredientData` is `null`.
94
+
95
+ ```ts
96
+ // Success
97
+ {
98
+ parsedIngredient: ParsedIngredient
99
+ ingredientData: IngredientData
100
+ id?: string
101
+ }
102
+
103
+ // Error
104
+ {
105
+ error: { message: string }
106
+ parsedIngredient: ParsedIngredient
107
+ ingredientData: null
108
+ id?: string
109
+ }
110
+ ```
111
+
112
+ ---
113
+
114
+ ### `parsedIngredient`
115
+
116
+ ```ts
117
+ {
118
+ quantity: 1,
119
+ unit: 'cup',
120
+ unitPlural: 'cups',
121
+ symbol: 'c',
122
+ ingredient: 'rice',
123
+ originalIngredientString: '1 cup rice, washed',
124
+ minQty: 1,
125
+ maxQty: 1,
126
+ comment: 'washed'
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ### `ingredientData`
133
+
134
+ ```ts
135
+ {
136
+ ingredientId: 20444,
137
+ originalName: 'rice',
138
+ name: 'rice',
139
+ amount: 1,
140
+ possibleUnits: ['g', 'oz', 'cup'],
141
+ consistency: 'solid',
142
+ shoppingListUnits: ['ounces', 'pounds'],
143
+ aisle: 'Pasta and Rice',
144
+ image: 'uncooked-white-rice.png',
145
+ imagePath: 'https://spoonacular.com/cdn/ingredients_100x100/uncooked-white-rice.png',
146
+ nutrition?: {
147
+ nutrients: [...],
148
+ properties: [...],
149
+ flavonoids: [...],
150
+ caloricBreakdown: {...},
151
+ weightPerServing: {...}
152
+ },
153
+ totalPriceUSACents: 75.71
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Error Handling
160
+
161
+ The function returns an error object (and `ingredientData: null`) when the ingredient cannot be identified or the API key is invalid. `parsedIngredient` is always populated.
162
+
163
+ ### Unknown Ingredient
164
+
165
+ ```ts
166
+ const result = await ingredientParser('Invalid Text', 'YOUR_API_KEY')
167
+
168
+ /*
169
+ {
170
+ error: { message: 'Ingredient not formatted correctly or Ingredient Unknown. Please pass ingredient comments/instructions after a comma' },
171
+ ingredientData: null,
172
+ parsedIngredient: {
173
+ quantity: null,
174
+ unit: null,
175
+ unitPlural: null,
176
+ symbol: null,
177
+ ingredient: 'Invalid Text',
178
+ originalIngredientString: 'Invalid Text',
179
+ minQty: null,
180
+ maxQty: null,
181
+ comment: null
182
+ }
183
+ }
184
+ */
185
+ ```
186
+
187
+ ### Invalid API Key
188
+
189
+ ```ts
190
+ const result = await ingredientParser('1 cup rice', 'INVALID_KEY')
191
+
192
+ /*
193
+ {
194
+ error: { message: 'API Key Not Valid' },
195
+ ingredientData: null,
196
+ parsedIngredient: {
197
+ quantity: 1,
198
+ unit: 'cup',
199
+ unitPlural: 'cups',
200
+ symbol: 'c',
201
+ ingredient: 'rice',
202
+ originalIngredientString: '1 cup rice',
203
+ minQty: 1,
204
+ maxQty: 1,
205
+ comment: null
206
+ }
207
+ }
208
+ */
209
+ ```
210
+
211
+ ---
212
+
213
+ ## TypeScript
214
+
215
+ This package ships with full TypeScript definitions. No additional `@types` package required.
216
+
217
+ ```ts
218
+ import {
219
+ ingredientParser,
220
+ parseIngredientString,
221
+ ParsedIngredient,
222
+ IngredientData,
223
+ IngredientResponse,
224
+ } from '@jclind/ingredient-parser'
225
+
226
+ const result: IngredientResponse = await ingredientParser(
227
+ '1 cup rice, washed',
228
+ 'YOUR_API_KEY'
229
+ )
230
+
231
+ if ('error' in result) {
232
+ console.error(result.error.message)
233
+ } else {
234
+ const parsed: ParsedIngredient = result.parsedIngredient
235
+ const data: IngredientData = result.ingredientData
236
+ }
237
+ ```
238
+
239
+ ---
240
+
241
+ ## Notes
242
+
243
+ - A valid Spoonacular API key is required for ingredient lookups via `ingredientParser`.
244
+ - `parseIngredientString` works offline with no API key.
245
+ - Nutrition data is optional and disabled by default to reduce API usage.
246
+ - `parsedIngredient` is always populated, even when the API call fails.
247
+
248
+ ## Issues & Contributing
249
+
250
+ Found a bug or have a feature request? [Open an issue](https://github.com/jclind/ingredient-parser/issues) on GitHub. PRs are welcome.
@@ -1,2 +1,3 @@
1
- export declare const spoonacularHttp: import("axios").AxiosInstance;
2
- export declare const createIngredientServerHttp: (serverUrl?: string) => import("axios").AxiosInstance;
1
+ import _axios from 'axios';
2
+ export declare const spoonacularHttp: _axios.AxiosInstance;
3
+ export declare const createIngredientServerHttp: (serverUrl?: string) => _axios.AxiosInstance;
@@ -4,7 +4,85 @@ exports.parseIngredientString = void 0;
4
4
  const convertFractions_js_1 = require("./convertFractions.js");
5
5
  const parseStringConsecutiveTs_js_1 = require("./parseStringConsecutiveTs.js");
6
6
  const parseIngredientString = (ingrStr) => {
7
- var _a, _b;
7
+ var _a, _b, _c;
8
+ // Input validation
9
+ if (typeof ingrStr !== 'string' || ingrStr === null || ingrStr === undefined) {
10
+ throw new TypeError('parseIngredientString expects a string input');
11
+ }
12
+ // Store original input before any modifications
13
+ const originalInput = ingrStr;
14
+ // Extract range quantities (e.g., "1-2 cups", "2 to 3 cups")
15
+ let minQty = null;
16
+ let maxQty = null;
17
+ const hyphenRangeMatch = ingrStr.match(/(\d+(?:\.\d+)?)\s*[-–]\s*(\d+(?:\.\d+)?)/);
18
+ const toRangeMatch = ingrStr.match(/(\d+(?:\.\d+)?)\s+to\s+(\d+(?:\.\d+)?)/i);
19
+ if (hyphenRangeMatch) {
20
+ minQty = parseFloat(hyphenRangeMatch[1]);
21
+ maxQty = parseFloat(hyphenRangeMatch[2]);
22
+ // Replace the range with minQty for parsing
23
+ ingrStr = ingrStr.replace(hyphenRangeMatch[0], String(minQty));
24
+ }
25
+ else if (toRangeMatch) {
26
+ minQty = parseFloat(toRangeMatch[1]);
27
+ maxQty = parseFloat(toRangeMatch[2]);
28
+ // Replace the range with minQty for parsing
29
+ ingrStr = ingrStr.replace(toRangeMatch[0], String(minQty));
30
+ }
31
+ // Store extracted ranges for later use
32
+ const extractedMinQty = minQty;
33
+ const extractedMaxQty = maxQty;
34
+ // Pre-processing: handle informal quantity patterns ("a pinch of", "handful", "dash")
35
+ // These patterns aren't well-handled by the upstream parser
36
+ const informalQtyPatterns = [
37
+ {
38
+ // "a pinch of salt"
39
+ regex: /^a\s+(pinch|dash|handful)\s+of\s+(.+)$/i,
40
+ extract: (match) => ({
41
+ quantity: 1,
42
+ unit: match[1].toLowerCase(),
43
+ ingredient: match[2].trim(),
44
+ })
45
+ },
46
+ {
47
+ // "pinch of salt", "dash of hot sauce"
48
+ regex: /^(pinch|dash|handful)\s+of\s+(.+)$/i,
49
+ extract: (match) => ({
50
+ quantity: 1,
51
+ unit: match[1].toLowerCase(),
52
+ ingredient: match[2].trim(),
53
+ })
54
+ },
55
+ {
56
+ // "handful spinach" (no "of")
57
+ regex: /^(pinch|dash|handful)\s+(.+)$/i,
58
+ extract: (match) => ({
59
+ quantity: 1,
60
+ unit: match[1].toLowerCase(),
61
+ ingredient: match[2].trim(),
62
+ })
63
+ },
64
+ ];
65
+ for (const pattern of informalQtyPatterns) {
66
+ const match = ingrStr.match(pattern.regex);
67
+ if (match) {
68
+ const { quantity, unit, ingredient } = pattern.extract(match);
69
+ // Apply descriptor stripping to ingredient
70
+ const wordsToRemove = ['small', 'medium', 'large', 'fresh', 'canned', 'freshly', 'finely', 'roughly', 'coarsely', 'grated', 'chopped'];
71
+ const regex = new RegExp('\\b(' + wordsToRemove.join('|') + ')\\b', 'gi');
72
+ const cleanedIngredient = ingredient.replace(regex, '').trim();
73
+ return {
74
+ quantity,
75
+ unit,
76
+ unitPlural: unit + 's',
77
+ symbol: null,
78
+ ingredient: cleanedIngredient,
79
+ originalIngredientString: originalInput,
80
+ minQty: quantity,
81
+ maxQty: quantity,
82
+ comment: '',
83
+ };
84
+ }
85
+ }
8
86
  // Define regular expressions for text inside parentheses and text before the first comma
9
87
  const parenRegex = /(\(.*?\))/;
10
88
  const commaRegex = /^(.*?)(?=,)/;
@@ -49,14 +127,83 @@ const parseIngredientString = (ingrStr) => {
49
127
  ml: 'milliliter',
50
128
  lb: 'pound',
51
129
  g: 'gram',
130
+ // Additional unit recognitions
131
+ sprigs: 'sprig',
132
+ sprig: 'sprig',
133
+ 'bay leaves': 'bay leaf',
134
+ 'bay leaf': 'bay leaf',
135
+ sheets: 'sheet',
136
+ sheet: 'sheet',
137
+ tblsp: 'tablespoon',
138
+ dessertspoon: 'dessertspoon',
139
+ dessertspoons: 'dessertspoon',
140
+ 'fl oz': 'fluid ounce',
141
+ 'fluid oz': 'fluid ounce',
52
142
  };
53
143
  const unitPattern = new RegExp('\\b(' + Object.keys(unitNormalizations).join('|') + ')\\b', 'gi');
54
144
  const prepIngrText = ingrText.replace(unitPattern, match => { var _a; return (_a = unitNormalizations[match.toLowerCase()]) !== null && _a !== void 0 ? _a : match; });
55
- const parsedIngrRes = (0, parseStringConsecutiveTs_js_1.parseStringConsecutiveTs)(prepIngrText);
145
+ let parsedIngrRes;
146
+ try {
147
+ parsedIngrRes = (0, parseStringConsecutiveTs_js_1.parseStringConsecutiveTs)(prepIngrText);
148
+ }
149
+ catch (_d) {
150
+ // Return degraded result for malformed input (e.g., division by zero)
151
+ return {
152
+ quantity: 0,
153
+ unit: null,
154
+ unitPlural: null,
155
+ symbol: null,
156
+ ingredient: ingrStr.replace(/[^a-zA-Z\s]/g, '').trim(),
157
+ minQty: null,
158
+ maxQty: null,
159
+ originalIngredientString: originalInput,
160
+ comment,
161
+ };
162
+ }
163
+ // Post-processing: check if ingredient name starts with an unrecognized unit
164
+ // The upstream parser doesn't recognize some units, so we extract them manually
165
+ const unrecognizedUnits = [
166
+ 'sprig', 'sprigs',
167
+ 'strip', 'strips',
168
+ 'sheet', 'sheets',
169
+ 'dessertspoon', 'dessertspoons',
170
+ 'handful', 'handfuls',
171
+ 'dash', 'dashes',
172
+ 'bay leaf', 'bay leaves',
173
+ ];
174
+ const unrecognizedUnitPattern = new RegExp('^(' + unrecognizedUnits.join('|') + ')\\b', 'i');
175
+ if (parsedIngrRes.ingredient && parsedIngrRes.unit === null) {
176
+ const unitMatch = parsedIngrRes.ingredient.match(unrecognizedUnitPattern);
177
+ if (unitMatch) {
178
+ let unit = unitMatch[1].toLowerCase();
179
+ // Normalize plural forms to singular
180
+ const unitSingular = {
181
+ sprigs: 'sprig',
182
+ strips: 'strip',
183
+ sheets: 'sheet',
184
+ dessertspoons: 'dessertspoon',
185
+ handfuls: 'handful',
186
+ dashes: 'dash',
187
+ 'bay leaves': 'bay leaf',
188
+ };
189
+ parsedIngrRes.unit = (_c = unitSingular[unit]) !== null && _c !== void 0 ? _c : unit;
190
+ parsedIngrRes.ingredient = parsedIngrRes.ingredient
191
+ .replace(unrecognizedUnitPattern, '')
192
+ .trim();
193
+ }
194
+ }
195
+ // Post-processing: handle "fl oz" / "fluid ounce" which upstream parser normalizes to "ounce"
196
+ if (parsedIngrRes.unit === 'ounce' &&
197
+ (originalInput.toLowerCase().includes('fl oz') ||
198
+ originalInput.toLowerCase().includes('fluid ounce'))) {
199
+ parsedIngrRes.unit = 'fluid ounce';
200
+ // Also fix the symbol
201
+ parsedIngrRes.symbol = 'fl oz';
202
+ }
56
203
  if (!parsedIngrRes.ingredient) {
57
- return Object.assign(Object.assign({}, parsedIngrRes), { originalIngredientString: ingrStr, comment });
204
+ return Object.assign(Object.assign({}, parsedIngrRes), { originalIngredientString: originalInput, comment });
58
205
  }
59
- const wordsToRemove = ['small', 'medium', 'large', 'fresh', 'canned'];
206
+ const wordsToRemove = ['small', 'medium', 'large', 'fresh', 'canned', 'freshly', 'finely', 'roughly', 'coarsely', 'grated', 'chopped'];
60
207
  const regex = new RegExp('\\b(' + wordsToRemove.join('|') + ')\\b', 'gi');
61
208
  const descriptorSet = new Set(wordsToRemove.map(w => w.toLowerCase()));
62
209
  const unit = parsedIngrRes.unit && descriptorSet.has(parsedIngrRes.unit.toLowerCase())
@@ -69,6 +216,6 @@ const parseIngredientString = (ingrStr) => {
69
216
  .replace(/^(fluid|fl|oz) /, '') // Remove "fluid ", "fl ", or "oz " at the beginning of the string
70
217
  .replace(regex, '')
71
218
  .trim();
72
- return Object.assign(Object.assign({}, parsedIngrRes), { unit, ingredient: formattedIngrName, originalIngredientString: ingrStr, comment });
219
+ return Object.assign(Object.assign({}, parsedIngrRes), { unit, ingredient: formattedIngrName, originalIngredientString: originalInput, comment, minQty: extractedMinQty !== null && extractedMinQty !== void 0 ? extractedMinQty : parsedIngrRes.minQty, maxQty: extractedMaxQty !== null && extractedMaxQty !== void 0 ? extractedMaxQty : parsedIngrRes.maxQty });
73
220
  };
74
221
  exports.parseIngredientString = parseIngredientString;
@@ -1,4 +1,3 @@
1
1
  import { ParsedIngredient } from '../../types.js';
2
- type ParsedIngredientOmitType = Omit<ParsedIngredient, 'originalIngredientString' | 'comment'>;
2
+ export type ParsedIngredientOmitType = Omit<ParsedIngredient, 'originalIngredientString' | 'comment'>;
3
3
  export declare const parseStringConsecutiveTs: (ingrStr: string) => ParsedIngredientOmitType;
4
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jclind/ingredient-parser",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Parses given sentence including ingredient information and attempts to return quantity, measurement and ingredient data",
5
5
  "keywords": [
6
6
  "recipe",
@@ -37,15 +37,15 @@
37
37
  "homepage": "https://github.com/jclind/ingredient-parser#readme",
38
38
  "dependencies": {
39
39
  "@jclind/ingredient-unit-converter": "^1.1.0",
40
- "axios": "^1.0.0",
40
+ "axios": "^1.16.0",
41
41
  "recipe-ingredient-parser-v3": "^1.5.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/jest": "^30.0.0",
45
- "@types/node": "^22.0.0",
45
+ "@types/node": "^25.6.0",
46
46
  "jest": "^30.3.0",
47
- "rimraf": "^5.0.0",
47
+ "rimraf": "^6.1.3",
48
48
  "ts-jest": "^29.4.9",
49
- "typescript": "^5.0.0"
49
+ "typescript": "^6.0.3"
50
50
  }
51
51
  }