Skip to content

Commit 317d2f0

Browse files
committed
fix(recipe): correctly filter cross-variant subgroup alternatives by variant
1 parent 9ac33ea commit 317d2f0

2 files changed

Lines changed: 73 additions & 5 deletions

File tree

src/classes/recipe.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,16 +241,20 @@ export class Recipe {
241241

242242
/**
243243
* Filters grouped choice subgroups based on active variant linkage.
244+
* Within each subgroup, only alternatives linked to the given variant are
245+
* kept. Subgroups that become empty after filtering are removed.
244246
*/
245247
private filterGroupSubgroupsForVariant(
246248
subgroups: IngredientAlternative[][],
247249
variant?: string,
248250
): IngredientAlternative[][] {
249-
return subgroups.filter((subgroup) =>
250-
subgroup.every((alternative) =>
251-
this.isAlternativeLinkedToVariant(alternative, variant),
252-
),
253-
);
251+
return subgroups
252+
.map((subgroup) =>
253+
subgroup.filter((alternative) =>
254+
this.isAlternativeLinkedToVariant(alternative, variant),
255+
),
256+
)
257+
.filter((subgroup) => subgroup.length > 0);
254258
}
255259

256260
/**

test/recipe_choices.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,5 +533,69 @@ Add @potato{1%=large|1.5%cup}|carrot{1%large} and @&potato{1%=small|0.5%cup}|&ca
533533
expect(syrup?.usedAsPrimary).toBeUndefined();
534534
expect(syrup?.quantities).toBeUndefined();
535535
});
536+
537+
it("correctly filters subgroup alternatives when multiple variants share the same subgroup key", () => {
538+
const recipe = new Recipe(`
539+
[*] Add @|sour/1|simple syrup{15%ml}, @|sour/1|lemon juice{30%ml}, @gin{45%ml} and stir. You can replace the simple syrup and lemon juice by @|sour|sour mix{30%ml}
540+
541+
[Tom Collins] Add @|sour/1|simple syrup{15%ml}, @|sour/1|lemon juice{30%ml}, @Old Tom Gin{45%ml} and stir. You can replace the simple syrup and lemon juice by @|sour|sour mix{30%ml}
542+
`);
543+
544+
// --- default variant ---
545+
const defaultChoices = recipe.getChoicesForVariant("*");
546+
const defaultSourSubgroups = defaultChoices.ingredientGroups.get("sour");
547+
// Expect two sub-choices: [simple syrup + lemon juice] OR [sour mix]
548+
expect(defaultSourSubgroups).toHaveLength(2);
549+
expect(defaultSourSubgroups![0]!.map((a) => a.displayName)).toEqual([
550+
"simple syrup",
551+
"lemon juice",
552+
]);
553+
expect(defaultSourSubgroups![1]!.map((a) => a.displayName)).toEqual([
554+
"sour mix",
555+
]);
556+
557+
// Default variant should select the first subgroup (simple syrup + lemon juice)
558+
const defaultIngredients = recipe.getIngredientQuantities({
559+
choices: { variant: "*" },
560+
});
561+
const simpleSyrupDefault = defaultIngredients.find(
562+
(ing) => ing.name === "simple syrup",
563+
);
564+
expect(simpleSyrupDefault?.usedAsPrimary).toBe(true);
565+
expect(simpleSyrupDefault?.quantities).toBeDefined();
566+
567+
const sourMixDefault = defaultIngredients.find(
568+
(ing) => ing.name === "sour mix",
569+
);
570+
expect(sourMixDefault?.usedAsPrimary).toBeUndefined();
571+
expect(sourMixDefault?.quantities).toBeUndefined();
572+
573+
// --- Tom Collins variant ---
574+
const tcChoices = recipe.getChoicesForVariant("Tom Collins");
575+
const tcSourSubgroups = tcChoices.ingredientGroups.get("sour");
576+
// Expect two sub-choices: [simple syrup + lemon juice] OR [sour mix]
577+
expect(tcSourSubgroups).toHaveLength(2);
578+
expect(tcSourSubgroups![0]!.map((a) => a.displayName)).toEqual([
579+
"simple syrup",
580+
"lemon juice",
581+
]);
582+
expect(tcSourSubgroups![1]!.map((a) => a.displayName)).toEqual([
583+
"sour mix",
584+
]);
585+
586+
// Tom Collins variant should also select the first subgroup by default
587+
const tcIngredients = recipe.getIngredientQuantities({
588+
choices: { variant: "Tom Collins" },
589+
});
590+
const simpleSyrupTC = tcIngredients.find(
591+
(ing) => ing.name === "simple syrup",
592+
);
593+
expect(simpleSyrupTC?.usedAsPrimary).toBe(true);
594+
expect(simpleSyrupTC?.quantities).toBeDefined();
595+
596+
const sourMixTC = tcIngredients.find((ing) => ing.name === "sour mix");
597+
expect(sourMixTC?.usedAsPrimary).toBeUndefined();
598+
expect(sourMixTC?.quantities).toBeUndefined();
599+
});
536600
});
537601
});

0 commit comments

Comments
 (0)