@tmlmt/cooklang-parser 3.0.0-alpha.10 → 3.0.0-alpha.12

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/dist/index.d.cts CHANGED
@@ -97,6 +97,18 @@ declare class Recipe {
97
97
  * @see {@link Recipe.scaleBy | scaleBy()} and {@link Recipe.scaleTo | scaleTo()} methods
98
98
  */
99
99
  servings?: number;
100
+ /**
101
+ * Gets the unit system specified in the recipe metadata.
102
+ * Used for resolving ambiguous units like tsp, tbsp, cup, etc.
103
+ *
104
+ * @returns The unit system if specified, or undefined to use defaults
105
+ */
106
+ get unitSystem(): SpecificUnitSystem | undefined;
107
+ /**
108
+ * External storage for unit system (not a property on instances).
109
+ * Used for resolving ambiguous units during quantity addition.
110
+ */
111
+ private static unitSystems;
100
112
  /**
101
113
  * External storage for item count (not a property on instances).
102
114
  * Used for giving ID numbers to items during parsing.
@@ -192,6 +204,26 @@ declare class Recipe {
192
204
  * @returns A new Recipe instance with the scaled ingredients.
193
205
  */
194
206
  scaleBy(factor: number | Big): Recipe;
207
+ /**
208
+ * Converts all ingredient quantities in the recipe to a target unit system.
209
+ *
210
+ * @param system - The target unit system to convert to (metric, US, UK, JP)
211
+ * @param method - How to handle existing quantities:
212
+ * - "keep": Keep all existing equivalents (swap if needed, or add converted)
213
+ * - "replace": Replace primary with target system quantity, discard equivalent used for conversion
214
+ * - "remove": Only keep target system quantity, delete all equivalents
215
+ * @returns A new Recipe instance with converted quantities
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * // Convert a recipe to metric, keeping original units as equivalents
220
+ * const metricRecipe = recipe.convertTo("metric", "keep");
221
+ *
222
+ * // Convert to US units, removing all other equivalents
223
+ * const usRecipe = recipe.convertTo("US", "remove");
224
+ * ```
225
+ */
226
+ convertTo(system: SpecificUnitSystem, method: "keep" | "replace" | "remove"): Recipe;
195
227
  /**
196
228
  * Gets the number of servings for the recipe.
197
229
  * @private
@@ -315,6 +347,12 @@ interface Metadata {
315
347
  picture?: string;
316
348
  /** The introduction of the recipe. */
317
349
  introduction?: string;
350
+ /**
351
+ * The unit system used in the recipe for ambiguous units like tsp, tbsp, cup.
352
+ * See [Unit Conversion Guide](/guide-unit-conversion) for more information.
353
+ * This stores the original value as written by the user.
354
+ */
355
+ "unit system"?: string;
318
356
  }
319
357
  /**
320
358
  * Represents a quantity described by text, e.g. "a pinch"
@@ -470,31 +508,27 @@ interface Ingredient {
470
508
  /** The collection of potential additional metadata for the ingredient */
471
509
  extras?: IngredientExtras;
472
510
  }
473
- /**
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).
477
- * @category Types
478
- */
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[];
511
+ type MaybeScalableQuantity = QuantityWithExtendedUnit & {
485
512
  /** Indicates whether this quantity should be scaled when the recipe serving size changes. */
486
513
  scalable: boolean;
487
- }
514
+ /** A list of equivalent quantities/units for this ingredient mention besides the primary quantity.
515
+ * For `@salt{1%tsp|5%g}`, the main quantity is 1 tsp and the equivalents will contain 5 g. */
516
+ equivalents?: QuantityWithExtendedUnit[];
517
+ };
518
+ type WithOptionalQuantity<T> = (T & MaybeScalableQuantity) | (T & {
519
+ quantity?: undefined;
520
+ scalable?: never;
521
+ unit?: never;
522
+ equivalents?: never;
523
+ });
488
524
  /**
489
525
  * Represents a single ingredient choice within a single or a group of `IngredientItem`s. It points
490
526
  * to a specific ingredient and its corresponding quantity information.
491
527
  * @category Types
492
528
  */
