@tmlmt/cooklang-parser 3.0.0-alpha.12 → 3.0.0-alpha.13
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.cjs +228 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -53
- package/dist/index.d.ts +68 -53
- package/dist/index.js +228 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -320,6 +320,12 @@ var i = (() => {
|
|
|
320
320
|
})();
|
|
321
321
|
|
|
322
322
|
// src/regex.ts
|
|
323
|
+
var metadataKeyRegex = /^([^:\n]+?):/gm;
|
|
324
|
+
var numericValueRegex = /^-?\d+(\.\d+)?$/;
|
|
325
|
+
var nestedMetaVarRegex = (varName) => new RegExp(
|
|
326
|
+
`^${varName}:\\s*\\r?\\n((?:[ ]+.+(?:\\r?\\n|$))+)`,
|
|
327
|
+
"m"
|
|
328
|
+
);
|
|
323
329
|
var metadataRegex = d().literal("---").newline().startCaptureGroup().anyCharacter().zeroOrMore().optional().endGroup().newline().literal("---").dotAll().toRegExp();
|
|
324
330
|
var scalingMetaValueRegex = (varName) => d().startAnchor().literal(varName).literal(":").anyOf("\\t ").zeroOrMore().startCaptureGroup().startCaptureGroup().notAnyOf(",\\n").oneOrMore().endGroup().startGroup().literal(",").whitespace().zeroOrMore().startCaptureGroup().anyCharacter().oneOrMore().endGroup().endGroup().optional().endGroup().endAnchor().multiline().toRegExp();
|
|
325
331
|
var nonWordChar = "\\s@#~\\[\\]{(,;:!?";
|
|
@@ -931,6 +937,20 @@ var InvalidQuantityFormat = class extends Error {
|
|
|
931
937
|
this.name = "InvalidQuantityFormat";
|
|
932
938
|
}
|
|
933
939
|
};
|
|
940
|
+
var NoTabAsIndentError = class extends Error {
|
|
941
|
+
constructor() {
|
|
942
|
+
super(
|
|
943
|
+
`Tabs are not allowed for indentation in metadata blocks. Please use spaces only.`
|
|
944
|
+
);
|
|
945
|
+
this.name = "NoTabAsIndentError";
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
var BadIndentationError = class extends Error {
|
|
949
|
+
constructor() {
|
|
950
|
+
super(`Bad identation of a nested block. Please use spaces only.`);
|
|
951
|
+
this.name = "BadIndentationError";
|
|
952
|
+
}
|
|
953
|
+
};
|
|
934
954
|
|
|
935
955
|
// src/utils/type_guards.ts
|
|
936
956
|
function isGroup(x) {
|
|
@@ -1488,6 +1508,108 @@ function parseListMetaVar(content, varName) {
|
|
|
1488
1508
|
return listMatch[2].split("\n").filter((line) => line.trim() !== "").map((line) => line.replace(/^\s*-\s*/, "").trim());
|
|
1489
1509
|
}
|
|
1490
1510
|
}
|
|
1511
|
+
function extractAllMetadataKeys(content) {
|
|
1512
|
+
const keys = [];
|
|
1513
|
+
for (const match of content.matchAll(metadataKeyRegex)) {
|
|
1514
|
+
keys.push(match[1].trim());
|
|
1515
|
+
}
|
|
1516
|
+
return [...new Set(keys)];
|
|
1517
|
+
}
|
|
1518
|
+
function parseNestedMetaVar(content, varName) {
|
|
1519
|
+
const match = content.match(nestedMetaVarRegex(varName));
|
|
1520
|
+
if (!match) return void 0;
|
|
1521
|
+
const nestedContent = match[1];
|
|
1522
|
+
return parseNestedBlock(nestedContent);
|
|
1523
|
+
}
|
|
1524
|
+
function parseNestedBlock(content) {
|
|
1525
|
+
const lines = content.split(/\r?\n/).filter((line) => line.trim() !== "");
|
|
1526
|
+
if (lines.length === 0) return void 0;
|
|
1527
|
+
const baseIndentMatch = lines[0].match(/^(\s*)/);
|
|
1528
|
+
if (baseIndentMatch?.[0]?.includes(" ")) {
|
|
1529
|
+
throw new NoTabAsIndentError();
|
|
1530
|
+
}
|
|
1531
|
+
const baseIndent = baseIndentMatch?.[1]?.length;
|
|
1532
|
+
if (lines[0].trim().startsWith("- ")) return void 0;
|
|
1533
|
+
const result = {};
|
|
1534
|
+
let i2 = 0;
|
|
1535
|
+
while (i2 < lines.length) {
|
|
1536
|
+
const line = lines[i2];
|
|
1537
|
+
const leadingWhitespace = line.match(/^(\s*)/)?.[1];
|
|
1538
|
+
if (leadingWhitespace && leadingWhitespace.includes(" ")) {
|
|
1539
|
+
throw new NoTabAsIndentError();
|
|
1540
|
+
}
|
|
1541
|
+
const currentIndent = leadingWhitespace.length;
|
|
1542
|
+
if (currentIndent < baseIndent) {
|
|
1543
|
+
break;
|
|
1544
|
+
}
|
|
1545
|
+
if (currentIndent !== baseIndent) {
|
|
1546
|
+
throw new BadIndentationError();
|
|
1547
|
+
}
|
|
1548
|
+
const keyValueMatch = line.match(/^[ ]*([^:\n]+?):\s*(.*)$/);
|
|
1549
|
+
if (!keyValueMatch) {
|
|
1550
|
+
i2++;
|
|
1551
|
+
continue;
|
|
1552
|
+
}
|
|
1553
|
+
const key = keyValueMatch[1].trim();
|
|
1554
|
+
const rawValue = keyValueMatch[2].trim();
|
|
1555
|
+
if (rawValue === "") {
|
|
1556
|
+
const childLines = [];
|
|
1557
|
+
let j = i2 + 1;
|
|
1558
|
+
while (j < lines.length) {
|
|
1559
|
+
const childLine = lines[j];
|
|
1560
|
+
const childIndent = childLine.match(/^([ ]*)/)?.[1]?.length;
|
|
1561
|
+
if (childIndent && childIndent > baseIndent) {
|
|
1562
|
+
childLines.push(childLine);
|
|
1563
|
+
j++;
|
|
1564
|
+
} else {
|
|
1565
|
+
break;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
if (childLines.length > 0) {
|
|
1569
|
+
const firstChildTrimmed = childLines[0].trim();
|
|
1570
|
+
if (firstChildTrimmed.startsWith("- ")) {
|
|
1571
|
+
const reconstructedContent = `${key}:
|
|
1572
|
+
${childLines.join("\n")}`;
|
|
1573
|
+
const listResult = parseListMetaVar(reconstructedContent, key);
|
|
1574
|
+
if (listResult) {
|
|
1575
|
+
result[key] = listResult.map(
|
|
1576
|
+
(item) => parseMetadataValue(item)
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
} else {
|
|
1580
|
+
const childContent = childLines.join("\n");
|
|
1581
|
+
const nested = parseNestedBlock(childContent);
|
|
1582
|
+
if (nested) {
|
|
1583
|
+
result[key] = nested;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
i2 = j;
|
|
1588
|
+
} else {
|
|
1589
|
+
result[key] = parseMetadataValue(rawValue);
|
|
1590
|
+
i2++;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
return result;
|
|
1594
|
+
}
|
|
1595
|
+
function parseMetadataValue(rawValue) {
|
|
1596
|
+
if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
|
|
1597
|
+
return rawValue.slice(1, -1).split(",").map((item) => item.trim());
|
|
1598
|
+
}
|
|
1599
|
+
if (numericValueRegex.test(rawValue)) {
|
|
1600
|
+
return Number(rawValue);
|
|
1601
|
+
}
|
|
1602
|
+
return rawValue;
|
|
1603
|
+
}
|
|
1604
|
+
function parseAnyMetaVar(content, varName) {
|
|
1605
|
+
const nested = parseNestedMetaVar(content, varName);
|
|
1606
|
+
if (nested) return nested;
|
|
1607
|
+
const list = parseListMetaVar(content, varName);
|
|
1608
|
+
if (list) return list;
|
|
1609
|
+
const simple = parseSimpleMetaVar(content, varName);
|
|
1610
|
+
if (simple) return parseMetadataValue(simple);
|
|
1611
|
+
return void 0;
|
|
1612
|
+
}
|
|
1491
1613
|
function extractMetadata(content) {
|
|
1492
1614
|
const metadata = {};
|
|
1493
1615
|
let servings = void 0;
|
|
@@ -1495,13 +1617,24 @@ function extractMetadata(content) {
|
|
|
1495
1617
|
if (!metadataContent) {
|
|
1496
1618
|
return { metadata };
|
|
1497
1619
|
}
|
|
1498
|
-
|
|
1620
|
+
const handledKeys = /* @__PURE__ */ new Set([
|
|
1621
|
+
// Simple string fields
|
|
1499
1622
|
"title",
|
|
1623
|
+
"author",
|
|
1624
|
+
"locale",
|
|
1625
|
+
"introduction",
|
|
1626
|
+
"description",
|
|
1627
|
+
"course",
|
|
1628
|
+
"category",
|
|
1629
|
+
"diet",
|
|
1630
|
+
"cuisine",
|
|
1631
|
+
"difficulty",
|
|
1632
|
+
// Source fields
|
|
1500
1633
|
"source",
|
|
1501
1634
|
"source.name",
|
|
1502
1635
|
"source.url",
|
|
1503
|
-
"author",
|
|
1504
1636
|
"source.author",
|
|
1637
|
+
// Time fields
|
|
1505
1638
|
"prep time",
|
|
1506
1639
|
"time.prep",
|
|
1507
1640
|
"cook time",
|
|
@@ -1509,6 +1642,23 @@ function extractMetadata(content) {
|
|
|
1509
1642
|
"time required",
|
|
1510
1643
|
"time",
|
|
1511
1644
|
"duration",
|
|
1645
|
+
// Image fields
|
|
1646
|
+
"image",
|
|
1647
|
+
"picture",
|
|
1648
|
+
"images",
|
|
1649
|
+
"pictures",
|
|
1650
|
+
// Unit system
|
|
1651
|
+
"unit system",
|
|
1652
|
+
// Scaling fields
|
|
1653
|
+
"servings",
|
|
1654
|
+
"yield",
|
|
1655
|
+
"serves",
|
|
1656
|
+
// List fields
|
|
1657
|
+
"tags"
|
|
1658
|
+
]);
|
|
1659
|
+
for (const metaVar of [
|
|
1660
|
+
"title",
|
|
1661
|
+
"author",
|
|
1512
1662
|
"locale",
|
|
1513
1663
|
"introduction",
|
|
1514
1664
|
"description",
|
|
@@ -1516,17 +1666,57 @@ function extractMetadata(content) {
|
|
|
1516
1666
|
"category",
|
|
1517
1667
|
"diet",
|
|
1518
1668
|
"cuisine",
|
|
1519
|
-
"difficulty"
|
|
1520
|
-
"image",
|
|
1521
|
-
"picture"
|
|
1669
|
+
"difficulty"
|
|
1522
1670
|
]) {
|
|
1523
1671
|
const stringMetaValue = parseSimpleMetaVar(metadataContent, metaVar);
|
|
1524
1672
|
if (stringMetaValue) metadata[metaVar] = stringMetaValue;
|
|
1525
1673
|
}
|
|
1674
|
+
const sourceNested = parseNestedMetaVar(metadataContent, "source");
|
|
1675
|
+
const sourceTxt = parseSimpleMetaVar(metadataContent, "source");
|
|
1676
|
+
const sourceName = parseSimpleMetaVar(metadataContent, "source.name");
|
|
1677
|
+
const sourceUrl = parseSimpleMetaVar(metadataContent, "source.url");
|
|
1678
|
+
const sourceAuthor = parseSimpleMetaVar(metadataContent, "source.author");
|
|
1679
|
+
if (sourceNested) {
|
|
1680
|
+
const source = {};
|
|
1681
|
+
if (typeof sourceNested.name === "string") source.name = sourceNested.name;
|
|
1682
|
+
if (typeof sourceNested.url === "string") source.url = sourceNested.url;
|
|
1683
|
+
if (typeof sourceNested.author === "string")
|
|
1684
|
+
source.author = sourceNested.author;
|
|
1685
|
+
if (Object.keys(source).length > 0) metadata.source = source;
|
|
1686
|
+
} else if (sourceName || sourceAuthor || sourceUrl) {
|
|
1687
|
+
const source = {};
|
|
1688
|
+
if (sourceName) source.name = sourceName;
|
|
1689
|
+
if (sourceUrl) source.url = sourceUrl;
|
|
1690
|
+
if (sourceAuthor) source.author = sourceAuthor;
|
|
1691
|
+
metadata.source = source;
|
|
1692
|
+
} else if (sourceTxt) {
|
|
1693
|
+
metadata.source = sourceTxt;
|
|
1694
|
+
}
|
|
1695
|
+
const timeNested = parseNestedMetaVar(metadataContent, "time");
|
|
1696
|
+
const prepTime = parseSimpleMetaVar(metadataContent, "prep time") ?? parseSimpleMetaVar(metadataContent, "time.prep");
|
|
1697
|
+
const cookTime = parseSimpleMetaVar(metadataContent, "cook time") ?? parseSimpleMetaVar(metadataContent, "time.cook");
|
|
1698
|
+
const totalTime = parseSimpleMetaVar(metadataContent, "time required") ?? parseSimpleMetaVar(metadataContent, "time") ?? parseSimpleMetaVar(metadataContent, "duration");
|
|
1699
|
+
if (timeNested) {
|
|
1700
|
+
const time = {};
|
|
1701
|
+
if (typeof timeNested.prep === "string") time.prep = timeNested.prep;
|
|
1702
|
+
if (typeof timeNested.cook === "string") time.cook = timeNested.cook;
|
|
1703
|
+
if (typeof timeNested.total === "string") time.total = timeNested.total;
|
|
1704
|
+
if (Object.keys(time).length > 0) metadata.time = time;
|
|
1705
|
+
} else if (prepTime || cookTime || totalTime) {
|
|
1706
|
+
const time = {};
|
|
1707
|
+
if (prepTime) time.prep = prepTime;
|
|
1708
|
+
if (cookTime) time.cook = cookTime;
|
|
1709
|
+
if (totalTime) time.total = totalTime;
|
|
1710
|
+
metadata.time = time;
|
|
1711
|
+
}
|
|
1712
|
+
const image = parseSimpleMetaVar(metadataContent, "image") ?? parseSimpleMetaVar(metadataContent, "picture");
|
|
1713
|
+
if (image) metadata.image = image;
|
|
1714
|
+
const images = parseListMetaVar(metadataContent, "images") ?? parseListMetaVar(metadataContent, "pictures");
|
|
1715
|
+
if (images) metadata.images = images;
|
|
1526
1716
|
let unitSystem;
|
|
1527
1717
|
const unitSystemRaw = parseSimpleMetaVar(metadataContent, "unit system");
|
|
1528
1718
|
if (unitSystemRaw) {
|
|
1529
|
-
metadata
|
|
1719
|
+
metadata.unitSystem = unitSystemRaw;
|
|
1530
1720
|
const unitSystemMap = {
|
|
1531
1721
|
metric: "metric",
|
|
1532
1722
|
us: "US",
|
|
@@ -1535,16 +1725,22 @@ function extractMetadata(content) {
|
|
|
1535
1725
|
};
|
|
1536
1726
|
unitSystem = unitSystemMap[unitSystemRaw.toLowerCase()];
|
|
1537
1727
|
}
|
|
1538
|
-
for (const metaVar of ["
|
|
1728
|
+
for (const metaVar of ["servings", "yield", "serves"]) {
|
|
1539
1729
|
const scalingMetaValue = parseScalingMetaVar(metadataContent, metaVar);
|
|
1540
1730
|
if (scalingMetaValue && scalingMetaValue[1]) {
|
|
1541
1731
|
metadata[metaVar] = scalingMetaValue[1];
|
|
1542
1732
|
servings = scalingMetaValue[0];
|
|
1543
1733
|
}
|
|
1544
1734
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1735
|
+
const tags = parseListMetaVar(metadataContent, "tags");
|
|
1736
|
+
if (tags) metadata.tags = tags;
|
|
1737
|
+
const allKeys = extractAllMetadataKeys(metadataContent);
|
|
1738
|
+
for (const key of allKeys) {
|
|
1739
|
+
if (handledKeys.has(key)) continue;
|
|
1740
|
+
const value = parseAnyMetaVar(metadataContent, key);
|
|
1741
|
+
if (value !== void 0) {
|
|
1742
|
+
metadata[key] = value;
|
|
1743
|
+
}
|
|
1548
1744
|
}
|
|
1549
1745
|
return { metadata, servings, unitSystem };
|
|
1550
1746
|
}
|
|
@@ -2445,7 +2641,7 @@ var _Recipe = class _Recipe {
|
|
|
2445
2641
|
* Quantities are grouped by their alternative signature and summed using addEquivalentsAndSimplify.
|
|
2446
2642
|
* @internal
|
|
2447
2643
|
*/
|
|
2448
|
-
|
|
2644
|
+
_populateIngredientQuantities() {
|
|
2449
2645
|
for (const ing of this.ingredients) {
|
|
2450
2646
|
delete ing.quantities;
|
|
2451
2647
|
delete ing.usedAsPrimary;
|
|
@@ -2806,7 +3002,7 @@ var _Recipe = class _Recipe {
|
|
|
2806
3002
|
if (!section.isBlank()) {
|
|
2807
3003
|
this.sections.push(section);
|
|
2808
3004
|
}
|
|
2809
|
-
this.
|
|
3005
|
+
this._populateIngredientQuantities();
|
|
2810
3006
|
}
|
|
2811
3007
|
/**
|
|
2812
3008
|
* Scales the recipe to a new number of servings. In practice, it calls
|
|
@@ -2904,7 +3100,7 @@ var _Recipe = class _Recipe {
|
|
|
2904
3100
|
factor
|
|
2905
3101
|
);
|
|
2906
3102
|
}
|
|
2907
|
-
newRecipe.
|
|
3103
|
+
newRecipe._populateIngredientQuantities();
|
|
2908
3104
|
newRecipe.servings = (0, import_big4.default)(originalServings).times(factor).toNumber();
|
|
2909
3105
|
if (newRecipe.metadata.servings && this.metadata.servings) {
|
|
2910
3106
|
if (floatRegex.test(String(this.metadata.servings).replace(",", ".").trim())) {
|
|
@@ -2969,9 +3165,9 @@ var _Recipe = class _Recipe {
|
|
|
2969
3165
|
if (method === "remove") {
|
|
2970
3166
|
return newPrimary;
|
|
2971
3167
|
} else if (method === "replace") {
|
|
3168
|
+
if (source === "converted") remainingEquivalents.push(oldPrimary);
|
|
2972
3169
|
if (remainingEquivalents.length > 0) {
|
|
2973
3170
|
newPrimary.equivalents = remainingEquivalents;
|
|
2974
|
-
if (source === "converted") newPrimary.equivalents.push(oldPrimary);
|
|
2975
3171
|
}
|
|
2976
3172
|
} else {
|
|
2977
3173
|
newPrimary.equivalents = [oldPrimary, ...remainingEquivalents];
|
|
@@ -3089,7 +3285,7 @@ var _Recipe = class _Recipe {
|
|
|
3089
3285
|
for (const alternatives of newRecipe.choices.ingredientItems.values()) {
|
|
3090
3286
|
convertAlternatives(alternatives);
|
|
3091
3287
|
}
|
|
3092
|
-
newRecipe.
|
|
3288
|
+
newRecipe._populateIngredientQuantities();
|
|
3093
3289
|
if (method !== "keep") _Recipe.unitSystems.set(newRecipe, system);
|
|
3094
3290
|
return newRecipe;
|
|
3095
3291
|
}
|
|
@@ -3142,9 +3338,9 @@ var Recipe = _Recipe;
|
|
|
3142
3338
|
var ShoppingList = class {
|
|
3143
3339
|
/**
|
|
3144
3340
|
* Creates a new ShoppingList instance
|
|
3145
|
-
* @param
|
|
3341
|
+
* @param categoryConfigStr - The category configuration to parse.
|
|
3146
3342
|
*/
|
|
3147
|
-
constructor(
|
|
3343
|
+
constructor(categoryConfigStr) {
|
|
3148
3344
|
// TODO: backport type change
|
|
3149
3345
|
/**
|
|
3150
3346
|
* The ingredients in the shopping list.
|
|
@@ -3157,16 +3353,16 @@ var ShoppingList = class {
|
|
|
3157
3353
|
/**
|
|
3158
3354
|
* The category configuration for the shopping list.
|
|
3159
3355
|
*/
|
|
3160
|
-
__publicField(this, "
|
|
3356
|
+
__publicField(this, "categoryConfig");
|
|
3161
3357
|
/**
|
|
3162
3358
|
* The categorized ingredients in the shopping list.
|
|
3163
3359
|
*/
|
|
3164
3360
|
__publicField(this, "categories");
|
|
3165
|
-
if (
|
|
3166
|
-
this.
|
|
3361
|
+
if (categoryConfigStr) {
|
|
3362
|
+
this.setCategoryConfig(categoryConfigStr);
|
|
3167
3363
|
}
|
|
3168
3364
|
}
|
|
3169
|
-
|
|
3365
|
+
calculateIngredients() {
|
|
3170
3366
|
this.ingredients = [];
|
|
3171
3367
|
const addIngredientQuantity = (name, quantityTotal) => {
|
|
3172
3368
|
const quantityTotalExtended = extendAllUnits(quantityTotal);
|
|
@@ -3253,7 +3449,7 @@ var ShoppingList = class {
|
|
|
3253
3449
|
* @param options - Options for adding the recipe.
|
|
3254
3450
|
* @throws Error if the recipe has alternatives without corresponding choices.
|
|
3255
3451
|
*/
|
|
3256
|
-
|
|
3452
|
+
addRecipe(recipe, options = {}) {
|
|
3257
3453
|
const errorMessage = this.getUnresolvedAlternativesError(
|
|
3258
3454
|
recipe,
|
|
3259
3455
|
options.choices
|
|
@@ -3282,7 +3478,7 @@ var ShoppingList = class {
|
|
|
3282
3478
|
});
|
|
3283
3479
|
}
|
|
3284
3480
|
}
|
|
3285
|
-
this.
|
|
3481
|
+
this.calculateIngredients();
|
|
3286
3482
|
this.categorize();
|
|
3287
3483
|
}
|
|
3288
3484
|
/**
|
|
@@ -3322,15 +3518,15 @@ var ShoppingList = class {
|
|
|
3322
3518
|
}
|
|
3323
3519
|
/**
|
|
3324
3520
|
* Removes a recipe from the shopping list, then automatically
|
|
3325
|
-
* recalculates the quantities and recategorize the ingredients.
|
|
3521
|
+
* recalculates the quantities and recategorize the ingredients.
|
|
3326
3522
|
* @param index - The index of the recipe to remove.
|
|
3327
3523
|
*/
|
|
3328
|
-
|
|
3524
|
+
removeRecipe(index) {
|
|
3329
3525
|
if (index < 0 || index >= this.recipes.length) {
|
|
3330
3526
|
throw new Error("Index out of bounds");
|
|
3331
3527
|
}
|
|
3332
3528
|
this.recipes.splice(index, 1);
|
|
3333
|
-
this.
|
|
3529
|
+
this.calculateIngredients();
|
|
3334
3530
|
this.categorize();
|
|
3335
3531
|
}
|
|
3336
3532
|
/**
|
|
@@ -3338,10 +3534,10 @@ var ShoppingList = class {
|
|
|
3338
3534
|
* and automatically categorize current ingredients from the list.
|
|
3339
3535
|
* @param config - The category configuration to parse.
|
|
3340
3536
|
*/
|
|
3341
|
-
|
|
3537
|
+
setCategoryConfig(config) {
|
|
3342
3538
|
if (typeof config === "string")
|
|
3343
|
-
this.
|
|
3344
|
-
else if (config instanceof CategoryConfig) this.
|
|
3539
|
+
this.categoryConfig = new CategoryConfig(config);
|
|
3540
|
+
else if (config instanceof CategoryConfig) this.categoryConfig = config;
|
|
3345
3541
|
else throw new Error("Invalid category configuration");
|
|
3346
3542
|
this.categorize();
|
|
3347
3543
|
}
|
|
@@ -3350,17 +3546,17 @@ var ShoppingList = class {
|
|
|
3350
3546
|
* Will use the category config if any, otherwise all ingredients will be placed in the "other" category
|
|
3351
3547
|
*/
|
|
3352
3548
|
categorize() {
|
|
3353
|
-
if (!this.
|
|
3549
|
+
if (!this.categoryConfig) {
|
|
3354
3550
|
this.categories = { other: this.ingredients };
|
|
3355
3551
|
return;
|
|
3356
3552
|
}
|
|
3357
3553
|
const categories = { other: [] };
|
|
3358
|
-
for (const category of this.
|
|
3554
|
+
for (const category of this.categoryConfig.categories) {
|
|
3359
3555
|
categories[category.name] = [];
|
|
3360
3556
|
}
|
|
3361
3557
|
for (const ingredient of this.ingredients) {
|
|
3362
3558
|
let found = false;
|
|
3363
|
-
for (const category of this.
|
|
3559
|
+
for (const category of this.categoryConfig.categories) {
|
|
3364
3560
|
for (const categoryIngredient of category.ingredients) {
|
|
3365
3561
|
if (categoryIngredient.aliases.includes(ingredient.name)) {
|
|
3366
3562
|
categories[category.name].push(ingredient);
|
|
@@ -3424,7 +3620,6 @@ var ShoppingCart = class {
|
|
|
3424
3620
|
setProductCatalog(catalog) {
|
|
3425
3621
|
this.productCatalog = catalog;
|
|
3426
3622
|
}
|
|
3427
|
-
// TODO: harmonize recipe name to use underscores
|
|
3428
3623
|
/**
|
|
3429
3624
|
* Sets the shopping list to build the cart from.
|
|
3430
3625
|
* To use if a shopping list was not provided at the creation of the instance
|