Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/yield input calculator #1765

Merged
merged 10 commits into from
Jul 21, 2023
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
[#1602](https://github.com/nextcloud/cookbook/pull/1602) @j0hannesr0th
- Enhance recipe recalculation algorithm
[#1723](https://github.com/nextcloud/cookbook/pull/1723) @j0hannesr0th
- Enhance recipe recalculation algorithm
[#1723](https://github.com/nextcloud/cookbook/pull/1743) @j0hannesr0th

### Fixed
- Fix translation string to not contain quotes
Expand Down
8 changes: 7 additions & 1 deletion src/components/RecipeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
v-model="recipeYield"
type="number"
min="0"
style="width: 65px"
/>
<button @click="changeRecipeYield">
<span class="icon-view-next" />
Expand Down Expand Up @@ -147,14 +148,19 @@
:key="'ingr' + idx"
:ingredient="ingredient"
:ingredient-has-correct-syntax="
/* yieldCalculator.isValidIngredientSyntax(ingredient) */
ingredientsWithValidSyntax[idx]
"
:recipe-ingredients-have-subgroups="
recipeIngredientsHaveSubgroups
"
:style="{
'font-style': ingredientsWithValidSyntax[idx]
? 'normal'
: 'italic',
}"
/>
</ul>

<div
v-if="!ingredientsSyntaxCorrect"
class="ingredient-parsing-error"
Expand Down
75 changes: 46 additions & 29 deletions src/js/yieldCalculator.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
/*
The ingredientFractionRegExp is used to identify fractions in the string.
This is used to exclude strings that contain fractions from being valid.
*/
const fractionRegExp = /^((\d+\s+)?(\d+)\s*\/\s*(\d+)).*/

function isValidIngredientSyntax(ingredient) {
/*
*** Outdated!!! ***
Explanation of ingredientSyntaxRegExp:
^: Start of string
(?:\d+(?:\.\d+)?|\.\d+): Non-capturing group that matches either a positive float value or a positive integer value. The first alternative matches one or more digits, followed by an optional decimal part consisting of a dot and one or more digits. The second alternative matches a decimal point followed by one or more digits.
(?:\s.+$|\s\S+$): Non-capturing group that matches a whitespace character followed by any character with unlimited length or any special character with unlimited length. The first alternative matches a whitespace character followed by any character(s) until the end of the string. The second alternative matches a whitespace character followed by any non-whitespace character(s) until the end of the string.
$: End of string
The ingredientSyntaxRegExp checks whether the ingredient string starts with a number,
possibly followed by a fractional part or a fraction. Then there should be a space
and then any sequence of characters.
*/
const ingredientSyntaxRegExp = /^(?:\d+(?:\.\d+)?(?:\/\d+)?)\s?.*$/
// Regular expression to match all possible fractions within a string
const ingredientFractionRegExp = /\b\d+\/\d+\b/g

/*
Explanation of ingredientMultipleSeperatorsRegExp:
/^ - Start of the string
-? - Matches an optional minus sign
\d+ - Matches one or more digits
(?:[.,]\d+){2,} - Non-capturing group that matches a separator (.,) followed by one or more digits.
The {2,} quantifier ensures that there are at least two occurrences of this pattern.
.* - Matches any characters (except newline) zero or more times.
The ingredientMultipleSeperatorsRegExp is used to check whether the string contains
more than one separators (.,) after a number. This is used to exclude strings that
contain more than one separator from being valid.
*/
const ingredientMultipleSeperatorsRegExp = /^-?\d+(?:[.,]\d+){2,}.*/

return (
ingredientSyntaxRegExp.test(ingredient) &&
!ingredientFractionRegExp.test(ingredient) &&
!ingredientMultipleSeperatorsRegExp.test(ingredient)
fractionRegExp.test(ingredient) ||
(ingredientSyntaxRegExp.test(ingredient) &&
!ingredientMultipleSeperatorsRegExp.test(ingredient))
)
}

Expand All @@ -33,28 +31,47 @@ function isIngredientsArrayValid(ingredients) {
}

function recalculateIngredients(ingredients, currentYield, originalYield) {
return ingredients.map((ingredient, index) => {
return ingredients.map((ingredient) => {
const matches = ingredient.match(fractionRegExp)

if (matches) {
const [
,
fractionMatch,
wholeNumberPartRaw,
numeratorRaw,
denominatorRaw,
] = matches
const wholeNumberPart = wholeNumberPartRaw
? parseInt(wholeNumberPartRaw, 10)
: 0
const numerator = parseInt(numeratorRaw, 10)
const denominator = parseInt(denominatorRaw, 10)

const decimalAmount = wholeNumberPart + numerator / denominator
let newAmount = (decimalAmount / originalYield) * currentYield
newAmount = newAmount.toFixed(2).replace(/[.]00$/, "")

const newIngredient = ingredient.replace(fractionMatch, newAmount)
return newIngredient
}

if (isValidIngredientSyntax(ingredient)) {
// For some cases, where the unit is not separated from the amount: 100g cheese
const possibleUnit = ingredient
.split(" ")[0]
.replace(/[^a-zA-Z]/g, "")
const amount = parseFloat(ingredients[index].split(" ")[0])
const amount = parseFloat(
ingredient.split(" ")[0].replace(",", "."),
)
const unitAndIngredient = ingredient.split(" ").slice(1).join(" ")

let newAmount = (amount / originalYield) * currentYield
newAmount = newAmount.toFixed(2).replace(/[.]00$/, "")

return `${newAmount}${possibleUnit} ${unitAndIngredient}`
}

const factor = currentYield / originalYield
const prefix = ((f) => {
if (f === 1) {
return ""
}
return `${f.toFixed(2)}x `
})(factor)
return `${prefix}${ingredient}`
return ingredient
})
}

Expand Down
Loading