493
- interface IngredientAlternative {
529
+ type IngredientAlternativeBase = {
494
530
  /** The index of the ingredient within the {@link Recipe.ingredients} array. */
495
531
  index: number;
496
- /** The quantity of this specific mention of the ingredient */
497
- itemQuantity?: IngredientItemQuantity;
498
532
  /** The alias/name of the ingredient as it should be displayed for this occurrence. */
499
533
  displayName: string;
500
534
  /** An optional note for this specific choice (e.g., "for a vegan version"). */
@@ -503,7 +537,8 @@ interface IngredientAlternative {
503
537
  * with group keys: the id of the corresponding ingredient item (e.g. "ingredient-item-2").
504
538
  * Can be useful for creating alternative selection UI elements with anchor links */
505
539
  itemId?: string;
506
- }
540
+ };
541
+ type IngredientAlternative = WithOptionalQuantity<IngredientAlternativeBase>;
507
542
  /**
508
543
  * Represents an ingredient item in a recipe step.
509
544
  * @category Types
@@ -853,12 +888,23 @@ type CartMisMatch = ProductMisMatch[];
853
888
  * Represents the type category of a unit used for quantities
854
889
  * @category Types
855
890
  */
856
- type UnitType = "mass" | "volume" | "count";
891
+ type UnitType = "mass" | "volume" | "count" | "other";
892
+ /**
893
+ * Represents the specific measurement systems
894
+ * @category Types
895
+ */
896
+ type SpecificUnitSystem = "metric" | "US" | "UK" | "JP";
857
897
  /**
858
898
  * Represents the measurement system a unit belongs to
859
899
  * @category Types
860
900
  */
861
- type UnitSystem = "metric" | "imperial";
901
+ type UnitSystem = SpecificUnitSystem | "ambiguous";
902
+ /**
903
+ * Conversion factors for ambiguous units that can belong to multiple systems.
904
+ * Maps each possible system to its toBase conversion factor.
905
+ * @category Types
906
+ */
907
+ type ToBaseBySystem = Partial<Record<SpecificUnitSystem, number>>;
862
908
  /**
863
909
  * Represents a unit used to describe quantities
864
910
  * @category Types
@@ -878,8 +924,28 @@ interface UnitDefinition extends Unit {
878
924
  system: UnitSystem;
879
925
  /** e.g. ['gram', 'grams'] */
880
926
  aliases: string[];
881
- /** Conversion factor to the base unit of its type */
927
+ /** Conversion factor to the base unit of its type (uses default system for ambiguous units) */
882
928
  toBase: number;
929
+ /** For ambiguous units: conversion factors for each possible system */
930
+ toBaseBySystem?: ToBaseBySystem;
931
+ /** Whether this unit is a candidate for "best unit" selection (default: true) */
932
+ isBestUnit?: boolean;
933
+ /** Maximum value before upgrading to a larger unit (default: 999) */
934
+ maxValue?: number;
935
+ /** Fraction display configuration */
936
+ fractions?: UnitFractionConfig;
937
+ }
938
+ /**
939
+ * Configuration for fraction display on a unit
940
+ * @category Types
941
+ */
942
+ interface UnitFractionConfig {
943
+ /** Whether to approximate decimals as fractions for this unit */
944
+ enabled: boolean;
945
+ /** Allowed denominators (default: [2, 3, 4, 8]) */
946
+ denominators?: number[];
947
+ /** Maximum whole number in mixed fraction before falling back to decimal (default: 4) */
948
+ maxWhole?: number;
883
949
  }
