| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | import type { RecipeIngredient } from "~/lib/api/types/recipe"; | 
					
						
							| 
									
										
										
										
											2022-12-29 23:00:31 +01:00
										 |  |  | import { parseIngredientText } from "~/composables/recipes"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function normalize(word: string): string { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   let normalizing = word; | 
					
						
							|  |  |  |   normalizing = removeTrailingPunctuation(normalizing); | 
					
						
							|  |  |  |   normalizing = removeStartingPunctuation(normalizing); | 
					
						
							|  |  |  |   return normalizing; | 
					
						
							| 
									
										
										
										
											2022-12-29 23:00:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function removeTrailingPunctuation(word: string): string { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   const punctuationAtEnding = /\p{P}+$/u; | 
					
						
							|  |  |  |   return word.replace(punctuationAtEnding, ""); | 
					
						
							| 
									
										
										
										
											2022-12-29 23:00:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function removeStartingPunctuation(word: string): string { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   const punctuationAtBeginning = /^\p{P}+/u; | 
					
						
							|  |  |  |   return word.replace(punctuationAtBeginning, ""); | 
					
						
							| 
									
										
										
										
											2022-12-29 23:00:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 10:36:24 -05:00
										 |  |  | function ingredientMatchesWord(ingredient: RecipeIngredient, word: string) { | 
					
						
							|  |  |  |   const searchText = parseIngredientText(ingredient); | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   return searchText.toLowerCase().includes(word.toLowerCase()); | 
					
						
							| 
									
										
										
										
											2022-12-29 23:00:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function isBlackListedWord(word: string) { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   // Ignore matching blacklisted words when auto-linking - This is kind of a cludgey implementation. We're blacklisting common words but
 | 
					
						
							|  |  |  |   // other common phrases trigger false positives and I'm not sure how else to approach this. In the future I maybe look at looking directly
 | 
					
						
							|  |  |  |   // at the food variable and seeing if the food is in the instructions, but I still need to support those who don't want to provide the value
 | 
					
						
							|  |  |  |   // and only use the "notes" feature.
 | 
					
						
							|  |  |  |   const blackListedText: string[] = [ | 
					
						
							|  |  |  |     "and", | 
					
						
							|  |  |  |     "the", | 
					
						
							|  |  |  |     "for", | 
					
						
							|  |  |  |     "with", | 
					
						
							|  |  |  |     "without", | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  |   const blackListedRegexMatch = /\d/gm; // Match Any Number
 | 
					
						
							|  |  |  |   return blackListedText.includes(word) || word.match(blackListedRegexMatch); | 
					
						
							| 
									
										
										
										
											2022-12-29 23:00:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-31 10:36:24 -05:00
										 |  |  | export function useExtractIngredientReferences(recipeIngredients: RecipeIngredient[], activeRefs: string[], text: string): Set<string> { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   const availableIngredients = recipeIngredients | 
					
						
							|  |  |  |     .filter(ingredient => ingredient.referenceId !== undefined) | 
					
						
							|  |  |  |     .filter(ingredient => !activeRefs.includes(ingredient.referenceId as string)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const allMatchedIngredientIds: string[] = text | 
					
						
							|  |  |  |     .toLowerCase() | 
					
						
							|  |  |  |     .split(/\s/) | 
					
						
							|  |  |  |     .map(normalize) | 
					
						
							|  |  |  |     .filter(word => word.length > 2) | 
					
						
							|  |  |  |     .filter(word => !isBlackListedWord(word)) | 
					
						
							| 
									
										
										
										
											2025-07-31 10:36:24 -05:00
										 |  |  |     .flatMap(word => availableIngredients.filter(ingredient => ingredientMatchesWord(ingredient, word))) | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     .map(ingredient => ingredient.referenceId as string); | 
					
						
							|  |  |  |   //  deduplicate
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return new Set<string>(allMatchedIngredientIds); | 
					
						
							| 
									
										
										
										
											2024-06-26 12:41:46 +02:00
										 |  |  | } |