healthy-meals-core 0.0.2

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.
Files changed (83) hide show
  1. package/dist/bmr.d.ts +3 -0
  2. package/dist/bmr.js +14 -0
  3. package/dist/dailyMealPlanGenerator.d.ts +3 -0
  4. package/dist/dailyMealPlanGenerator.js +211 -0
  5. package/dist/data/detailed-recipes-bs.json +417 -0
  6. package/dist/data/detailed-recipes.json +744 -0
  7. package/dist/foodConversion.d.ts +55 -0
  8. package/dist/foodConversion.js +200 -0
  9. package/dist/index.d.ts +12 -0
  10. package/dist/index.js +27 -0
  11. package/dist/planner.d.ts +2 -0
  12. package/dist/planner.js +24 -0
  13. package/dist/recipeBasedMealPlanGenerator.d.ts +17 -0
  14. package/dist/recipeBasedMealPlanGenerator.js +255 -0
  15. package/dist/recipeService.d.ts +28 -0
  16. package/dist/recipeService.js +136 -0
  17. package/dist/rules/cholesterol.d.ts +2 -0
  18. package/dist/rules/cholesterol.js +7 -0
  19. package/dist/rules/diabetes.d.ts +2 -0
  20. package/dist/rules/diabetes.js +7 -0
  21. package/dist/rules/fattyLiver.d.ts +2 -0
  22. package/dist/rules/fattyLiver.js +7 -0
  23. package/dist/rules/index.d.ts +7 -0
  24. package/dist/rules/index.js +47 -0
  25. package/dist/rules/lowCarb.d.ts +2 -0
  26. package/dist/rules/lowCarb.js +7 -0
  27. package/dist/rules/triglycerides.d.ts +2 -0
  28. package/dist/rules/triglycerides.js +7 -0
  29. package/dist/src/bmr.d.ts +3 -0
  30. package/dist/src/bmr.js +13 -0
  31. package/dist/src/dailyMealPlanGenerator.d.ts +3 -0
  32. package/dist/src/dailyMealPlanGenerator.js +210 -0
  33. package/dist/src/foodConversion.d.ts +55 -0
  34. package/dist/src/foodConversion.js +199 -0
  35. package/dist/src/index.d.ts +12 -0
  36. package/dist/src/index.js +27 -0
  37. package/dist/src/planner.d.ts +2 -0
  38. package/dist/src/planner.js +23 -0
  39. package/dist/src/recipeBasedMealPlanGenerator.d.ts +17 -0
  40. package/dist/src/recipeBasedMealPlanGenerator.js +254 -0
  41. package/dist/src/recipeService.d.ts +28 -0
  42. package/dist/src/recipeService.js +136 -0
  43. package/dist/src/rules/cholesterol.d.ts +2 -0
  44. package/dist/src/rules/cholesterol.js +6 -0
  45. package/dist/src/rules/diabetes.d.ts +2 -0
  46. package/dist/src/rules/diabetes.js +6 -0
  47. package/dist/src/rules/fattyLiver.d.ts +2 -0
  48. package/dist/src/rules/fattyLiver.js +6 -0
  49. package/dist/src/rules/index.d.ts +7 -0
  50. package/dist/src/rules/index.js +46 -0
  51. package/dist/src/rules/lowCarb.d.ts +2 -0
  52. package/dist/src/rules/lowCarb.js +6 -0
  53. package/dist/src/rules/triglycerides.d.ts +2 -0
  54. package/dist/src/rules/triglycerides.js +6 -0
  55. package/dist/src/types/firestore.d.ts +100 -0
  56. package/dist/src/types/firestore.js +2 -0
  57. package/dist/src/types/openfoodfacts.d.ts +113 -0
  58. package/dist/src/types/openfoodfacts.js +3 -0
  59. package/dist/src/types/recipe.d.ts +36 -0
  60. package/dist/src/types/recipe.js +2 -0
  61. package/dist/src/types.d.ts +24 -0
  62. package/dist/src/types.js +2 -0
  63. package/dist/src/variety.d.ts +17 -0
  64. package/dist/src/variety.js +129 -0
  65. package/dist/src/weeklyMealPlanGenerator.d.ts +3 -0
  66. package/dist/src/weeklyMealPlanGenerator.js +468 -0
  67. package/dist/src/weeklyPlanner.d.ts +12 -0
  68. package/dist/src/weeklyPlanner.js +31 -0
  69. package/dist/types/firestore.d.ts +100 -0
  70. package/dist/types/firestore.js +2 -0
  71. package/dist/types/openfoodfacts.d.ts +113 -0
  72. package/dist/types/openfoodfacts.js +3 -0
  73. package/dist/types/recipe.d.ts +36 -0
  74. package/dist/types/recipe.js +2 -0
  75. package/dist/types.d.ts +24 -0
  76. package/dist/types.js +2 -0
  77. package/dist/variety.d.ts +17 -0
  78. package/dist/variety.js +130 -0
  79. package/dist/weeklyMealPlanGenerator.d.ts +3 -0
  80. package/dist/weeklyMealPlanGenerator.js +469 -0
  81. package/dist/weeklyPlanner.d.ts +12 -0
  82. package/dist/weeklyPlanner.js +32 -0
  83. package/package.json +66 -0
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertFoodItemToIngredient = convertFoodItemToIngredient;
4
+ exports.calculateTotalNutrition = calculateTotalNutrition;
5
+ exports.createMealFromFoodItems = createMealFromFoodItems;
6
+ exports.getNutritionDensityScore = getNutritionDensityScore;
7
+ exports.checkDietaryRestrictions = checkDietaryRestrictions;
8
+ exports.getRecommendedServingSize = getRecommendedServingSize;
9
+ exports.filterFoodsByHealthGoals = filterFoodsByHealthGoals;
10
+ /**
11
+ * Convert Open Food Facts item to Ingredient for meal planning
12
+ */
13
+ function convertFoodItemToIngredient(foodItem, amount = 100, unit = 'g') {
14
+ // Calculate nutrition values based on amount (default is per 100g)
15
+ const multiplier = amount / 100;
16
+ return {
17
+ id: `${foodItem.name.toLowerCase().replace(/\s+/g, '-')}-${Date.now()}`,
18
+ name: foodItem.name,
19
+ quantity: amount,
20
+ unit,
21
+ calories: Math.round((foodItem.nutritionPer100g?.calories || 0) * multiplier) || 0,
22
+ protein: Math.round(((foodItem.nutritionPer100g?.protein || 0) * multiplier * 10)) / 10 || 0,
23
+ carbs: Math.round(((foodItem.nutritionPer100g?.carbs || 0) * multiplier * 10)) / 10 || 0,
24
+ fat: Math.round(((foodItem.nutritionPer100g?.fat || 0) * multiplier * 10)) / 10 || 0,
25
+ fiber: Math.round(((foodItem.nutritionPer100g?.fiber || 0) * multiplier * 10)) / 10 || 0,
26
+ sugar: Math.round(((foodItem.nutritionPer100g?.sugar || 0) * multiplier * 10)) / 10 || 0,
27
+ sodium: Math.round(((foodItem.nutritionPer100g?.sodium || 0) * multiplier * 10)) / 10 || 0,
28
+ };
29
+ }
30
+ /**
31
+ * Calculate total nutrition for a list of ingredients
32
+ */
33
+ function calculateTotalNutrition(ingredients) {
34
+ return ingredients.reduce((total, ingredient) => ({
35
+ calories: total.calories + (ingredient.calories || 0),
36
+ protein: Math.round((total.protein + (ingredient.protein || 0)) * 10) / 10,
37
+ carbs: Math.round((total.carbs + (ingredient.carbs || 0)) * 10) / 10,
38
+ fat: Math.round((total.fat + (ingredient.fat || 0)) * 10) / 10,
39
+ fiber: Math.round((total.fiber + (ingredient.fiber || 0)) * 10) / 10,
40
+ sugar: Math.round((total.sugar + (ingredient.sugar || 0)) * 10) / 10,
41
+ sodium: Math.round((total.sodium + (ingredient.sodium || 0)) * 10) / 10,
42
+ }), { calories: 0, protein: 0, carbs: 0, fat: 0, fiber: 0, sugar: 0, sodium: 0 });
43
+ }
44
+ /**
45
+ * Create a meal from selected food items
46
+ */
47
+ function createMealFromFoodItems(name, type, foodItems) {
48
+ const ingredients = foodItems.map(({ food, amount, unit }) => convertFoodItemToIngredient(food, amount, unit));
49
+ const nutrition = calculateTotalNutrition(ingredients);
50
+ return {
51
+ id: `${type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
52
+ name,
53
+ type,
54
+ ingredients,
55
+ nutrition: {
56
+ calories: nutrition.calories,
57
+ protein: nutrition.protein,
58
+ carbs: nutrition.carbs,
59
+ fat: nutrition.fat,
60
+ fiber: nutrition.fiber,
61
+ sugar: nutrition.sugar,
62
+ sodium: nutrition.sodium,
63
+ },
64
+ instructions: [],
65
+ prepTime: 15,
66
+ cookTime: 20,
67
+ servings: 1,
68
+ tags: [type],
69
+ difficulty: 'easy',
70
+ createdAt: new Date(),
71
+ updatedAt: new Date(),
72
+ };
73
+ }
74
+ /**
75
+ * Get nutrition density score (protein per calorie ratio)
76
+ */
77
+ function getNutritionDensityScore(foodItem) {
78
+ if (foodItem.nutritionPer100g.calories === 0)
79
+ return 0;
80
+ return foodItem.nutritionPer100g.protein / foodItem.nutritionPer100g.calories;
81
+ }
82
+ /**
83
+ * Check if food item meets dietary restrictions
84
+ */
85
+ function checkDietaryRestrictions(foodItem, restrictions) {
86
+ const violations = [];
87
+ // Check categories for dietary restrictions
88
+ const categories = foodItem.categories?.map(c => c.toLowerCase()) || [];
89
+ const ingredients = foodItem.ingredients?.toLowerCase() || '';
90
+ const allergens = foodItem.allergens?.map(a => a.toLowerCase()) || [];
91
+ restrictions.forEach(restriction => {
92
+ const restrictionLower = restriction.toLowerCase();
93
+ switch (restrictionLower) {
94
+ case 'vegetarian':
95
+ if (categories.some((cat) => cat.includes('meat') || cat.includes('fish') || cat.includes('poultry'))) {
96
+ violations.push('Contains meat/fish');
97
+ }
98
+ break;
99
+ case 'vegan':
100
+ if (categories.some((cat) => cat.includes('meat') || cat.includes('fish') || cat.includes('dairy') ||
101
+ cat.includes('eggs') || cat.includes('honey')) || ingredients.includes('milk') || ingredients.includes('egg')) {
102
+ violations.push('Contains animal products');
103
+ }
104
+ break;
105
+ case 'gluten-free':
106
+ if (allergens.includes('gluten') || ingredients.includes('wheat') ||
107
+ ingredients.includes('barley') || ingredients.includes('rye')) {
108
+ violations.push('Contains gluten');
109
+ }
110
+ break;
111
+ case 'dairy-free':
112
+ if (allergens.includes('milk') || categories.some((cat) => cat.includes('dairy')) ||
113
+ ingredients.includes('milk') || ingredients.includes('lactose')) {
114
+ violations.push('Contains dairy');
115
+ }
116
+ break;
117
+ case 'nut-free':
118
+ if (allergens.some((a) => a.includes('nut')) || ingredients.includes('nuts')) {
119
+ violations.push('Contains nuts');
120
+ }
121
+ break;
122
+ }
123
+ });
124
+ return {
125
+ meets: violations.length === 0,
126
+ violations
127
+ };
128
+ }
129
+ /**
130
+ * Get recommended serving size based on meal type and nutrition goals
131
+ */
132
+ function getRecommendedServingSize(foodItem, mealType, targetCalories) {
133
+ // Default serving size from product data
134
+ if (foodItem.servingSize) {
135
+ const match = foodItem.servingSize.match(/(\d+(?:\.\d+)?)\s*(\w+)/);
136
+ if (match) {
137
+ return {
138
+ amount: parseFloat(match[1]),
139
+ unit: match[2]
140
+ };
141
+ }
142
+ }
143
+ // Calculate based on target calories if provided
144
+ if (targetCalories && foodItem.nutritionPer100g.calories > 0) {
145
+ const amount = Math.round((targetCalories / foodItem.nutritionPer100g.calories) * 100);
146
+ return { amount, unit: 'g' };
147
+ }
148
+ // Default serving sizes by meal type
149
+ const defaultServings = {
150
+ breakfast: 150, // g
151
+ lunch: 200, // g
152
+ dinner: 200, // g
153
+ snack: 50 // g
154
+ };
155
+ return {
156
+ amount: defaultServings[mealType],
157
+ unit: 'g'
158
+ };
159
+ }
160
+ /**
161
+ * Filter foods by health goals
162
+ */
163
+ function filterFoodsByHealthGoals(foods, healthGoals) {
164
+ return foods.filter(food => {
165
+ for (const goal of healthGoals) {
166
+ switch (goal.toLowerCase()) {
167
+ case 'weight_loss':
168
+ // Prefer low-calorie, high-protein foods
169
+ if (food.nutritionPer100g.calories > 300 ||
170
+ getNutritionDensityScore(food) < 0.05) {
171
+ return false;
172
+ }
173
+ break;
174
+ case 'muscle_gain':
175
+ // Prefer high-protein foods
176
+ if (food.nutritionPer100g.protein < 10) {
177
+ return false;
178
+ }
179
+ break;
180
+ case 'heart_health':
181
+ // Prefer foods with good nutrition grades and low sodium
182
+ if (food.nutritionGrade && !['a', 'b'].includes(food.nutritionGrade.toLowerCase())) {
183
+ return false;
184
+ }
185
+ if (food.nutritionPer100g.sodium && food.nutritionPer100g.sodium > 600) {
186
+ return false;
187
+ }
188
+ break;
189
+ case 'diabetes_management':
190
+ // Prefer low-sugar, high-fiber foods
191
+ if (food.nutritionPer100g.sugar && food.nutritionPer100g.sugar > 15) {
192
+ return false;
193
+ }
194
+ break;
195
+ }
196
+ }
197
+ return true;
198
+ });
199
+ }
@@ -0,0 +1,12 @@
1
+ export { UserProfile, HealthCondition, Gender } from './types';
2
+ export * from './bmr';
3
+ export * from './planner';
4
+ export * from './rules';
5
+ export * from './weeklyPlanner';
6
+ export * from './variety';
7
+ export * from './dailyMealPlanGenerator';
8
+ export * from './weeklyMealPlanGenerator';
9
+ export * from './foodConversion';
10
+ export * from './types/recipe';
11
+ export * from './recipeService';
12
+ export * from './recipeBasedMealPlanGenerator';
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./bmr"), exports);
18
+ __exportStar(require("./planner"), exports);
19
+ __exportStar(require("./rules"), exports);
20
+ __exportStar(require("./weeklyPlanner"), exports);
21
+ __exportStar(require("./variety"), exports);
22
+ __exportStar(require("./dailyMealPlanGenerator"), exports);
23
+ __exportStar(require("./weeklyMealPlanGenerator"), exports);
24
+ __exportStar(require("./foodConversion"), exports);
25
+ __exportStar(require("./types/recipe"), exports);
26
+ __exportStar(require("./recipeService"), exports);
27
+ __exportStar(require("./recipeBasedMealPlanGenerator"), exports);
@@ -0,0 +1,2 @@
1
+ import { Recipe, MealPlan, UserProfile } from './types';
2
+ export declare function generateDailyPlan(profile: UserProfile, recipes: Recipe[]): MealPlan;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateDailyPlan = generateDailyPlan;
4
+ const bmr_1 = require("./bmr");
5
+ const rules_1 = require("./rules");
6
+ function generateDailyPlan(profile, recipes) {
7
+ const targetCalories = Math.round((0, bmr_1.calculateTDEE)(profile));
8
+ const filtered = (0, rules_1.applyHealthRules)(recipes, profile.conditions);
9
+ let total = 0;
10
+ const meals = [];
11
+ for (const recipe of filtered) {
12
+ if (total + recipe.calories <= targetCalories) {
13
+ meals.push(recipe);
14
+ total += recipe.calories;
15
+ }
16
+ if (total >= targetCalories * 0.95)
17
+ break;
18
+ }
19
+ return {
20
+ dailyCalories: total,
21
+ meals
22
+ };
23
+ }
@@ -0,0 +1,17 @@
1
+ import { UserProfile, MealPlan, Meal } from './types/firestore';
2
+ import { Recipe } from './types/recipe';
3
+ /**
4
+ * Generate a daily meal plan using recipes from the recipe database
5
+ * Each meal will have complete ingredients and cooking instructions
6
+ */
7
+ export declare function generateDailyMealPlanWithRecipes(profile: UserProfile, userId: string): MealPlan;
8
+ /**
9
+ * Generate a weekly meal plan using recipes from the recipe database
10
+ * Each day will have 4 meals with complete ingredients and cooking instructions
11
+ */
12
+ export declare function generateWeeklyMealPlanWithRecipes(profile: UserProfile, userId: string): MealPlan;
13
+ /**
14
+ * Get recipe details for a meal in a meal plan
15
+ * This allows you to retrieve the full recipe with instructions for any meal
16
+ */
17
+ export declare function getRecipeForMeal(meal: Meal): Recipe | undefined;
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateDailyMealPlanWithRecipes = generateDailyMealPlanWithRecipes;
4
+ exports.generateWeeklyMealPlanWithRecipes = generateWeeklyMealPlanWithRecipes;
5
+ exports.getRecipeForMeal = getRecipeForMeal;
6
+ const recipeService_1 = require("./recipeService");
7
+ function calculateDailyNeeds(profile) {
8
+ const age = profile.age || 30;
9
+ const height = profile.height || 170;
10
+ const weight = profile.weight || 70;
11
+ const gender = profile.gender || 'male';
12
+ const activityLevel = profile.activityLevel || 'moderately_active';
13
+ const bmr = gender === 'male'
14
+ ? 88.362 + (13.397 * weight) + (4.799 * height) - (5.677 * age)
15
+ : 447.593 + (9.247 * weight) + (3.098 * height) - (4.330 * age);
16
+ const activityMultipliers = {
17
+ sedentary: 1.2,
18
+ lightly_active: 1.375,
19
+ moderately_active: 1.55,
20
+ very_active: 1.725,
21
+ extremely_active: 1.9
22
+ };
23
+ const tdee = bmr * (activityMultipliers[activityLevel] || 1.2);
24
+ let dailyCalories = tdee;
25
+ if (profile.healthGoals?.includes('weight_loss')) {
26
+ dailyCalories -= 500;
27
+ }
28
+ else if (profile.healthGoals?.includes('weight_gain')) {
29
+ dailyCalories += 500;
30
+ }
31
+ return {
32
+ calories: Math.round(Math.max(dailyCalories, 1200)),
33
+ protein: Math.round(Math.max(dailyCalories * 0.3 / 4, 50)),
34
+ carbs: Math.round(Math.max(dailyCalories * 0.4 / 4, 100)),
35
+ fat: Math.round(Math.max(dailyCalories * 0.3 / 9, 30))
36
+ };
37
+ }
38
+ function convertRecipeToMeal(recipe) {
39
+ return {
40
+ id: recipe.id,
41
+ name: recipe.name,
42
+ type: recipe.category,
43
+ ingredients: recipe.ingredients.map(ing => ({
44
+ id: `${recipe.id}-${ing.name}`,
45
+ name: ing.name,
46
+ quantity: ing.quantity,
47
+ unit: ing.unit,
48
+ calories: 0,
49
+ protein: 0,
50
+ carbs: 0,
51
+ fat: 0,
52
+ fiber: 0,
53
+ sugar: 0,
54
+ sodium: 0
55
+ })),
56
+ instructions: recipe.instructions,
57
+ prepTime: recipe.prepTime,
58
+ cookTime: recipe.cookTime,
59
+ servings: recipe.servings,
60
+ nutrition: {
61
+ calories: recipe.nutrition.calories,
62
+ protein: recipe.nutrition.protein,
63
+ carbs: recipe.nutrition.carbs,
64
+ fat: recipe.nutrition.fat,
65
+ fiber: recipe.nutrition.fiber,
66
+ sugar: recipe.nutrition.sugar,
67
+ sodium: recipe.nutrition.sodium
68
+ },
69
+ tags: recipe.tags,
70
+ difficulty: recipe.difficulty,
71
+ createdAt: new Date(),
72
+ updatedAt: new Date()
73
+ };
74
+ }
75
+ /**
76
+ * Generate a daily meal plan using recipes from the recipe database
77
+ * Each meal will have complete ingredients and cooking instructions
78
+ */
79
+ function generateDailyMealPlanWithRecipes(profile, userId) {
80
+ const needs = calculateDailyNeeds(profile);
81
+ // Get recipes filtered by user preferences
82
+ let availableRecipes = recipeService_1.recipeService.getAllRecipes();
83
+ // Filter by dietary restrictions
84
+ if (profile.dietaryRestrictions && profile.dietaryRestrictions.length > 0) {
85
+ availableRecipes = recipeService_1.recipeService.getRecipesForDietaryRestrictions(profile.dietaryRestrictions);
86
+ }
87
+ // Filter by health goals
88
+ if (profile.healthGoals && profile.healthGoals.length > 0) {
89
+ const healthRecipes = recipeService_1.recipeService.getRecipesForHealthGoals(profile.healthGoals);
90
+ availableRecipes = availableRecipes.filter(r => healthRecipes.some(hr => hr.id === r.id));
91
+ }
92
+ // Filter by cooking time preference if available
93
+ if (profile.preferences?.cookingTime) {
94
+ availableRecipes = availableRecipes.filter(r => recipeService_1.recipeService.getTotalTime(r) <= profile.preferences.cookingTime);
95
+ }
96
+ // Select one recipe for each meal type
97
+ const breakfastRecipes = availableRecipes.filter(r => r.category === 'breakfast');
98
+ const lunchRecipes = availableRecipes.filter(r => r.category === 'lunch');
99
+ const dinnerRecipes = availableRecipes.filter(r => r.category === 'dinner');
100
+ const snackRecipes = availableRecipes.filter(r => r.category === 'snack');
101
+ // Pick random recipes or first available
102
+ const selectedRecipes = {
103
+ breakfast: breakfastRecipes.length > 0
104
+ ? breakfastRecipes[Math.floor(Math.random() * breakfastRecipes.length)]
105
+ : recipeService_1.recipeService.getRecipeById('breakfast-1'),
106
+ lunch: lunchRecipes.length > 0
107
+ ? lunchRecipes[Math.floor(Math.random() * lunchRecipes.length)]
108
+ : recipeService_1.recipeService.getRecipeById('lunch-1'),
109
+ dinner: dinnerRecipes.length > 0
110
+ ? dinnerRecipes[Math.floor(Math.random() * dinnerRecipes.length)]
111
+ : recipeService_1.recipeService.getRecipeById('dinner-1'),
112
+ snack: snackRecipes.length > 0
113
+ ? snackRecipes[Math.floor(Math.random() * snackRecipes.length)]
114
+ : recipeService_1.recipeService.getRecipeById('snack-1')
115
+ };
116
+ // Convert recipes to meals
117
+ const meals = [
118
+ convertRecipeToMeal(selectedRecipes.breakfast),
119
+ convertRecipeToMeal(selectedRecipes.lunch),
120
+ convertRecipeToMeal(selectedRecipes.dinner),
121
+ convertRecipeToMeal(selectedRecipes.snack)
122
+ ];
123
+ // Calculate total nutrition
124
+ const totalNutrition = meals.reduce((total, meal) => ({
125
+ calories: total.calories + (meal.nutrition?.calories || 0),
126
+ protein: Math.round((total.protein + (meal.nutrition?.protein || 0)) * 10) / 10,
127
+ carbs: Math.round((total.carbs + (meal.nutrition?.carbs || 0)) * 10) / 10,
128
+ fat: Math.round((total.fat + (meal.nutrition?.fat || 0)) * 10) / 10
129
+ }), { calories: 0, protein: 0, carbs: 0, fat: 0 });
130
+ const today = new Date();
131
+ return {
132
+ id: `daily-recipe-plan-${Date.now()}`,
133
+ userId: userId,
134
+ name: `Daily Meal Plan - ${today.toLocaleDateString()}`,
135
+ description: `Personalized daily meal plan with complete recipes (${Math.round(totalNutrition.calories)} cal)`,
136
+ startDate: today.toISOString().split('T')[0],
137
+ endDate: today.toISOString().split('T')[0],
138
+ dailyPlans: [],
139
+ meals,
140
+ totalCalories: totalNutrition.calories,
141
+ totalProtein: totalNutrition.protein,
142
+ totalCarbs: totalNutrition.carbs,
143
+ totalFat: totalNutrition.fat,
144
+ uid: userId,
145
+ goals: {
146
+ dailyCalories: needs.calories,
147
+ proteinPercentage: 25,
148
+ carbsPercentage: 45,
149
+ fatPercentage: 30,
150
+ },
151
+ createdAt: new Date(),
152
+ updatedAt: new Date()
153
+ };
154
+ }
155
+ /**
156
+ * Generate a weekly meal plan using recipes from the recipe database
157
+ * Each day will have 4 meals with complete ingredients and cooking instructions
158
+ */
159
+ function generateWeeklyMealPlanWithRecipes(profile, userId) {
160
+ const needs = calculateDailyNeeds(profile);
161
+ // Get recipes filtered by user preferences
162
+ let availableRecipes = recipeService_1.recipeService.getAllRecipes();
163
+ // Filter by dietary restrictions
164
+ if (profile.dietaryRestrictions && profile.dietaryRestrictions.length > 0) {
165
+ availableRecipes = recipeService_1.recipeService.getRecipesForDietaryRestrictions(profile.dietaryRestrictions);
166
+ }
167
+ // Filter by health goals
168
+ if (profile.healthGoals && profile.healthGoals.length > 0) {
169
+ const healthRecipes = recipeService_1.recipeService.getRecipesForHealthGoals(profile.healthGoals);
170
+ availableRecipes = availableRecipes.filter(r => healthRecipes.some(hr => hr.id === r.id));
171
+ }
172
+ // Filter by cooking time preference
173
+ if (profile.preferences?.cookingTime) {
174
+ availableRecipes = availableRecipes.filter(r => recipeService_1.recipeService.getTotalTime(r) <= profile.preferences.cookingTime);
175
+ }
176
+ // Separate by category
177
+ const breakfastRecipes = availableRecipes.filter(r => r.category === 'breakfast');
178
+ const lunchRecipes = availableRecipes.filter(r => r.category === 'lunch');
179
+ const dinnerRecipes = availableRecipes.filter(r => r.category === 'dinner');
180
+ const snackRecipes = availableRecipes.filter(r => r.category === 'snack');
181
+ const allMeals = [];
182
+ const daysOfWeek = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
183
+ // Generate meals for each day
184
+ daysOfWeek.forEach((day, dayIndex) => {
185
+ // Select different recipes for variety (cycle through available recipes)
186
+ const breakfast = breakfastRecipes.length > 0
187
+ ? breakfastRecipes[dayIndex % breakfastRecipes.length]
188
+ : recipeService_1.recipeService.getRecipeById('breakfast-1');
189
+ const lunch = lunchRecipes.length > 0
190
+ ? lunchRecipes[dayIndex % lunchRecipes.length]
191
+ : recipeService_1.recipeService.getRecipeById('lunch-1');
192
+ const dinner = dinnerRecipes.length > 0
193
+ ? dinnerRecipes[dayIndex % dinnerRecipes.length]
194
+ : recipeService_1.recipeService.getRecipeById('dinner-1');
195
+ const snack = snackRecipes.length > 0
196
+ ? snackRecipes[dayIndex % snackRecipes.length]
197
+ : recipeService_1.recipeService.getRecipeById('snack-1');
198
+ // Convert to meals and add day prefix
199
+ const dayMeals = [
200
+ { ...convertRecipeToMeal(breakfast), name: `${day} - ${breakfast.name}` },
201
+ { ...convertRecipeToMeal(lunch), name: `${day} - ${lunch.name}` },
202
+ { ...convertRecipeToMeal(dinner), name: `${day} - ${dinner.name}` },
203
+ { ...convertRecipeToMeal(snack), name: `${day} - ${snack.name}` }
204
+ ];
205
+ allMeals.push(...dayMeals);
206
+ });
207
+ // Calculate total nutrition
208
+ const totalNutrition = allMeals.reduce((total, meal) => ({
209
+ calories: total.calories + (meal.nutrition?.calories || 0),
210
+ protein: Math.round((total.protein + (meal.nutrition?.protein || 0)) * 10) / 10,
211
+ carbs: Math.round((total.carbs + (meal.nutrition?.carbs || 0)) * 10) / 10,
212
+ fat: Math.round((total.fat + (meal.nutrition?.fat || 0)) * 10) / 10
213
+ }), { calories: 0, protein: 0, carbs: 0, fat: 0 });
214
+ const startDate = new Date();
215
+ const endDate = new Date();
216
+ endDate.setDate(startDate.getDate() + 6);
217
+ return {
218
+ id: `weekly-recipe-plan-${Date.now()}`,
219
+ userId: userId,
220
+ name: `Weekly Meal Plan - ${startDate.toLocaleDateString()} to ${endDate.toLocaleDateString()}`,
221
+ description: `7-day meal plan with complete recipes and instructions (${Math.round(totalNutrition.calories / 7)} cal/day avg)`,
222
+ startDate: startDate.toISOString().split('T')[0],
223
+ endDate: endDate.toISOString().split('T')[0],
224
+ dailyPlans: [],
225
+ meals: allMeals,
226
+ totalCalories: totalNutrition.calories,
227
+ totalProtein: totalNutrition.protein,
228
+ totalCarbs: totalNutrition.carbs,
229
+ totalFat: totalNutrition.fat,
230
+ uid: userId,
231
+ goals: {
232
+ dailyCalories: needs.calories,
233
+ proteinPercentage: 25,
234
+ carbsPercentage: 45,
235
+ fatPercentage: 30,
236
+ },
237
+ createdAt: new Date(),
238
+ updatedAt: new Date()
239
+ };
240
+ }
241
+ /**
242
+ * Get recipe details for a meal in a meal plan
243
+ * This allows you to retrieve the full recipe with instructions for any meal
244
+ */
245
+ function getRecipeForMeal(meal) {
246
+ // Try to find the recipe by ID (if meal ID matches recipe ID)
247
+ const recipe = recipeService_1.recipeService.getRecipeById(meal.id);
248
+ if (recipe) {
249
+ return recipe;
250
+ }
251
+ // Try to find by name (remove day prefix if present)
252
+ const cleanName = meal.name.replace(/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday) - /, '');
253
+ return recipeService_1.recipeService.searchRecipes(cleanName)[0];
254
+ }
@@ -0,0 +1,28 @@
1
+ import { Recipe, RecipeFilter } from './types/recipe';
2
+ export { RecipeFilter };
3
+ export declare class RecipeService {
4
+ private recipes;
5
+ private recipesBS;
6
+ private currentLocale;
7
+ constructor(locale?: string);
8
+ setLocale(locale: string): void;
9
+ private getCurrentRecipes;
10
+ getAllRecipes(): Recipe[];
11
+ getRecipeById(id: string): Recipe | undefined;
12
+ getRecipesByCategory(category: 'breakfast' | 'lunch' | 'dinner' | 'snack'): Recipe[];
13
+ filterRecipes(filter: RecipeFilter): Recipe[];
14
+ getRecipesByTags(tags: string[]): Recipe[];
15
+ getRecipesForHealthGoals(healthGoals: string[]): Recipe[];
16
+ getRecipesForDietaryRestrictions(restrictions: string[]): Recipe[];
17
+ getRandomRecipe(category?: 'breakfast' | 'lunch' | 'dinner' | 'snack'): Recipe;
18
+ getWeeklyRecipeSuggestions(healthGoals: string[], dietaryRestrictions: string[]): {
19
+ breakfast: Recipe[];
20
+ lunch: Recipe[];
21
+ dinner: Recipe[];
22
+ snack: Recipe[];
23
+ };
24
+ searchRecipes(query: string): Recipe[];
25
+ getTotalTime(recipe: Recipe): number;
26
+ getRecipesByTotalTime(maxMinutes: number): Recipe[];
27
+ }
28
+ export declare const recipeService: RecipeService;