884
950
  /**
885
951
  * Represents a resolved unit definition or a lightweight placeholder for non-standard units
@@ -1313,10 +1379,30 @@ declare class ShoppingCart {
1313
1379
  summarize(): ShoppingCartSummary;
1314
1380
  }
1315
1381
 
1382
+ /**
1383
+ * Render a fraction using Unicode vulgar fraction characters when available.
1384
+ * Handles improper fractions by extracting the whole part (e.g., 5/4 → "1¼").
1385
+ *
1386
+ * @param num - The numerator
1387
+ * @param den - The denominator
1388
+ * @returns The fraction as a string, using vulgar characters if available
1389
+ * @category Helpers
1390
+ *
1391
+ * @example
1392
+ * ```typescript
1393
+ * renderFractionAsVulgar(1, 2); // "½"
1394
+ * renderFractionAsVulgar(3, 4); // "¾"
1395
+ * renderFractionAsVulgar(5, 4); // "1¼"
1396
+ * renderFractionAsVulgar(7, 3); // "2⅓"
1397
+ * renderFractionAsVulgar(2, 5); // "2/5" (no vulgar character available)
1398
+ * ```
1399
+ */
1400
+ declare function renderFractionAsVulgar(num: number, den: number): string;
1316
1401
  /**
1317
1402
  * Format a numeric value (decimal or fraction) to a string.
1318
1403
  *
1319
1404
  * @param value - The decimal or fraction value to format
1405
+ * @param useVulgar - Whether to use Unicode vulgar fraction characters (default: false)
1320
1406
  * @returns The formatted string representation
1321
1407
  * @category Helpers
1322
1408
  *
@@ -1324,9 +1410,11 @@ declare class ShoppingCart {
1324
1410
  * ```typescript
1325
1411
  * formatNumericValue({ type: "decimal", decimal: 1.5 }); // "1.5"
1326
1412
  * formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "1/2"
1413
+ * formatNumericValue({ type: "fraction", num: 1, den: 2 }, true); // "½"
1414
+ * formatNumericValue({ type: "fraction", num: 5, den: 4 }, true); // "1¼"
1327
1415
  * ```
1328
1416
  */
1329
- declare function formatNumericValue(value: DecimalValue | FractionValue): string;
1417
+ declare function formatNumericValue(value: DecimalValue | FractionValue, useVulgar?: boolean): string;
1330
1418
  /**
1331
1419
  * Format a single value (text, decimal, or fraction) to a string.
1332
1420
  *
@@ -1409,7 +1497,7 @@ declare function formatExtendedQuantity(item: QuantityWithExtendedUnit): string;
1409
1497
  * formatItemQuantity(itemQuantity, " / "); // "100 g / 3.5 oz"
1410
1498
  * ```
1411
1499
  */
1412
- declare function formatItemQuantity(itemQuantity: IngredientItemQuantity, separator?: string): string;
1500
+ declare function formatItemQuantity(itemQuantity: MaybeScalableQuantity, separator?: string): string;
1413
1501
  /**
1414
1502
  * Check if an ingredient item is a grouped alternative (vs inline alternative).
1415
1503
  *
@@ -1523,6 +1611,19 @@ declare function hasAlternatives(entry: IngredientQuantityGroup | IngredientQuan
1523
1611
  alternatives: AlternativeIngredientRef[];
1524
1612
  };
1525
1613
 
1614
+ /**
1615
+ * Converts a quantity to the best unit in a target system.
1616
+ * Returns the converted quantity, or undefined if the unit type is "other" or not convertible.
1617
+ *
1618
+ * @category Helpers
1619
+ *
1620
+ * @param quantity - The quantity to convert
1621
+ * @param system - The target unit system
1622
+ * @returns The converted quantity, or undefined if conversion not possible
1623
+ */
1624
+ declare function convertQuantityToSystem(quantity: QuantityWithPlainUnit, system: SpecificUnitSystem): QuantityWithPlainUnit | undefined;
1625
+ declare function convertQuantityToSystem(quantity: QuantityWithExtendedUnit, system: SpecificUnitSystem): QuantityWithExtendedUnit | undefined;
1626
+
1526
1627
  /**
1527
1628
  * Error thrown when trying to build a shopping cart without a product catalog
1528
1629
  * @category Errors
@@ -1538,4 +1639,4 @@ declare class NoShoppingListForCartError extends Error {
1538
1639
  constructor();
1539
1640
  }
1540
1641
 
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 };
1642
+ 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 IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type MaybeScalableQuantity, 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 SpecificUnitSystem, type Step, type StepItem, type TextItem, type TextValue, type Timer, type TimerItem, type ToBaseBySystem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitSystem, type UnitType, convertQuantityToSystem, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup, renderFractionAsVulgar };
package/dist/index.d.ts CHANGED
@@ -97,6 +97,18 @@ declare class Recipe {
97
97
  * @see {@link Recipe.scaleBy | scaleBy()} and {@link Recipe.scaleTo | scaleTo()} methods
98
98
  */
