@tmlmt/cooklang-parser 2.1.7 → 3.0.0-alpha.10
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 +1 -1
- package/dist/index.cjs +2117 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +972 -70
- package/dist/index.d.ts +972 -70
- package/dist/index.js +2100 -391
- package/dist/index.js.map +1 -1
- package/package.json +23 -19
package/dist/index.d.cts
CHANGED
|
@@ -65,6 +65,10 @@ declare class Recipe {
|
|
|
65
65
|
* The parsed recipe metadata.
|
|
66
66
|
*/
|
|
67
67
|
metadata: Metadata;
|
|
68
|
+
/**
|
|
69
|
+
* The possible choices of alternative ingredients for this recipe.
|
|
70
|
+
*/
|
|
71
|
+
choices: RecipeAlternatives;
|
|
68
72
|
/**
|
|
69
73
|
* The parsed recipe ingredients.
|
|
70
74
|
*/
|
|
@@ -81,6 +85,10 @@ declare class Recipe {
|
|
|
81
85
|
* The parsed recipe timers.
|
|
82
86
|
*/
|
|
83
87
|
timers: Timer[];
|
|
88
|
+
/**
|
|
89
|
+
* The parsed arbitrary quantities.
|
|
90
|
+
*/
|
|
91
|
+
arbitraries: ArbitraryScalable[];
|
|
84
92
|
/**
|
|
85
93
|
* The parsed recipe servings. Used for scaling. Parsed from one of
|
|
86
94
|
* {@link Metadata.servings}, {@link Metadata.yield} or {@link Metadata.serves}
|
|
@@ -89,11 +97,80 @@ declare class Recipe {
|
|
|
89
97
|
* @see {@link Recipe.scaleBy | scaleBy()} and {@link Recipe.scaleTo | scaleTo()} methods
|
|
90
98
|
*/
|
|
91
99
|
servings?: number;
|
|
100
|
+
/**
|
|
101
|
+
* External storage for item count (not a property on instances).
|
|
102
|
+
* Used for giving ID numbers to items during parsing.
|
|
103
|
+
*/
|
|
104
|
+
private static itemCounts;
|
|
105
|
+
/**
|
|
106
|
+
* Gets the current item count for this recipe.
|
|
107
|
+
*/
|
|
108
|
+
private getItemCount;
|
|
109
|
+
/**
|
|
110
|
+
* Gets the current item count and increments it.
|
|
111
|
+
*/
|
|
112
|
+
private getAndIncrementItemCount;
|
|
92
113
|
/**
|
|
93
114
|
* Creates a new Recipe instance.
|
|
94
115
|
* @param content - The recipe content to parse.
|
|
95
116
|
*/
|
|
96
117
|
constructor(content?: string);
|
|
118
|
+
/**
|
|
119
|
+
* Parses a matched arbitrary scalable quantity and adds it to the given array.
|
|
120
|
+
* @private
|
|
121
|
+
* @param regexMatchGroups - The regex match groups from arbitrary scalable regex.
|
|
122
|
+
* @param intoArray - The array to push the parsed arbitrary scalable item into.
|
|
123
|
+
*/
|
|
124
|
+
private _parseArbitraryScalable;
|
|
125
|
+
/**
|
|
126
|
+
* Parses text for arbitrary scalables and returns NoteItem array.
|
|
127
|
+
* @param text - The text to parse for arbitrary scalables.
|
|
128
|
+
* @returns Array of NoteItem (text and arbitrary scalable items).
|
|
129
|
+
*/
|
|
130
|
+
private _parseNoteText;
|
|
131
|
+
private _parseQuantityRecursive;
|
|
132
|
+
private _parseIngredientWithAlternativeRecursive;
|
|
133
|
+
private _parseIngredientWithGroupKey;
|
|
134
|
+
/**
|
|
135
|
+
* Populates the `quantities` property for each ingredient based on
|
|
136
|
+
* how they appear in the recipe preparation. Only primary ingredients
|
|
137
|
+
* get quantities populated. Primary ingredients get `usedAsPrimary: true` flag.
|
|
138
|
+
*
|
|
139
|
+
* For inline alternatives (e.g. `\@a|b|c`), the first alternative is primary.
|
|
140
|
+
* For grouped alternatives (e.g. `\@|group|a`, `\@|group|b`), the first item in the group is primary.
|
|
141
|
+
*
|
|
142
|
+
* Quantities are grouped by their alternative signature and summed using addEquivalentsAndSimplify.
|
|
143
|
+
* @internal
|
|
144
|
+
*/
|
|
145
|
+
private _populate_ingredient_quantities;
|
|
146
|
+
/**
|
|
147
|
+
* Gets ingredients with their quantities populated, optionally filtered by section/step
|
|
148
|
+
* and respecting user choices for alternatives.
|
|
149
|
+
*
|
|
150
|
+
* When no options are provided, returns all recipe ingredients with quantities
|
|
151
|
+
* calculated using primary alternatives (same as after parsing).
|
|
152
|
+
*
|
|
153
|
+
* @param options - Options for filtering and choice selection:
|
|
154
|
+
* - `section`: Filter to a specific section (Section object or 0-based index)
|
|
155
|
+
* - `step`: Filter to a specific step (Step object or 0-based index)
|
|
156
|
+
* - `choices`: Choices for alternative ingredients (defaults to primary)
|
|
157
|
+
* @returns Array of Ingredient objects with quantities populated
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // Get all ingredients with primary alternatives
|
|
162
|
+
* const ingredients = recipe.getIngredientQuantities();
|
|
163
|
+
*
|
|
164
|
+
* // Get ingredients for a specific section
|
|
165
|
+
* const sectionIngredients = recipe.getIngredientQuantities({ section: 0 });
|
|
166
|
+
*
|
|
167
|
+
* // Get ingredients with specific choices applied
|
|
168
|
+
* const withChoices = recipe.getIngredientQuantities({
|
|
169
|
+
* choices: { ingredientItems: new Map([['ingredient-item-2', 1]]) }
|
|
170
|
+
* });
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
getIngredientQuantities(options?: GetIngredientQuantitiesOptions): Ingredient[];
|
|
97
174
|
/**
|
|
98
175
|
* Parses a recipe from a string.
|
|
99
176
|
* @param content - The recipe content to parse.
|
|
@@ -128,11 +205,6 @@ declare class Recipe {
|
|
|
128
205
|
clone(): Recipe;
|
|
129
206
|
}
|
|
130
207
|
|
|
131
|
-
interface Quantity {
|
|
132
|
-
value: FixedValue | Range;
|
|
133
|
-
unit?: string;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
208
|
/**
|
|
137
209
|
* Represents the metadata of a recipe.
|
|
138
210
|
* @category Types
|
|
@@ -250,7 +322,7 @@ interface Metadata {
|
|
|
250
322
|
*/
|
|
251
323
|
interface TextValue {
|
|
252
324
|
type: "text";
|
|
253
|
-
|
|
325
|
+
text: string;
|
|
254
326
|
}
|
|
255
327
|
/**
|
|
256
328
|
* Represents a quantity described by a decimal number, e.g. "1.5"
|
|
@@ -258,7 +330,7 @@ interface TextValue {
|
|
|
258
330
|
*/
|
|
259
331
|
interface DecimalValue {
|
|
260
332
|
type: "decimal";
|
|
261
|
-
|
|
333
|
+
decimal: number;
|
|
262
334
|
}
|
|
263
335
|
/**
|
|
264
336
|
* Represents a quantity described by a fraction, e.g. "1/2"
|
|
@@ -280,6 +352,15 @@ interface FixedValue {
|
|
|
280
352
|
type: "fixed";
|
|
281
353
|
value: TextValue | DecimalValue | FractionValue;
|
|
282
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Represents a single, fixed numeric quantity.
|
|
357
|
+
* This can be a decimal or fraction.
|
|
358
|
+
* @category Types
|
|
359
|
+
*/
|
|
360
|
+
interface FixedNumericValue {
|
|
361
|
+
type: "fixed";
|
|
362
|
+
value: DecimalValue | FractionValue;
|
|
363
|
+
}
|
|
283
364
|
/**
|
|
284
365
|
* Represents a range of quantities, e.g. "1-2"
|
|
285
366
|
* @category Types
|
|
@@ -289,16 +370,6 @@ interface Range {
|
|
|
289
370
|
min: DecimalValue | FractionValue;
|
|
290
371
|
max: DecimalValue | FractionValue;
|
|
291
372
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Represents a contributor to an ingredient's total quantity
|
|
294
|
-
* @category Types
|
|
295
|
-
*/
|
|
296
|
-
interface QuantityPart extends Quantity {
|
|
297
|
-
/** - If _true_, the quantity will scale
|
|
298
|
-
* - If _false_, the quantity is fixed
|
|
299
|
-
*/
|
|
300
|
-
scalable: boolean;
|
|
301
|
-
}
|
|
302
373
|
/**
|
|
303
374
|
* Represents a possible state modifier or other flag for an ingredient in a recipe
|
|
304
375
|
* @category Types
|
|
@@ -324,6 +395,48 @@ interface IngredientExtras {
|
|
|
324
395
|
*/
|
|
325
396
|
path: string;
|
|
326
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* Represents a reference to an alternative ingredient along with its quantities.
|
|
400
|
+
*
|
|
401
|
+
* Used in {@link IngredientQuantityGroup} to describe what other ingredients
|
|
402
|
+
* could be used in place of the main ingredient.
|
|
403
|
+
* @category Types
|
|
404
|
+
*/
|
|
405
|
+
interface AlternativeIngredientRef {
|
|
406
|
+
/** The index of the alternative ingredient within the {@link Recipe.ingredients} array. */
|
|
407
|
+
index: number;
|
|
408
|
+
/** The quantities of the alternative ingredient. Multiple entries when units are incompatible. */
|
|
409
|
+
quantities?: QuantityWithPlainUnit[];
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Represents a group of summed quantities for an ingredient, optionally with alternatives.
|
|
413
|
+
* Quantities with the same alternative signature are summed together into a single group.
|
|
414
|
+
* When units are incompatible, separate IngredientQuantityGroup entries are created instead of merging.
|
|
415
|
+
* @category Types
|
|
416
|
+
*/
|
|
417
|
+
interface IngredientQuantityGroup extends QuantityWithPlainUnit {
|
|
418
|
+
/**
|
|
419
|
+
* References to alternative ingredients for this quantity group.
|
|
420
|
+
* If undefined, this group has no alternatives.
|
|
421
|
+
*/
|
|
422
|
+
alternatives?: AlternativeIngredientRef[];
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Represents an AND group of quantities when primary units are incompatible but equivalents can be summed.
|
|
426
|
+
* For example: 1 large carrot + 2 small carrots, both with cup equivalents (resp. 2 cup and 1.5 cup) that sum to 5 cups.
|
|
427
|
+
* @category Types
|
|
428
|
+
*/
|
|
429
|
+
interface IngredientQuantityAndGroup extends FlatAndGroup<QuantityWithPlainUnit> {
|
|
430
|
+
/**
|
|
431
|
+
* The summed equivalent quantities (e.g., "5 cups" from summing "1.5 cup + 2 cup + 1.5 cup").
|
|
432
|
+
*/
|
|
433
|
+
equivalents?: QuantityWithPlainUnit[];
|
|
434
|
+
/**
|
|
435
|
+
* References to alternative ingredients for this quantity group.
|
|
436
|
+
* If undefined, this group has no alternatives.
|
|
437
|
+
*/
|
|
438
|
+
alternatives?: AlternativeIngredientRef[];
|
|
439
|
+
}
|
|
327
440
|
/**
|
|
328
441
|
* Represents an ingredient in a recipe.
|
|
329
442
|
* @category Types
|
|
@@ -331,40 +444,65 @@ interface IngredientExtras {
|
|
|
331
444
|
interface Ingredient {
|
|
332
445
|
/** The name of the ingredient. */
|
|
333
446
|
name: string;
|
|
334
|
-
/**
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
447
|
+
/**
|
|
448
|
+
* Represents the quantities list for an ingredient as groups.
|
|
449
|
+
* Each group contains summed quantities that share the same alternative signature.
|
|
450
|
+
* Groups can be either simple (single unit) or AND groups (incompatible primary units with summed equivalents).
|
|
451
|
+
* Only populated for primary ingredients (not alternative-only).
|
|
452
|
+
* Quantities without alternatives are merged opportunistically when units are compatible.
|
|
453
|
+
* Quantities with alternatives are only merged if the alternatives are exactly the same.
|
|
454
|
+
*/
|
|
455
|
+
quantities?: (IngredientQuantityGroup | IngredientQuantityAndGroup)[];
|
|
340
456
|
/** The preparation of the ingredient. */
|
|
341
457
|
preparation?: string;
|
|
458
|
+
/** The list of indexes of the ingredients mentioned in the preparation as alternatives to this ingredient */
|
|
459
|
+
alternatives?: Set<number>;
|
|
460
|
+
/**
|
|
461
|
+
* True if this ingredient appears as the primary choice (first in an alternatives list).
|
|
462
|
+
* Only primary ingredients have quantities populated directly.
|
|
463
|
+
*
|
|
464
|
+
* Alternative-only ingredients (usedAsPrimary undefined/false) have their quantities
|
|
465
|
+
* available via the {@link Recipe.choices} structure.
|
|
466
|
+
*/
|
|
467
|
+
usedAsPrimary?: boolean;
|
|
342
468
|
/** A list of potential state modifiers or other flags for the ingredient */
|
|
343
469
|
flags?: IngredientFlag[];
|
|
344
470
|
/** The collection of potential additional metadata for the ingredient */
|
|
345
471
|
extras?: IngredientExtras;
|
|
346
472
|
}
|
|
347
473
|
/**
|
|
348
|
-
* Represents a
|
|
474
|
+
* Represents a contributor to an ingredient's total quantity, corresponding
|
|
475
|
+
* to a single mention in the recipe text. It can contain multiple
|
|
476
|
+
* equivalent quantities (e.g., in different units).
|
|
349
477
|
* @category Types
|
|
350
478
|
*/
|
|
351
|
-
interface
|
|
352
|
-
/**
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
479
|
+
interface IngredientItemQuantity extends QuantityWithExtendedUnit {
|
|
480
|
+
/**
|
|
481
|
+
* A list of equivalent quantities/units for this ingredient mention besides the primary quantity.
|
|
482
|
+
* For `@salt{1%tsp|5%g}`, the main quantity is 1 tsp and the equivalents will contain 5 g.
|
|
483
|
+
*/
|
|
484
|
+
equivalents?: QuantityWithExtendedUnit[];
|
|
485
|
+
/** Indicates whether this quantity should be scaled when the recipe serving size changes. */
|
|
486
|
+
scalable: boolean;
|
|
358
487
|
}
|
|
359
488
|
/**
|
|
360
|
-
* Represents a
|
|
489
|
+
* Represents a single ingredient choice within a single or a group of `IngredientItem`s. It points
|
|
490
|
+
* to a specific ingredient and its corresponding quantity information.
|
|
361
491
|
* @category Types
|
|
362
492
|
*/
|
|
363
|
-
interface
|
|
364
|
-
/** The
|
|
365
|
-
|
|
366
|
-
/** The
|
|
367
|
-
|
|
493
|
+
interface IngredientAlternative {
|
|
494
|
+
/** The index of the ingredient within the {@link Recipe.ingredients} array. */
|
|
495
|
+
index: number;
|
|
496
|
+
/** The quantity of this specific mention of the ingredient */
|
|
497
|
+
itemQuantity?: IngredientItemQuantity;
|
|
498
|
+
/** The alias/name of the ingredient as it should be displayed for this occurrence. */
|
|
499
|
+
displayName: string;
|
|
500
|
+
/** An optional note for this specific choice (e.g., "for a vegan version"). */
|
|
501
|
+
note?: string;
|
|
502
|
+
/** When {@link Recipe.choices} is populated for alternatives ingredients
|
|
503
|
+
* with group keys: the id of the corresponding ingredient item (e.g. "ingredient-item-2").
|
|
504
|
+
* Can be useful for creating alternative selection UI elements with anchor links */
|
|
505
|
+
itemId?: string;
|
|
368
506
|
}
|
|
369
507
|
/**
|
|
370
508
|
* Represents an ingredient item in a recipe step.
|
|
@@ -373,14 +511,67 @@ interface TextItem {
|
|
|
373
511
|
interface IngredientItem {
|
|
374
512
|
/** The type of the item. */
|
|
375
513
|
type: "ingredient";
|
|
376
|
-
/** The
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* of
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
514
|
+
/** The item identifier */
|
|
515
|
+
id: string;
|
|
516
|
+
/**
|
|
517
|
+
* A list of alternative ingredient choices. For a standard ingredient,
|
|
518
|
+
* this array will contain a single element.
|
|
519
|
+
*/
|
|
520
|
+
alternatives: IngredientAlternative[];
|
|
521
|
+
/**
|
|
522
|
+
* An optional identifier for linking distributed alternatives. If multiple
|
|
523
|
+
* `IngredientItem`s in a recipe share the same `group` ID (e.g., from
|
|
524
|
+
* `@|group|...` syntax), they represent a single logical choice.
|
|
525
|
+
*/
|
|
526
|
+
group?: string;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Represents the choices one can make in a recipe
|
|
530
|
+
* @category Types
|
|
531
|
+
*/
|
|
532
|
+
interface RecipeAlternatives {
|
|
533
|
+
/** Map of choices that can be made at Ingredient StepItem level
|
|
534
|
+
* - Keys are the Ingredient StepItem IDs (e.g. "ingredient-item-2")
|
|
535
|
+
* - Values are arrays of IngredientAlternative objects representing the choices available for that item
|
|
536
|
+
*/
|
|
537
|
+
ingredientItems: Map<string, IngredientAlternative[]>;
|
|
538
|
+
/** Map of choices that can be made for Grouped Ingredient StepItem's
|
|
539
|
+
* - Keys are the Group IDs (e.g. "eggs" for `@|eggs|...`)
|
|
540
|
+
* - Values are arrays of IngredientAlternative objects representing the choices available for that group
|
|
541
|
+
*/
|
|
542
|
+
ingredientGroups: Map<string, IngredientAlternative[]>;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Represents the choices to apply when computing ingredient quantities.
|
|
546
|
+
* Maps item/group IDs to the index of the selected alternative.
|
|
547
|
+
* @category Types
|
|
548
|
+
*/
|
|
549
|
+
interface RecipeChoices {
|
|
550
|
+
/** Map of choices that can be made at Ingredient StepItem level */
|
|
551
|
+
ingredientItems?: Map<string, number>;
|
|
552
|
+
/** Map of choices that can be made for Grouped Ingredient StepItem's */
|
|
553
|
+
ingredientGroups?: Map<string, number>;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Options for the {@link Recipe.getIngredientQuantities | getIngredientQuantities()} method.
|
|
557
|
+
* @category Types
|
|
558
|
+
*/
|
|
559
|
+
interface GetIngredientQuantitiesOptions {
|
|
560
|
+
/**
|
|
561
|
+
* Filter ingredients to only those appearing in a specific section.
|
|
562
|
+
* Can be a Section object or section index (0-based).
|
|
563
|
+
*/
|
|
564
|
+
section?: Section | number;
|
|
565
|
+
/**
|
|
566
|
+
* Filter ingredients to only those appearing in a specific step.
|
|
567
|
+
* Can be a Step object or step index (0-based within the section, or global if no section specified).
|
|
568
|
+
*/
|
|
569
|
+
step?: Step | number;
|
|
570
|
+
/**
|
|
571
|
+
* The choices to apply when computing quantities.
|
|
572
|
+
* If not provided, uses primary alternatives (index 0 for all).
|
|
573
|
+
*/
|
|
574
|
+
choices?: RecipeChoices;
|
|
384
575
|
}
|
|
385
576
|
/**
|
|
386
577
|
* Represents a cookware item in a recipe step.
|
|
@@ -391,9 +582,8 @@ interface CookwareItem {
|
|
|
391
582
|
type: "cookware";
|
|
392
583
|
/** The index of the cookware, within the {@link Recipe.cookware | list of cookware} */
|
|
393
584
|
index: number;
|
|
394
|
-
/**
|
|
395
|
-
|
|
396
|
-
quantityPartIndex?: number;
|
|
585
|
+
/** The quantity of this specific mention of the cookware */
|
|
586
|
+
quantity?: FixedValue | Range;
|
|
397
587
|
}
|
|
398
588
|
/**
|
|
399
589
|
* Represents a timer item in a recipe step.
|
|
@@ -405,11 +595,55 @@ interface TimerItem {
|
|
|
405
595
|
/** The index of the timer, within the {@link Recipe.timers | list of timers} */
|
|
406
596
|
index: number;
|
|
407
597
|
}
|
|
598
|
+
/**
|
|
599
|
+
* Represents a timer in a recipe.
|
|
600
|
+
* @category Types
|
|
601
|
+
*/
|
|
602
|
+
interface Timer {
|
|
603
|
+
/** The name of the timer. */
|
|
604
|
+
name?: string;
|
|
605
|
+
/** The duration of the timer. */
|
|
606
|
+
duration: FixedValue | Range;
|
|
607
|
+
/** The unit of the timer. */
|
|
608
|
+
unit: string;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Represents a text item in a recipe step.
|
|
612
|
+
* @category Types
|
|
613
|
+
*/
|
|
614
|
+
interface TextItem {
|
|
615
|
+
/** The type of the item. */
|
|
616
|
+
type: "text";
|
|
617
|
+
/** The content of the text item. */
|
|
618
|
+
value: string;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Represents an arbitrary scalable quantity in a recipe.
|
|
622
|
+
* @category Types
|
|
623
|
+
*/
|
|
624
|
+
interface ArbitraryScalable {
|
|
625
|
+
/** The name of the arbitrary scalable quantity. */
|
|
626
|
+
name?: string;
|
|
627
|
+
/** The numerical value of the arbitrary scalable quantity. */
|
|
628
|
+
quantity: FixedNumericValue;
|
|
629
|
+
/** The unit of the arbitrary scalable quantity. */
|
|
630
|
+
unit?: string;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Represents an arbitrary scalable quantity item in a recipe step.
|
|
634
|
+
* @category Types
|
|
635
|
+
*/
|
|
636
|
+
interface ArbitraryScalableItem {
|
|
637
|
+
/** The type of the item. */
|
|
638
|
+
type: "arbitrary";
|
|
639
|
+
/** The index of the arbitrary scalable quantity, within the {@link Recipe.arbitraries | list of arbitrary scalable quantities} */
|
|
640
|
+
index: number;
|
|
641
|
+
}
|
|
408
642
|
/**
|
|
409
643
|
* Represents an item in a recipe step.
|
|
410
644
|
* @category Types
|
|
411
645
|
*/
|
|
412
|
-
type
|
|
646
|
+
type StepItem = TextItem | IngredientItem | CookwareItem | TimerItem | ArbitraryScalableItem;
|
|
413
647
|
/**
|
|
414
648
|
* Represents a step in a recipe.
|
|
415
649
|
* @category Types
|
|
@@ -417,16 +651,21 @@ type Item = TextItem | IngredientItem | CookwareItem | TimerItem;
|
|
|
417
651
|
interface Step {
|
|
418
652
|
type: "step";
|
|
419
653
|
/** The items in the step. */
|
|
420
|
-
items:
|
|
654
|
+
items: StepItem[];
|
|
421
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* Represents an item in a note (can be text or arbitrary scalable).
|
|
658
|
+
* @category Types
|
|
659
|
+
*/
|
|
660
|
+
type NoteItem = TextItem | ArbitraryScalableItem;
|
|
422
661
|
/**
|
|
423
662
|
* Represents a note in a recipe.
|
|
424
663
|
* @category Types
|
|
425
664
|
*/
|
|
426
665
|
interface Note {
|
|
427
666
|
type: "note";
|
|
428
|
-
/** The
|
|
429
|
-
|
|
667
|
+
/** The items in the note. */
|
|
668
|
+
items: NoteItem[];
|
|
430
669
|
}
|
|
431
670
|
/**
|
|
432
671
|
* Represents a possible state modifier or other flag for cookware used in a recipe
|
|
@@ -442,17 +681,15 @@ interface Cookware {
|
|
|
442
681
|
name: string;
|
|
443
682
|
/** The quantity of cookware */
|
|
444
683
|
quantity?: FixedValue | Range;
|
|
445
|
-
/** The array of contributors to the cookware's total quantity. */
|
|
446
|
-
quantityParts?: (FixedValue | Range)[];
|
|
447
684
|
/** A list of potential state modifiers or other flags for the cookware */
|
|
448
|
-
flags
|
|
685
|
+
flags?: CookwareFlag[];
|
|
449
686
|
}
|
|
450
687
|
/**
|
|
451
688
|
* Represents categorized ingredients.
|
|
452
689
|
* @category Types
|
|
453
690
|
*/
|
|
454
691
|
interface CategorizedIngredients {
|
|
455
|
-
[category: string]:
|
|
692
|
+
[category: string]: AddedIngredient[];
|
|
456
693
|
}
|
|
457
694
|
/**
|
|
458
695
|
* Represents a recipe together with a scaling factor
|
|
@@ -463,6 +700,8 @@ interface RecipeWithFactor {
|
|
|
463
700
|
recipe: Recipe;
|
|
464
701
|
/** The factor the recipe is scaled by. */
|
|
465
702
|
factor: number;
|
|
703
|
+
/** The choices for alternative ingredients. */
|
|
704
|
+
choices?: RecipeChoices;
|
|
466
705
|
}
|
|
467
706
|
/**
|
|
468
707
|
* Represents a recipe together with a servings value for scaling
|
|
@@ -473,12 +712,36 @@ interface RecipeWithServings {
|
|
|
473
712
|
recipe: Recipe;
|
|
474
713
|
/** The servings the recipe is scaled to */
|
|
475
714
|
servings: number;
|
|
715
|
+
/** The choices for alternative ingredients. */
|
|
716
|
+
choices?: RecipeChoices;
|
|
476
717
|
}
|
|
477
718
|
/**
|
|
478
719
|
* Represents a recipe that has been added to a shopping list.
|
|
479
720
|
* @category Types
|
|
480
721
|
*/
|
|
481
722
|
type AddedRecipe = RecipeWithFactor | RecipeWithServings;
|
|
723
|
+
/**
|
|
724
|
+
* Options for adding a recipe to a shopping list
|
|
725
|
+
* @category Types
|
|
726
|
+
*/
|
|
727
|
+
type AddedRecipeOptions = {
|
|
728
|
+
/** The scaling option for the recipe. Can be either a factor or a number of servings */
|
|
729
|
+
scaling?: {
|
|
730
|
+
factor: number;
|
|
731
|
+
} | {
|
|
732
|
+
servings: number;
|
|
733
|
+
};
|
|
734
|
+
/** The choices for alternative ingredients. */
|
|
735
|
+
choices?: RecipeChoices;
|
|
736
|
+
};
|
|
737
|
+
/**
|
|
738
|
+
* Represents an ingredient that has been added to a shopping list
|
|
739
|
+
* @category Types
|
|
740
|
+
*/
|
|
741
|
+
type AddedIngredient = Pick<Ingredient, "name"> & {
|
|
742
|
+
/** The total quantity of the ingredient after applying choices. */
|
|
743
|
+
quantityTotal?: QuantityWithPlainUnit | MaybeNestedGroup<QuantityWithPlainUnit>;
|
|
744
|
+
};
|
|
482
745
|
/**
|
|
483
746
|
* Represents an ingredient in a category.
|
|
484
747
|
* @category Types
|
|
@@ -499,6 +762,223 @@ interface Category {
|
|
|
499
762
|
/** The ingredients in the category. */
|
|
500
763
|
ingredients: CategoryIngredient[];
|
|
501
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Represents a single size expression for a product (value + optional unit)
|
|
767
|
+
* @category Types
|
|
768
|
+
*/
|
|
769
|
+
interface ProductSize {
|
|
770
|
+
/** The numeric size value */
|
|
771
|
+
size: FixedNumericValue;
|
|
772
|
+
/** The unit of the size (optional) */
|
|
773
|
+
unit?: string;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Core properties for {@link ProductOption}
|
|
777
|
+
* @category Types
|
|
778
|
+
*/
|
|
779
|
+
interface ProductOptionCore {
|
|
780
|
+
/** The ID of the product */
|
|
781
|
+
id: string;
|
|
782
|
+
/** The name of the product */
|
|
783
|
+
productName: string;
|
|
784
|
+
/** The name of the ingredient it corresponds to */
|
|
785
|
+
ingredientName: string;
|
|
786
|
+
/** The aliases of the ingredient it also corresponds to */
|
|
787
|
+
ingredientAliases?: string[];
|
|
788
|
+
/** The price of the product */
|
|
789
|
+
price: number;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Base type for {@link ProductOption} allowing arbitrary additional metadata
|
|
793
|
+
* @category Types
|
|
794
|
+
*/
|
|
795
|
+
type ProductOptionBase = ProductOptionCore & Record<string, unknown>;
|
|
796
|
+
/**
|
|
797
|
+
* Represents a product option in a {@link ProductCatalog}
|
|
798
|
+
* @category Types
|
|
799
|
+
*/
|
|
800
|
+
type ProductOption = ProductOptionBase & {
|
|
801
|
+
/** The size(s) of the product. Multiple sizes allow equivalent expressions (e.g., "1%dozen" and "12") */
|
|
802
|
+
sizes: ProductSize[];
|
|
803
|
+
};
|
|
804
|
+
/**
|
|
805
|
+
* Represents a product selection in a {@link ShoppingCart}
|
|
806
|
+
* @category Types
|
|
807
|
+
*/
|
|
808
|
+
interface ProductSelection {
|
|
809
|
+
/** The selected product */
|
|
810
|
+
product: ProductOption;
|
|
811
|
+
/** The quantity of the selected product */
|
|
812
|
+
quantity: number;
|
|
813
|
+
/** The total price for this selected product */
|
|
814
|
+
totalPrice: number;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Represents the content of the actual cart of the {@link ShoppingCart}
|
|
818
|
+
* @category Types
|
|
819
|
+
*/
|
|
820
|
+
type CartContent = ProductSelection[];
|
|
821
|
+
/**
|
|
822
|
+
* Represents a successful match between a ingredient and product(s) in the product catalog, in a {@link ShoppingCart}
|
|
823
|
+
* @category Types
|
|
824
|
+
*/
|
|
825
|
+
interface ProductMatch {
|
|
826
|
+
ingredient: Ingredient;
|
|
827
|
+
selection: ProductSelection[];
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Represents all successful matches between ingredients and the product catalog, in a {@link ShoppingCart}
|
|
831
|
+
* @category Types
|
|
832
|
+
*/
|
|
833
|
+
type CartMatch = ProductMatch[];
|
|
834
|
+
/**
|
|
835
|
+
* Represents the error codes for an ingredient which didn't match with any product in the product catalog, in a {@link ShoppingCart}
|
|
836
|
+
* @category Types
|
|
837
|
+
*/
|
|
838
|
+
type NoProductMatchErrorCode = "incompatibleUnits" | "textValue" | "textValue_incompatibleUnits" | "noProduct" | "noQuantity";
|
|
839
|
+
/**
|
|
840
|
+
* Represents an ingredient which didn't match with any product in the product catalog, in a {@link ShoppingCart}
|
|
841
|
+
* @category Types
|
|
842
|
+
*/
|
|
843
|
+
interface ProductMisMatch {
|
|
844
|
+
ingredient: Ingredient;
|
|
845
|
+
reason: NoProductMatchErrorCode;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Represents all ingredients which didn't match with any product in the product catalog, in a {@link ShoppingCart}
|
|
849
|
+
* @category Types
|
|
850
|
+
*/
|
|
851
|
+
type CartMisMatch = ProductMisMatch[];
|
|
852
|
+
/**
|
|
853
|
+
* Represents the type category of a unit used for quantities
|
|
854
|
+
* @category Types
|
|
855
|
+
*/
|
|
856
|
+
type UnitType = "mass" | "volume" | "count";
|
|
857
|
+
/**
|
|
858
|
+
* Represents the measurement system a unit belongs to
|
|
859
|
+
* @category Types
|
|
860
|
+
*/
|
|
861
|
+
type UnitSystem = "metric" | "imperial";
|
|
862
|
+
/**
|
|
863
|
+
* Represents a unit used to describe quantities
|
|
864
|
+
* @category Types
|
|
865
|
+
*/
|
|
866
|
+
interface Unit {
|
|
867
|
+
name: string;
|
|
868
|
+
/** This property is set to true when the unit is prefixed by an `=` sign in the cooklang file, e.g. `=g`
|
|
869
|
+
* Indicates that quantities with this unit should be treated as integers only (no decimal/fractional values). */
|
|
870
|
+
integerProtected?: boolean;
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Represents a fully defined unit with conversion and alias information
|
|
874
|
+
* @category Types
|
|
875
|
+
*/
|
|
876
|
+
interface UnitDefinition extends Unit {
|
|
877
|
+
type: UnitType;
|
|
878
|
+
system: UnitSystem;
|
|
879
|
+
/** e.g. ['gram', 'grams'] */
|
|
880
|
+
aliases: string[];
|
|
881
|
+
/** Conversion factor to the base unit of its type */
|
|
882
|
+
toBase: number;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Represents a resolved unit definition or a lightweight placeholder for non-standard units
|
|
886
|
+
* @category Types
|
|
887
|
+
*/
|
|
888
|
+
type UnitDefinitionLike = UnitDefinition | {
|
|
889
|
+
name: string;
|
|
890
|
+
type: "other";
|
|
891
|
+
system: "none";
|
|
892
|
+
integerProtected?: boolean;
|
|
893
|
+
};
|
|
894
|
+
/**
|
|
895
|
+
* Core quantity container holding a fixed value or a range
|
|
896
|
+
* @category Types
|
|
897
|
+
*/
|
|
898
|
+
interface QuantityBase {
|
|
899
|
+
quantity: FixedValue | Range;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Represents a quantity with an optional plain (string) unit
|
|
903
|
+
* @category Types
|
|
904
|
+
*/
|
|
905
|
+
interface QuantityWithPlainUnit extends QuantityBase {
|
|
906
|
+
unit?: string;
|
|
907
|
+
/** Optional equivalent quantities in different units (for alternative units like `@flour{100%g|3.5%oz}`) */
|
|
908
|
+
equivalents?: QuantityWithPlainUnit[];
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Represents a quantity with an optional extended `Unit` object
|
|
912
|
+
* @category Types
|
|
913
|
+
*/
|
|
914
|
+
interface QuantityWithExtendedUnit extends QuantityBase {
|
|
915
|
+
unit?: Unit;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Represents a quantity with a resolved unit definition
|
|
919
|
+
* @category Types
|
|
920
|
+
*/
|
|
921
|
+
interface QuantityWithUnitDef extends QuantityBase {
|
|
922
|
+
unit: UnitDefinitionLike;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Represents any quantity shape supported by the parser (plain, extended, or resolved unit)
|
|
926
|
+
* @category Types
|
|
927
|
+
*/
|
|
928
|
+
type QuantityWithUnitLike = QuantityWithPlainUnit | QuantityWithExtendedUnit | QuantityWithUnitDef;
|
|
929
|
+
/**
|
|
930
|
+
* Represents a flat "or" group of alternative quantities (for alternative units)
|
|
931
|
+
* @category Types
|
|
932
|
+
*/
|
|
933
|
+
interface FlatOrGroup<T = QuantityWithUnitLike> {
|
|
934
|
+
or: T[];
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Represents an "or" group of alternative quantities that may contain nested groups (alternatives with nested structure)
|
|
938
|
+
* @category Types
|
|
939
|
+
*/
|
|
940
|
+
interface MaybeNestedOrGroup<T = QuantityWithUnitLike> {
|
|
941
|
+
or: (T | MaybeNestedGroup<T>)[];
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Represents a flat "and" group of quantities (combined quantities)
|
|
945
|
+
* @category Types
|
|
946
|
+
*/
|
|
947
|
+
interface FlatAndGroup<T = QuantityWithUnitLike> {
|
|
948
|
+
and: T[];
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Represents an "and" group of quantities that may contain nested groups (combinations with nested structure)
|
|
952
|
+
* @category Types
|
|
953
|
+
*/
|
|
954
|
+
interface MaybeNestedAndGroup<T = QuantityWithUnitLike> {
|
|
955
|
+
and: (T | MaybeNestedGroup<T>)[];
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Represents any flat group type ("and" or "or")
|
|
959
|
+
* @category Types
|
|
960
|
+
*/
|
|
961
|
+
type FlatGroup<T = QuantityWithUnitLike> = FlatAndGroup<T> | FlatOrGroup<T>;
|
|
962
|
+
/**
|
|
963
|
+
* Represents any group type that may include nested groups
|
|
964
|
+
* @category Types
|
|
965
|
+
*/
|
|
966
|
+
type MaybeNestedGroup<T = QuantityWithUnitLike> = MaybeNestedAndGroup<T> | MaybeNestedOrGroup<T>;
|
|
967
|
+
/**
|
|
968
|
+
* Represents any group type (flat or nested)
|
|
969
|
+
* @category Types
|
|
970
|
+
*/
|
|
971
|
+
type Group<T = QuantityWithUnitLike> = MaybeNestedGroup<T> | FlatGroup<T>;
|
|
972
|
+
/**
|
|
973
|
+
* Represents any "or" group (flat or nested)
|
|
974
|
+
* @category Types
|
|
975
|
+
*/
|
|
976
|
+
type OrGroup<T = QuantityWithUnitLike> = MaybeNestedOrGroup<T> | FlatOrGroup<T>;
|
|
977
|
+
/**
|
|
978
|
+
* Represents any "and" group (flat or nested)
|
|
979
|
+
* @category Types
|
|
980
|
+
*/
|
|
981
|
+
type AndGroup<T = QuantityWithUnitLike> = MaybeNestedAndGroup<T> | FlatAndGroup<T>;
|
|
502
982
|
|
|
503
983
|
/**
|
|
504
984
|
* Parser for category configurations specified à-la-cooklang.
|
|
@@ -549,6 +1029,62 @@ declare class CategoryConfig {
|
|
|
549
1029
|
parse(config: string): void;
|
|
550
1030
|
}
|
|
551
1031
|
|
|
1032
|
+
/**
|
|
1033
|
+
* Product Catalog Manager: used in conjunction with {@link ShoppingCart}
|
|
1034
|
+
*
|
|
1035
|
+
* ## Usage
|
|
1036
|
+
*
|
|
1037
|
+
* You can either directly populate the products by feeding the {@link ProductCatalog.products | products} property. Alternatively,
|
|
1038
|
+
* you can provide a catalog in TOML format to either the constructor itself or to the {@link ProductCatalog.parse | parse()} method.
|
|
1039
|
+
*
|
|
1040
|
+
* @category Classes
|
|
1041
|
+
*
|
|
1042
|
+
* @example
|
|
1043
|
+
* ```typescript
|
|
1044
|
+
* import { ProductCatalog } from "@tmlmt/cooklang-parser";
|
|
1045
|
+
*
|
|
1046
|
+
* const catalog = `
|
|
1047
|
+
* [eggs]
|
|
1048
|
+
* aliases = ["oeuf", "huevo"]
|
|
1049
|
+
* 01123 = { name = "Single Egg", size = "1", price = 2 }
|
|
1050
|
+
* 11244 = { name = "Pack of 6 eggs", size = "6", price = 10 }
|
|
1051
|
+
*
|
|
1052
|
+
* [flour]
|
|
1053
|
+
* aliases = ["farine", "Mehl"]
|
|
1054
|
+
* 01124 = { name = "Small pack", size = "100%g", price = 1.5 }
|
|
1055
|
+
* 14141 = { name = "Big pack", size = "6%kg", price = 10 }
|
|
1056
|
+
* `
|
|
1057
|
+
* const catalog = new ProductCatalog(catalog);
|
|
1058
|
+
* const eggs = catalog.find("oeuf");
|
|
1059
|
+
* ```
|
|
1060
|
+
*/
|
|
1061
|
+
declare class ProductCatalog {
|
|
1062
|
+
products: ProductOption[];
|
|
1063
|
+
constructor(tomlContent?: string);
|
|
1064
|
+
/**
|
|
1065
|
+
* Parses a TOML string into a list of product options.
|
|
1066
|
+
* @param tomlContent - The TOML string to parse.
|
|
1067
|
+
* @returns A parsed list of `ProductOption`.
|
|
1068
|
+
*/
|
|
1069
|
+
parse(tomlContent: string): ProductOption[];
|
|
1070
|
+
/**
|
|
1071
|
+
* Stringifies the catalog to a TOML string.
|
|
1072
|
+
* @returns The TOML string representation of the catalog.
|
|
1073
|
+
*/
|
|
1074
|
+
stringify(): string;
|
|
1075
|
+
/**
|
|
1076
|
+
* Adds a product to the catalog.
|
|
1077
|
+
* @param productOption - The product to add.
|
|
1078
|
+
*/
|
|
1079
|
+
add(productOption: ProductOption): void;
|
|
1080
|
+
/**
|
|
1081
|
+
* Removes a product from the catalog by its ID.
|
|
1082
|
+
* @param productId - The ID of the product to remove.
|
|
1083
|
+
*/
|
|
1084
|
+
remove(productId: string): void;
|
|
1085
|
+
private isValidTomlContent;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
552
1088
|
/**
|
|
553
1089
|
* Shopping List generator.
|
|
554
1090
|
*
|
|
@@ -579,7 +1115,7 @@ declare class ShoppingList {
|
|
|
579
1115
|
/**
|
|
580
1116
|
* The ingredients in the shopping list.
|
|
581
1117
|
*/
|
|
582
|
-
ingredients:
|
|
1118
|
+
ingredients: AddedIngredient[];
|
|
583
1119
|
/**
|
|
584
1120
|
* The recipes in the shopping list.
|
|
585
1121
|
*/
|
|
@@ -602,21 +1138,17 @@ declare class ShoppingList {
|
|
|
602
1138
|
* Adds a recipe to the shopping list, then automatically
|
|
603
1139
|
* recalculates the quantities and recategorize the ingredients.
|
|
604
1140
|
* @param recipe - The recipe to add.
|
|
605
|
-
* @param
|
|
1141
|
+
* @param options - Options for adding the recipe.
|
|
1142
|
+
* @throws Error if the recipe has alternatives without corresponding choices.
|
|
606
1143
|
*/
|
|
607
|
-
add_recipe(recipe: Recipe,
|
|
608
|
-
factor: number;
|
|
609
|
-
} | {
|
|
610
|
-
servings: number;
|
|
611
|
-
}): void;
|
|
1144
|
+
add_recipe(recipe: Recipe, options?: AddedRecipeOptions): void;
|
|
612
1145
|
/**
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
* @param
|
|
616
|
-
* @
|
|
617
|
-
* @deprecated since v2.0.3. Use the other call signature with `scaling` instead. Will be removed in v3
|
|
1146
|
+
* Checks if a recipe has unresolved alternatives (alternatives without provided choices).
|
|
1147
|
+
* @param recipe - The recipe to check.
|
|
1148
|
+
* @param choices - The choices provided for the recipe.
|
|
1149
|
+
* @returns An error message if there are unresolved alternatives, undefined otherwise.
|
|
618
1150
|
*/
|
|
619
|
-
|
|
1151
|
+
private getUnresolvedAlternativesError;
|
|
620
1152
|
/**
|
|
621
1153
|
* Removes a recipe from the shopping list, then automatically
|
|
622
1154
|
* recalculates the quantities and recategorize the ingredients.s
|
|
@@ -636,4 +1168,374 @@ declare class ShoppingList {
|
|
|
636
1168
|
categorize(): void;
|
|
637
1169
|
}
|
|
638
1170
|
|
|
639
|
-
|
|
1171
|
+
/**
|
|
1172
|
+
* Options for the {@link ShoppingCart} constructor
|
|
1173
|
+
* @category Types
|
|
1174
|
+
*/
|
|
1175
|
+
interface ShoppingCartOptions {
|
|
1176
|
+
/**
|
|
1177
|
+
* A product catalog to connect to the cart
|
|
1178
|
+
*/
|
|
1179
|
+
catalog?: ProductCatalog;
|
|
1180
|
+
/**
|
|
1181
|
+
* A shopping list to connect to the cart
|
|
1182
|
+
*/
|
|
1183
|
+
list?: ShoppingList;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Key information about the {@link ShoppingCart}
|
|
1187
|
+
* @category Types
|
|
1188
|
+
*/
|
|
1189
|
+
interface ShoppingCartSummary {
|
|
1190
|
+
/**
|
|
1191
|
+
* The total price of the cart
|
|
1192
|
+
*/
|
|
1193
|
+
totalPrice: number;
|
|
1194
|
+
/**
|
|
1195
|
+
* The total number of items in the cart
|
|
1196
|
+
*/
|
|
1197
|
+
totalItems: number;
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Shopping Cart Manager: a tool to find the best combination of products to buy (defined in a {@link ProductCatalog}) to satisfy a {@link ShoppingList}.
|
|
1201
|
+
*
|
|
1202
|
+
* @example
|
|
1203
|
+
* ```ts
|
|
1204
|
+
* const shoppingList = new ShoppingList();
|
|
1205
|
+
* const recipe = new Recipe("@flour{600%g}");
|
|
1206
|
+
* shoppingList.add_recipe(recipe);
|
|
1207
|
+
*
|
|
1208
|
+
* const catalog = new ProductCatalog();
|
|
1209
|
+
* catalog.products = [
|
|
1210
|
+
* {
|
|
1211
|
+
* id: "flour-1kg",
|
|
1212
|
+
* productName: "Flour (1kg)",
|
|
1213
|
+
* ingredientName: "flour",
|
|
1214
|
+
* price: 10,
|
|
1215
|
+
* size: { type: "fixed", value: { type: "decimal", value: 1000 } },
|
|
1216
|
+
* unit: "g",
|
|
1217
|
+
* },
|
|
1218
|
+
* {
|
|
1219
|
+
* id: "flour-500g",
|
|
1220
|
+
* productName: "Flour (500g)",
|
|
1221
|
+
* ingredientName: "flour",
|
|
1222
|
+
* price: 6,
|
|
1223
|
+
* size: { type: "fixed", value: { type: "decimal", value: 500 } },
|
|
1224
|
+
* unit: "g",
|
|
1225
|
+
* },
|
|
1226
|
+
* ];
|
|
1227
|
+
*
|
|
1228
|
+
* const shoppingCart = new ShoppingCart({list: shoppingList, catalog}))
|
|
1229
|
+
* shoppingCart.buildCart();
|
|
1230
|
+
* ```
|
|
1231
|
+
*
|
|
1232
|
+
* @category Classes
|
|
1233
|
+
*/
|
|
1234
|
+
declare class ShoppingCart {
|
|
1235
|
+
/**
|
|
1236
|
+
* The product catalog to use for matching products
|
|
1237
|
+
*/
|
|
1238
|
+
productCatalog?: ProductCatalog;
|
|
1239
|
+
/**
|
|
1240
|
+
* The shopping list to build the cart from
|
|
1241
|
+
*/
|
|
1242
|
+
shoppingList?: ShoppingList;
|
|
1243
|
+
/**
|
|
1244
|
+
* The content of the cart
|
|
1245
|
+
*/
|
|
1246
|
+
cart: CartContent;
|
|
1247
|
+
/**
|
|
1248
|
+
* The ingredients that were successfully matched with products
|
|
1249
|
+
*/
|
|
1250
|
+
match: CartMatch;
|
|
1251
|
+
/**
|
|
1252
|
+
* The ingredients that could not be matched with products
|
|
1253
|
+
*/
|
|
1254
|
+
misMatch: CartMisMatch;
|
|
1255
|
+
/**
|
|
1256
|
+
* Key information about the shopping cart
|
|
1257
|
+
*/
|
|
1258
|
+
summary: ShoppingCartSummary;
|
|
1259
|
+
/**
|
|
1260
|
+
* Creates a new ShoppingCart instance
|
|
1261
|
+
* @param options - {@link ShoppingCartOptions | Options} for the constructor
|
|
1262
|
+
*/
|
|
1263
|
+
constructor(options?: ShoppingCartOptions);
|
|
1264
|
+
/**
|
|
1265
|
+
* Sets the product catalog to use for matching products
|
|
1266
|
+
* To use if a catalog was not provided at the creation of the instance
|
|
1267
|
+
* @param catalog - The {@link ProductCatalog} to set
|
|
1268
|
+
*/
|
|
1269
|
+
setProductCatalog(catalog: ProductCatalog): void;
|
|
1270
|
+
/**
|
|
1271
|
+
* Sets the shopping list to build the cart from.
|
|
1272
|
+
* To use if a shopping list was not provided at the creation of the instance
|
|
1273
|
+
* @param list - The {@link ShoppingList} to set
|
|
1274
|
+
*/
|
|
1275
|
+
setShoppingList(list: ShoppingList): void;
|
|
1276
|
+
/**
|
|
1277
|
+
* Builds the cart from the shopping list and product catalog
|
|
1278
|
+
* @remarks
|
|
1279
|
+
* - If a combination of product(s) is successfully found for a given ingredient, the latter will be listed in the {@link ShoppingCart.match | match} array
|
|
1280
|
+
* in addition to that combination being added to the {@link ShoppingCart.cart | cart}.
|
|
1281
|
+
* - Otherwise, the latter will be listed in the {@link ShoppingCart.misMatch | misMatch} array. Possible causes can be:
|
|
1282
|
+
* - No product is listed in the catalog for that ingredient
|
|
1283
|
+
* - The ingredient has no quantity, a text quantity
|
|
1284
|
+
* - The ingredient's quantity unit is incompatible with the units of the candidate products listed in the catalog
|
|
1285
|
+
* @throws {@link NoProductCatalogForCartError} if no product catalog is set
|
|
1286
|
+
* @throws {@link NoShoppingListForCartError} if no shopping list is set
|
|
1287
|
+
* @returns `true` if all ingredients in the shopping list have been matched to products in the catalog, or `false` otherwise
|
|
1288
|
+
*/
|
|
1289
|
+
buildCart(): boolean;
|
|
1290
|
+
/**
|
|
1291
|
+
* Gets the product options for a given ingredient
|
|
1292
|
+
* @param ingredient - The ingredient to get the product options for
|
|
1293
|
+
* @returns An array of {@link ProductOption}
|
|
1294
|
+
*/
|
|
1295
|
+
private getProductOptions;
|
|
1296
|
+
/**
|
|
1297
|
+
* Gets the optimum match for a given ingredient and product option
|
|
1298
|
+
* @param ingredient - The ingredient to match
|
|
1299
|
+
* @param options - The product options to choose from
|
|
1300
|
+
* @returns An array of {@link ProductSelection}
|
|
1301
|
+
* @throws {@link NoProductMatchError} if no match can be found
|
|
1302
|
+
*/
|
|
1303
|
+
private getOptimumMatch;
|
|
1304
|
+
/**
|
|
1305
|
+
* Reset the cart's properties
|
|
1306
|
+
*/
|
|
1307
|
+
private resetCart;
|
|
1308
|
+
/**
|
|
1309
|
+
* Calculate the cart's key info and store it in the cart's {@link ShoppingCart.summary | summary} property.
|
|
1310
|
+
* This function is automatically invoked by {@link ShoppingCart.buildCart | buildCart() } method.
|
|
1311
|
+
* @returns the total price and number of items in the cart
|
|
1312
|
+
*/
|
|
1313
|
+
summarize(): ShoppingCartSummary;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Format a numeric value (decimal or fraction) to a string.
|
|
1318
|
+
*
|
|
1319
|
+
* @param value - The decimal or fraction value to format
|
|
1320
|
+
* @returns The formatted string representation
|
|
1321
|
+
* @category Helpers
|
|
1322
|
+
*
|
|
1323
|
+
* @example
|
|
1324
|
+
* ```typescript
|
|
1325
|
+
* formatNumericValue({ type: "decimal", decimal: 1.5 }); // "1.5"
|
|
1326
|
+
* formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "1/2"
|
|
1327
|
+
* ```
|
|
1328
|
+
*/
|
|
1329
|
+
declare function formatNumericValue(value: DecimalValue | FractionValue): string;
|
|
1330
|
+
/**
|
|
1331
|
+
* Format a single value (text, decimal, or fraction) to a string.
|
|
1332
|
+
*
|
|
1333
|
+
* @param value - The value to format
|
|
1334
|
+
* @returns The formatted string representation
|
|
1335
|
+
* @category Helpers
|
|
1336
|
+
*
|
|
1337
|
+
* @example
|
|
1338
|
+
* ```typescript
|
|
1339
|
+
* formatSingleValue({ type: "text", text: "a pinch" }); // "a pinch"
|
|
1340
|
+
* formatSingleValue({ type: "decimal", decimal: 2 }); // "2"
|
|
1341
|
+
* formatSingleValue({ type: "fraction", num: 3, den: 4 }); // "3/4"
|
|
1342
|
+
* ```
|
|
1343
|
+
*/
|
|
1344
|
+
declare function formatSingleValue(value: TextValue | DecimalValue | FractionValue): string;
|
|
1345
|
+
/**
|
|
1346
|
+
* Format a quantity (fixed value or range) to a string.
|
|
1347
|
+
*
|
|
1348
|
+
* @param quantity - The quantity to format
|
|
1349
|
+
* @returns The formatted string representation
|
|
1350
|
+
* @category Helpers
|
|
1351
|
+
*
|
|
1352
|
+
* @example
|
|
1353
|
+
* ```typescript
|
|
1354
|
+
* formatQuantity({ type: "fixed", value: { type: "decimal", decimal: 100 } }); // "100"
|
|
1355
|
+
* formatQuantity({ type: "range", min: { type: "decimal", decimal: 1 }, max: { type: "decimal", decimal: 2 } }); // "1-2"
|
|
1356
|
+
* ```
|
|
1357
|
+
*/
|
|
1358
|
+
declare function formatQuantity(quantity: FixedValue | Range): string;
|
|
1359
|
+
/**
|
|
1360
|
+
* Format a unit to a string. Handles both plain string units and Unit objects.
|
|
1361
|
+
*
|
|
1362
|
+
* @param unit - The unit to format (string, Unit object, or undefined)
|
|
1363
|
+
* @returns The formatted unit string, or empty string if undefined
|
|
1364
|
+
* @category Helpers
|
|
1365
|
+
*
|
|
1366
|
+
* @example
|
|
1367
|
+
* ```typescript
|
|
1368
|
+
* formatUnit("g"); // "g"
|
|
1369
|
+
* formatUnit({ name: "grams" }); // "grams"
|
|
1370
|
+
* formatUnit(undefined); // ""
|
|
1371
|
+
* ```
|
|
1372
|
+
*/
|
|
1373
|
+
declare function formatUnit(unit: string | Unit | undefined): string;
|
|
1374
|
+
/**
|
|
1375
|
+
* Format a quantity with its unit to a string.
|
|
1376
|
+
*
|
|
1377
|
+
* @param quantity - The quantity to format
|
|
1378
|
+
* @param unit - The unit to append (string, Unit object, or undefined)
|
|
1379
|
+
* @returns The formatted string with quantity and unit
|
|
1380
|
+
* @category Helpers
|
|
1381
|
+
*
|
|
1382
|
+
* @example
|
|
1383
|
+
* ```typescript
|
|
1384
|
+
* formatQuantityWithUnit({ type: "fixed", value: { type: "decimal", decimal: 100 } }, "g"); // "100 g"
|
|
1385
|
+
* formatQuantityWithUnit({ type: "fixed", value: { type: "decimal", decimal: 2 } }, undefined); // "2"
|
|
1386
|
+
* ```
|
|
1387
|
+
*/
|
|
1388
|
+
declare function formatQuantityWithUnit(quantity: FixedValue | Range | undefined, unit: string | Unit | undefined): string;
|
|
1389
|
+
/**
|
|
1390
|
+
* Format a QuantityWithExtendedUnit to a string.
|
|
1391
|
+
*
|
|
1392
|
+
* @param item - The quantity with extended unit to format
|
|
1393
|
+
* @returns The formatted string
|
|
1394
|
+
* @category Helpers
|
|
1395
|
+
*/
|
|
1396
|
+
declare function formatExtendedQuantity(item: QuantityWithExtendedUnit): string;
|
|
1397
|
+
/**
|
|
1398
|
+
* Format an IngredientItemQuantity with all its equivalents to a string.
|
|
1399
|
+
*
|
|
1400
|
+
* @param itemQuantity - The ingredient item quantity to format
|
|
1401
|
+
* @param separator - The separator between primary and equivalent quantities (default: " | ")
|
|
1402
|
+
* @returns The formatted string with all quantities
|
|
1403
|
+
* @category Helpers
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* ```typescript
|
|
1407
|
+
* // For an ingredient like @flour{100%g|3.5%oz}
|
|
1408
|
+
* formatItemQuantity(itemQuantity); // "100 g | 3.5 oz"
|
|
1409
|
+
* formatItemQuantity(itemQuantity, " / "); // "100 g / 3.5 oz"
|
|
1410
|
+
* ```
|
|
1411
|
+
*/
|
|
1412
|
+
declare function formatItemQuantity(itemQuantity: IngredientItemQuantity, separator?: string): string;
|
|
1413
|
+
/**
|
|
1414
|
+
* Check if an ingredient item is a grouped alternative (vs inline alternative).
|
|
1415
|
+
*
|
|
1416
|
+
* Grouped alternatives are ingredients that share a group key (e.g., `@|milk|...`)
|
|
1417
|
+
* and are distributed across multiple tokens in the recipe.
|
|
1418
|
+
*
|
|
1419
|
+
* @param item - The ingredient item to check
|
|
1420
|
+
* @returns true if this is a grouped alternative
|
|
1421
|
+
* @category Helpers
|
|
1422
|
+
*
|
|
1423
|
+
* @example
|
|
1424
|
+
* ```typescript
|
|
1425
|
+
* for (const item of step.items) {
|
|
1426
|
+
* if (item.type === 'ingredient') {
|
|
1427
|
+
* if (isGroupedItem(item)) {
|
|
1428
|
+
* // Handle grouped alternative (e.g., show with strikethrough if not selected)
|
|
1429
|
+
* } else {
|
|
1430
|
+
* // Handle inline alternative (e.g., hide if not selected)
|
|
1431
|
+
* }
|
|
1432
|
+
* }
|
|
1433
|
+
* }
|
|
1434
|
+
* ```
|
|
1435
|
+
*/
|
|
1436
|
+
declare function isGroupedItem(item: IngredientItem): boolean;
|
|
1437
|
+
/**
|
|
1438
|
+
* Determines if a specific alternative in an IngredientItem is selected
|
|
1439
|
+
* based on the applied choices.
|
|
1440
|
+
*
|
|
1441
|
+
* Use this in renderers to determine how an ingredient alternative should be displayed.
|
|
1442
|
+
*
|
|
1443
|
+
* @param recipe - The Recipe instance containing choices
|
|
1444
|
+
* @param choices - The choices that have been made
|
|
1445
|
+
* @param item - The IngredientItem to check
|
|
1446
|
+
* @param alternativeIndex - The index within item.alternatives to check (for inline alternatives only)
|
|
1447
|
+
* @returns true if this alternative is the selected one
|
|
1448
|
+
* @category Helpers
|
|
1449
|
+
*
|
|
1450
|
+
* @example
|
|
1451
|
+
* ```typescript
|
|
1452
|
+
* const recipe = new Recipe(cooklangText);
|
|
1453
|
+
* for (const item of step.items) {
|
|
1454
|
+
* if (item.type === 'ingredient') {
|
|
1455
|
+
* item.alternatives.forEach((alt, idx) => {
|
|
1456
|
+
* const isSelected = isAlternativeSelected(item, idx, recipe, choices);
|
|
1457
|
+
* // Render differently based on isSelected
|
|
1458
|
+
* });
|
|
1459
|
+
* }
|
|
1460
|
+
* }
|
|
1461
|
+
* ```
|
|
1462
|
+
*/
|
|
1463
|
+
declare function isAlternativeSelected(recipe: Recipe, choices: RecipeChoices, item: IngredientItem, alternativeIndex?: number): boolean;
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* Type guard to check if an ingredient quantity-like object is an AND group.
|
|
1467
|
+
* *
|
|
1468
|
+
* @param x - The quantity-like entry to check
|
|
1469
|
+
* @returns true if this is an AND group (has `and` property)
|
|
1470
|
+
* @category Helpers
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```typescript
|
|
1474
|
+
* for (const entry of ingredient.quantities) {
|
|
1475
|
+
* if (isAndGroup(entry)) {
|
|
1476
|
+
* // entry.and contains the list of quantities in the AND group
|
|
1477
|
+
* }
|
|
1478
|
+
* }
|
|
1479
|
+
* ```
|
|
1480
|
+
*/
|
|
1481
|
+
declare function isAndGroup(x: IngredientQuantityGroup | IngredientQuantityAndGroup): x is IngredientQuantityAndGroup;
|
|
1482
|
+
declare function isAndGroup(x: QuantityWithUnitLike | Group): x is AndGroup;
|
|
1483
|
+
/**
|
|
1484
|
+
* Type guard to check if an ingredient quantity entry is a simple group.
|
|
1485
|
+
*
|
|
1486
|
+
* Simple groups have a single quantity with optional unit and equivalents.
|
|
1487
|
+
*
|
|
1488
|
+
* @param entry - The quantity entry to check
|
|
1489
|
+
* @returns true if this is a simple group (has `quantity` property)
|
|
1490
|
+
* @category Helpers
|
|
1491
|
+
*
|
|
1492
|
+
* @example
|
|
1493
|
+
* ```typescript
|
|
1494
|
+
* for (const entry of ingredient.quantities) {
|
|
1495
|
+
* if (isSimpleGroup(entry)) {
|
|
1496
|
+
* // entry.quantity is available
|
|
1497
|
+
* // entry.unit is available
|
|
1498
|
+
* }
|
|
1499
|
+
* }
|
|
1500
|
+
* ```
|
|
1501
|
+
*/
|
|
1502
|
+
declare function isSimpleGroup(entry: IngredientQuantityGroup | IngredientQuantityAndGroup): entry is IngredientQuantityGroup;
|
|
1503
|
+
/**
|
|
1504
|
+
* Type guard to check if an ingredient quantity entry has alternatives.
|
|
1505
|
+
*
|
|
1506
|
+
* @param entry - The quantity entry to check
|
|
1507
|
+
* @returns true if this entry has alternatives
|
|
1508
|
+
* @category Helpers
|
|
1509
|
+
*
|
|
1510
|
+
* @example
|
|
1511
|
+
* ```typescript
|
|
1512
|
+
* for (const entry of ingredient.quantities) {
|
|
1513
|
+
* if (hasAlternatives(entry)) {
|
|
1514
|
+
* // entry.alternatives is available and non-empty
|
|
1515
|
+
* for (const alt of entry.alternatives) {
|
|
1516
|
+
* console.log(`Alternative ingredient index: ${alt.index}`);
|
|
1517
|
+
* }
|
|
1518
|
+
* }
|
|
1519
|
+
* }
|
|
1520
|
+
* ```
|
|
1521
|
+
*/
|
|
1522
|
+
declare function hasAlternatives(entry: IngredientQuantityGroup | IngredientQuantityAndGroup): entry is (IngredientQuantityGroup | IngredientQuantityAndGroup) & {
|
|
1523
|
+
alternatives: AlternativeIngredientRef[];
|
|
1524
|
+
};
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* Error thrown when trying to build a shopping cart without a product catalog
|
|
1528
|
+
* @category Errors
|
|
1529
|
+
*/
|
|
1530
|
+
declare class NoProductCatalogForCartError extends Error {
|
|
1531
|
+
constructor();
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Error thrown when trying to build a shopping cart without a shopping list
|
|
1535
|
+
* @category Errors
|
|
1536
|
+
*/
|
|
1537
|
+
declare class NoShoppingListForCartError extends Error {
|
|
1538
|
+
constructor();
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
export { type AddedIngredient, type AddedRecipe, type AddedRecipeOptions, type AlternativeIngredientRef, type AndGroup, type ArbitraryScalable, type ArbitraryScalableItem, type CartContent, type CartMatch, type CartMisMatch, type CategorizedIngredients, type Category, CategoryConfig, type CategoryIngredient, type Cookware, type CookwareFlag, type CookwareItem, type DecimalValue, type FixedNumericValue, type FixedValue, type FlatAndGroup, type FlatGroup, type FlatOrGroup, type FractionValue, type GetIngredientQuantitiesOptions, type Group, type Ingredient, type IngredientAlternative, type IngredientExtras, type IngredientFlag, type IngredientItem, type IngredientItemQuantity, type IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type Metadata, NoProductCatalogForCartError, type NoProductMatchErrorCode, NoShoppingListForCartError, type Note, type NoteItem, type OrGroup, ProductCatalog, type ProductMatch, type ProductMisMatch, type ProductOption, type ProductOptionBase, type ProductOptionCore, type ProductSelection, type ProductSize, type QuantityBase, type QuantityWithExtendedUnit, type QuantityWithPlainUnit, type QuantityWithUnitDef, type QuantityWithUnitLike, type Range, Recipe, type RecipeAlternatives, type RecipeChoices, type RecipeWithFactor, type RecipeWithServings, Section, ShoppingCart, type ShoppingCartOptions, type ShoppingCartSummary, ShoppingList, type Step, type StepItem, type TextItem, type TextValue, type Timer, type TimerItem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitSystem, type UnitType, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup };
|