@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.cjs
CHANGED
|
@@ -32,11 +32,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
32
32
|
// src/index.ts
|
|
33
33
|
var index_exports = {};
|
|
34
34
|
__export(index_exports, {
|
|
35
|
-
BadIndentationError: () => BadIndentationError,
|
|
36
35
|
CategoryConfig: () => CategoryConfig,
|
|
37
36
|
NoProductCatalogForCartError: () => NoProductCatalogForCartError,
|
|
38
37
|
NoShoppingListForCartError: () => NoShoppingListForCartError,
|
|
39
|
-
NoTabAsIndentError: () => NoTabAsIndentError,
|
|
40
38
|
Pantry: () => Pantry,
|
|
41
39
|
ProductCatalog: () => ProductCatalog,
|
|
42
40
|
Recipe: () => Recipe,
|
|
@@ -51,11 +49,14 @@ __export(index_exports, {
|
|
|
51
49
|
formatQuantityWithUnit: () => formatQuantityWithUnit,
|
|
52
50
|
formatSingleValue: () => formatSingleValue,
|
|
53
51
|
formatUnit: () => formatUnit,
|
|
52
|
+
getEffectiveChoices: () => getEffectiveChoices,
|
|
54
53
|
hasAlternatives: () => hasAlternatives,
|
|
55
54
|
isAlternativeSelected: () => isAlternativeSelected,
|
|
56
55
|
isAndGroup: () => isAndGroup,
|
|
57
56
|
isGroupedItem: () => isGroupedItem,
|
|
57
|
+
isSectionActive: () => isSectionActive,
|
|
58
58
|
isSimpleGroup: () => isSimpleGroup,
|
|
59
|
+
isStepActive: () => isStepActive,
|
|
59
60
|
renderFractionAsVulgar: () => renderFractionAsVulgar
|
|
60
61
|
});
|
|
61
62
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -335,7 +336,7 @@ var nonWordCharStrict = "\\s@#~\\[\\]{(,;:!?|";
|
|
|
335
336
|
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();
|
|
336
337
|
var inlineIngredientAlternativesRegex = new RegExp("\\|" + ingredientWithAlternativeRegex.source.slice(1));
|
|
337
338
|
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();
|
|
338
|
-
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();
|
|
339
|
+
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();
|
|
339
340
|
var ingredientAliasRegex = d().startAnchor().startNamedGroup("ingredientListName").notAnyOf("|").oneOrMore().endGroup().literal("|").startNamedGroup("ingredientDisplayName").notAnyOf("|").oneOrMore().endGroup().endAnchor().toRegExp();
|
|
340
341
|
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();
|
|
341
342
|
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();
|
|
@@ -363,6 +364,7 @@ var shoppingListRegex = d().literal("[").startNamedGroup("name").anyCharacter().
|
|
|
363
364
|
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();
|
|
364
365
|
var numberLikeRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
365
366
|
var floatRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
367
|
+
var variantTagRegex = d().startAnchor().literal("[").startNamedGroup("variantOptionalPrefix").literal("?").endGroup().optional().startNamedGroup("variantNames").notAnyOf("\\]").zeroOrMore().endGroup().literal("]").whitespace().zeroOrMore().toRegExp();
|
|
366
368
|
var mdEscaped = d().literal("\\").startCaptureGroup().anyOf("*_`").endGroup();
|
|
367
369
|
var mdInlineCode = d().literal("`").startCaptureGroup().notAnyOf("`").oneOrMore().lazy().endGroup().literal("`");
|
|
368
370
|
var mdLink = d().literal("[").startCaptureGroup().notAnyOf("\\]").oneOrMore().lazy().endGroup().literal("](").startCaptureGroup().notAnyOf(")").oneOrMore().lazy().endGroup().literal(")");
|
|
@@ -1417,9 +1419,12 @@ function flushPendingNote(section, noteItems) {
|
|
|
1417
1419
|
}
|
|
1418
1420
|
return noteItems;
|
|
1419
1421
|
}
|
|
1420
|
-
function flushPendingItems(section, items) {
|
|
1422
|
+
function flushPendingItems(section, items, stepVariants, stepOptional) {
|
|
1421
1423
|
if (items.length > 0) {
|
|
1422
|
-
|
|
1424
|
+
const step = { type: "step", items: [...items] };
|
|
1425
|
+
if (stepVariants) step.variants = stepVariants;
|
|
1426
|
+
if (stepOptional) step.optional = true;
|
|
1427
|
+
section.content.push(step);
|
|
1423
1428
|
items.length = 0;
|
|
1424
1429
|
return true;
|
|
1425
1430
|
}
|
|
@@ -1963,7 +1968,8 @@ function extractMetadata(content) {
|
|
|
1963
1968
|
"yield",
|
|
1964
1969
|
"serves",
|
|
1965
1970
|
// List fields
|
|
1966
|
-
"tags"
|
|
1971
|
+
"tags",
|
|
1972
|
+
"variants"
|
|
1967
1973
|
]);
|
|
1968
1974
|
for (const metaVar of [
|
|
1969
1975
|
"title",
|
|
@@ -2050,6 +2056,8 @@ function extractMetadata(content) {
|
|
|
2050
2056
|
}
|
|
2051
2057
|
const tags = parseListMetaVar(metadataContent, "tags");
|
|
2052
2058
|
if (tags) metadata.tags = tags;
|
|
2059
|
+
const variants = parseListMetaVar(metadataContent, "variants");
|
|
2060
|
+
if (variants) metadata.variants = variants;
|
|
2053
2061
|
const allKeys = extractAllMetadataKeys(metadataContent);
|
|
2054
2062
|
for (const key of allKeys) {
|
|
2055
2063
|
if (handledKeys.has(key)) continue;
|
|
@@ -2437,8 +2445,10 @@ var Section = class {
|
|
|
2437
2445
|
/**
|
|
2438
2446
|
* Creates an instance of Section.
|
|
2439
2447
|
* @param name - The name of the section. Defaults to an empty string.
|
|
2448
|
+
* @param variants - Optional variant names for this section.
|
|
2449
|
+
* @param optional - Whether the section is optional.
|
|
2440
2450
|
*/
|
|
2441
|
-
constructor(name = "") {
|
|
2451
|
+
constructor(name = "", variants, optional) {
|
|
2442
2452
|
/**
|
|
2443
2453
|
* The name of the section. Can be an empty string for the default (first) section.
|
|
2444
2454
|
* @defaultValue `""`
|
|
@@ -2446,7 +2456,13 @@ var Section = class {
|
|
|
2446
2456
|
__publicField(this, "name");
|
|
2447
2457
|
/** An array of steps and notes that make up the content of the section. */
|
|
2448
2458
|
__publicField(this, "content", []);
|
|
2459
|
+
/** Optional list of variant names this section belongs to. */
|
|
2460
|
+
__publicField(this, "variants");
|
|
2461
|
+
/** Whether the section has been marked as optional ([?]) */
|
|
2462
|
+
__publicField(this, "optional");
|
|
2449
2463
|
this.name = name;
|
|
2464
|
+
if (variants) this.variants = variants;
|
|
2465
|
+
if (optional) this.optional = true;
|
|
2450
2466
|
}
|
|
2451
2467
|
/**
|
|
2452
2468
|
* Checks if the section is blank (has no name and no content).
|
|
@@ -2806,7 +2822,8 @@ var _Recipe = class _Recipe {
|
|
|
2806
2822
|
*/
|
|
2807
2823
|
__publicField(this, "choices", {
|
|
2808
2824
|
ingredientItems: /* @__PURE__ */ new Map(),
|
|
2809
|
-
ingredientGroups: /* @__PURE__ */ new Map()
|
|
2825
|
+
ingredientGroups: /* @__PURE__ */ new Map(),
|
|
2826
|
+
variants: []
|
|
2810
2827
|
});
|
|
2811
2828
|
/**
|
|
2812
2829
|
* The parsed recipe ingredients.
|
|
@@ -2837,6 +2854,7 @@ var _Recipe = class _Recipe {
|
|
|
2837
2854
|
*/
|
|
2838
2855
|
__publicField(this, "servings");
|
|
2839
2856
|
_Recipe.itemCounts.set(this, 0);
|
|
2857
|
+
_Recipe.subgroupIndices.set(this, /* @__PURE__ */ new Map());
|
|
2840
2858
|
if (content) {
|
|
2841
2859
|
this.parse(content);
|
|
2842
2860
|
}
|
|
@@ -3054,6 +3072,7 @@ var _Recipe = class _Recipe {
|
|
|
3054
3072
|
if (!match?.groups) return;
|
|
3055
3073
|
const groups = match.groups;
|
|
3056
3074
|
const groupKey = groups.gIngredientGroupKey;
|
|
3075
|
+
const subgroupKey = groups.gIngredientSubgroupKey;
|
|
3057
3076
|
let name = groups.gmIngredientName || groups.gsIngredientName;
|
|
3058
3077
|
const preparation = groups.gIngredientPreparation;
|
|
3059
3078
|
const modifiers = groups.gIngredientModifiers;
|
|
@@ -3121,7 +3140,12 @@ var _Recipe = class _Recipe {
|
|
|
3121
3140
|
if (itemQuantity) {
|
|
3122
3141
|
Object.assign(alternative, itemQuantity);
|
|
3123
3142
|
}
|
|
3124
|
-
const
|
|
3143
|
+
const note = groups.gIngredientNote?.trim();
|
|
3144
|
+
if (note) {
|
|
3145
|
+
alternative.note = note;
|
|
3146
|
+
}
|
|
3147
|
+
const existingSubgroups = this.choices.ingredientGroups.get(groupKey);
|
|
3148
|
+
const existingAlternativesFlat = existingSubgroups?.flat();
|
|
3125
3149
|
function upsertAlternativeToIngredient(ingredients, ingredientIdx, newAlternativeIdx) {
|
|
3126
3150
|
const ingredient = ingredients[ingredientIdx];
|
|
3127
3151
|
if (ingredient) {
|
|
@@ -3132,8 +3156,8 @@ var _Recipe = class _Recipe {
|
|
|
3132
3156
|
}
|
|
3133
3157
|
}
|
|
3134
3158
|
}
|
|
3135
|
-
if (
|
|
3136
|
-
for (const alt of
|
|
3159
|
+
if (existingAlternativesFlat) {
|
|
3160
|
+
for (const alt of existingAlternativesFlat) {
|
|
3137
3161
|
upsertAlternativeToIngredient(this.ingredients, alt.index, idxInList);
|
|
3138
3162
|
upsertAlternativeToIngredient(this.ingredients, idxInList, alt.index);
|
|
3139
3163
|
}
|
|
@@ -3145,14 +3169,35 @@ var _Recipe = class _Recipe {
|
|
|
3145
3169
|
group: groupKey,
|
|
3146
3170
|
alternatives: [alternative]
|
|
3147
3171
|
};
|
|
3172
|
+
if (subgroupKey !== void 0) {
|
|
3173
|
+
newItem.subgroup = subgroupKey;
|
|
3174
|
+
}
|
|
3148
3175
|
items.push(newItem);
|
|
3149
3176
|
const choiceAlternative = deepClone(alternative);
|
|
3150
3177
|
choiceAlternative.itemId = id;
|
|
3151
3178
|
const existingChoice = this.choices.ingredientGroups.get(groupKey);
|
|
3179
|
+
const sgMap = _Recipe.subgroupIndices.get(this);
|
|
3152
3180
|
if (!existingChoice) {
|
|
3153
|
-
this.choices.ingredientGroups.set(groupKey, [choiceAlternative]);
|
|
3181
|
+
this.choices.ingredientGroups.set(groupKey, [[choiceAlternative]]);
|
|
3182
|
+
if (subgroupKey !== void 0) {
|
|
3183
|
+
sgMap.set(groupKey, /* @__PURE__ */ new Map([[subgroupKey, 0]]));
|
|
3184
|
+
}
|
|
3185
|
+
} else if (subgroupKey !== void 0) {
|
|
3186
|
+
const groupSgMap = sgMap.get(groupKey);
|
|
3187
|
+
const existingIdx = groupSgMap?.get(subgroupKey);
|
|
3188
|
+
if (existingIdx !== void 0) {
|
|
3189
|
+
existingChoice[existingIdx].push(choiceAlternative);
|
|
3190
|
+
} else {
|
|
3191
|
+
const newIdx = existingChoice.length;
|
|
3192
|
+
existingChoice.push([choiceAlternative]);
|
|
3193
|
+
if (!groupSgMap) {
|
|
3194
|
+
sgMap.set(groupKey, /* @__PURE__ */ new Map([[subgroupKey, newIdx]]));
|
|
3195
|
+
} else {
|
|
3196
|
+
groupSgMap.set(subgroupKey, newIdx);
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3154
3199
|
} else {
|
|
3155
|
-
existingChoice.push(choiceAlternative);
|
|
3200
|
+
existingChoice.push([choiceAlternative]);
|
|
3156
3201
|
}
|
|
3157
3202
|
}
|
|
3158
3203
|
/**
|
|
@@ -3192,6 +3237,8 @@ var _Recipe = class _Recipe {
|
|
|
3192
3237
|
/** @internal */
|
|
3193
3238
|
collectQuantityGroups(options) {
|
|
3194
3239
|
const { section, step, choices } = options || {};
|
|
3240
|
+
const activeVariant = choices?.variant;
|
|
3241
|
+
const isDefaultVariant = activeVariant === void 0 || activeVariant === "*";
|
|
3195
3242
|
const sectionsToProcess = section !== void 0 ? (() => {
|
|
3196
3243
|
const idx = typeof section === "number" ? section : this.sections.indexOf(section);
|
|
3197
3244
|
return idx >= 0 && idx < this.sections.length ? [this.sections[idx]] : [];
|
|
@@ -3199,36 +3246,89 @@ var _Recipe = class _Recipe {
|
|
|
3199
3246
|
const ingredientGroups = /* @__PURE__ */ new Map();
|
|
3200
3247
|
const selectedIndices = /* @__PURE__ */ new Set();
|
|
3201
3248
|
const referencedIndices = /* @__PURE__ */ new Set();
|
|
3249
|
+
const dynamicOptionalIndices = /* @__PURE__ */ new Set();
|
|
3202
3250
|
for (const currentSection of sectionsToProcess) {
|
|
3251
|
+
if (currentSection.variants) {
|
|
3252
|
+
if (isDefaultVariant) {
|
|
3253
|
+
if (!currentSection.variants.includes("*")) continue;
|
|
3254
|
+
} else {
|
|
3255
|
+
if (!currentSection.variants.includes(activeVariant)) continue;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3203
3258
|
const allSteps = currentSection.content.filter(
|
|
3204
3259
|
(item) => item.type === "step"
|
|
3205
3260
|
);
|
|
3261
|
+
const isOptionalSection = currentSection.optional === true;
|
|
3206
3262
|
const stepsToProcess = step === void 0 ? allSteps : typeof step === "number" ? step >= 0 && step < allSteps.length ? [allSteps[step]] : [] : allSteps.includes(step) ? [step] : [];
|
|
3207
3263
|
for (const currentStep of stepsToProcess) {
|
|
3264
|
+
if (currentStep.variants) {
|
|
3265
|
+
if (isDefaultVariant) {
|
|
3266
|
+
if (!currentStep.variants.includes("*")) continue;
|
|
3267
|
+
} else {
|
|
3268
|
+
if (!currentStep.variants.includes(activeVariant)) continue;
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
const isOptionalStep = currentStep.optional === true || isOptionalSection;
|
|
3208
3272
|
for (const item of currentStep.items.filter(
|
|
3209
3273
|
(item2) => item2.type === "ingredient"
|
|
3210
3274
|
)) {
|
|
3211
3275
|
const isGrouped = "group" in item && item.group !== void 0;
|
|
3212
|
-
const
|
|
3276
|
+
const groupSubgroups = isGrouped ? this.choices.ingredientGroups.get(item.group) : void 0;
|
|
3213
3277
|
let selectedAltIndex = 0;
|
|
3214
3278
|
let isSelected;
|
|
3215
3279
|
let hasExplicitChoice;
|
|
3216
3280
|
if (isGrouped) {
|
|
3217
3281
|
const groupChoice = choices?.ingredientGroups?.get(item.group);
|
|
3218
3282
|
hasExplicitChoice = groupChoice !== void 0;
|
|
3219
|
-
|
|
3220
|
-
|
|
3283
|
+
if (!hasExplicitChoice && !isDefaultVariant) {
|
|
3284
|
+
const matchingSubgroupIdx = groupSubgroups?.findIndex(
|
|
3285
|
+
(sg) => sg.some(
|
|
3286
|
+
(alt) => alt.note && alt.note.toLowerCase().includes(activeVariant.toLowerCase())
|
|
3287
|
+
)
|
|
3288
|
+
);
|
|
3289
|
+
if (matchingSubgroupIdx !== void 0 && matchingSubgroupIdx >= 0) {
|
|
3290
|
+
const matchedSubgroup = groupSubgroups[matchingSubgroupIdx];
|
|
3291
|
+
isSelected = matchedSubgroup.some(
|
|
3292
|
+
(alt) => alt.itemId === item.id
|
|
3293
|
+
);
|
|
3294
|
+
hasExplicitChoice = true;
|
|
3295
|
+
selectedAltIndex = 0;
|
|
3296
|
+
} else {
|
|
3297
|
+
const targetSubgroupIndex = 0;
|
|
3298
|
+
const selectedSubgroup = groupSubgroups?.[targetSubgroupIndex];
|
|
3299
|
+
isSelected = selectedSubgroup?.some((alt) => alt.itemId === item.id) ?? false;
|
|
3300
|
+
}
|
|
3301
|
+
} else {
|
|
3302
|
+
const targetSubgroupIndex = groupChoice ?? 0;
|
|
3303
|
+
const selectedSubgroup = groupSubgroups?.[targetSubgroupIndex];
|
|
3304
|
+
isSelected = selectedSubgroup?.some((alt) => alt.itemId === item.id) ?? false;
|
|
3305
|
+
}
|
|
3221
3306
|
} else {
|
|
3222
3307
|
const itemChoice = choices?.ingredientItems?.get(item.id);
|
|
3223
3308
|
hasExplicitChoice = itemChoice !== void 0;
|
|
3224
|
-
|
|
3309
|
+
if (!hasExplicitChoice && !isDefaultVariant) {
|
|
3310
|
+
const matchingIndices = item.alternatives.map((alt, idx) => ({ alt, idx })).filter(
|
|
3311
|
+
({ alt }) => alt.note && alt.note.toLowerCase().includes(activeVariant.toLowerCase())
|
|
3312
|
+
).map(({ idx }) => idx);
|
|
3313
|
+
if (matchingIndices.length > 0) {
|
|
3314
|
+
selectedAltIndex = matchingIndices[0];
|
|
3315
|
+
hasExplicitChoice = true;
|
|
3316
|
+
} else {
|
|
3317
|
+
selectedAltIndex = itemChoice ?? 0;
|
|
3318
|
+
}
|
|
3319
|
+
} else {
|
|
3320
|
+
selectedAltIndex = itemChoice ?? 0;
|
|
3321
|
+
}
|
|
3225
3322
|
isSelected = true;
|
|
3226
3323
|
}
|
|
3227
3324
|
const alternative = item.alternatives[selectedAltIndex];
|
|
3228
3325
|
if (!alternative || !isSelected) continue;
|
|
3229
3326
|
selectedIndices.add(alternative.index);
|
|
3230
|
-
|
|
3231
|
-
|
|
3327
|
+
if (isOptionalStep) {
|
|
3328
|
+
dynamicOptionalIndices.add(alternative.index);
|
|
3329
|
+
}
|
|
3330
|
+
const allAltsFlat = isGrouped ? groupSubgroups.flat() : item.alternatives;
|
|
3331
|
+
for (const alt of allAltsFlat) {
|
|
3232
3332
|
referencedIndices.add(alt.index);
|
|
3233
3333
|
}
|
|
3234
3334
|
if (!alternative.quantity) continue;
|
|
@@ -3240,10 +3340,34 @@ var _Recipe = class _Recipe {
|
|
|
3240
3340
|
};
|
|
3241
3341
|
const quantityEntry = alternative.equivalents?.length ? { or: [baseQty, ...alternative.equivalents] } : baseQty;
|
|
3242
3342
|
let alternativeRefs;
|
|
3243
|
-
if (!hasExplicitChoice &&
|
|
3244
|
-
|
|
3245
|
-
(
|
|
3246
|
-
)
|
|
3343
|
+
if (!hasExplicitChoice && groupSubgroups && groupSubgroups.length > 1) {
|
|
3344
|
+
const currentSubgroupIdx = groupSubgroups.findIndex(
|
|
3345
|
+
(sg) => sg.some((alt) => alt.itemId === item.id)
|
|
3346
|
+
);
|
|
3347
|
+
alternativeRefs = groupSubgroups.filter((_, idx) => idx !== currentSubgroupIdx).flatMap(
|
|
3348
|
+
(subgroup) => subgroup.map((otherAlt) => {
|
|
3349
|
+
const ref = {
|
|
3350
|
+
index: otherAlt.index
|
|
3351
|
+
};
|
|
3352
|
+
if (otherAlt.quantity) {
|
|
3353
|
+
const altQty = {
|
|
3354
|
+
quantity: otherAlt.quantity,
|
|
3355
|
+
...otherAlt.unit && {
|
|
3356
|
+
unit: otherAlt.unit.name
|
|
3357
|
+
},
|
|
3358
|
+
...otherAlt.equivalents && {
|
|
3359
|
+
equivalents: otherAlt.equivalents.map(
|
|
3360
|
+
(eq) => toPlainUnit(eq)
|
|
3361
|
+
)
|
|
3362
|
+
}
|
|
3363
|
+
};
|
|
3364
|
+
ref.quantities = [altQty];
|
|
3365
|
+
}
|
|
3366
|
+
return ref;
|
|
3367
|
+
})
|
|
3368
|
+
);
|
|
3369
|
+
} else if (!hasExplicitChoice && !isGrouped && allAltsFlat.length > 1) {
|
|
3370
|
+
alternativeRefs = allAltsFlat.filter((alt) => alt.index !== alternative.index).map((otherAlt) => {
|
|
3247
3371
|
const ref = { index: otherAlt.index };
|
|
3248
3372
|
if (otherAlt.quantity) {
|
|
3249
3373
|
const altQty = {
|
|
@@ -3308,7 +3432,12 @@ var _Recipe = class _Recipe {
|
|
|
3308
3432
|
}
|
|
3309
3433
|
}
|
|
3310
3434
|
}
|
|
3311
|
-
return {
|
|
3435
|
+
return {
|
|
3436
|
+
ingredientGroups,
|
|
3437
|
+
selectedIndices,
|
|
3438
|
+
referencedIndices,
|
|
3439
|
+
dynamicOptionalIndices
|
|
3440
|
+
};
|
|
3312
3441
|
}
|
|
3313
3442
|
/**
|
|
3314
3443
|
* Gets the raw (unprocessed) quantity groups for each ingredient, before
|
|
@@ -3327,12 +3456,21 @@ var _Recipe = class _Recipe {
|
|
|
3327
3456
|
* ```
|
|
3328
3457
|
*/
|
|
3329
3458
|
getRawQuantityGroups(options) {
|
|
3330
|
-
const {
|
|
3459
|
+
const {
|
|
3460
|
+
ingredientGroups,
|
|
3461
|
+
selectedIndices,
|
|
3462
|
+
referencedIndices,
|
|
3463
|
+
dynamicOptionalIndices
|
|
3464
|
+
} = this.collectQuantityGroups(options);
|
|
3331
3465
|
const result = [];
|
|
3332
3466
|
for (let index = 0; index < this.ingredients.length; index++) {
|
|
3333
3467
|
if (!referencedIndices.has(index)) continue;
|
|
3334
3468
|
const orig = this.ingredients[index];
|
|
3335
3469
|
const usedAsPrimary = selectedIndices.has(index);
|
|
3470
|
+
let flags = orig.flags;
|
|
3471
|
+
if (dynamicOptionalIndices.has(index) && !flags?.includes("optional")) {
|
|
3472
|
+
flags = [...flags ?? [], "optional"];
|
|
3473
|
+
}
|
|
3336
3474
|
const quantities = [];
|
|
3337
3475
|
if (usedAsPrimary) {
|
|
3338
3476
|
const groupsForIng = ingredientGroups.get(index);
|
|
@@ -3345,7 +3483,7 @@ var _Recipe = class _Recipe {
|
|
|
3345
3483
|
result.push({
|
|
3346
3484
|
name: orig.name,
|
|
3347
3485
|
...usedAsPrimary && { usedAsPrimary: true },
|
|
3348
|
-
...
|
|
3486
|
+
...flags && { flags },
|
|
3349
3487
|
quantities
|
|
3350
3488
|
});
|
|
3351
3489
|
}
|
|
@@ -3379,15 +3517,24 @@ var _Recipe = class _Recipe {
|
|
|
3379
3517
|
* ```
|
|
3380
3518
|
*/
|
|
3381
3519
|
getIngredientQuantities(options) {
|
|
3382
|
-
const {
|
|
3520
|
+
const {
|
|
3521
|
+
ingredientGroups,
|
|
3522
|
+
selectedIndices,
|
|
3523
|
+
referencedIndices,
|
|
3524
|
+
dynamicOptionalIndices
|
|
3525
|
+
} = this.collectQuantityGroups(options);
|
|
3383
3526
|
const result = [];
|
|
3384
3527
|
for (let index = 0; index < this.ingredients.length; index++) {
|
|
3385
3528
|
if (!referencedIndices.has(index)) continue;
|
|
3386
3529
|
const orig = this.ingredients[index];
|
|
3530
|
+
let flags = orig.flags;
|
|
3531
|
+
if (dynamicOptionalIndices.has(index) && !flags?.includes("optional")) {
|
|
3532
|
+
flags = [...flags ?? [], "optional"];
|
|
3533
|
+
}
|
|
3387
3534
|
const ing = {
|
|
3388
3535
|
name: orig.name,
|
|
3389
3536
|
...orig.preparation && { preparation: orig.preparation },
|
|
3390
|
-
...
|
|
3537
|
+
...flags && { flags },
|
|
3391
3538
|
...orig.extras && { extras: orig.extras }
|
|
3392
3539
|
};
|
|
3393
3540
|
if (selectedIndices.has(index)) {
|
|
@@ -3438,6 +3585,59 @@ var _Recipe = class _Recipe {
|
|
|
3438
3585
|
}
|
|
3439
3586
|
return result;
|
|
3440
3587
|
}
|
|
3588
|
+
/**
|
|
3589
|
+
* Returns the list of cookware items that are used in the active variant.
|
|
3590
|
+
* Cookware in steps/sections not matching the active variant are excluded.
|
|
3591
|
+
* Hidden cookware is always excluded.
|
|
3592
|
+
*
|
|
3593
|
+
* @param options - Options for filtering:
|
|
3594
|
+
* - `choices`: The choices to apply (only `variant` is used)
|
|
3595
|
+
* @returns Array of Cookware objects referenced by active steps
|
|
3596
|
+
*
|
|
3597
|
+
* @example
|
|
3598
|
+
* ```typescript
|
|
3599
|
+
* // Get all cookware for the default variant
|
|
3600
|
+
* const cookware = recipe.getCookwareForVariant();
|
|
3601
|
+
*
|
|
3602
|
+
* // Get cookware for a specific variant
|
|
3603
|
+
* const veganCookware = recipe.getCookwareForVariant({ choices: { variant: 'vegan' } });
|
|
3604
|
+
* ```
|
|
3605
|
+
*/
|
|
3606
|
+
getCookwareForVariant(options) {
|
|
3607
|
+
const { choices } = options || {};
|
|
3608
|
+
const activeVariant = choices?.variant;
|
|
3609
|
+
const isDefaultVariant = activeVariant === void 0 || activeVariant === "*";
|
|
3610
|
+
const cookwareIndices = /* @__PURE__ */ new Set();
|
|
3611
|
+
for (const currentSection of this.sections) {
|
|
3612
|
+
if (currentSection.variants) {
|
|
3613
|
+
if (isDefaultVariant) {
|
|
3614
|
+
if (!currentSection.variants.includes("*")) continue;
|
|
3615
|
+
} else {
|
|
3616
|
+
if (!currentSection.variants.includes(activeVariant)) continue;
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
const allSteps = currentSection.content.filter(
|
|
3620
|
+
(item) => item.type === "step"
|
|
3621
|
+
);
|
|
3622
|
+
for (const currentStep of allSteps) {
|
|
3623
|
+
if (currentStep.variants) {
|
|
3624
|
+
if (isDefaultVariant) {
|
|
3625
|
+
if (!currentStep.variants.includes("*")) continue;
|
|
3626
|
+
} else {
|
|
3627
|
+
if (!currentStep.variants.includes(activeVariant)) continue;
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
for (const item of currentStep.items) {
|
|
3631
|
+
if (item.type === "cookware") {
|
|
3632
|
+
cookwareIndices.add(item.index);
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
return this.cookware.filter(
|
|
3638
|
+
(cw, idx) => cookwareIndices.has(idx) && !cw.flags?.includes("hidden")
|
|
3639
|
+
);
|
|
3640
|
+
}
|
|
3441
3641
|
/**
|
|
3442
3642
|
* Parses a recipe from a string.
|
|
3443
3643
|
* @param content - The recipe content to parse.
|
|
@@ -3453,9 +3653,14 @@ var _Recipe = class _Recipe {
|
|
|
3453
3653
|
const items = [];
|
|
3454
3654
|
let noteText = "";
|
|
3455
3655
|
let inNote = false;
|
|
3656
|
+
let stepVariants;
|
|
3657
|
+
let stepOptional;
|
|
3658
|
+
const discoveredVariants = /* @__PURE__ */ new Set();
|
|
3456
3659
|
for (const line of cleanContent) {
|
|
3457
3660
|
if (line.trim().length === 0) {
|
|
3458
|
-
flushPendingItems(section, items);
|
|
3661
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3662
|
+
stepVariants = void 0;
|
|
3663
|
+
stepOptional = void 0;
|
|
3459
3664
|
flushPendingNote(
|
|
3460
3665
|
section,
|
|
3461
3666
|
noteText ? this._parseNoteText(noteText) : []
|
|
@@ -3466,26 +3671,48 @@ var _Recipe = class _Recipe {
|
|
|
3466
3671
|
continue;
|
|
3467
3672
|
}
|
|
3468
3673
|
if (line.startsWith("=")) {
|
|
3469
|
-
flushPendingItems(section, items);
|
|
3674
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3675
|
+
stepVariants = void 0;
|
|
3676
|
+
stepOptional = void 0;
|
|
3470
3677
|
flushPendingNote(
|
|
3471
3678
|
section,
|
|
3472
3679
|
noteText ? this._parseNoteText(noteText) : []
|
|
3473
3680
|
);
|
|
3474
3681
|
noteText = "";
|
|
3682
|
+
let sectionName = line.replace(/^=+|=+$/g, "").trim();
|
|
3683
|
+
let sectionVariants;
|
|
3684
|
+
let sectionOptional;
|
|
3685
|
+
const sectionVarMatch = sectionName.match(variantTagRegex);
|
|
3686
|
+
if (sectionVarMatch?.groups) {
|
|
3687
|
+
const isOptionalPrefix = sectionVarMatch.groups.variantOptionalPrefix === "?";
|
|
3688
|
+
const names = (sectionVarMatch.groups.variantNames ?? "").split(",").map((n2) => n2.trim()).filter((n2) => n2.length > 0);
|
|
3689
|
+
if (names.length > 0) {
|
|
3690
|
+
sectionVariants = names;
|
|
3691
|
+
for (const v of names) discoveredVariants.add(v);
|
|
3692
|
+
}
|
|
3693
|
+
if (isOptionalPrefix) {
|
|
3694
|
+
sectionOptional = true;
|
|
3695
|
+
}
|
|
3696
|
+
sectionName = sectionName.slice(sectionVarMatch[0].length).trim();
|
|
3697
|
+
}
|
|
3475
3698
|
if (this.sections.length === 0 && section.isBlank()) {
|
|
3476
|
-
section.name =
|
|
3699
|
+
section.name = sectionName;
|
|
3700
|
+
if (sectionVariants) section.variants = sectionVariants;
|
|
3701
|
+
if (sectionOptional) section.optional = true;
|
|
3477
3702
|
} else {
|
|
3478
3703
|
if (!section.isBlank()) {
|
|
3479
3704
|
this.sections.push(section);
|
|
3480
3705
|
}
|
|
3481
|
-
section = new Section(
|
|
3706
|
+
section = new Section(sectionName, sectionVariants, sectionOptional);
|
|
3482
3707
|
}
|
|
3483
3708
|
blankLineBefore = true;
|
|
3484
3709
|
inNote = false;
|
|
3485
3710
|
continue;
|
|
3486
3711
|
}
|
|
3487
3712
|
if (blankLineBefore && line.startsWith(">")) {
|
|
3488
|
-
flushPendingItems(section, items);
|
|
3713
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3714
|
+
stepVariants = void 0;
|
|
3715
|
+
stepOptional = void 0;
|
|
3489
3716
|
noteText = line.substring(1).trim();
|
|
3490
3717
|
inNote = true;
|
|
3491
3718
|
blankLineBefore = false;
|
|
@@ -3500,11 +3727,31 @@ var _Recipe = class _Recipe {
|
|
|
3500
3727
|
blankLineBefore = false;
|
|
3501
3728
|
continue;
|
|
3502
3729
|
}
|
|
3730
|
+
let currentLine = line;
|
|
3731
|
+
if (items.length === 0) {
|
|
3732
|
+
const varMatch = currentLine.match(variantTagRegex);
|
|
3733
|
+
if (varMatch?.groups) {
|
|
3734
|
+
const isOptionalPrefix = varMatch.groups.variantOptionalPrefix === "?";
|
|
3735
|
+
const names = (varMatch.groups.variantNames ?? "").split(",").map((n2) => n2.trim()).filter((n2) => n2.length > 0);
|
|
3736
|
+
if (names.length > 0) {
|
|
3737
|
+
stepVariants = names;
|
|
3738
|
+
for (const v of names) discoveredVariants.add(v);
|
|
3739
|
+
}
|
|
3740
|
+
if (isOptionalPrefix) {
|
|
3741
|
+
stepOptional = true;
|
|
3742
|
+
}
|
|
3743
|
+
currentLine = currentLine.slice(varMatch[0].length);
|
|
3744
|
+
if (currentLine.trim().length === 0) {
|
|
3745
|
+
blankLineBefore = false;
|
|
3746
|
+
continue;
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3503
3750
|
let cursor = 0;
|
|
3504
|
-
for (const match of
|
|
3751
|
+
for (const match of currentLine.matchAll(tokensRegex)) {
|
|
3505
3752
|
const idx = match.index;
|
|
3506
3753
|
if (idx > cursor) {
|
|
3507
|
-
items.push(...parseMarkdownSegments(
|
|
3754
|
+
items.push(...parseMarkdownSegments(currentLine.slice(cursor, idx)));
|
|
3508
3755
|
}
|
|
3509
3756
|
const groups = match.groups;
|
|
3510
3757
|
if (groups.mIngredientName || groups.sIngredientName) {
|
|
@@ -3565,16 +3812,21 @@ var _Recipe = class _Recipe {
|
|
|
3565
3812
|
}
|
|
3566
3813
|
cursor = idx + match[0].length;
|
|
3567
3814
|
}
|
|
3568
|
-
if (cursor <
|
|
3569
|
-
items.push(...parseMarkdownSegments(
|
|
3815
|
+
if (cursor < currentLine.length) {
|
|
3816
|
+
items.push(...parseMarkdownSegments(currentLine.slice(cursor)));
|
|
3570
3817
|
}
|
|
3571
3818
|
blankLineBefore = false;
|
|
3572
3819
|
}
|
|
3573
|
-
flushPendingItems(section, items);
|
|
3820
|
+
flushPendingItems(section, items, stepVariants, stepOptional);
|
|
3574
3821
|
flushPendingNote(section, noteText ? this._parseNoteText(noteText) : []);
|
|
3575
3822
|
if (!section.isBlank()) {
|
|
3576
3823
|
this.sections.push(section);
|
|
3577
3824
|
}
|
|
3825
|
+
const metaVariants = this.metadata.variants ?? [];
|
|
3826
|
+
const allVariants = /* @__PURE__ */ new Set([...metaVariants, ...discoveredVariants]);
|
|
3827
|
+
if (allVariants.size > 0) {
|
|
3828
|
+
this.choices.variants = [...allVariants];
|
|
3829
|
+
}
|
|
3578
3830
|
this._populateIngredientQuantities();
|
|
3579
3831
|
}
|
|
3580
3832
|
/**
|
|
@@ -3661,8 +3913,10 @@ var _Recipe = class _Recipe {
|
|
|
3661
3913
|
}
|
|
3662
3914
|
}
|
|
3663
3915
|
}
|
|
3664
|
-
for (const
|
|
3665
|
-
|
|
3916
|
+
for (const subgroups of newRecipe.choices.ingredientGroups.values()) {
|
|
3917
|
+
for (const subgroup of subgroups) {
|
|
3918
|
+
scaleAlternativesBy(subgroup, factor);
|
|
3919
|
+
}
|
|
3666
3920
|
}
|
|
3667
3921
|
for (const alternatives of newRecipe.choices.ingredientItems.values()) {
|
|
3668
3922
|
scaleAlternativesBy(alternatives, factor);
|
|
@@ -3849,8 +4103,10 @@ var _Recipe = class _Recipe {
|
|
|
3849
4103
|
}
|
|
3850
4104
|
}
|
|
3851
4105
|
}
|
|
3852
|
-
for (const
|
|
3853
|
-
|
|
4106
|
+
for (const subgroups of newRecipe.choices.ingredientGroups.values()) {
|
|
4107
|
+
for (const subgroup of subgroups) {
|
|
4108
|
+
convertAlternatives(subgroup);
|
|
4109
|
+
}
|
|
3854
4110
|
}
|
|
3855
4111
|
for (const alternatives of newRecipe.choices.ingredientItems.values()) {
|
|
3856
4112
|
convertAlternatives(alternatives);
|
|
@@ -3881,7 +4137,11 @@ var _Recipe = class _Recipe {
|
|
|
3881
4137
|
newRecipe.metadata = deepClone(this.metadata);
|
|
3882
4138
|
newRecipe.ingredients = deepClone(this.ingredients);
|
|
3883
4139
|
newRecipe.sections = this.sections.map((section) => {
|
|
3884
|
-
const newSection = new Section(
|
|
4140
|
+
const newSection = new Section(
|
|
4141
|
+
section.name,
|
|
4142
|
+
section.variants,
|
|
4143
|
+
section.optional
|
|
4144
|
+
);
|
|
3885
4145
|
newSection.content = deepClone(section.content);
|
|
3886
4146
|
return newSection;
|
|
3887
4147
|
});
|
|
@@ -3902,6 +4162,11 @@ __publicField(_Recipe, "unitSystems", /* @__PURE__ */ new WeakMap());
|
|
|
3902
4162
|
* Used for giving ID numbers to items during parsing.
|
|
3903
4163
|
*/
|
|
3904
4164
|
__publicField(_Recipe, "itemCounts", /* @__PURE__ */ new WeakMap());
|
|
4165
|
+
/**
|
|
4166
|
+
* External storage for subgroup index tracking during parsing.
|
|
4167
|
+
* Maps groupKey → subgroupKey → index within the subgroups array.
|
|
4168
|
+
*/
|
|
4169
|
+
__publicField(_Recipe, "subgroupIndices", /* @__PURE__ */ new WeakMap());
|
|
3905
4170
|
var Recipe = _Recipe;
|
|
3906
4171
|
|
|
3907
4172
|
// src/classes/shopping_list.ts
|
|
@@ -4739,23 +5004,63 @@ function isGroupedItem(item) {
|
|
|
4739
5004
|
function isAlternativeSelected(recipe, choices, item, alternativeIndex) {
|
|
4740
5005
|
if (item.group) {
|
|
4741
5006
|
const selectedIndex2 = choices?.ingredientGroups?.get(item.group);
|
|
4742
|
-
const
|
|
4743
|
-
if (
|
|
4744
|
-
const
|
|
4745
|
-
return
|
|
5007
|
+
const groupSubgroups = recipe.choices.ingredientGroups.get(item.group);
|
|
5008
|
+
if (groupSubgroups && selectedIndex2 !== void 0 && selectedIndex2 < groupSubgroups.length) {
|
|
5009
|
+
const selectedSubgroup = groupSubgroups[selectedIndex2];
|
|
5010
|
+
return selectedSubgroup?.some((alt) => alt.itemId === item.id);
|
|
4746
5011
|
}
|
|
4747
5012
|
return false;
|
|
4748
5013
|
}
|
|
4749
5014
|
const selectedIndex = choices?.ingredientItems?.get(item.id);
|
|
4750
5015
|
return alternativeIndex === selectedIndex;
|
|
4751
5016
|
}
|
|
5017
|
+
function isSectionActive(section, variant) {
|
|
5018
|
+
if (!section.variants) return true;
|
|
5019
|
+
const isDefault = variant === void 0 || variant === "*";
|
|
5020
|
+
if (isDefault) {
|
|
5021
|
+
return section.variants.includes("*");
|
|
5022
|
+
}
|
|
5023
|
+
return section.variants.includes(variant);
|
|
5024
|
+
}
|
|
5025
|
+
function isStepActive(step, variant) {
|
|
5026
|
+
if (!step.variants) return true;
|
|
5027
|
+
const isDefault = variant === void 0 || variant === "*";
|
|
5028
|
+
if (isDefault) {
|
|
5029
|
+
return step.variants.includes("*");
|
|
5030
|
+
}
|
|
5031
|
+
return step.variants.includes(variant);
|
|
5032
|
+
}
|
|
5033
|
+
function getEffectiveChoices(recipe, variant) {
|
|
5034
|
+
const choices = { variant };
|
|
5035
|
+
if (variant === void 0 || variant === "*") return choices;
|
|
5036
|
+
const variantLower = variant.toLowerCase();
|
|
5037
|
+
for (const [itemId, alternatives] of recipe.choices.ingredientItems) {
|
|
5038
|
+
const matchIdx = alternatives.findIndex(
|
|
5039
|
+
(alt) => alt.note && alt.note.toLowerCase().includes(variantLower)
|
|
5040
|
+
);
|
|
5041
|
+
if (matchIdx >= 0) {
|
|
5042
|
+
if (!choices.ingredientItems) choices.ingredientItems = /* @__PURE__ */ new Map();
|
|
5043
|
+
choices.ingredientItems.set(itemId, matchIdx);
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
for (const [groupId, subgroups] of recipe.choices.ingredientGroups) {
|
|
5047
|
+
const matchIdx = subgroups.findIndex(
|
|
5048
|
+
(sg) => sg.some(
|
|
5049
|
+
(alt) => alt.note && alt.note.toLowerCase().includes(variantLower)
|
|
5050
|
+
)
|
|
5051
|
+
);
|
|
5052
|
+
if (matchIdx >= 0) {
|
|
5053
|
+
if (!choices.ingredientGroups) choices.ingredientGroups = /* @__PURE__ */ new Map();
|
|
5054
|
+
choices.ingredientGroups.set(groupId, matchIdx);
|
|
5055
|
+
}
|
|
5056
|
+
}
|
|
5057
|
+
return choices;
|
|
5058
|
+
}
|
|
4752
5059
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4753
5060
|
0 && (module.exports = {
|
|
4754
|
-
BadIndentationError,
|
|
4755
5061
|
CategoryConfig,
|
|
4756
5062
|
NoProductCatalogForCartError,
|
|
4757
5063
|
NoShoppingListForCartError,
|
|
4758
|
-
NoTabAsIndentError,
|
|
4759
5064
|
Pantry,
|
|
4760
5065
|
ProductCatalog,
|
|
4761
5066
|
Recipe,
|
|
@@ -4770,11 +5075,14 @@ function isAlternativeSelected(recipe, choices, item, alternativeIndex) {
|
|
|
4770
5075
|
formatQuantityWithUnit,
|
|
4771
5076
|
formatSingleValue,
|
|
4772
5077
|
formatUnit,
|
|
5078
|
+
getEffectiveChoices,
|
|
4773
5079
|
hasAlternatives,
|
|
4774
5080
|
isAlternativeSelected,
|
|
4775
5081
|
isAndGroup,
|
|
4776
5082
|
isGroupedItem,
|
|
5083
|
+
isSectionActive,
|
|
4777
5084
|
isSimpleGroup,
|
|
5085
|
+
isStepActive,
|
|
4778
5086
|
renderFractionAsVulgar
|
|
4779
5087
|
});
|
|
4780
5088
|
/* v8 ignore else -- @preserve */
|