99
99
  servings?: number;
100
+ /**
101
+ * Gets the unit system specified in the recipe metadata.
102
+ * Used for resolving ambiguous units like tsp, tbsp, cup, etc.
103
+ *
104
+ * @returns The unit system if specified, or undefined to use defaults
105
+ */
106
+ get unitSystem(): SpecificUnitSystem | undefined;
107
+ /**
108
+ * External storage for unit system (not a property on instances).
109
+ * Used for resolving ambiguous units during quantity addition.
110
+ */
111
+ private static unitSystems;
100
112
  /**
101
113
  * External storage for item count (not a property on instances).
102
114
  * Used for giving ID numbers to items during parsing.
@@ -192,6 +204,26 @@ declare class Recipe {
192
204
  * @returns A new Recipe instance with the scaled ingredients.
193
205
  */
194
206
  scaleBy(factor: number | Big): Recipe;
207
+ /**
208
+ * Converts all ingredient quantities in the recipe to a target unit system.
209
+ *
210
+ * @param system - The target unit system to convert to (metric, US, UK, JP)
211
+ * @param method - How to handle existing quantities:
212
+ * - "keep": Keep all existing equivalents (swap if needed, or add converted)
213
+ * - "replace": Replace primary with target system quantity, discard equivalent used for conversion
214
+ * - "remove": Only keep target system quantity, delete all equivalents
215
+ * @returns A new Recipe instance with converted quantities
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * // Convert a recipe to metric, keeping original units as equivalents
220
+ * const metricRecipe = recipe.convertTo("metric", "keep");
221
+ *
222
+ * // Convert to US units, removing all other equivalents
223
+ * const usRecipe = recipe.convertTo("US", "remove");
224
+ * ```
225
+ */
226
+ convertTo(system: SpecificUnitSystem, method: "keep" | "replace" | "remove"): Recipe;
195
227
  /**
196
228
  * Gets the number of servings for the recipe.
197
229
  * @private
@@ -315,6 +347,12 @@ interface Metadata {
315
347
  picture?: string;
316
348
  /** The introduction of the recipe. */
317
349
  introduction?: string;
350
+ /**
351
+ * The unit system used in the recipe for ambiguous units like tsp, tbsp, cup.
352
+ * See [Unit Conversion Guide](/guide-unit-conversion) for more information.
353
+ * This stores the original value as written by the user.
354
+ */
355
+ "unit system"?: string;
318
356
  }
319
357
  /**
320
358
  * Represents a quantity described by text, e.g. "a pinch"
@@ -470,31 +508,27 @@ interface Ingredient {
470
508
  /** The collection of potential additional metadata for the ingredient */
471
509
  extras?: IngredientExtras;
472
510
  }
473
- /**
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).
477
- * @category Types
478
- */
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[];
511
+ type MaybeScalableQuantity = QuantityWithExtendedUnit & {
485
512
  /** Indicates whether this quantity should be scaled when the recipe serving size changes. */
486
513
  scalable: boolean;
487
- }
514
+ /** A list of equivalent quantities/units for this ingredient mention besides the primary quantity.
515
+ * For `@salt{1%tsp|5%g}`, the main quantity is 1 tsp and the equivalents will contain 5 g. */
516
+ equivalents?: QuantityWithExtendedUnit[];
517
+ };
518
+ type WithOptionalQuantity<T> = (T & MaybeScalableQuantity) | (T & {
519
+ quantity?: undefined;
520
+ scalable?: never;
521
+ unit?: never;
522
+ equivalents?: never;
523
+ });
488
524
  /**
489
525
  * Represents a single ingredient choice within a single or a group of `IngredientItem`s. It points
490
526
  * to a specific ingredient and its corresponding quantity information.
491
527
  * @category Types
492
528
  */
