diff --git a/lib/utils/text-utils.js b/lib/utils/text-utils.js --- a/lib/utils/text-utils.js +++ b/lib/utils/text-utils.js @@ -1,24 +1,52 @@ // @flow -function pluralize( - nouns: $ReadOnlyArray, +function basePluralize( + nouns: $ReadOnlyArray, maxNumberOfNouns: number = 3, -): string { + composeFunc: (T | string, ?T | string) => T, +): T { + const baseCase = composeFunc(''); + if (nouns.length === 0 || maxNumberOfNouns <= 0) { - return ''; + return baseCase; } else if (nouns.length === 1) { return nouns[0]; } else if (maxNumberOfNouns === 1) { - return `${nouns.length} users`; + return composeFunc(`${nouns.length} users`); } const comma = maxNumberOfNouns > 2 && nouns.length > 2 ? ',' : ''; if (nouns.length <= maxNumberOfNouns) { - const prefix = nouns.slice(0, -1).join(', '); - return `${prefix}${comma} and ${nouns[nouns.length - 1]}`; + const allButLast = nouns.slice(0, -1); + const mostlyComposed = allButLast.reduce( + (partlyComposed, noun) => + composeFunc(composeFunc(partlyComposed, noun), `${comma} `), + baseCase, + ); + return composeFunc( + composeFunc(mostlyComposed, 'and '), + nouns[nouns.length - 1], + ); } - const prefix = nouns.slice(0, maxNumberOfNouns - 1).join(', '); - return `${prefix}${comma} and ${nouns.length - maxNumberOfNouns + 1} others`; + const explicitNouns = nouns.slice(0, maxNumberOfNouns - 1); + const mostlyComposed = explicitNouns.reduce( + (partlyComposed, noun) => + composeFunc(composeFunc(partlyComposed, noun), `${comma} `), + baseCase, + ); + return composeFunc( + composeFunc(mostlyComposed, 'and '), + `${nouns.length - maxNumberOfNouns + 1} others`, + ); +} + +function pluralize( + nouns: $ReadOnlyArray, + maxNumberOfNouns: number = 3, +): string { + return basePluralize(nouns, maxNumberOfNouns, (a: string, b: ?string) => + b ? a + b : a, + ); } function trimText(text: string, maxLength: number): string { @@ -43,4 +71,4 @@ return trimText(pluralize(nouns, 1), maxLength); } -export { pluralize, trimText, pluralizeAndTrim }; +export { basePluralize, pluralize, trimText, pluralizeAndTrim };