private internalSingularize()

in packages/libs/codegen/src/pluralization.ts [950:1175]


  private internalSingularize(word: string): string {
    // words that we know of
    if (this.userDictionary.existsInSecond(word)) {
      return this.userDictionary.getFirstValue(word);
    }

    if (this.isNoOpWord(word)) {
      return word;
    }

    const { prefixWord, suffixWord } = this.getSuffixWord(word);

    if (this.isNoOpWord(suffixWord)) {
      return prefixWord + suffixWord;
    }

    // handle the word that is the same as the plural form
    if (this.isUninflective(suffixWord)) {
      return prefixWord + suffixWord;
    }

    // if word is one of the known singular words, then just return

    if (this.knownSingluarWords.includes(suffixWord.toLowerCase())) {
      return prefixWord + suffixWord;
    }

    // handle simple irregular verbs, e.g. was -> were
    if (this.irregularVerbPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.irregularVerbPluralizationService.getFirstValue(suffixWord);
    }

    // handle irregular plurals, e.g. "ox" -> "oxen"
    if (this.irregularPluralsPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.irregularPluralsPluralizationService.getFirstValue(suffixWord);
    }

    // handle singluarization for words ending with sis and pluralized to ses,
    // e.g. "ses" -> "sis"
    if (this.wordsEndingWithSisPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.wordsEndingWithSisPluralizationService.getFirstValue(suffixWord);
    }

    // handle words ending with se, e.g. "ses" -> "se"
    if (this.wordsEndingWithSePluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.wordsEndingWithSePluralizationService.getFirstValue(suffixWord);
    }

    // handle words ending with sus, e.g. "suses" -> "sus"
    if (this.wordsEndingWithSusPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.wordsEndingWithSusPluralizationService.getFirstValue(suffixWord);
    }

    let newSuffixWord: string | null;
    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["men"],
      (s) => `${s.slice(0, -2)}an`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    // handle irregular inflections for common suffixes, e.g. "mouse" -> "mice"
    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["lice", "mice"],
      (s) => `${s.slice(0, -3)}ouse`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["teeth"],
      (s) => `${s.slice(0, -4)}ooth`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["geese"],
      (s) => `${s.slice(0, -4)}oose`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["feet"],
      (s) => `${s.slice(0, -3)}oot`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["zoa"],
      (s) => `${s.slice(0, -2)}oon`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    // [cs]h and ss that take es as plural form, this is being moved up since the sses will be override by the ses
    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(suffixWord, ["ches", "shes", "sses"], (s) =>
      s.slice(0, -2),
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    // handle assimilated classical inflections, e.g. vertebra -> vertebrae
    if (this.assimilatedClassicalInflectionPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.assimilatedClassicalInflectionPluralizationService.getFirstValue(suffixWord);
    }

    // Handle the classical variants of modern inflections
    //
    if (this.classicalInflectionPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.classicalInflectionPluralizationService.getFirstValue(suffixWord);
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["trices"],
      (s) => `${s.slice(0, -3)}x`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(suffixWord, ["eaux", "ieux"], (s) =>
      s.slice(0, -1),
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    if (this.wordsEndingWithInxAnxYnxPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.wordsEndingWithInxAnxYnxPluralizationService.getFirstValue(suffixWord);
    }

    // f, fe that take ves as plural form
    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["alves", "elves", "olves", "eaves", "arves"],
      (s) => `${s.slice(0, -3)}f`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["nives", "lives", "wives"],
      (s) => `${s.slice(0, -3)}fe`,
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    // y takes ys as plural form if preceded by a vowel, but ies if preceded by a consonant, e.g. stays, skies
    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["ays", "eys", "iys", "oys", "uys"],
      (s) => s.slice(0, -1),
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    //

    if (endsWithIgnoreCase(suffixWord, "ies")) {
      return prefixWord + suffixWord.slice(0, -3) + "y";
    }

    // handle some of the words o -> os, and [vowel]o -> os, and the rest are o->oes
    if (this.oSuffixPluralizationService.existsInSecond(suffixWord)) {
      return prefixWord + this.oSuffixPluralizationService.getFirstValue(suffixWord);
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(
      suffixWord,
      ["aos", "eos", "ios", "oos", "uos"],
      (s) => s.slice(0, -1),
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    //

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(suffixWord, ["ces"], (s) => s.slice(0, -1));
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    newSuffixWord = PluralizationServiceUtil.TryInflectOnSuffixInWord(suffixWord, ["ces", "ses", "xes"], (s) =>
      s.slice(0, -2),
    );
    if (newSuffixWord !== null) {
      return prefixWord + newSuffixWord;
    }

    if (endsWithIgnoreCase(suffixWord, "oes")) {
      return prefixWord + suffixWord.slice(0, -2);
    }

    if (endsWithIgnoreCase(suffixWord, "ss")) {
      return prefixWord + suffixWord;
    }

    if (endsWithIgnoreCase(suffixWord, "s")) {
      return prefixWord + suffixWord.slice(0, -1);
    }

    // word is a singlar
    return prefixWord + suffixWord;
  }