493
- interface IngredientAlternative {
529
+ type IngredientAlternativeBase = {
494
530
  /** The index of the ingredient within the {@link Recipe.ingredients} array. */
495
531
  index: number;
496
- /** The quantity of this specific mention of the ingredient */
497
- itemQuantity?: IngredientItemQuantity;
498
532
  /** The alias/name of the ingredient as it should be displayed for this occurrence. */
499
533
  displayName: string;
500
534
  /** An optional note for this specific choice (e.g., "for a vegan version"). */
@@ -503,7 +537,8 @@ interface IngredientAlternative {
503
537
  * with group keys: the id of the corresponding ingredient item (e.g. "ingredient-item-2").
504
538
  * Can be useful for creating alternative selection UI elements with anchor links */
505
539
  itemId?: string;
506
- }
540
+ };
541
+ type IngredientAlternative = WithOptionalQuantity<IngredientAlternativeBase>;
507
542
  /**
508
543
  * Represents an ingredient item in a recipe step.
509
544
  * @category Types
@@ -853,12 +888,23 @@ type CartMisMatch = ProductMisMatch[];
853
888
  * Represents the type category of a unit used for quantities
854
889
  * @category Types
855
890
  */
856
- type UnitType = "mass" | "volume" | "count";
891
+ type UnitType = "mass" | "volume" | "count" | "other";
892
+ /**
893
+ * Represents the specific measurement systems
894
+ * @category Types
895
+ */
896
+ type SpecificUnitSystem = "metric" | "US" | "UK" | "JP";
857
897
  /**
858
898
  * Represents the measurement system a unit belongs to
859
899
  * @category Types
860
900
  */
861
- type UnitSystem = "metric" | "imperial";
901
+ type UnitSystem = SpecificUnitSystem | "ambiguous";
902
+ /**
903
+ * Conversion factors for ambiguous units that can belong to multiple systems.
904
+ * Maps each possible system to its toBase conversion factor.
905
+ * @category Types
906
+ */
907
+ type ToBaseBySystem = Partial<Record<SpecificUnitSystem, number>>;
862
908
  /**
863
909
  * Represents a unit used to describe quantities
864
910
  * @category Types
@@ -878,8 +924,28 @@ interface UnitDefinition extends Unit {
878
924
  system: UnitSystem;
879
925
  /** e.g. ['gram', 'grams'] */
880
926
  aliases: string[];
881
- /** Conversion factor to the base unit of its type */
927
+ /** Conversion factor to the base unit of its type (uses default system for ambiguous units) */
882
928
  toBase: number;
929
+ /** For ambiguous units: conversion factors for each possible system */
930
+ toBaseBySystem?: ToBaseBySystem;
931
+ /** Whether this unit is a candidate for "best unit" selection (default: true) */
932
+ isBestUnit?: boolean;
933
+ /** Maximum value before upgrading to a larger unit (default: 999) */
934
+ maxValue?: number;
935
+ /** Fraction display configuration */
936
+ fractions?: UnitFractionConfig;
937
+ }
938
+ /**
939
+ * Configuration for fraction display on a unit
940
+ * @category Types
941
+ */
942
+ interface UnitFractionConfig {
943
+ /** Whether to approximate decimals as fractions for this unit */
944
+ enabled: boolean;
945
+ /** Allowed denominators (default: [2, 3, 4, 8]) */
946
+ denominators?: number[];
947
+ /** Maximum whole number in mixed fraction before falling back to decimal (default: 4) */
948
+ maxWhole?: number;
883
949
  }
