54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import type { NutritionValues, Unit } from "@app/shared-types";
|
||
import { computeItemNutrition, roundNutrition, scaleNutrition, sumNutrition } from "./calc.js";
|
||
import type { IngredientUnitInfo } from "./units.js";
|
||
import type { NutritionDeclaration } from "@app/shared-types";
|
||
|
||
export interface RecipeIngredientForCalc {
|
||
canonicalIngredientId: string;
|
||
quantity: number;
|
||
unit: Unit;
|
||
optional?: boolean;
|
||
}
|
||
|
||
export interface IngredientNutritionSource extends IngredientUnitInfo {
|
||
nutritionPer100: NutritionDeclaration;
|
||
}
|
||
|
||
export interface RecipeNutritionResult {
|
||
perPortion: NutritionValues;
|
||
total: NutritionValues;
|
||
/** Ingredienser som inte kunde beräknas (saknad densitet etc.) – redovisas öppet. */
|
||
uncomputableIngredientIds: string[];
|
||
}
|
||
|
||
/**
|
||
* Beräkna ett recepts näringsvärden ur dess ingredienser – deterministiskt.
|
||
* Valfria ingredienser exkluderas ur grundberäkningen.
|
||
*/
|
||
export function computeRecipeNutrition(
|
||
ingredients: RecipeIngredientForCalc[],
|
||
portions: number,
|
||
sources: Map<string, IngredientNutritionSource>,
|
||
): RecipeNutritionResult {
|
||
const parts: NutritionValues[] = [];
|
||
const uncomputable: string[] = [];
|
||
for (const ing of ingredients) {
|
||
if (ing.optional) continue;
|
||
const source = sources.get(ing.canonicalIngredientId);
|
||
if (!source) {
|
||
uncomputable.push(ing.canonicalIngredientId);
|
||
continue;
|
||
}
|
||
const values = computeItemNutrition(ing.quantity, ing.unit, source.nutritionPer100, source);
|
||
if (values == null) {
|
||
uncomputable.push(ing.canonicalIngredientId);
|
||
continue;
|
||
}
|
||
parts.push(values);
|
||
}
|
||
const total = sumNutrition(parts);
|
||
const perPortion =
|
||
portions > 0 ? roundNutrition(scaleNutrition(total, 1 / portions)) : roundNutrition(total);
|
||
return { perPortion, total: roundNutrition(total), uncomputableIngredientIds: uncomputable };
|
||
}
|