feat: added support for adding plurality to ingredients

This commit is contained in:
Leyla Becker 2026-02-22 19:53:18 -06:00
parent 750bfb912f
commit 8855d6ba19
9 changed files with 468 additions and 8 deletions

View file

@ -0,0 +1,72 @@
/**
* Noun pluralization for count measurements in recipes.
*
* Each entry has a singular and plural form. Entries are sorted
* longest-first so that "garlic clove" matches before "clove",
* "bell pepper" before "pepper", etc.
*/
const PLURALS = [
{ singular: 'portobello mushroom', plural: 'portobello mushrooms' },
{ singular: 'chile pepper', plural: 'chile peppers' },
{ singular: 'garlic clove', plural: 'garlic cloves' },
{ singular: 'bell pepper', plural: 'bell peppers' },
{ singular: 'egg white', plural: 'egg whites' },
{ singular: 'egg yolk', plural: 'egg yolks' },
{ singular: 'egg yoke', plural: 'egg yokes' },
{ singular: 'tortilla', plural: 'tortillas' },
{ singular: 'mushroom', plural: 'mushrooms' },
{ singular: 'biscuit', plural: 'biscuits' },
{ singular: 'potato', plural: 'potatoes' },
{ singular: 'tomato', plural: 'tomatoes' },
{ singular: 'pepper', plural: 'peppers' },
{ singular: 'hoagie', plural: 'hoagies' },
{ singular: 'banana', plural: 'bananas' },
{ singular: 'carrot', plural: 'carrots' },
{ singular: 'onion', plural: 'onions' },
{ singular: 'lemon', plural: 'lemons' },
{ singular: 'apple', plural: 'apples' },
{ singular: 'clove', plural: 'cloves' },
{ singular: 'lime', plural: 'limes' },
{ singular: 'egg', plural: 'eggs' },
];
/**
* Check if text ends with a known singular or plural noun.
* Case-insensitive, word-boundary-aware (the noun must appear at a
* word boundary in the text).
*
* @param {string} textBefore - text preceding the count measurement
* @returns {{ singular: string, plural: string, matchStart: number, matchLength: number } | null}
*/
function matchPlural(textBefore) {
if (!textBefore) return null;
const trimmed = textBefore.trimEnd();
if (!trimmed) return null;
const lower = trimmed.toLowerCase();
for (const entry of PLURALS) {
// Try both singular and plural forms
for (const form of [entry.singular, entry.plural]) {
if (lower.length < form.length) continue;
const tail = lower.slice(-form.length);
if (tail !== form) continue;
// Check word boundary: either start of string or preceded by non-word char
const beforeIdx = lower.length - form.length;
if (beforeIdx > 0 && /\w/.test(lower[beforeIdx - 1])) continue;
return {
singular: entry.singular,
plural: entry.plural,
matchStart: trimmed.length - form.length,
matchLength: form.length,
};
}
}
return null;
}
module.exports = { PLURALS, matchPlural };