884
950
  /**
885
951
  * Represents a resolved unit definition or a lightweight placeholder for non-standard units
@@ -1313,10 +1379,30 @@ declare class ShoppingCart {
1313
1379
  summarize(): ShoppingCartSummary;
1314
1380
  }
1315
1381
 
1382
+ /**
1383
+ * Render a fraction using Unicode vulgar fraction characters when available.
1384
+ * Handles improper fractions by extracting the whole part (e.g., 5/4 → "1¼").
1385
+ *
1386
+ * @param num - The numerator
1387
+ * @param den - The denominator
1388
+ * @returns The fraction as a string, using vulgar characters if available
1389
+ * @category Helpers
1390
+ *
1391
+ * @example
1392
+ * ```typescript
1393
+ * renderFractionAsVulgar(1, 2); // "½"
1394
+ * renderFractionAsVulgar(3, 4); // "¾"
1395
+ * renderFractionAsVulgar(5, 4); // "1¼"
1396
+ * renderFractionAsVulgar(7, 3); // "2⅓"
1397
+ * renderFractionAsVulgar(2, 5); // "2/5" (no vulgar character available)
1398
+ * ```
1399
+ */
1400
+ declare function renderFractionAsVulgar(num: number, den: number): string;
1316
1401
  /**
1317
1402
  * Format a numeric value (decimal or fraction) to a string.
1318
1403
  *
1319
1404
  * @param value - The decimal or fraction value to format
1405
+ * @param useVulgar - Whether to use Unicode vulgar fraction characters (default: false)
1320
1406
  * @returns The formatted string representation
1321
1407
  * @category Helpers
1322
1408
  *
@@ -1324,9 +1410,11 @@ declare class ShoppingCart {
1324
1410
  * ```typescript
1325
1411
  * formatNumericValue({ type: "decimal", decimal: 1.5 }); // "1.5"
1326
1412
  * formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "1/2"
1413
+ * formatNumericValue({ type: "fraction", num: 1, den: 2 }, true); // "½"
1414
+ * formatNumericValue({ type: "fraction", num: 5, den: 4 }, true); // "1¼"
1327
1415
  * ```
1328
1416
  */
1329
- declare function formatNumericValue(value: DecimalValue | FractionValue): string;
1417
+ declare function formatNumericValue(value: DecimalValue | FractionValue, useVulgar?: boolean): string;
1330
1418
  /**
1331
1419
  * Format a single value (text, decimal, or fraction) to a string.
1332
1420
  *
@@ -1409,7 +1497,7 @@ declare function formatExtendedQuantity(item: QuantityWithExtendedUnit): string;
1409
1497
  * formatItemQuantity(itemQuantity, " / "); // "100 g / 3.5 oz"
1410
1498
  * ```
1411
1499
  */
1412
- declare function formatItemQuantity(itemQuantity: IngredientItemQuantity, separator?: string): string;
1500
+ declare function formatItemQuantity(itemQuantity: MaybeScalableQuantity, separator?: string): string;
1413
1501
  /**
1414
1502
  * Check if an ingredient item is a grouped alternative (vs inline alternative).
1415
1503
  *
@@ -1523,6 +1611,19 @@ declare function hasAlternatives(entry: IngredientQuantityGroup | IngredientQuan
1523
1611
  alternatives: AlternativeIngredientRef[];
1524
1612
  };
1525
1613
 
1614
+ /**
1615
+ * Converts a quantity to the best unit in a target system.
1616
+ * Returns the converted quantity, or undefined if the unit type is "other" or not convertible.
1617
+ *
1618
+ * @category Helpers
1619
+ *
1620
+ * @param quantity - The quantity to convert
1621
+ * @param system - The target unit system
1622
+ * @returns The converted quantity, or undefined if conversion not possible
1623
+ */
1624
+ declare function convertQuantityToSystem(quantity: QuantityWithPlainUnit, system: SpecificUnitSystem): QuantityWithPlainUnit | undefined;
1625
+ declare function convertQuantityToSystem(quantity: QuantityWithExtendedUnit, system: SpecificUnitSystem): QuantityWithExtendedUnit | undefined;
1626
+
1526
1627
  /**
1527
1628
  * Error thrown when trying to build a shopping cart without a product catalog
1528
1629
  * @category Errors
@@ -1538,4 +1639,4 @@ declare class NoShoppingListForCartError extends Error {
1538
1639
  constructor();
1539
1640
  }
1540
1641
 
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 };
1642
+ 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 IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type MaybeScalableQuantity, 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 SpecificUnitSystem, type Step, type StepItem, type TextItem, type TextValue, type Timer, type TimerItem, type ToBaseBySystem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitSystem, type UnitType, convertQuantityToSystem, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup, renderFractionAsVulgar };