mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-11-03 18:53:17 -05:00 
			
		
		
		
	
		
			
	
	
		
			133 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			133 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 
								 | 
							
								import { useFraction } from "~/composables/recipes";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const matchMixedFraction = /(?:\d*\s\d*\d*|0)\/\d*\d*/;
							 | 
						||
| 
								 | 
							
								const matchFraction = /(?:\d*\d*|0)\/\d*\d*/;
							 | 
						||
| 
								 | 
							
								const matchDecimal = /(\d+.\d+)|(.\d+)/;
							 | 
						||
| 
								 | 
							
								const matchInt = /\d+/;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function extractServingsFromMixedFraction(fractionString: string): number | undefined {
							 | 
						||
| 
								 | 
							
								    const mixedSplit = fractionString.split(/\s/);
							 | 
						||
| 
								 | 
							
								    const wholeNumber = parseInt(mixedSplit[0]);
							 | 
						||
| 
								 | 
							
								    const fraction = mixedSplit[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const fractionSplit = fraction.split("/");
							 | 
						||
| 
								 | 
							
								    const numerator = parseInt(fractionSplit[0]);
							 | 
						||
| 
								 | 
							
								    const denominator = parseInt(fractionSplit[1]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (denominator === 0) {
							 | 
						||
| 
								 | 
							
								        return undefined;  // if the denominator is zero, just give up
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        return wholeNumber + (numerator / denominator);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function extractServingsFromFraction(fractionString: string): number | undefined {
							 | 
						||
| 
								 | 
							
								    const fractionSplit = fractionString.split("/");
							 | 
						||
| 
								 | 
							
								    const numerator = parseInt(fractionSplit[0]);
							 | 
						||
| 
								 | 
							
								    const denominator = parseInt(fractionSplit[1]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (denominator === 0) {
							 | 
						||
| 
								 | 
							
								        return undefined;  // if the denominator is zero, just give up
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        return numerator / denominator;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function findMatch(yieldString: string): [matchString: string, servings: number, isFraction: boolean] | null {
							 | 
						||
| 
								 | 
							
								    if (!yieldString) {
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const mixedFractionMatch = yieldString.match(matchMixedFraction);
							 | 
						||
| 
								 | 
							
								    if (mixedFractionMatch?.length) {
							 | 
						||
| 
								 | 
							
								        const match = mixedFractionMatch[0];
							 | 
						||
| 
								 | 
							
								        const servings = extractServingsFromMixedFraction(match);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // if the denominator is zero, return no match
							 | 
						||
| 
								 | 
							
								        if (servings === undefined) {
							 | 
						||
| 
								 | 
							
								            return null;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            return [match, servings, true];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const fractionMatch = yieldString.match(matchFraction);
							 | 
						||
| 
								 | 
							
								    if (fractionMatch?.length) {
							 | 
						||
| 
								 | 
							
								        const match = fractionMatch[0]
							 | 
						||
| 
								 | 
							
								        const servings = extractServingsFromFraction(match);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // if the denominator is zero, return no match
							 | 
						||
| 
								 | 
							
								        if (servings === undefined) {
							 | 
						||
| 
								 | 
							
								            return null;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            return [match, servings, true];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const decimalMatch = yieldString.match(matchDecimal);
							 | 
						||
| 
								 | 
							
								    if (decimalMatch?.length) {
							 | 
						||
| 
								 | 
							
								        const match = decimalMatch[0];
							 | 
						||
| 
								 | 
							
								        return [match, parseFloat(match), false];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const intMatch = yieldString.match(matchInt);
							 | 
						||
| 
								 | 
							
								    if (intMatch?.length) {
							 | 
						||
| 
								 | 
							
								        const match = intMatch[0];
							 | 
						||
| 
								 | 
							
								        return [match, parseInt(match), false];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return null;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function formatServings(servings: number, scale: number, isFraction: boolean): string {
							 | 
						||
| 
								 | 
							
								    const val = servings * scale;
							 | 
						||
| 
								 | 
							
								    if (Number.isInteger(val)) {
							 | 
						||
| 
								 | 
							
								        return val.toString();
							 | 
						||
| 
								 | 
							
								    } else if (!isFraction) {
							 | 
						||
| 
								 | 
							
								        return (Math.round(val * 1000) / 1000).toString();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // convert val into a fraction string
							 | 
						||
| 
								 | 
							
								    const { frac } = useFraction();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let valString = "";
							 | 
						||
| 
								 | 
							
								    const fraction = frac(val, 10, true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (fraction[0] !== undefined && fraction[0] > 0) {
							 | 
						||
| 
								 | 
							
								        valString += fraction[0];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (fraction[1] > 0) {
							 | 
						||
| 
								 | 
							
								        valString += ` ${fraction[1]}/${fraction[2]}`;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return valString.trim();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function useExtractRecipeYield(yieldString: string | null, scale: number): string {
							 | 
						||
| 
								 | 
							
								    if (!yieldString) {
							 | 
						||
| 
								 | 
							
								        return "";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const match = findMatch(yieldString);
							 | 
						||
| 
								 | 
							
								    if (!match) {
							 | 
						||
| 
								 | 
							
								        return yieldString;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const [matchString, servings, isFraction] = match;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const formattedServings = formatServings(servings, scale, isFraction);
							 | 
						||
| 
								 | 
							
								    if (!formattedServings) {
							 | 
						||
| 
								 | 
							
								        return yieldString  // this only happens with very weird or small fractions
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        return yieldString.replace(matchString, formatServings(servings, scale, isFraction));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |