@tmlmt/cooklang-parser 3.0.0-alpha.16 → 3.0.0-alpha.19
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 +357 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +162 -15
- package/dist/index.d.ts +162 -15
- package/dist/index.js +354 -47
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -277,7 +277,7 @@ var nonWordCharStrict = "\\s@#~\\[\\]{(,;:!?|";
|
|
|
277
277
|
var ingredientWithAlternativeRegex = d().literal("@").startNamedGroup("ingredientModifiers").anyOf("@\\-&?").zeroOrMore().endGroup().optional().startNamedGroup("ingredientRecipeAnchor").literal("./").endGroup().optional().startGroup().startGroup().startNamedGroup("mIngredientName").notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\}|\\([^)]*\\))").endGroup().or().startNamedGroup("sIngredientName").notAnyOf(nonWordChar).zeroOrMore().notAnyOf("\\." + nonWordChar).endGroup().endGroup().startGroup().literal("{").startNamedGroup("ingredientQuantityModifier").literal("=").exactly(1).endGroup().optional().startNamedGroup("ingredientQuantity").startGroup().notAnyOf("}|%").oneOrMore().endGroup().optional().startGroup().literal("%").notAnyOf("|}").oneOrMore().lazy().endGroup().optional().startGroup().literal("|").notAnyOf("}").oneOrMore().lazy().endGroup().zeroOrMore().endGroup().literal("}").endGroup().optional().startGroup().literal("(").startNamedGroup("ingredientPreparation").notAnyOf(")").oneOrMore().lazy().endGroup().literal(")").endGroup().optional().startGroup().literal("[").startNamedGroup("ingredientNote").notAnyOf("\\]").oneOrMore().lazy().endGroup().literal("]").endGroup().optional().startNamedGroup("ingredientAlternative").startGroup().literal("|").startGroup().anyOf("@\\-&?").zeroOrMore().endGroup().optional().startGroup().literal("./").endGroup().optional().startGroup().startGroup().startGroup().notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\}|\\([^)]*\\))").endGroup().or().startGroup().notAnyOf(nonWordChar).oneOrMore().endGroup().endGroup().startGroup().literal("{").startGroup().literal("=").exactly(1).endGroup().optional().startGroup().notAnyOf("}%").oneOrMore().endGroup().optional().startGroup().literal("%").startGroup().notAnyOf("}").oneOrMore().lazy().endGroup().endGroup().optional().literal("}").endGroup().optional().startGroup().literal("(").startGroup().notAnyOf(")").oneOrMore().lazy().endGroup().literal(")").endGroup().optional().startGroup().literal("[").startGroup().notAnyOf("\\]").oneOrMore().lazy().endGroup().literal("]").endGroup().optional().endGroup().zeroOrMore().endGroup().toRegExp();
|
|
278
278
|
var inlineIngredientAlternativesRegex = new RegExp("\\|" + ingredientWithAlternativeRegex.source.slice(1));
|
|
279
279
|
var quantityAlternativeRegex = d().startNamedGroup("quantity").notAnyOf("}|%").oneOrMore().endGroup().optional().startGroup().literal("%").startNamedGroup("unit").notAnyOf("|}").oneOrMore().endGroup().endGroup().optional().startGroup().literal("|").startNamedGroup("alternative").startGroup().notAnyOf("}").oneOrMore().endGroup().zeroOrMore().endGroup().endGroup().optional().toRegExp();
|
|
280
|
-
var ingredientWithGroupKeyRegex = d().literal("@|").startNamedGroup("gIngredientGroupKey").notAnyOf(nonWordCharStrict).oneOrMore().endGroup().literal("|").startNamedGroup("gIngredientModifiers").anyOf("@\\-&?").zeroOrMore().endGroup().optional().startNamedGroup("gIngredientRecipeAnchor").literal("./").endGroup().optional().startGroup().startGroup().startNamedGroup("gmIngredientName").notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\}|\\([^)]*\\))").endGroup().or().startNamedGroup("gsIngredientName").notAnyOf(nonWordChar).zeroOrMore().notAnyOf("\\." + nonWordChar).endGroup().endGroup().startGroup().literal("{").startNamedGroup("gIngredientQuantityModifier").literal("=").exactly(1).endGroup().optional().startNamedGroup("gIngredientQuantity").startGroup().notAnyOf("}|%").oneOrMore().endGroup().optional().startGroup().literal("%").notAnyOf("|}").oneOrMore().lazy().endGroup().optional().startGroup().literal("|").notAnyOf("}").oneOrMore().lazy().endGroup().zeroOrMore().endGroup().literal("}").endGroup().optional().startGroup().literal("(").startNamedGroup("gIngredientPreparation").notAnyOf(")").oneOrMore().lazy().endGroup().literal(")").endGroup().optional().toRegExp();
|
|
280
|
+
var ingredientWithGroupKeyRegex = d().literal("@|").startNamedGroup("gIngredientGroupKey").notAnyOf(nonWordCharStrict + "/").oneOrMore().endGroup().startGroup().literal("/").startNamedGroup("gIngredientSubgroupKey").notAnyOf(nonWordCharStrict).oneOrMore().endGroup().endGroup().optional().literal("|").startNamedGroup("gIngredientModifiers").anyOf("@\\-&?").zeroOrMore().endGroup().optional().startNamedGroup("gIngredientRecipeAnchor").literal("./").endGroup().optional().startGroup().startGroup().startNamedGroup("gmIngredientName").notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\}|\\([^)]*\\))").endGroup().or().startNamedGroup("gsIngredientName").notAnyOf(nonWordChar).zeroOrMore().notAnyOf("\\." + nonWordChar).endGroup().endGroup().startGroup().literal("{").startNamedGroup("gIngredientQuantityModifier").literal("=").exactly(1).endGroup().optional().startNamedGroup("gIngredientQuantity").startGroup().notAnyOf("}|%").oneOrMore().endGroup().optional().startGroup().literal("%").notAnyOf("|}").oneOrMore().lazy().endGroup().optional().startGroup().literal("|").notAnyOf("}").oneOrMore().lazy().endGroup().zeroOrMore().endGroup().literal("}").endGroup().optional().startGroup().literal("(").startNamedGroup("gIngredientPreparation").notAnyOf(")").oneOrMore().lazy().endGroup().literal(")").endGroup().optional().startGroup().literal("[").startNamedGroup("gIngredientNote").notAnyOf("\\]").oneOrMore().lazy().endGroup().literal("]").endGroup().optional().toRegExp();
|
|
281
281
|
var ingredientAliasRegex = d().startAnchor().startNamedGroup("ingredientListName").notAnyOf("|").oneOrMore().endGroup().literal("|").startNamedGroup("ingredientDisplayName").notAnyOf("|").oneOrMore().endGroup().endAnchor().toRegExp();
|
|
282
282
|
var cookwareRegex = d().literal("#").startNamedGroup("cookwareModifiers").anyOf("\\-&?").zeroOrMore().endGroup().startGroup().startGroup().startNamedGroup("mCookwareName").notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\})").endGroup().or().startNamedGroup("sCookwareName").notAnyOf(nonWordChar).zeroOrMore().notAnyOf("\\." + nonWordChar).endGroup().endGroup().startGroup().literal("{").startNamedGroup("cookwareQuantity").anyCharacter().zeroOrMore().lazy().endGroup().literal("}").endGroup().optional().toRegExp();
|
|
283
283
|
var timerRegex = d().literal("~").startNamedGroup("timerName").anyCharacter().zeroOrMore().lazy().endGroup().literal("{").startNamedGroup("timerQuantity").anyCharacter().oneOrMore().lazy().endGroup().startGroup().literal("%").startNamedGroup("timerUnit").anyCharacter().oneOrMore().lazy().endGroup().endGroup().optional().literal("}").toRegExp();
|
|
@@ -305,6 +305,7 @@ var shoppingListRegex = d().literal("[").startNamedGroup("name").anyCharacter().
|
|
|
305
305
|
var rangeRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().literal("-").digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
306
306
|
var numberLikeRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
307
307
|
var floatRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
308
|
+
var variantTagRegex = d().startAnchor().literal("[").startNamedGroup("variantOptionalPrefix").literal("?").endGroup().optional().startNamedGroup("variantNames").notAnyOf("\\]").zeroOrMore().endGroup().literal("]").whitespace().zeroOrMore().toRegExp();
|
|
308
309
|
var mdEscaped = d().literal("\\").startCaptureGroup().anyOf("*_`").endGroup();
|
|
309
310
|
var mdInlineCode = d().literal("`").startCaptureGroup().notAnyOf("`").oneOrMore().lazy().endGroup().literal("`");
|
|
310
311
|
var mdLink = d().literal("[").startCaptureGroup().notAnyOf("\\]").oneOrMore().lazy().endGroup().literal("](").startCaptureGroup().notAnyOf(")").oneOrMore().lazy().endGroup().literal(")");
|
|
@@ -1359,9 +1360,12 @@ function flushPendingNote(section, noteItems) {
|
|
|
1359
1360
|
}
|
|
1360
1361
|
return noteItems;
|
|
1361
1362
|
}
|
|
1362
|
-
function flushPendingItems(section, items) {
|
|
1363
|
+
function flushPendingItems(section, items, stepVariants, stepOptional) {
|
|
1363
1364
|
if (items.length > 0) {
|
|
1364
|
-
|
|
1365
|
+
const step = { type: "step", items: [...items] };
|
|
1366
|
+
if (stepVariants) step.variants = stepVariants;
|
|
1367
|
+
if (stepOptional) step.optional = true;
|
|
1368
|
+
section.content.push(step);
|
|
1365
1369
|
items.length = 0;
|
|
1366
1370
|
return true;
|
|
1367
1371
|
}
|
|
@@ -1905,7 +1909,8 @@ function extractMetadata(content) {
|
|
|
1905
1909
|
"yield",
|
|
1906
1910
|
"serves",
|
|
1907
1911
|
// List fields
|
|
1908
|
-
"tags"
|
|
1912
|
+
"tags",
|
|
1913
|
+
"variants"
|
|
1909
1914
|
]);
|
|
1910
1915
|
for (const metaVar of [
|
|
1911
1916
|
"title",
|
|
@@ -1992,6 +1997,8 @@ function extractMetadata(content) {
|
|
|
1992
1997
|
}
|
|
1993
1998
|
const tags = parseListMetaVar(metadataContent, "tags");
|
|
1994
1999
|
if (tags) metadata.tags = tags;
|
|
2000
|
+
const variants = parseListMetaVar(metadataContent, "variants");
|
|
2001
|
+
if (variants) metadata.variants = variants;
|
|
1995
2002
|
const allKeys = extractAllMetadataKeys(metadataContent);
|
|
1996
2003
|
for (const key of allKeys) {
|
|
1997
2004
|
if (handledKeys.has(key)) continue;
|
|
@@ -2379,8 +2386,10 @@ var Section = class {
|
|
|
2379
2386
|
/**
|
|
2380
2387
|
* Creates an instance of Section.
|
|
2381
2388
|
* @param name - The name of the section. Defaults to an empty string.
|
|
2389
|
+
* @param variants - Optional variant names for this section.
|
|
2390
|
+
* @param optional - Whether the section is optional.
|
|
2382
2391
|
*/
|
|
2383
|
-
constructor(name = "") {
|
|
2392
|
+
constructor(name = "", variants, optional) {
|
|
2384
2393
|
/**
|
|
2385
2394
|
* The name of the section. Can be an empty string for the default (first) section.
|
|
2386
2395
|
* @defaultValue `""`
|
|
@@ -2388,7 +2397,13 @@ var Section = class {
|
|
|
2388
2397
|
__publicField(this, "name");
|
|
2389
2398
|
/** An array of steps and notes that make up the content of the section. */
|
|
2390
2399
|
__publicField(this, "content", []);
|
|
2400
|
+
/** Optional list of variant names this section belongs to. */
|
|
2401
|
+
__publicField(this, "variants");
|
|
2402
|
+
/** Whether the section has been marked as optional ([?]) */
|
|
2403
|
+
__publicField(this, "optional");
|
|
2391
2404
|
this.name = name;
|
|
2405
|
+
if (variants) this.variants = variants;
|
|
2406
|
+
if (optional) this.optional = true;
|
|
2392
2407
|
}
|
|
2393
2408
|
/**
|
|
2394
2409
|
* Checks if the section is blank (has no name and no content).
|
|
@@ -2748,7 +2763,8 @@ var _Recipe = class _Recipe {
|
|
|
2748
2763
|
*/
|
|
2749
2764
|
__publicField(this, "choices", {
|
|
2750
2765
|
ingredientItems: /* @__PURE__ */ new Map(),
|
|
2751
|
-
ingredientGroups: /* @__PURE__ */ new Map()
|
|
2766
|
+
ingredientGroups: /* @__PURE__ */ new Map(),
|
|
2767
|
+
variants: []
|
|
2752
2768
|
});
|
|
2753
2769
|
/**
|
|
2754
2770
|
* The parsed recipe ingredients.
|
|
@@ -2779,6 +2795,7 @@ var _Recipe = class _Recipe {
|
|
|
2779
2795
|
*/
|
|
2780
2796
|
__publicField(this, "servings");
|
|
2781
2797
|
_Recipe.itemCounts.set(this, 0);
|
|
2798
|
+
_Recipe.subgroupIndices.set(this, /* @__PURE__ */ new Map());
|
|
2782
2799
|
if (content) {
|
|
2783
2800
|
this.parse(content);
|
|
2784
2801
|
}
|
|
@@ -2996,6 +3013,7 @@ var _Recipe = class _Recipe {
|
|
|
2996
3013
|
if (!match?.groups) return;
|
|
2997
3014
|
const groups = match.groups;
|
|
2998
3015
|
const groupKey = groups.gIngredientGroupKey;
|
|
3016
|
+
const subgroupKey = groups.gIngredientSubgroupKey;
|
|
2999
3017
|
let name = groups.gmIngredientName || groups.gsIngredientName;
|
|
3000
3018
|
const preparation = groups.gIngredientPreparation;
|
|
3001
3019
|
const modifiers = groups.gIngredientModifiers;
|
|
@@ -3063,7 +3081,12 @@ var _Recipe = class _Recipe {
|
|
|
3063
3081
|
if (itemQuantity) {
|
|
3064
3082
|
Object.assign(alternative, itemQuantity);
|
|
3065
3083
|
}
|
|
3066
|
-
const
|
|
3084
|
+
const note = groups.gIngredientNote?.trim();
|
|
3085
|
+
if (note) {
|
|
3086
|
+
alternative.note = note;
|
|
3087
|
+
}
|
|
3088
|
+
const existingSubgroups = this.choices.ingredientGroups.get(groupKey);
|
|
3089
|
+
const existingAlternativesFlat = existingSubgroups?.flat();
|
|
3067
3090
|
function upsertAlternativeToIngredient(ingredients, ingredientIdx, newAlternativeIdx) {
|
|
3068
3091
|
const ingredient = ingredients[ingredientIdx];
|
|
3069
3092
|
if (ingredient) {
|
|
@@ -3074,8 +3097,8 @@ var _Recipe = class _Recipe {
|
|
|
3074
3097
|
}
|
|
3075
3098
|
}
|
|
3076
3099
|
}
|
|
3077
|
-
if (
|
|
3078
|
-
for (const alt of
|
|
3100
|
+
if (existingAlternativesFlat) {
|
|
3101
|
+
for (const alt of existingAlternativesFlat) {
|
|
3079
3102
|
upsertAlternativeToIngredient(this.ingredients, alt.index, idxInList);
|
|
3080
3103
|
upsertAlternativeToIngredient(this.ingredients, idxInList, alt.index);
|
|
3081
3104
|
}
|
|
@@ -3087,14 +3110,35 @@ var _Recipe = class _Recipe {
|
|
|
3087
3110
|
group: groupKey,
|
|
3088
3111
|
alternatives: [alternative]
|
|
3089
3112
|
};
|
|
3113
|
+
if (subgroupKey !== void 0) {
|
|
3114
|
+
newItem.subgroup = subgroupKey;
|
|
3115
|
+
}
|
|
3090
3116
|
items.push(newItem);
|
|
3091
3117
|
const choiceAlternative = deepClone(alternative);
|
|
3092
3118
|
choiceAlternative.itemId = id;
|
|
3093
3119
|
const existingChoice = this.choices.ingredientGroups.get(groupKey);
|
|
3120
|
+
const sgMap = _Recipe.subgroupIndices.get(this);
|
|
3094
3121
|
if (!existingChoice) {
|
|
3095
|
-
this.choices.ingredientGroups.set(groupKey, [choiceAlternative]);
|
|
3122
|
+
this.choices.ingredientGroups.set(groupKey, [[choiceAlternative]]);
|
|
3123
|
+
if (subgroupKey !== void 0) {
|
|
3124
|
+
sgMap.set(groupKey, /* @__PURE__ */ new Map([[subgroupKey, 0]]));
|
|
3125
|
+
}
|
|
3126
|
+
} else if (subgroupKey !== void 0) {
|
|
3127
|
+
const groupSgMap = sgMap.get(groupKey);
|
|
3128
|
+
const existingIdx = groupSgMap?.get(subgroupKey);
|
|
3129
|
+
if (existingIdx !== void 0) {
|
|
3130
|
+
existingChoice[existingIdx].push(choiceAlternative);
|
|
3131
|
+
} else {
|
|
3132
|
+
const newIdx = existingChoice.length;
|
|
3133
|
+
existingChoice.push([choiceAlternative]);
|
|
3134
|
+
if (!groupSgMap) {
|
|
3135
|
+
sgMap.set(groupKey, /* @__PURE__ */ new Map([[subgroupKey, newIdx]]));
|
|
3136
|
+
} else {
|
|
3137
|
+
groupSgMap.set(subgroupKey, newIdx);
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3096
3140
|
} else {
|
|
3097
|
-
existingChoice.push(choiceAlternative);
|
|
3141
|
+
existingChoice.push([choiceAlternative]);
|
|
3098
3142
|
}
|
|
3099
3143
|
}
|
|
3100
3144
|
/**
|
|
@@ -3134,6 +3178,8 @@ var _Recipe = class _Recipe {
|
|
|
3134
3178
|
/** @internal */
|
|
3135
3179
|
collectQuantityGroups(options) {
|
|
3136
3180
|
const { section, step, choices } = options || {};
|
|
3181
|
+
const activeVariant = choices?.variant;
|
|
3182
|
+
const isDefaultVariant = activeVariant === void 0 || activeVariant === "*";
|
|
3137
3183
|
const sectionsToProcess = section !== void 0 ? (() => {
|
|
3138
3184
|
const idx = typeof section === "number" ? section : this.sections.indexOf(section);
|
|
3139
3185
|
return idx >= 0 && idx < this.sections.length ? [this.sections[idx]] : [];
|
|
@@ -3141,36 +3187,89 @@ var _Recipe = class _Recipe {
|
|
|
3141
3187
|
const ingredientGroups = /* @__PURE__ */ new Map();
|
|
3142
3188
|
const selectedIndices = /* @__PURE__ */ new Set();
|
|
3143
3189
|
const referencedIndices = /* @__PURE__ */ new Set();
|
|
3190
|
+
const dynamicOptionalIndices = /* @__PURE__ */ new Set();
|
|
3144
3191
|
for (const currentSection of sectionsToProcess) {
|
|
3192
|
+
if (currentSection.variants) {
|
|
3193
|
+
if (isDefaultVariant) {
|
|
3194
|
+
if (!currentSection.variants.includes("*")) continue;
|
|
3195
|
+
} else {
|
|
3196
|
+
if (!currentSection.variants.includes(activeVariant)) continue;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3145
3199
|
const allSteps = currentSection.content.filter(
|
|
3146
3200
|
(item) => item.type === "step"
|
|
3147
3201
|
);
|
|
3202
|
+
const isOptionalSection = currentSection.optional === true;
|
|
3148
3203
|
const stepsToProcess = step === void 0 ? allSteps : typeof step === "number" ? step >= 0 && step < allSteps.length ? [allSteps[step]] : [] : allSteps.includes(step) ? [step] : [];
|
|
3149
3204
|
for (const currentStep of stepsToProcess) {
|
|
3205
|
+
if (currentStep.variants) {
|
|
3206
|
+
if (isDefaultVariant) {
|
|
3207
|
+
if (!currentStep.variants.includes("*")) continue;
|
|
3208
|
+
} else {
|
|
3209
|
+
if (!currentStep.variants.includes(activeVariant)) continue;
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
const isOptionalStep = currentStep.optional === true || isOptionalSection;
|
|
3150
3213
|
for (const item of currentStep.items.filter(
|
|
3151
3214
|
(item2) => item2.type === "ingredient"
|
|
3152
3215
|
)) {
|
|
3153
3216
|
const isGrouped = "group" in item && item.group !== void 0;
|
|
3154
|
-
const
|
|
3217
|
+
const groupSubgroups = isGrouped ? this.choices.ingredientGroups.get(item.group) : void 0;
|
|
3155
3218
|
let selectedAltIndex = 0;
|
|
3156
3219
|
let isSelected;
|
|
3157
3220
|
let hasExplicitChoice;
|
|
3158
3221
|
if (isGrouped) {
|
|
3159
3222
|
const groupChoice = choices?.ingredientGroups?.get(item.group);
|
|
3160
3223
|
hasExplicitChoice = groupChoice !== void 0;
|
|
3161
|
-
|
|
3162
|
-
|
|
3224
|
+
if (!hasExplicitChoice && !isDefaultVariant) {
|
|
3225
|
+
const matchingSubgroupIdx = groupSubgroups?.findIndex(
|
|
3226
|
+
(sg) => sg.some(
|
|
3227
|
+
(alt) => alt.note && alt.note.toLowerCase().includes(activeVariant.toLowerCase())
|
|
3228
|
+
)
|
|
3229
|
+
);
|
|
3230
|
+
if (matchingSubgroupIdx !== void 0 && matchingSubgroupIdx >= 0) {
|
|
3231
|
+
const matchedSubgroup = groupSubgroups[matchingSubgroupIdx];
|
|
3232
|
+
isSelected = matchedSubgroup.some(
|
|
3233
|
+
(alt) => alt.itemId === item.id
|
|
3234
|
+
);
|
|
3235
|
+
hasExplicitChoice = true;
|
|
3236
|
+
selectedAltIndex = 0;
|
|
3237
|
+
} else {
|
|
3238
|
+
const targetSubgroupIndex = 0;
|
|
3239
|
+
const selectedSubgroup = groupSubgroups?.[targetSubgroupIndex];
|
|
3240
|
+
isSelected = selectedSubgroup?.some((alt) => alt.itemId === item.id) ?? false;
|
|
3241
|
+
}
|
|
3242
|
+
} else {
|
|
3243
|
+
const targetSubgroupIndex = groupChoice ?? 0;
|
|
3244
|
+
const selectedSubgroup = groupSubgroups?.[targetSubgroupIndex];
|
|
3245
|
+
isSelected = selectedSubgroup?.some((alt) => alt.itemId === item.id) ?? false;
|
|
3246
|
+
}
|
|
3163
3247
|
} else {
|
|
3164
3248
|
const itemChoice = choices?.ingredientItems?.get(item.id);
|
|
3165
3249
|
hasExplicitChoice = itemChoice !== void 0;
|
|
3166
|
-
|
|
3250
|
+
if (!hasExplicitChoice && !isDefaultVariant) {
|
|
3251
|
+
const matchingIndices = item.alternatives.map((alt, idx) => ({ alt, idx })).filter(
|
|
3252
|
+
({ alt }) => alt.note && alt.note.toLowerCase().includes(activeVariant.toLowerCase())
|
|
3253
|
+
).map(({ idx }) => idx);
|
|
3254
|
+
if (matchingIndices.length > 0) {
|
|
3255
|
+
selectedAltIndex = matchingIndices[0];
|
|
3256
|
+
hasExplicitChoice = true;
|
|
3257
|
+
} else {
|
|
3258
|
+
selectedAltIndex = itemChoice ?? 0;
|
|
3259
|
+
}
|
|
3260
|
+
} else {
|
|
3261
|
+
selectedAltIndex = itemChoice ?? 0;
|
|
3262
|
+
}
|
|
3167
3263
|
isSelected = true;
|
|
3168
3264
|
}
|
|
3169
3265
|
const alternative = item.alternatives[selectedAltIndex];
|
|
3170
3266
|
if (!alternative || !isSelected) continue;
|
|
3171
3267
|
selectedIndices.add(alternative.index);
|
|
3172
|
-
|
|
3173
|
-
|
|
3268
|
+
if (isOptionalStep) {
|
|
3269
|
+
dynamicOptionalIndices.add(alternative.index);
|
|
3270
|
+
}
|
|
3271
|
+
const allAltsFlat = isGrouped ? groupSubgroups.flat() : item.alternatives;
|
|
3272
|
+
for (const alt of allAltsFlat) {
|
|
3174
3273
|
referencedIndices.add(alt.index);
|
|
3175
3274
|
}
|
|
3176
3275
|
if (!alternative.quantity) continue;
|
|
@@ -3182,10 +3281,34 @@ var _Recipe = class _Recipe {
|
|
|
3182
3281
|
};
|
|
3183
3282
|
const quantityEntry = alternative.equivalents?.length ? { or: [baseQty, ...alternative.equivalents] } : baseQty;
|
|
3184
3283
|
let alternativeRefs;
|
|
3185
|
-
if (!hasExplicitChoice &&
|
|
3186
|
-
|
|
3187
|
-
(
|
|
3188
|
-
)
|
|
3284
|
+
if (!hasExplicitChoice && groupSubgroups && groupSubgroups.length > 1) {
|
|
3285
|
+
const currentSubgroupIdx = groupSubgroups.findIndex(
|
|
3286
|
+
(sg) => sg.some((alt) => alt.itemId === item.id)
|
|
3287
|
+
);
|
|
3288
|
+
alternativeRefs = groupSubgroups.filter((_, idx) => idx !== currentSubgroupIdx).flatMap(
|
|
3289
|
+
(subgroup) => subgroup.map((otherAlt) => {
|
|
3290
|
+
const ref = {
|
|
3291
|
+
index: otherAlt.index
|
|
3292
|
+
};
|
|
3293
|
+
if (otherAlt.quantity) {
|
|
3294
|
+
const altQty = {
|
|
3295
|
+
quantity: otherAlt.quantity,
|
|
3296
|
+
...otherAlt.unit && {
|
|
3297
|
+
unit: otherAlt.unit.name
|
|
3298
|
+
},
|
|
3299
|
+
...otherAlt.equivalents && {
|
|
3300
|
+
equivalents: otherAlt.equivalents.map(
|
|
3301
|
+
(eq) => toPlainUnit(eq)
|
|
3302
|
+
)
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
ref.quantities = [altQty];
|
|
3306
|
+
}
|
|
3307
|
+
return ref;
|
|
3308
|
+
})
|
|
3309
|
+
);
|
|
3310
|
+
} else if (!hasExplicitChoice && !isGrouped && allAltsFlat.length > 1) {
|
|
3311
|
+
alternativeRefs = allAltsFlat.filter((alt) => alt.index !== alternative.index).map((otherAlt) => {
|
|
3189
3312
|
const ref = { index: otherAlt.index };
|
|
3190
3313
|
if (otherAlt.quantity) {
|
|
3191
3314
|
const altQty = {
|
|
@@ -3250,7 +3373,12 @@ var _Recipe = class _Recipe {
|
|
|
3250
3373
|
}
|
|
3251
3374
|
}
|
|
3252
3375
|
}
|
|
3253
|
-
return {
|
|
3376
|
+
return {
|
|
3377
|
+
ingredientGroups,
|
|
3378
|
+
selectedIndices,
|
|
3379
|
+
referencedIndices,
|
|
3380
|
+
dynamicOptionalIndices
|
|
3381
|
+
};
|
|
3254
3382
|
}
|
|
3255
3383
|
/**
|
|
3256
3384
|
* Gets the raw (unprocessed) quantity groups for each ingredient, before
|
|
@@ -3269,12 +3397,21 @@ var _Recipe = class _Recipe {
|
|
|
3269
3397
|
* ```
|
|
3270
3398
|
*/
|
|
3271
3399
|
getRawQuantityGroups(options) {
|
|
3272
|
-
const {
|
|
3400
|
+
const {
|
|
3401
|
+
ingredientGroups,
|
|
3402
|
+
selectedIndices,
|
|
3403
|
+
referencedIndices,
|
|
3404
|
+
dynamicOptionalIndices
|
|
3405
|
+
} = this.collectQuantityGroups(options);
|
|
3273
3406
|
const result = [];
|
|
3274
3407
|
for (let index = 0; index < this.ingredients.length; index++) {
|
|
3275
3408
|
if (!referencedIndices.has(index)) continue;
|
|
3276
3409
|
const orig = this.ingredients[index];
|
|
3277
3410
|
const usedAsPrimary = selectedIndices.has(index);
|
|
3411
|
+
let flags = orig.flags;
|
|
3412
|
+
if (dynamicOptionalIndices.has(index) && !flags?.includes("optional")) {
|
|
3413
|
+
flags = [...flags ?? [], "optional"];
|
|
3414
|
+
}
|
|
3278
3415
|
const quantities = [];
|
|
3279
3416
|
if (usedAsPrimary) {
|
|
3280
3417
|
const groupsForIng = ingredientGroups.get(index);
|
|
@@ -3287,7 +3424,7 @@ var _Recipe = class _Recipe {
|
|
|
3287
3424
|
result.push({
|
|
3288
3425
|
name: orig.name,
|
|
3289
3426
|
...usedAsPrimary && { usedAsPrimary: true },
|
|
3290
|
-
...
|
|
3427
|
+
...flags && { flags },
|
|
3291
3428
|
quantities
|
|
3292
3429
|
});
|
|
3293
3430
|
}
|
|
@@ -3321,15 +3458,24 @@ var _Recipe = class _Recipe {
|
|
|
3321
3458
|
* ```
|
|
3322
3459
|
*/
|
|
3323
3460
|
getIngredientQuantities(options) {
|
|
3324
|
-
const {
|
|
3461
|
+
const {
|
|
3462
|
+
ingredientGroups,
|
|
3463
|
+
selectedIndices,
|
|
3464
|
+
referencedIndices,
|
|
3465
|
+
dynamicOptionalIndices
|
|
3466
|
+
} = this.collectQuantityGroups(options);
|
|
3325
3467
|
const result = [];
|
|
3326
3468
|
for (let index = 0; index < this.ingredients.length; index++) {
|
|
3327
3469
|
if (!referencedIndices.has(index)) continue;
|
|
3328
3470
|
const orig = this.ingredients[index];
|
|
3471
|
+
let flags = orig.flags;
|
|
3472
|
+
if (dynamicOptionalIndices.has(index) && !flags?.includes("optional")) {
|
|
3473
|
+
flags = [...flags ?? [], "optional"];
|
|
3474
|
+
}
|
|
3329
3475
|
const ing = {
|
|
3330
3476
|
name: orig.name,
|
|
3331
3477
|
...orig.preparation && { preparation: orig.preparation },
|
|
3332
|
-
...
|
|
3478
|
+
...flags && { flags },
|
|
3333
3479
|
...orig.extras && { extras: orig.extras }
|
|
3334
3480
|
};
|
|
3335
3481
|
if (selectedIndices.has(index)) {
|
|
@@ -3380,6 +3526,59 @@ var _Recipe = class _Recipe {
|
|
|
3380
3526
|
}
|
|
3381
3527
|
return result;
|
|
3382
3528
|
}
|
|
3529
|
+
/**
|
|
3530
|
+
* Returns the list of cookware items that are used in the active variant.
|
|
3531
|
+
* Cookware in steps/sections not matching the active variant are excluded.
|
|
3532
|
+
* Hidden cookware is always excluded.
|
|
3533
|
+
*
|
|
3534
|
+
* @param options - Options for filtering:
|
|
3535
|
+
* - `choices`: The choices to apply (only `variant` is used)
|
|
3536
|
+
* @returns Array of Cookware objects referenced by active steps
|
|
3537
|
+
*
|
|
3538
|
+
* @example
|
|
3539
|
+
* ```typescript
|
|
3540
|
+
* // Get all cookware for the default variant
|
|
3541
|
+
* const cookware = recipe.getCookwareForVariant();
|
|
3542
|
+
*
|
|
3543
|
+
* // Get cookware for a specific variant
|
|
3544
|
+
* const veganCookware = recipe.getCookwareForVariant({ choices: { variant: 'vegan' } });
|
|
3545
|
+
* ```
|
|
3546
|
+
*/
|
|
3547
|
+
getCookwareForVariant(options) {
|
|
3548
|
+
const { choices } = options || {};
|
|
3549
|
+
const activeVariant = choices?.variant;
|
|
3550
|
+
const isDefaultVariant = activeVariant === void 0 || activeVariant === "*";
|
|
3551
|
+
const cookwareIndices = /* @__PURE__ */ new Set();
|
|
3552
|
+
for (const currentSection of this.sections) {
|
|
3553
|
+
if (currentSection.variants) {
|
|
3554
|
+
if (isDefaultVariant) {
|
|
3555
|
+
if (!currentSection.variants.includes("*")) continue;
|
|
3556
|
+
} else {
|
|
3557
|
+
if (!currentSection.variants.includes(activeVariant)) continue;
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
const allSteps = currentSection.content.filter(
|
|
3561
|
+
(item) => item.type === "step"
|
|
3562
|
+
);
|
|
3563
|
+
for (const currentStep of allSteps) {
|
|
3564
|
+
if (currentStep.variants) {
|
|
3565
|
+
if (isDefaultVariant) {
|
|
3566
|
+
if (!currentStep.variants.includes("*")) continue;
|
|
3567
|
+
} else {
|
|
3568
|
+
if (!currentStep.variants.includes(activeVariant)) continue;
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
for (const item of currentStep.items) {
|
|
3572
|
+
if (item.type === "cookware") {
|
|
3573
|
+
cookwareIndices.add(item.index);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
return this.cookware.filter(
|
|
3579
|
+
(cw, idx) => cookwareIndices.has(idx) && !cw.flags?.includes("hidden")
|
|
3580
|
+
);
|
|
3581
|
+
}
|
|
3383
3582
|
/**
|
|
3384
3583
|
* Parses a recipe from a string.
|
|
3385
3584
|
* @param content - The recipe content to parse.
|
|
@@ -3395,9 +3594,14 @@ var _Recipe = class _Recipe {
|
|
|
3395
3594
|
const items = [];
|
|
3396
3595
|
let noteText = "";
|
|
3397
3596
|
let inNote = false;
|
|
3597
|
+
let stepVariants;
|
|
3598
|
+
let stepOptional;
|
|
3599
|
+
const discoveredVariants = /* @__PURE__ */ new Set();
|
|
3398
3600
|
for (const line of cleanContent) {
|
|
3399
3601
|
if (line.trim().length === 0) {
|
|
3400
|
-
flushPendingItems(section, items);
|
|
3602
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3603
|
+
stepVariants = void 0;
|
|
3604
|
+
stepOptional = void 0;
|
|
3401
3605
|
flushPendingNote(
|
|
3402
3606
|
section,
|
|
3403
3607
|
noteText ? this._parseNoteText(noteText) : []
|
|
@@ -3408,26 +3612,48 @@ var _Recipe = class _Recipe {
|
|
|
3408
3612
|
continue;
|
|
3409
3613
|
}
|
|
3410
3614
|
if (line.startsWith("=")) {
|
|
3411
|
-
flushPendingItems(section, items);
|
|
3615
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3616
|
+
stepVariants = void 0;
|
|
3617
|
+
stepOptional = void 0;
|
|
3412
3618
|
flushPendingNote(
|
|
3413
3619
|
section,
|
|
3414
3620
|
noteText ? this._parseNoteText(noteText) : []
|
|
3415
3621
|
);
|
|
3416
3622
|
noteText = "";
|
|
3623
|
+
let sectionName = line.replace(/^=+|=+$/g, "").trim();
|
|
3624
|
+
let sectionVariants;
|
|
3625
|
+
let sectionOptional;
|
|
3626
|
+
const sectionVarMatch = sectionName.match(variantTagRegex);
|
|
3627
|
+
if (sectionVarMatch?.groups) {
|
|
3628
|
+
const isOptionalPrefix = sectionVarMatch.groups.variantOptionalPrefix === "?";
|
|
3629
|
+
const names = (sectionVarMatch.groups.variantNames ?? "").split(",").map((n2) => n2.trim()).filter((n2) => n2.length > 0);
|
|
3630
|
+
if (names.length > 0) {
|
|
3631
|
+
sectionVariants = names;
|
|
3632
|
+
for (const v of names) discoveredVariants.add(v);
|
|
3633
|
+
}
|
|
3634
|
+
if (isOptionalPrefix) {
|
|
3635
|
+
sectionOptional = true;
|
|
3636
|
+
}
|
|
3637
|
+
sectionName = sectionName.slice(sectionVarMatch[0].length).trim();
|
|
3638
|
+
}
|
|
3417
3639
|
if (this.sections.length === 0 && section.isBlank()) {
|
|
3418
|
-
section.name =
|
|
3640
|
+
section.name = sectionName;
|
|
3641
|
+
if (sectionVariants) section.variants = sectionVariants;
|
|
3642
|
+
if (sectionOptional) section.optional = true;
|
|
3419
3643
|
} else {
|
|
3420
3644
|
if (!section.isBlank()) {
|
|
3421
3645
|
this.sections.push(section);
|
|
3422
3646
|
}
|
|
3423
|
-
section = new Section(
|
|
3647
|
+
section = new Section(sectionName, sectionVariants, sectionOptional);
|
|
3424
3648
|
}
|
|
3425
3649
|
blankLineBefore = true;
|
|
3426
3650
|
inNote = false;
|
|
3427
3651
|
continue;
|
|
3428
3652
|
}
|
|
3429
3653
|
if (blankLineBefore && line.startsWith(">")) {
|
|
3430
|
-
flushPendingItems(section, items);
|
|
3654
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3655
|
+
stepVariants = void 0;
|
|
3656
|
+
stepOptional = void 0;
|
|
3431
3657
|
noteText = line.substring(1).trim();
|
|
3432
3658
|
inNote = true;
|
|
3433
3659
|
blankLineBefore = false;
|
|
@@ -3442,11 +3668,31 @@ var _Recipe = class _Recipe {
|
|
|
3442
3668
|
blankLineBefore = false;
|
|
3443
3669
|
continue;
|
|
3444
3670
|
}
|
|
3671
|
+
let currentLine = line;
|
|
3672
|
+
if (items.length === 0) {
|
|
3673
|
+
const varMatch = currentLine.match(variantTagRegex);
|
|
3674
|
+
if (varMatch?.groups) {
|
|
3675
|
+
const isOptionalPrefix = varMatch.groups.variantOptionalPrefix === "?";
|
|
3676
|
+
const names = (varMatch.groups.variantNames ?? "").split(",").map((n2) => n2.trim()).filter((n2) => n2.length > 0);
|
|
3677
|
+
if (names.length > 0) {
|
|
3678
|
+
stepVariants = names;
|
|
3679
|
+
for (const v of names) discoveredVariants.add(v);
|
|
3680
|
+
}
|
|
3681
|
+
if (isOptionalPrefix) {
|
|
3682
|
+
stepOptional = true;
|
|
3683
|
+
}
|
|
3684
|
+
currentLine = currentLine.slice(varMatch[0].length);
|
|
3685
|
+
if (currentLine.trim().length === 0) {
|
|
3686
|
+
blankLineBefore = false;
|
|
3687
|
+
continue;
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3445
3691
|
let cursor = 0;
|
|
3446
|
-
for (const match of
|
|
3692
|
+
for (const match of currentLine.matchAll(tokensRegex)) {
|
|
3447
3693
|
const idx = match.index;
|
|
3448
3694
|
if (idx > cursor) {
|
|
3449
|
-
items.push(...parseMarkdownSegments(
|
|
3695
|
+
items.push(...parseMarkdownSegments(currentLine.slice(cursor, idx)));
|
|
3450
3696
|
}
|
|
3451
3697
|
const groups = match.groups;
|
|
3452
3698
|
if (groups.mIngredientName || groups.sIngredientName) {
|
|
@@ -3507,16 +3753,21 @@ var _Recipe = class _Recipe {
|
|
|
3507
3753
|
}
|
|
3508
3754
|
cursor = idx + match[0].length;
|
|
3509
3755
|
}
|
|
3510
|
-
if (cursor <
|
|
3511
|
-
items.push(...parseMarkdownSegments(
|
|
3756
|
+
if (cursor < currentLine.length) {
|
|
3757
|
+
items.push(...parseMarkdownSegments(currentLine.slice(cursor)));
|
|
3512
3758
|
}
|
|
3513
3759
|
blankLineBefore = false;
|
|
3514
3760
|
}
|
|
3515
|
-
flushPendingItems(section, items);
|
|
3761
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3516
3762
|
flushPendingNote(section, noteText ? this._parseNoteText(noteText) : []);
|
|
3517
3763
|
if (!section.isBlank()) {
|
|
3518
3764
|
this.sections.push(section);
|
|
3519
3765
|
}
|
|
3766
|
+
const metaVariants = this.metadata.variants ?? [];
|
|
3767
|
+
const allVariants = /* @__PURE__ */ new Set([...metaVariants, ...discoveredVariants]);
|
|
3768
|
+
if (allVariants.size > 0) {
|
|
3769
|
+
this.choices.variants = [...allVariants];
|
|
3770
|
+
}
|
|
3520
3771
|
this._populateIngredientQuantities();
|
|
3521
3772
|
}
|
|
3522
3773
|
/**
|
|
@@ -3603,8 +3854,10 @@ var _Recipe = class _Recipe {
|
|
|
3603
3854
|
}
|
|
3604
3855
|
}
|
|
3605
3856
|
}
|
|
3606
|
-
for (const
|
|
3607
|
-
|
|
3857
|
+
for (const subgroups of newRecipe.choices.ingredientGroups.values()) {
|
|
3858
|
+
for (const subgroup of subgroups) {
|
|
3859
|
+
scaleAlternativesBy(subgroup, factor);
|
|
3860
|
+
}
|
|
3608
3861
|
}
|
|
3609
3862
|
for (const alternatives of newRecipe.choices.ingredientItems.values()) {
|
|
3610
3863
|
scaleAlternativesBy(alternatives, factor);
|
|
@@ -3791,8 +4044,10 @@ var _Recipe = class _Recipe {
|
|
|
3791
4044
|
}
|
|
3792
4045
|
}
|
|
3793
4046
|
}
|
|
3794
|
-
for (const
|
|
3795
|
-
|
|
4047
|
+
for (const subgroups of newRecipe.choices.ingredientGroups.values()) {
|
|
4048
|
+
for (const subgroup of subgroups) {
|
|
4049
|
+
convertAlternatives(subgroup);
|
|
4050
|
+
}
|
|
3796
4051
|
}
|
|
3797
4052
|
for (const alternatives of newRecipe.choices.ingredientItems.values()) {
|
|
3798
4053
|
convertAlternatives(alternatives);
|
|
@@ -3823,7 +4078,11 @@ var _Recipe = class _Recipe {
|
|
|
3823
4078
|
newRecipe.metadata = deepClone(this.metadata);
|
|
3824
4079
|
newRecipe.ingredients = deepClone(this.ingredients);
|
|
3825
4080
|
newRecipe.sections = this.sections.map((section) => {
|
|
3826
|
-
const newSection = new Section(
|
|
4081
|
+
const newSection = new Section(
|
|
4082
|
+
section.name,
|
|
4083
|
+
section.variants,
|
|
4084
|
+
section.optional
|
|
4085
|
+
);
|
|
3827
4086
|
newSection.content = deepClone(section.content);
|
|
3828
4087
|
return newSection;
|
|
3829
4088
|
});
|
|
@@ -3844,6 +4103,11 @@ __publicField(_Recipe, "unitSystems", /* @__PURE__ */ new WeakMap());
|
|
|
3844
4103
|
* Used for giving ID numbers to items during parsing.
|
|
3845
4104
|
*/
|
|
3846
4105
|
__publicField(_Recipe, "itemCounts", /* @__PURE__ */ new WeakMap());
|
|
4106
|
+
/**
|
|
4107
|
+
* External storage for subgroup index tracking during parsing.
|
|
4108
|
+
* Maps groupKey → subgroupKey → index within the subgroups array.
|
|
4109
|
+
*/
|
|
4110
|
+
__publicField(_Recipe, "subgroupIndices", /* @__PURE__ */ new WeakMap());
|
|
3847
4111
|
var Recipe = _Recipe;
|
|
3848
4112
|
|
|
3849
4113
|
// src/classes/shopping_list.ts
|
|
@@ -4681,22 +4945,62 @@ function isGroupedItem(item) {
|
|
|
4681
4945
|
function isAlternativeSelected(recipe, choices, item, alternativeIndex) {
|
|
4682
4946
|
if (item.group) {
|
|
4683
4947
|
const selectedIndex2 = choices?.ingredientGroups?.get(item.group);
|
|
4684
|
-
const
|
|
4685
|
-
if (
|
|
4686
|
-
const
|
|
4687
|
-
return
|
|
4948
|
+
const groupSubgroups = recipe.choices.ingredientGroups.get(item.group);
|
|
4949
|
+
if (groupSubgroups && selectedIndex2 !== void 0 && selectedIndex2 < groupSubgroups.length) {
|
|
4950
|
+
const selectedSubgroup = groupSubgroups[selectedIndex2];
|
|
4951
|
+
return selectedSubgroup?.some((alt) => alt.itemId === item.id);
|
|
4688
4952
|
}
|
|
4689
4953
|
return false;
|
|
4690
4954
|
}
|
|
4691
4955
|
const selectedIndex = choices?.ingredientItems?.get(item.id);
|
|
4692
4956
|
return alternativeIndex === selectedIndex;
|
|
4693
4957
|
}
|
|
4958
|
+
function isSectionActive(section, variant) {
|
|
4959
|
+
if (!section.variants) return true;
|
|
4960
|
+
const isDefault = variant === void 0 || variant === "*";
|
|
4961
|
+
if (isDefault) {
|
|
4962
|
+
return section.variants.includes("*");
|
|
4963
|
+
}
|
|
4964
|
+
return section.variants.includes(variant);
|
|
4965
|
+
}
|
|
4966
|
+
function isStepActive(step, variant) {
|
|
4967
|
+
if (!step.variants) return true;
|
|
4968
|
+
const isDefault = variant === void 0 || variant === "*";
|
|
4969
|
+
if (isDefault) {
|
|
4970
|
+
return step.variants.includes("*");
|
|
4971
|
+
}
|
|
4972
|
+
return step.variants.includes(variant);
|
|
4973
|
+
}
|
|
4974
|
+
function getEffectiveChoices(recipe, variant) {
|
|
4975
|
+
const choices = { variant };
|
|
4976
|
+
if (variant === void 0 || variant === "*") return choices;
|
|
4977
|
+
const variantLower = variant.toLowerCase();
|
|
4978
|
+
for (const [itemId, alternatives] of recipe.choices.ingredientItems) {
|
|
4979
|
+
const matchIdx = alternatives.findIndex(
|
|
4980
|
+
(alt) => alt.note && alt.note.toLowerCase().includes(variantLower)
|
|
4981
|
+
);
|
|
4982
|
+
if (matchIdx >= 0) {
|
|
4983
|
+
if (!choices.ingredientItems) choices.ingredientItems = /* @__PURE__ */ new Map();
|
|
4984
|
+
choices.ingredientItems.set(itemId, matchIdx);
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
for (const [groupId, subgroups] of recipe.choices.ingredientGroups) {
|
|
4988
|
+
const matchIdx = subgroups.findIndex(
|
|
4989
|
+
(sg) => sg.some(
|
|
4990
|
+
(alt) => alt.note && alt.note.toLowerCase().includes(variantLower)
|
|
4991
|
+
)
|
|
4992
|
+
);
|
|
4993
|
+
if (matchIdx >= 0) {
|
|
4994
|
+
if (!choices.ingredientGroups) choices.ingredientGroups = /* @__PURE__ */ new Map();
|
|
4995
|
+
choices.ingredientGroups.set(groupId, matchIdx);
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
return choices;
|
|
4999
|
+
}
|
|
4694
5000
|
export {
|
|
4695
|
-
BadIndentationError,
|
|
4696
5001
|
CategoryConfig,
|
|
4697
5002
|
NoProductCatalogForCartError,
|
|
4698
5003
|
NoShoppingListForCartError,
|
|
4699
|
-
NoTabAsIndentError,
|
|
4700
5004
|
Pantry,
|
|
4701
5005
|
ProductCatalog,
|
|
4702
5006
|
Recipe,
|
|
@@ -4711,11 +5015,14 @@ export {
|
|
|
4711
5015
|
formatQuantityWithUnit,
|
|
4712
5016
|
formatSingleValue,
|
|
4713
5017
|
formatUnit,
|
|
5018
|
+
getEffectiveChoices,
|
|
4714
5019
|
hasAlternatives,
|
|
4715
5020
|
isAlternativeSelected,
|
|
4716
5021
|
isAndGroup,
|
|
4717
5022
|
isGroupedItem,
|
|
5023
|
+
isSectionActive,
|
|
4718
5024
|
isSimpleGroup,
|
|
5025
|
+
isStepActive,
|
|
4719
5026
|
renderFractionAsVulgar
|
|
4720
5027
|
};
|
|
4721
5028
|
/* v8 ignore else -- @preserve */
|