nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
157 lines (156 loc) • 5.57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.pluralizer = exports.Pluralizer = void 0;
const primitives_1 = require("../guards/primitives");
const utilities_1 = require("../number/utilities");
const rules_1 = require("./rules");
class Pluralizer {
#pluralRules = [];
#singularRules = [];
#uncountables = new Set();
#irregularSingles = {};
#irregularPlurals = {};
constructor() {
this.#loadRules();
}
#loadRules() {
rules_1.irregularRules.forEach(([single, plural]) => {
this.addIrregular(single, plural);
});
rules_1.pluralRules.forEach(([rule, replacement]) => {
this.addPluralRule(rule, replacement);
});
rules_1.singularRules.forEach(([rule, replacement]) => {
this.addSingularRule(rule, replacement);
});
rules_1.uncountables.forEach((word) => {
this.addUncountable(word);
});
}
#restoreCase(original, transformed) {
original = original?.trim();
if (original === transformed)
return transformed;
if (original === original.toLowerCase()) {
return transformed.toLowerCase();
}
if (original === original.toUpperCase()) {
return transformed.toUpperCase();
}
if (original[0] === original[0].toUpperCase() &&
original.slice(1) === original.slice(1).toLowerCase()) {
return transformed.charAt(0).toUpperCase() + transformed.slice(1).toLowerCase();
}
let result = '';
for (let i = 0; i < transformed.length; i++) {
const origChar = original[i];
if (origChar &&
origChar === origChar.toUpperCase() &&
origChar !== origChar.toLowerCase()) {
result += transformed[i].toUpperCase();
}
else {
result += transformed[i].toLowerCase();
}
}
return result;
}
#applyRules(word, rules) {
if (!(0, primitives_1.isNonEmptyString)(word))
return '';
if (this.#isUncountable(word)) {
return word;
}
for (let i = rules.length - 1; i >= 0; i--) {
const [rule, replacement] = rules[i];
if (rule.test(word)) {
return word.replace(rule, replacement);
}
}
return word;
}
#isUncountable(word) {
for (const entry of this.#uncountables) {
if ((0, primitives_1.isString)(entry)) {
if (entry.toLowerCase() === word)
return true;
}
else {
if (entry?.test(word))
return true;
}
}
return false;
}
addPluralRule(rule, replacement) {
this.#pluralRules.push([rule, replacement]);
}
addSingularRule(rule, replacement) {
this.#singularRules.push([rule, replacement]);
}
addUncountable(word) {
this.#uncountables.add((0, primitives_1.isString)(word) ? word?.toLowerCase() : word);
}
addIrregular(single, plural) {
const singleLower = single?.toLowerCase();
const pluralLower = plural?.toLowerCase();
this.#irregularSingles[singleLower] = pluralLower;
this.#irregularPlurals[pluralLower] = singleLower;
}
pluralize(word, options = {}) {
const count = (0, utilities_1.normalizeNumber)(options?.count);
if (!(0, primitives_1.isUndefined)(count)) {
const pluralized = count === 1 ? this.toSingular(word) : this.toPlural(word);
return options?.inclusive ? `${count} ${pluralized}` : pluralized;
}
return this.toPlural(word);
}
toPlural(word) {
if (!(0, primitives_1.isNonEmptyString)(word))
return '';
const lower = word?.trim()?.toLowerCase();
if (this.#isUncountable(lower))
return word;
if (this.#irregularSingles[lower]) {
return this.#restoreCase(word, this.#irregularSingles[lower]);
}
return this.#restoreCase(word, this.#applyRules(lower, this.#pluralRules));
}
toSingular(word) {
if (!(0, primitives_1.isNonEmptyString)(word))
return '';
const lower = word?.trim()?.toLowerCase();
if (this.#isUncountable(lower))
return word;
if (this.#irregularPlurals[lower]) {
return this.#restoreCase(word, this.#irregularPlurals[lower]);
}
return this.#restoreCase(word, this.#applyRules(lower, this.#singularRules));
}
isPlural(word) {
if (!(0, primitives_1.isNonEmptyString)(word))
return false;
const lower = word?.trim()?.toLowerCase();
if (this.#isUncountable(lower))
return true;
if (this.#irregularPlurals[lower])
return true;
if (this.#irregularSingles[lower])
return false;
return this.toSingular(lower) !== lower;
}
isSingular(word) {
if (!(0, primitives_1.isNonEmptyString)(word))
return false;
const lower = word?.trim()?.toLowerCase();
if (this.#isUncountable(lower))
return true;
if (this.#irregularSingles[lower])
return true;
if (this.#irregularPlurals[lower])
return false;
return this.toSingular(lower) === lower;
}
}
exports.Pluralizer = Pluralizer;
exports.pluralizer = new Pluralizer();