@tmlmt/cooklang-parser 3.0.0-alpha.21 → 3.0.0-alpha.23
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 +112 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -11
- package/dist/index.d.ts +20 -11
- package/dist/index.js +112 -47
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.d.cts
CHANGED
|
@@ -334,7 +334,7 @@ interface MetadataObject {
|
|
|
334
334
|
* Represents any value that can appear in recipe metadata.
|
|
335
335
|
* @category Types
|
|
336
336
|
*/
|
|
337
|
-
type MetadataValue = string | number | (string | number)[] | MetadataObject | MetadataSource | MetadataTime | Yield | undefined;
|
|
337
|
+
type MetadataValue = string | number | (string | number | MetadataObject)[] | MetadataObject | MetadataSource | MetadataTime | Yield | undefined;
|
|
338
338
|
/**
|
|
339
339
|
* Represents the metadata of a recipe.
|
|
340
340
|
* @category Types
|
|
@@ -509,7 +509,7 @@ interface IngredientExtras {
|
|
|
509
509
|
* Used if: the ingredient is a recipe
|
|
510
510
|
*
|
|
511
511
|
* @example
|
|
512
|
-
* ```
|
|
512
|
+
* ```yaml
|
|
513
513
|
* Take @./essentials/doughs/pizza dough{1} out of the freezer and let it unfreeze overnight
|
|
514
514
|
* ```
|
|
515
515
|
* Would lead to:
|
|
@@ -541,9 +541,12 @@ interface AlternativeIngredientRef {
|
|
|
541
541
|
interface IngredientQuantityGroup extends QuantityWithPlainUnit {
|
|
542
542
|
/**
|
|
543
543
|
* References to alternative ingredients for this quantity group.
|
|
544
|
+
* Each inner array represents one alternative choice option (subgroup).
|
|
545
|
+
* Items within the same inner array are combined with "+" (AND),
|
|
546
|
+
* while different inner arrays represent "or" alternatives.
|
|
544
547
|
* If undefined, this group has no alternatives.
|
|
545
548
|
*/
|
|
546
|
-
alternatives?: AlternativeIngredientRef[];
|
|
549
|
+
alternatives?: AlternativeIngredientRef[][];
|
|
547
550
|
}
|
|
548
551
|
/**
|
|
549
552
|
* Represents an AND group of quantities when primary units are incompatible but equivalents can be summed.
|
|
@@ -557,9 +560,12 @@ interface IngredientQuantityAndGroup extends FlatAndGroup<QuantityWithPlainUnit>
|
|
|
557
560
|
equivalents?: QuantityWithPlainUnit[];
|
|
558
561
|
/**
|
|
559
562
|
* References to alternative ingredients for this quantity group.
|
|
563
|
+
* Each inner array represents one alternative choice option (subgroup).
|
|
564
|
+
* Items within the same inner array are combined with "+" (AND),
|
|
565
|
+
* while different inner arrays represent "or" alternatives.
|
|
560
566
|
* If undefined, this group has no alternatives.
|
|
561
567
|
*/
|
|
562
|
-
alternatives?: AlternativeIngredientRef[];
|
|
568
|
+
alternatives?: AlternativeIngredientRef[][];
|
|
563
569
|
}
|
|
564
570
|
/**
|
|
565
571
|
* Represents an ingredient in a recipe.
|
|
@@ -1760,15 +1766,15 @@ declare function renderFractionAsVulgar(num: number, den: number): string;
|
|
|
1760
1766
|
* Format a numeric value (decimal or fraction) to a string.
|
|
1761
1767
|
*
|
|
1762
1768
|
* @param value - The decimal or fraction value to format
|
|
1763
|
-
* @param useVulgar - Whether to use Unicode vulgar fraction characters (default:
|
|
1769
|
+
* @param useVulgar - Whether to use Unicode vulgar fraction characters (default: true)
|
|
1764
1770
|
* @returns The formatted string representation
|
|
1765
1771
|
* @category Helpers
|
|
1766
1772
|
*
|
|
1767
1773
|
* @example
|
|
1768
1774
|
* ```typescript
|
|
1769
1775
|
* formatNumericValue({ type: "decimal", decimal: 1.5 }); // "1.5"
|
|
1770
|
-
* formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "
|
|
1771
|
-
* formatNumericValue({ type: "fraction", num: 1, den: 2 },
|
|
1776
|
+
* formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "½"
|
|
1777
|
+
* formatNumericValue({ type: "fraction", num: 1, den: 2 }, false); // "1/2"
|
|
1772
1778
|
* formatNumericValue({ type: "fraction", num: 5, den: 4 }, true); // "1¼"
|
|
1773
1779
|
* ```
|
|
1774
1780
|
*/
|
|
@@ -1899,7 +1905,7 @@ declare function isGroupedItem(item: IngredientItem): boolean;
|
|
|
1899
1905
|
* for (const item of step.items) {
|
|
1900
1906
|
* if (item.type === 'ingredient') {
|
|
1901
1907
|
* item.alternatives.forEach((alt, idx) => {
|
|
1902
|
-
* const isSelected = isAlternativeSelected(
|
|
1908
|
+
* const isSelected = isAlternativeSelected(recipe, choices, item, idx);
|
|
1903
1909
|
* // Render differently based on isSelected
|
|
1904
1910
|
* });
|
|
1905
1911
|
* }
|
|
@@ -2033,15 +2039,18 @@ declare function isSimpleGroup(entry: IngredientQuantityGroup | IngredientQuanti
|
|
|
2033
2039
|
* for (const entry of ingredient.quantities) {
|
|
2034
2040
|
* if (hasAlternatives(entry)) {
|
|
2035
2041
|
* // entry.alternatives is available and non-empty
|
|
2036
|
-
* for (const
|
|
2037
|
-
*
|
|
2042
|
+
* for (const subgroup of entry.alternatives) {
|
|
2043
|
+
* // Each subgroup is one "or" choice; items within are combined with "+"
|
|
2044
|
+
* for (const alt of subgroup) {
|
|
2045
|
+
* console.log(`Alternative ingredient index: ${alt.index}`);
|
|
2046
|
+
* }
|
|
2038
2047
|
* }
|
|
2039
2048
|
* }
|
|
2040
2049
|
* }
|
|
2041
2050
|
* ```
|
|
2042
2051
|
*/
|
|
2043
2052
|
declare function hasAlternatives(entry: IngredientQuantityGroup | IngredientQuantityAndGroup): entry is (IngredientQuantityGroup | IngredientQuantityAndGroup) & {
|
|
2044
|
-
alternatives: AlternativeIngredientRef[];
|
|
2053
|
+
alternatives: AlternativeIngredientRef[][];
|
|
2045
2054
|
};
|
|
2046
2055
|
|
|
2047
2056
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -334,7 +334,7 @@ interface MetadataObject {
|
|
|
334
334
|
* Represents any value that can appear in recipe metadata.
|
|
335
335
|
* @category Types
|
|
336
336
|
*/
|
|
337
|
-
type MetadataValue = string | number | (string | number)[] | MetadataObject | MetadataSource | MetadataTime | Yield | undefined;
|
|
337
|
+
type MetadataValue = string | number | (string | number | MetadataObject)[] | MetadataObject | MetadataSource | MetadataTime | Yield | undefined;
|
|
338
338
|
/**
|
|
339
339
|
* Represents the metadata of a recipe.
|
|
340
340
|
* @category Types
|
|
@@ -509,7 +509,7 @@ interface IngredientExtras {
|
|
|
509
509
|
* Used if: the ingredient is a recipe
|
|
510
510
|
*
|
|
511
511
|
* @example
|
|
512
|
-
* ```
|
|
512
|
+
* ```yaml
|
|
513
513
|
* Take @./essentials/doughs/pizza dough{1} out of the freezer and let it unfreeze overnight
|
|
514
514
|
* ```
|
|
515
515
|
* Would lead to:
|
|
@@ -541,9 +541,12 @@ interface AlternativeIngredientRef {
|
|
|
541
541
|
interface IngredientQuantityGroup extends QuantityWithPlainUnit {
|
|
542
542
|
/**
|
|
543
543
|
* References to alternative ingredients for this quantity group.
|
|
544
|
+
* Each inner array represents one alternative choice option (subgroup).
|
|
545
|
+
* Items within the same inner array are combined with "+" (AND),
|
|
546
|
+
* while different inner arrays represent "or" alternatives.
|
|
544
547
|
* If undefined, this group has no alternatives.
|
|
545
548
|
*/
|
|
546
|
-
alternatives?: AlternativeIngredientRef[];
|
|
549
|
+
alternatives?: AlternativeIngredientRef[][];
|
|
547
550
|
}
|
|
548
551
|
/**
|
|
549
552
|
* Represents an AND group of quantities when primary units are incompatible but equivalents can be summed.
|
|
@@ -557,9 +560,12 @@ interface IngredientQuantityAndGroup extends FlatAndGroup<QuantityWithPlainUnit>
|
|
|
557
560
|
equivalents?: QuantityWithPlainUnit[];
|
|
558
561
|
/**
|
|
559
562
|
* References to alternative ingredients for this quantity group.
|
|
563
|
+
* Each inner array represents one alternative choice option (subgroup).
|
|
564
|
+
* Items within the same inner array are combined with "+" (AND),
|
|
565
|
+
* while different inner arrays represent "or" alternatives.
|
|
560
566
|
* If undefined, this group has no alternatives.
|
|
561
567
|
*/
|
|
562
|
-
alternatives?: AlternativeIngredientRef[];
|
|
568
|
+
alternatives?: AlternativeIngredientRef[][];
|
|
563
569
|
}
|
|
564
570
|
/**
|
|
565
571
|
* Represents an ingredient in a recipe.
|
|
@@ -1760,15 +1766,15 @@ declare function renderFractionAsVulgar(num: number, den: number): string;
|
|
|
1760
1766
|
* Format a numeric value (decimal or fraction) to a string.
|
|
1761
1767
|
*
|
|
1762
1768
|
* @param value - The decimal or fraction value to format
|
|
1763
|
-
* @param useVulgar - Whether to use Unicode vulgar fraction characters (default:
|
|
1769
|
+
* @param useVulgar - Whether to use Unicode vulgar fraction characters (default: true)
|
|
1764
1770
|
* @returns The formatted string representation
|
|
1765
1771
|
* @category Helpers
|
|
1766
1772
|
*
|
|
1767
1773
|
* @example
|
|
1768
1774
|
* ```typescript
|
|
1769
1775
|
* formatNumericValue({ type: "decimal", decimal: 1.5 }); // "1.5"
|
|
1770
|
-
* formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "
|
|
1771
|
-
* formatNumericValue({ type: "fraction", num: 1, den: 2 },
|
|
1776
|
+
* formatNumericValue({ type: "fraction", num: 1, den: 2 }); // "½"
|
|
1777
|
+
* formatNumericValue({ type: "fraction", num: 1, den: 2 }, false); // "1/2"
|
|
1772
1778
|
* formatNumericValue({ type: "fraction", num: 5, den: 4 }, true); // "1¼"
|
|
1773
1779
|
* ```
|
|
1774
1780
|
*/
|
|
@@ -1899,7 +1905,7 @@ declare function isGroupedItem(item: IngredientItem): boolean;
|
|
|
1899
1905
|
* for (const item of step.items) {
|
|
1900
1906
|
* if (item.type === 'ingredient') {
|
|
1901
1907
|
* item.alternatives.forEach((alt, idx) => {
|
|
1902
|
-
* const isSelected = isAlternativeSelected(
|
|
1908
|
+
* const isSelected = isAlternativeSelected(recipe, choices, item, idx);
|
|
1903
1909
|
* // Render differently based on isSelected
|
|
1904
1910
|
* });
|
|
1905
1911
|
* }
|
|
@@ -2033,15 +2039,18 @@ declare function isSimpleGroup(entry: IngredientQuantityGroup | IngredientQuanti
|
|
|
2033
2039
|
* for (const entry of ingredient.quantities) {
|
|
2034
2040
|
* if (hasAlternatives(entry)) {
|
|
2035
2041
|
* // entry.alternatives is available and non-empty
|
|
2036
|
-
* for (const
|
|
2037
|
-
*
|
|
2042
|
+
* for (const subgroup of entry.alternatives) {
|
|
2043
|
+
* // Each subgroup is one "or" choice; items within are combined with "+"
|
|
2044
|
+
* for (const alt of subgroup) {
|
|
2045
|
+
* console.log(`Alternative ingredient index: ${alt.index}`);
|
|
2046
|
+
* }
|
|
2038
2047
|
* }
|
|
2039
2048
|
* }
|
|
2040
2049
|
* }
|
|
2041
2050
|
* ```
|
|
2042
2051
|
*/
|
|
2043
2052
|
declare function hasAlternatives(entry: IngredientQuantityGroup | IngredientQuantityAndGroup): entry is (IngredientQuantityGroup | IngredientQuantityAndGroup) & {
|
|
2044
|
-
alternatives: AlternativeIngredientRef[];
|
|
2053
|
+
alternatives: AlternativeIngredientRef[][];
|
|
2045
2054
|
};
|
|
2046
2055
|
|
|
2047
2056
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1774,6 +1774,10 @@ function parseNestedMetaVar(content, varName) {
|
|
|
1774
1774
|
const match = content.match(nestedMetaVarRegex(varName));
|
|
1775
1775
|
if (!match) return void 0;
|
|
1776
1776
|
const nestedContent = match[1];
|
|
1777
|
+
const lines = nestedContent.split(/\r?\n/).filter((line) => line.trim() !== "");
|
|
1778
|
+
if (lines.length > 0 && lines[0].trim().startsWith("- ")) {
|
|
1779
|
+
return parseListItems(lines);
|
|
1780
|
+
}
|
|
1777
1781
|
return parseNestedBlock(nestedContent);
|
|
1778
1782
|
}
|
|
1779
1783
|
function parseNestedBlock(content) {
|
|
@@ -1800,7 +1804,7 @@ function parseNestedBlock(content) {
|
|
|
1800
1804
|
if (currentIndent !== baseIndent) {
|
|
1801
1805
|
throw new BadIndentationError();
|
|
1802
1806
|
}
|
|
1803
|
-
const keyValueMatch = line.match(/^
|
|
1807
|
+
const keyValueMatch = line.match(/^ *([^:\n]+?):\s*(.*)$/);
|
|
1804
1808
|
if (!keyValueMatch) {
|
|
1805
1809
|
i2++;
|
|
1806
1810
|
continue;
|
|
@@ -1812,7 +1816,7 @@ function parseNestedBlock(content) {
|
|
|
1812
1816
|
let j = i2 + 1;
|
|
1813
1817
|
while (j < lines.length) {
|
|
1814
1818
|
const childLine = lines[j];
|
|
1815
|
-
const childIndent = childLine.match(/^(
|
|
1819
|
+
const childIndent = childLine.match(/^( *)/)?.[1]?.length;
|
|
1816
1820
|
if (childIndent && childIndent > baseIndent) {
|
|
1817
1821
|
childLines.push(childLine);
|
|
1818
1822
|
j++;
|
|
@@ -1823,14 +1827,7 @@ function parseNestedBlock(content) {
|
|
|
1823
1827
|
if (childLines.length > 0) {
|
|
1824
1828
|
const firstChildTrimmed = childLines[0].trim();
|
|
1825
1829
|
if (firstChildTrimmed.startsWith("- ")) {
|
|
1826
|
-
|
|
1827
|
-
${childLines.join("\n")}`;
|
|
1828
|
-
const listResult = parseListMetaVar(reconstructedContent, key);
|
|
1829
|
-
if (listResult) {
|
|
1830
|
-
result[key] = listResult.map(
|
|
1831
|
-
(item) => parseMetadataValue(item)
|
|
1832
|
-
);
|
|
1833
|
-
}
|
|
1830
|
+
result[key] = parseListItems(childLines);
|
|
1834
1831
|
} else {
|
|
1835
1832
|
const childContent = childLines.join("\n");
|
|
1836
1833
|
const nested = parseNestedBlock(childContent);
|
|
@@ -1838,16 +1835,67 @@ ${childLines.join("\n")}`;
|
|
|
1838
1835
|
result[key] = nested;
|
|
1839
1836
|
}
|
|
1840
1837
|
}
|
|
1838
|
+
} else {
|
|
1839
|
+
result[key] = "";
|
|
1841
1840
|
}
|
|
1842
1841
|
i2 = j;
|
|
1843
1842
|
} else {
|
|
1844
|
-
result[key] =
|
|
1843
|
+
result[key] = parseSingleLineMetadataValue(rawValue);
|
|
1845
1844
|
i2++;
|
|
1846
1845
|
}
|
|
1847
1846
|
}
|
|
1848
1847
|
return result;
|
|
1849
1848
|
}
|
|
1850
|
-
function
|
|
1849
|
+
function parseListItems(childLines) {
|
|
1850
|
+
const listIndent = childLines[0].match(/^( *)/)?.[1]?.length;
|
|
1851
|
+
const groups = [];
|
|
1852
|
+
let currentGroup = [];
|
|
1853
|
+
for (const line of childLines) {
|
|
1854
|
+
const indent = line.match(/^( *)/)?.[1]?.length;
|
|
1855
|
+
if (indent === listIndent && line.trim().startsWith("- ")) {
|
|
1856
|
+
if (currentGroup.length > 0) {
|
|
1857
|
+
groups.push(currentGroup);
|
|
1858
|
+
}
|
|
1859
|
+
currentGroup = [line];
|
|
1860
|
+
} else {
|
|
1861
|
+
currentGroup.push(line);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
groups.push(currentGroup);
|
|
1865
|
+
const isObjectItem = (group) => {
|
|
1866
|
+
if (group.length > 1) return true;
|
|
1867
|
+
const value = group[0].replace(/^\s*-\s*/, "").trim();
|
|
1868
|
+
return /^[^:\n]+:\s/.test(value);
|
|
1869
|
+
};
|
|
1870
|
+
const hasObjectItems = groups.some(isObjectItem);
|
|
1871
|
+
if (!hasObjectItems) {
|
|
1872
|
+
return groups.map((group) => {
|
|
1873
|
+
const value = group[0].replace(/^\s*-\s*/, "").trim();
|
|
1874
|
+
return parseSingleLineMetadataValue(value);
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
const items = [];
|
|
1878
|
+
for (const group of groups) {
|
|
1879
|
+
const firstLine = group[0];
|
|
1880
|
+
const afterDash = firstLine.replace(/^\s*-\s*/, "");
|
|
1881
|
+
const dashPrefixMatch = firstLine.match(/^( *-\s*)/);
|
|
1882
|
+
const contentIndent = dashPrefixMatch?.[1]?.length;
|
|
1883
|
+
const objectLines = [" ".repeat(contentIndent) + afterDash];
|
|
1884
|
+
for (let k = 1; k < group.length; k++) {
|
|
1885
|
+
objectLines.push(group[k]);
|
|
1886
|
+
}
|
|
1887
|
+
const parsed = parseNestedBlock(objectLines.join("\n"));
|
|
1888
|
+
if (parsed) {
|
|
1889
|
+
items.push(parsed);
|
|
1890
|
+
} else {
|
|
1891
|
+
items.push(
|
|
1892
|
+
parseSingleLineMetadataValue(afterDash.trim())
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
return items;
|
|
1897
|
+
}
|
|
1898
|
+
function parseSingleLineMetadataValue(rawValue) {
|
|
1851
1899
|
if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
|
|
1852
1900
|
return rawValue.slice(1, -1).split(",").map((item) => item.trim());
|
|
1853
1901
|
}
|
|
@@ -1862,7 +1910,7 @@ function parseAnyMetaVar(content, varName) {
|
|
|
1862
1910
|
const list = parseListMetaVar(content, varName);
|
|
1863
1911
|
if (list) return list;
|
|
1864
1912
|
const simple = parseSimpleMetaVar(content, varName);
|
|
1865
|
-
if (simple) return
|
|
1913
|
+
if (simple) return parseSingleLineMetadataValue(simple);
|
|
1866
1914
|
return void 0;
|
|
1867
1915
|
}
|
|
1868
1916
|
function getNumericValueFromYield(v) {
|
|
@@ -1946,7 +1994,7 @@ function extractMetadata(content) {
|
|
|
1946
1994
|
const sourceName = parseSimpleMetaVar(metadataContent, "source.name");
|
|
1947
1995
|
const sourceUrl = parseSimpleMetaVar(metadataContent, "source.url");
|
|
1948
1996
|
const sourceAuthor = parseSimpleMetaVar(metadataContent, "source.author");
|
|
1949
|
-
if (sourceNested) {
|
|
1997
|
+
if (sourceNested && !Array.isArray(sourceNested)) {
|
|
1950
1998
|
const source = {};
|
|
1951
1999
|
if (typeof sourceNested.name === "string") source.name = sourceNested.name;
|
|
1952
2000
|
if (typeof sourceNested.url === "string") source.url = sourceNested.url;
|
|
@@ -1966,7 +2014,7 @@ function extractMetadata(content) {
|
|
|
1966
2014
|
const prepTime = parseSimpleMetaVar(metadataContent, "prep time") ?? parseSimpleMetaVar(metadataContent, "time.prep");
|
|
1967
2015
|
const cookTime = parseSimpleMetaVar(metadataContent, "cook time") ?? parseSimpleMetaVar(metadataContent, "time.cook");
|
|
1968
2016
|
const totalTime = parseSimpleMetaVar(metadataContent, "time required") ?? parseSimpleMetaVar(metadataContent, "time") ?? parseSimpleMetaVar(metadataContent, "duration");
|
|
1969
|
-
if (timeNested) {
|
|
2017
|
+
if (timeNested && !Array.isArray(timeNested)) {
|
|
1970
2018
|
const time = {};
|
|
1971
2019
|
if (typeof timeNested.prep === "string") time.prep = timeNested.prep;
|
|
1972
2020
|
if (typeof timeNested.cook === "string") time.cook = timeNested.cook;
|
|
@@ -2033,7 +2081,7 @@ function unionOfSets(s1, s2) {
|
|
|
2033
2081
|
}
|
|
2034
2082
|
function getAlternativeSignature(alternatives) {
|
|
2035
2083
|
if (!alternatives || alternatives.length === 0) return null;
|
|
2036
|
-
return alternatives.map((a2) => a2.index).sort((a2, b) => a2 - b).join(",");
|
|
2084
|
+
return alternatives.flat().map((a2) => a2.index).sort((a2, b) => a2 - b).join(",");
|
|
2037
2085
|
}
|
|
2038
2086
|
|
|
2039
2087
|
// src/classes/pantry.ts
|
|
@@ -3346,7 +3394,7 @@ var _Recipe = class _Recipe {
|
|
|
3346
3394
|
const currentSubgroupIdx = groupSubgroups.findIndex(
|
|
3347
3395
|
(sg) => sg.some((alt) => alt.itemId === item.id)
|
|
3348
3396
|
);
|
|
3349
|
-
alternativeRefs = groupSubgroups.filter((_, idx) => idx !== currentSubgroupIdx).
|
|
3397
|
+
alternativeRefs = groupSubgroups.filter((_, idx) => idx !== currentSubgroupIdx).map(
|
|
3350
3398
|
(subgroup) => subgroup.map((otherAlt) => {
|
|
3351
3399
|
const ref = {
|
|
3352
3400
|
index: otherAlt.index
|
|
@@ -3385,7 +3433,7 @@ var _Recipe = class _Recipe {
|
|
|
3385
3433
|
};
|
|
3386
3434
|
ref.quantities = [altQty];
|
|
3387
3435
|
}
|
|
3388
|
-
return ref;
|
|
3436
|
+
return [ref];
|
|
3389
3437
|
});
|
|
3390
3438
|
}
|
|
3391
3439
|
const altIndices = getAlternativeSignature(alternativeRefs) ?? "";
|
|
@@ -3406,28 +3454,36 @@ var _Recipe = class _Recipe {
|
|
|
3406
3454
|
if (!groupsForIng.has(signature)) {
|
|
3407
3455
|
groupsForIng.set(signature, {
|
|
3408
3456
|
quantities: [],
|
|
3409
|
-
alternativeQuantities: /* @__PURE__ */ new Map()
|
|
3457
|
+
alternativeQuantities: /* @__PURE__ */ new Map(),
|
|
3458
|
+
alternativeSubgroups: []
|
|
3410
3459
|
});
|
|
3411
3460
|
}
|
|
3412
3461
|
const group = groupsForIng.get(signature);
|
|
3413
3462
|
group.quantities.push(quantityEntry);
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3463
|
+
if (alternativeRefs && alternativeRefs.length > 0 && group.alternativeSubgroups.length === 0) {
|
|
3464
|
+
group.alternativeSubgroups = alternativeRefs.map(
|
|
3465
|
+
(subgroup) => subgroup.map((ref) => ref.index)
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3468
|
+
for (const subgroup of alternativeRefs ?? []) {
|
|
3469
|
+
for (const ref of subgroup) {
|
|
3470
|
+
if (!group.alternativeQuantities.has(ref.index)) {
|
|
3471
|
+
group.alternativeQuantities.set(ref.index, []);
|
|
3472
|
+
}
|
|
3473
|
+
for (const altQty of ref.quantities ?? []) {
|
|
3474
|
+
const extended = toExtendedUnit({
|
|
3475
|
+
quantity: altQty.quantity,
|
|
3476
|
+
unit: altQty.unit
|
|
3477
|
+
});
|
|
3478
|
+
if (altQty.equivalents?.length) {
|
|
3479
|
+
const eqEntries = [
|
|
3480
|
+
extended,
|
|
3481
|
+
...altQty.equivalents.map((eq) => toExtendedUnit(eq))
|
|
3482
|
+
];
|
|
3483
|
+
group.alternativeQuantities.get(ref.index).push({ or: eqEntries });
|
|
3484
|
+
} else {
|
|
3485
|
+
group.alternativeQuantities.get(ref.index).push(extended);
|
|
3486
|
+
}
|
|
3431
3487
|
}
|
|
3432
3488
|
}
|
|
3433
3489
|
}
|
|
@@ -3550,17 +3606,25 @@ var _Recipe = class _Recipe {
|
|
|
3550
3606
|
this.unitSystem
|
|
3551
3607
|
);
|
|
3552
3608
|
const flattened = flattenPlainUnitGroup(summed);
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3609
|
+
let alternatives;
|
|
3610
|
+
if (group.alternativeSubgroups.length > 0) {
|
|
3611
|
+
alternatives = group.alternativeSubgroups.map(
|
|
3612
|
+
(subgroupIndices) => subgroupIndices.map((altIdx) => {
|
|
3613
|
+
const altQtys = group.alternativeQuantities.get(altIdx);
|
|
3614
|
+
return {
|
|
3615
|
+
index: altIdx,
|
|
3616
|
+
...altQtys.length > 0 && {
|
|
3617
|
+
quantities: flattenPlainUnitGroup(
|
|
3618
|
+
addEquivalentsAndSimplify(altQtys, this.unitSystem)
|
|
3619
|
+
).flatMap(
|
|
3620
|
+
/* v8 ignore next -- item.and branch requires complex nested AND-with-equivalents structure */
|
|
3621
|
+
(item) => "quantity" in item ? [item] : item.and
|
|
3622
|
+
)
|
|
3623
|
+
}
|
|
3624
|
+
};
|
|
3625
|
+
})
|
|
3626
|
+
);
|
|
3627
|
+
}
|
|
3564
3628
|
for (const gq of flattened) {
|
|
3565
3629
|
if ("and" in gq) {
|
|
3566
3630
|
quantityGroups.push({
|
|
@@ -5084,6 +5148,7 @@ export {
|
|
|
5084
5148
|
// v8 ignore if -- @preserve
|
|
5085
5149
|
/* v8 ignore else -- expliciting error type -- @preserve */
|
|
5086
5150
|
/* v8 ignore next 4 -- @preserve: defensive guard; regex always matches */
|
|
5151
|
+
/* v8 ignore else -- @preserve: empty non nested block will in practice be detected earlier */
|
|
5087
5152
|
// v8 ignore if -- @preserve: defensive type guard
|
|
5088
5153
|
/* v8 ignore if -- @preserve */
|
|
5089
5154
|
// v8 ignore next -- @preserve
|