refactor with more abstraction

This commit is contained in:
adueck 2024-07-27 12:10:32 -04:00
parent 502031b054
commit 46fd6e66e8
4 changed files with 560 additions and 560 deletions

View File

@ -14,6 +14,7 @@ import {
hasShwaEnding, hasShwaEnding,
mapPsString, mapPsString,
endsWith, endsWith,
psStringFromEntry,
} from "./p-text-helpers"; } from "./p-text-helpers";
import { removeDuplicates } from "./phrase-building/vp-tools"; import { removeDuplicates } from "./phrase-building/vp-tools";
import { import {
@ -25,6 +26,16 @@ import {
isNounEntry, isNounEntry,
isNumberEntry, isNumberEntry,
} from "./type-predicates"; } from "./type-predicates";
import { semigroupPsString } from "../dist/lib/src/fp-ps";
const concatPs = semigroupPsString.concat;
const o = { p: "و", f: "o" };
const ó = { p: "و", f: "ó" };
const a = { p: "ه", f: "a" };
const á = { p: "ه", f: "á" };
const e = { p: "ې", f: "e" };
const é = { p: "ې", f: "é" };
type Plurals = type Plurals =
| { | {
@ -33,11 +44,11 @@ type Plurals =
} }
| undefined; | undefined;
const endingInSingleARegex = /[^a]'??[aá]'??$/; // const endingInSingleARegex = /[^a]'??[aá]'??$/;
const endingInHayOrAynRegex = /[^ا][هع]$/; // const endingInHayOrAynRegex = /[^ا][هع]$/;
export function getInfsAndVocative( export function getInfsAndVocative(
entry: T.DictionaryEntryNoFVars, entryR: T.DictionaryEntryNoFVars,
plurals: Plurals plurals: Plurals
): ):
| { | {
@ -45,51 +56,51 @@ export function getInfsAndVocative(
vocative?: T.PluralInflections; vocative?: T.PluralInflections;
} }
| false { | false {
if (!isInflectableEntry(entry)) { if (!isInflectableEntry(entryR)) {
return false; return false;
} }
// @ts-ignore // @ts-ignore
const e: T.InflectableEntry = entry as T.InflectableEntry; const entry: T.InflectableEntry = entryR as T.InflectableEntry;
const pattern = getInflectionPattern(e); const pattern = getInflectionPattern(entry);
if ( if (
pattern === 0 && pattern === 0 &&
isFemNounEntry(e) && isFemNounEntry(entry) &&
isAnimNounEntry(e) && isAnimNounEntry(entry) &&
endsInConsonant(e) endsInConsonant(entry)
) { ) {
return { return {
vocative: vocFemAnimException({ vocative: vocFemAnimException({
e, entry,
plurals: genderPlural("fem", plurals), plurals: genderPlural("fem", plurals),
}), }),
}; };
} }
const gender: T.Gender | "unisex" = const gender: T.Gender | "unisex" =
isAdjOrUnisexNounEntry(e) || isNumberEntry(e) isAdjOrUnisexNounEntry(entry) || isNumberEntry(entry)
? "unisex" ? "unisex"
: isMascNounEntry(e) : isMascNounEntry(entry)
? "masc" ? "masc"
: "fem"; : "fem";
if (pattern === 0) { if (pattern === 0) {
return false; return false;
} }
if (pattern === 6) { if (pattern === 6) {
return pattern6({ e, plurals: genderPlural("fem", plurals) }); return pattern6({ entry, plurals: genderPlural("fem", plurals) });
} }
const funcs = patternFuncs[pattern]; const funcs = patternFuncs[pattern];
const masc = const masc =
gender === "unisex" || gender === "masc" gender === "unisex" || gender === "masc"
? funcs.masc({ e, plurals: genderPlural("masc", plurals) }) ? funcs.masc({ entry, plurals: genderPlural("masc", plurals) })
: undefined; : undefined;
const fem = const fem =
gender === "unisex" || gender === "fem" gender === "unisex" || gender === "fem"
? funcs.fem({ e, plurals: genderPlural("fem", plurals) }) ? funcs.fem({ entry, plurals: genderPlural("fem", plurals) })
: undefined; : undefined;
return aggregateInfsAndVoc(masc, fem); return aggregateInfsAndVoc(masc, fem);
} }
type PatternInput = { type PatternInput = {
e: T.DictionaryEntryNoFVars | T.NounEntry | T.InflectableEntry; entry: T.DictionaryEntryNoFVars | T.NounEntry | T.InflectableEntry;
plurals: T.PsString[]; plurals: T.PsString[];
}; };
@ -107,45 +118,45 @@ const patternFuncs: Record<
fem: vocPattern1Fem, fem: vocPattern1Fem,
}, },
2: { 2: {
masc: vocPattern2Masc, masc: pattern2Masc,
fem: vocPattern2Fem, fem: pattern2Fem,
}, },
3: { 3: {
masc: vocPattern3Masc, masc: pattern3Masc,
fem: vocPattern3Fem, fem: pattern3Fem,
}, },
4: { 4: {
masc: vocPattern4Masc, masc: pattern4Masc,
fem: vocPattern4Fem, fem: pattern4Fem,
}, },
5: { 5: {
masc: vocPattern5Masc, masc: vocPattern5Masc,
fem: vocPattern5Fem, fem: pattern5Fem,
}, },
}; };
function addPlurals( function addPlurals(
e: T.ArrayOneOrMore<T.PsString>, x: T.ArrayOneOrMore<T.PsString>,
plurals: T.PsString[] plurals: T.PsString[]
): T.ArrayOneOrMore<T.PsString> { ): T.ArrayOneOrMore<T.PsString> {
if (!plurals) { if (!plurals) {
return e; return x;
} }
return removeDuplicates([...e, ...plurals]) as T.ArrayOneOrMore<T.PsString>; return removeDuplicates([...x, ...plurals]) as T.ArrayOneOrMore<T.PsString>;
} }
function pattern6({ e, plurals }: PatternInput): { function pattern6({ entry, plurals }: PatternInput): {
inflections: T.Inflections; inflections: T.Inflections;
vocative: T.PluralInflections; vocative: T.PluralInflections;
} { } {
const base = removeAccents({ p: e.p.slice(0, -1), f: e.f.slice(0, -2) }); const base = removeAccents({
p: entry.p.slice(0, -1),
f: entry.f.slice(0, -2),
});
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[{ p: `${base.p}ۍ`, f: `${base.f}úy` }], [concatPs(base, { p: "ۍ", f: "úy" })],
[ [concatPs(base, { p: "یو", f: "úyo" }), concatPs(base, ó)],
{ p: `${base.p}یو`, f: `${base.f}úyo` },
{ p: `${base.p}و`, f: `${base.f}ó` },
],
]; ];
return { return {
inflections: { inflections: {
@ -158,83 +169,88 @@ function pattern6({ e, plurals }: PatternInput): {
} }
function vocFemAnimException({ function vocFemAnimException({
e, entry,
plurals, plurals,
}: PatternInput): T.PluralInflections { }: PatternInput): T.PluralInflections {
if (!e.ppp || !e.ppf) { if (!entry.ppp || !entry.ppf) {
throw new Error( throw new Error(
"plural missing for feminine animate exception noun " + e.p "plural missing for feminine animate exception noun " + entry.p
); );
} }
// TODO: HANDLE BETTER WITH PLURALS! // TODO: HANDLE BETTER WITH PLURALS!
const plurBase = mapPsString( const plurBase = mapPsString(
(x) => x.slice(0, -1), (x) => x.slice(0, -1),
makePsString(e.ppp, e.ppf) makePsString(entry.ppp, entry.ppf)
); );
const base = const base =
countSyllables(e) === 1 ? accentOnNFromEnd(e, 0) : makePsString(e.p, e.f); countSyllables(entry) === 1
? accentOnNFromEnd(entry, 0)
: psStringFromEntry(entry);
return { return {
fem: [ fem: [[concatPs(base, e)], addPlurals([concatPs(plurBase, o)], plurals)],
[{ p: `${base.p}ې`, f: `${base.f}e` }],
addPlurals([{ p: `${plurBase.p}و`, f: `${plurBase.f}o` }], plurals),
],
}; };
} }
function vocPattern1Masc({ e, plurals }: PatternInput): InflectionsAndVocative { function vocPattern1Masc({
if (isNounEntry(e) && endsInTob(e)) { entry,
const base = mapPsString((x) => x.slice(0, -3), e); plurals,
const second: T.ArrayOneOrMore<T.PsString> = [ }: PatternInput): InflectionsAndVocative {
{ p: `${base.p}تبو`, f: `${base.f}tábo` }, const plain = psStringFromEntry(entry);
if (isNounEntry(entry) && endsInTob(entry)) {
const base = mapPsString((x) => x.slice(0, -3), entry);
const inflections: T.InflectionSet = [
[plain],
[concatPs(base, { p: "تابه", f: "taabú" })],
[concatPs(base, { p: "تبو", f: "tábo" })],
]; ];
return { return {
inflections: [ inflections,
[{ p: e.p, f: e.f }], vocative: [[concatPs(plain, a)], addPlurals(inflections[2], plurals)],
[{ p: `${base.p}تابه`, f: `${base.f}taabú` }],
second,
],
vocative: [[{ p: `${e.p}ه`, f: `${e.f}a` }], addPlurals(second, plurals)],
}; };
} }
const shwaEnding = hasShwaEnding(e); const shwaEnding = hasShwaEnding(entry);
const base = mapGen( const base = mapGen(
(ps) => (countSyllables(e) === 1 ? accentOnNFromEnd(ps, 0) : ps), (ps) => (countSyllables(entry) === 1 ? accentOnNFromEnd(ps, 0) : ps),
mapPsString((x: string): string => (shwaEnding ? x.slice(0, -1) : x), e) mapPsString((x: string): string => (shwaEnding ? x.slice(0, -1) : x), entry)
); );
if (shwaEnding && e.f.endsWith("ú")) { if (shwaEnding && entry.f.endsWith("ú")) {
const second: T.ArrayOneOrMore<T.PsString> = [ const inflections: T.InflectionSet = [
{ p: `${base.p}و`, f: `${base.f}ó` }, [plain],
[plain],
[concatPs(base, ó)],
]; ];
return { return {
inflections: [[{ p: e.p, f: e.f }], [{ p: e.p, f: e.f }], second], inflections,
vocative: [ vocative: [[concatPs(base, á)], addPlurals(inflections[2], plurals)],
[{ p: `${base.p}ه`, f: `${base.f}á` }],
addPlurals(second, plurals),
],
}; };
} }
// TODO: shouldn't this be accent-sensitive? // TODO: shouldn't this be accent-sensitive?
const second: T.ArrayOneOrMore<T.PsString> = [ const inflections: T.InflectionSet = [[plain], [plain], [concatPs(base, o)]];
{ p: `${base.p}و`, f: `${base.f}o` },
];
return { return {
inflections: [[{ p: e.p, f: e.f }], [{ p: e.p, f: e.f }], second], inflections,
vocative: [ vocative: [
[{ p: `${base.p}ه`, f: `${base.f}a` }], [concatPs(base, { p: "ه", f: "a" })],
addPlurals(second, plurals), addPlurals(inflections[2], plurals),
], ],
}; };
} }
// TODO this is HUGELY repetitive refactor this! // TODO this is HUGELY repetitive refactor this!
function vocPattern1Fem({ e, plurals }: PatternInput): InflectionsAndVocative { function vocPattern1Fem({
const shwaEnding = hasShwaEnding(e); entry,
const hasFemEnding = endsWith([{ p: "ه", f: "a" }], e) || shwaEnding; plurals,
}: PatternInput): InflectionsAndVocative {
const shwaEnding = hasShwaEnding(entry);
const hasFemEnding = endsWith([{ p: "ه", f: "a" }], entry) || shwaEnding;
const endAccented = accentIsOnEnd(entry);
const base = mapGen( const base = mapGen(
(ps) => (countSyllables(e) === 1 ? accentOnNFromEnd(ps, 0) : ps), (ps) =>
countSyllables(entry) === 1 && !endAccented
? accentOnNFromEnd(ps, 0)
: ps,
hasFemEnding hasFemEnding
? mapPsString((x) => x.slice(0, -1), e) ? mapPsString((x) => x.slice(0, -1), entry)
: makePsString(e.p, e.f) : psStringFromEntry(entry)
); );
if ( if (
endsWith( endsWith(
@ -242,291 +258,268 @@ function vocPattern1Fem({ e, plurals }: PatternInput): InflectionsAndVocative {
{ p: "ع", f: "a" }, { p: "ع", f: "a" },
{ p: "ع", f: "a'" }, { p: "ع", f: "a'" },
], ],
e entry
) && ) &&
!["ا", "ی", "ې"].includes(e.p.at(-2) || "") !["ا", "ی", "ې"].includes(e.p.at(-2) || "")
) { ) {
const base = applyPsString( const base2 = applyPsString(
{ {
f: (f) => f.slice(0, f.endsWith("'") ? -2 : -1), f: (f) => f.slice(0, f.endsWith("'") ? -2 : -1),
}, },
e entry
); );
if (accentIsOnEnd(e)) { if (endAccented) {
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}ó` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[{ p: `${base.p}ې`, f: `${base.f}é` }], [concatPs(base2, é)],
second, [concatPs(base2, ó)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}o` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[{ p: `${base.p}ې`, f: `${base.f}e` }], [concatPs(base2, e)],
second, [concatPs(base2, o)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
if ( if (
endsWith([{ p: "ح", f: "a" }], e) && endsWith([{ p: "ح", f: "a" }], entry) &&
!["ا", "ی", "ې"].includes(e.p.at(-2) || "") !["ا", "ی", "ې"].includes(entry.p.at(-2) || "")
) { ) {
const base = applyPsString( const base = applyPsString(
{ {
f: (f) => f.slice(0, -1), f: (f) => f.slice(0, -1),
}, },
e entry
); );
if (accentIsOnEnd(e)) { if (accentIsOnEnd(entry)) {
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}ó` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[{ p: `${base.p}ې`, f: `${base.f}é` }], [concatPs(base, é)],
second, [concatPs(base, ó)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}o` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[{ p: `${base.p}ې`, f: `${base.f}e` }], [concatPs(base, e)],
second, [concatPs(base, o)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
if (hasFemEnding && accentIsOnEnd(e)) { if (hasFemEnding && accentIsOnEnd(entry)) {
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}ó` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: `${base.p}ه`, f: `${base.f}á` }], [concatPs(base, á)],
[{ p: `${base.p}ې`, f: `${base.f}é` }], [concatPs(base, é)],
second, [concatPs(base, ó)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
if (isFemNounEntry(e) && endsInConsonant(e)) { if (isFemNounEntry(entry) && endsInConsonant(entry)) {
const baseForInf = countSyllables(e) === 1 ? accentOnNFromEnd(e, 0) : e; const baseForInf =
const second: T.ArrayOneOrMore<T.PsString> = [ countSyllables(entry) === 1 ? accentOnNFromEnd(entry, 0) : e;
{ p: `${baseForInf.p}و`, f: `${baseForInf.f}o` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[{ p: `${baseForInf.p}ې`, f: `${baseForInf.f}e` }], [concatPs(baseForInf, e)],
second, [concatPs(baseForInf, o)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}o` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: `${base.p}ه`, f: `${base.f}a` }], [concatPs(base, a)],
[{ p: `${base.p}ې`, f: `${base.f}e` }], [concatPs(base, e)],
second, [concatPs(base, o)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
function vocPattern2Masc({ e, plurals }: PatternInput): InflectionsAndVocative { function pattern2Masc({
const base = makePsString(e.p.slice(0, -1), e.f.slice(0, -2)); entry,
const second: T.ArrayOneOrMore<T.PsString> = [ plurals,
{ p: `${base.p}یو`, f: `${base.f}iyo` }, }: PatternInput): InflectionsAndVocative {
{ p: `${base.p}و`, f: `${base.f}o` }, const base = makePsString(entry.p.slice(0, -1), entry.f.slice(0, -2));
const inflections: T.InflectionSet = [
[psStringFromEntry(entry)],
[concatPs(base, { p: "ي", f: "ee" })],
[concatPs(base, { p: "یو", f: "iyo" }), concatPs(base, { p: "و", f: "o" })],
]; ];
return { return {
inflections: [ inflections,
[{ p: e.p, f: e.f }],
[{ p: `${base.p}ي`, f: `${base.f}ee` }],
second,
],
vocative: [ vocative: [
[{ p: `${base.p}یه`, f: `${base.f}iya` }], [concatPs(base, { p: "یه", f: "iya" })],
addPlurals(second, plurals), addPlurals(inflections[2], plurals),
], ],
}; };
} }
function vocPattern2Fem({ e, plurals }: PatternInput): InflectionsAndVocative { function pattern2Fem({ entry, plurals }: PatternInput): InflectionsAndVocative {
const base = makePsString( const base = makePsString(
e.p.slice(0, -1), entry.p.slice(0, -1),
e.f.slice(0, e.f.endsWith("ay") ? -2 : -1) entry.f.slice(0, entry.f.endsWith("ay") ? -2 : -1)
); );
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}یو`, f: `${base.f}iyo` },
{ p: `${base.p}و`, f: `${base.f}o` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: `${base.p}ې`, f: `${base.f}e` }], [concatPs(base, e)],
[{ p: `${base.p}ې`, f: `${base.f}e` }], [concatPs(base, e)],
second, [concatPs(base, { p: "یو", f: "iyo" }), concatPs(base, o)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[0], addPlurals(second, plurals)], vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }
function vocPattern3Masc({ e, plurals }: PatternInput): InflectionsAndVocative { function pattern3Masc({
entry,
plurals,
}: PatternInput): InflectionsAndVocative {
const base = makePsString( const base = makePsString(
e.p.slice(0, -1), entry.p.slice(0, -1),
// shouldn't be accents here but remove just to be sure // shouldn't be accents here but remove just to be sure
removeAccents(e.f.slice(0, -2)) removeAccents(entry.f.slice(0, -2))
); );
const baseSyls = countSyllables(base); const baseSyls = countSyllables(base);
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}یو`, f: `${base.f}úyo` },
{ p: `${base.p}و`, f: `${base.f}${baseSyls ? "ó" : "o"}` },
];
return {
inflections: [
[{ p: e.p, f: e.f }],
[{ p: `${base.p}ي`, f: `${base.f}${baseSyls ? "ée" : "ee"}` }],
second,
],
vocative: [
[{ p: `${base.p}یه`, f: `${base.f}úya` }],
addPlurals(second, plurals),
],
};
}
function vocPattern3Fem({ e, plurals }: PatternInput): InflectionsAndVocative {
const base = makePsString(
e.p.slice(0, -1),
// shouldn't be accents here but remove just to be sure
removeAccents(e.f.slice(0, -2))
);
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}یو`, f: `${base.f}úyo` },
{ p: `${base.p}و`, f: `${base.f}ó` },
];
const plain: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}ۍ`, f: `${base.f}úy` },
];
return {
inflections: [plain, plain, second],
vocative: [plain, addPlurals(second, plurals)],
};
}
function vocPattern4Masc({ e, plurals }: PatternInput): InflectionsAndVocative {
const base = countSyllables(e) === 1 ? accentOnNFromEnd(e, 0) : e;
const firstInf = accentOnNFromEnd(
makePsString(e.infap || "", e.infaf || ""),
0
);
const secondBase = makePsString(e.infbp || "", e.infbf || "");
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${secondBase.p}و`, f: `${secondBase.f}ó` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: e.p, f: e.f }], [psStringFromEntry(entry)],
[firstInf], [concatPs(base, { p: `ي`, f: baseSyls ? "ée" : "ee" })],
second, [
concatPs(base, { p: "یو", f: "úyo" }),
concatPs(base, { p: "و", f: baseSyls ? "ó" : "o" }),
],
]; ];
if (endsInConsonant(e)) {
return { return {
inflections, inflections,
vocative: [ vocative: [
[{ p: `${base.p}ه`, f: `${base.f}a` }], [concatPs(base, { p: "یه", f: "úya" })],
addPlurals(second, plurals), addPlurals(inflections[2], plurals),
], ],
}; };
}
function pattern3Fem({ entry, plurals }: PatternInput): InflectionsAndVocative {
const base = makePsString(
entry.p.slice(0, -1),
// shouldn't be accents here but remove just to be sure
removeAccents(entry.f.slice(0, -2))
);
const baseSyls = countSyllables(base);
const plain: T.ArrayOneOrMore<T.PsString> = [
concatPs(base, { p: "ۍ", f: "úy" }),
];
const inflections: T.InflectionSet = [
plain,
plain,
[concatPs(base, { p: "یو", f: "úyo" }), concatPs(base, baseSyls ? ó : o)],
];
return {
inflections,
vocative: [plain, addPlurals(inflections[2], plurals)],
};
}
function pattern4Masc({
entry,
plurals,
}: PatternInput): InflectionsAndVocative {
const base = countSyllables(entry) === 1 ? accentOnNFromEnd(entry, 0) : entry;
const firstInf = accentOnNFromEnd(
makePsString(entry.infap || "", entry.infaf || ""),
0
);
const secondBase = makePsString(entry.infbp || "", entry.infbf || "");
const inflections: T.InflectionSet = [
[psStringFromEntry(entry)],
[firstInf],
[concatPs(secondBase, ó)],
];
if (endsInConsonant(entry)) {
return {
inflections,
vocative: [[concatPs(base, a)], addPlurals(inflections[2], plurals)],
};
} }
// TODO: is this even possible? // TODO: is this even possible?
if (hasShwaEnding(e)) { if (hasShwaEnding(entry)) {
return { return {
inflections, inflections,
vocative: [ vocative: [
[{ p: `${base.p.slice(0, -1)}ه`, f: `${base.f.slice(0, -1)}á` }], [
addPlurals(second, plurals), concatPs(
mapPsString((x) => x.slice(0, -1), base),
á
),
],
addPlurals(inflections[2], plurals),
], ],
}; };
} }
// exception for مېلمه, کوربه // exception for مېلمه, کوربه
return { return {
inflections, inflections,
vocative: [[{ p: e.p, f: e.f }], second], vocative: [[psStringFromEntry(entry)], inflections[2]],
}; };
} }
function vocPattern4Fem({ e, plurals }: PatternInput): InflectionsAndVocative { function pattern4Fem({ entry }: PatternInput): InflectionsAndVocative {
const base = makePsString(e.infbp || "", e.infbf || ""); const base = makePsString(entry.infbp || "", entry.infbf || "");
const second = addPlurals([{ p: `${base.p}و`, f: `${base.f}ó` }], plurals);
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: `${base.p}ه`, f: `${base.f}á` }], [concatPs(base, á)],
[{ p: `${base.p}ې`, f: `${base.f}é` }], [concatPs(base, é)],
second, [concatPs(base, ó)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], second], vocative: [inflections[1], inflections[2]],
}; };
} }
function vocPattern5Masc({ e, plurals }: PatternInput): InflectionsAndVocative { function vocPattern5Masc({
const base = makePsString(e.infbp || "", e.infbf || ""); entry,
const second: T.ArrayOneOrMore<T.PsString> = [ plurals,
{ p: `${base.p}و`, f: `${base.f}o` }, }: PatternInput): InflectionsAndVocative {
]; const base = makePsString(entry.infbp || "", entry.infbf || "");
return {
inflections: [
[{ p: e.p, f: e.f }],
[{ p: `${base.p}ه`, f: `${base.f}u` }],
second,
],
vocative: [
[{ p: `${base.p}ه`, f: `${base.f}a` }],
addPlurals(second, plurals),
],
};
}
function vocPattern5Fem({ e, plurals }: PatternInput): InflectionsAndVocative {
const base = makePsString(e.infbp || "", e.infbf || "");
const second: T.ArrayOneOrMore<T.PsString> = [
{ p: `${base.p}و`, f: `${base.f}o` },
];
const inflections: T.InflectionSet = [ const inflections: T.InflectionSet = [
[{ p: `${base.p}ه`, f: `${base.f}a` }], [psStringFromEntry(entry)],
[{ p: `${base.p}ې`, f: `${base.f}e` }], [concatPs(base, { p: "ه", f: "u" })],
second, [concatPs(base, o)],
]; ];
return { return {
inflections, inflections,
vocative: [inflections[1], addPlurals(second, plurals)], vocative: [[concatPs(base, a)], addPlurals(inflections[2], plurals)],
};
}
function pattern5Fem({ entry, plurals }: PatternInput): InflectionsAndVocative {
const base = makePsString(entry.infbp || "", entry.infbf || "");
const inflections: T.InflectionSet = [
[concatPs(base, a)],
[concatPs(base, e)],
[concatPs(base, o)],
];
return {
inflections,
vocative: [inflections[1], addPlurals(inflections[2], plurals)],
}; };
} }

320
src/lib/src/nouns-plural.ts Normal file
View File

@ -0,0 +1,320 @@
import {
concatPsString,
endsInConsonant,
endsInAaOrOo,
addOEnding,
splitPsByVarients,
removeEndTick,
endsWith,
hasShwaEnding,
} from "./p-text-helpers";
import { makePsString } from "./accent-and-ps-utils";
import {
accentOnNFromEnd,
countSyllables,
removeAccents,
} from "./accent-helpers";
import * as T from "../../types";
function makePashtoPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!(word.ppp && word.ppf)) return undefined;
const base = splitPsByVarients(makePsString(word.ppp, word.ppf));
function getBaseAndO(): T.PluralInflectionSet {
return [base, base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
}
if (word.c?.includes("n. m.")) {
return { masc: getBaseAndO() };
}
if (word.c?.includes("n. f.")) {
return { fem: getBaseAndO() };
}
// TODO: handle masculine and unisex
return undefined;
}
function makeBundledPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!endsInConsonant(word) || !word.c?.includes("n.")) {
return undefined;
}
const w = makePsString(word.p, word.f);
const base = countSyllables(w) === 1 ? accentOnNFromEnd(w, 0) : w;
return {
masc: [
[concatPsString(base, { p: "ه", f: "a" })],
[concatPsString(base, { p: "و", f: "o" })],
],
};
}
function makeArabicPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!(word.apf && word.app)) return undefined;
const w = makePsString(word.app, word.apf);
const plural = splitPsByVarients(w);
const end = removeAccents(removeEndTick(word.apf).slice(-1));
// again typescript being dumb and not letting me use a typed key here
const value = [
plural,
plural.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
] as T.PluralInflectionSet;
// feminine words that have arabic plurals stay feminine with the plural - ie مرجع - مراجع
// but masculine words that appear feminine in the plural aren't femening with the Arabic plural - ie. نبي - انبیا
if (["i", "e", "a"].includes(end) && word.c?.includes("n. f.")) {
return { fem: value };
}
return { masc: value };
}
export function makePlural(
w: T.DictionaryEntryNoFVars
):
| { plural: T.PluralInflections; bundledPlural?: T.PluralInflections }
| { arabicPlural: T.PluralInflections; bundledPlural?: T.PluralInflections }
| undefined {
function addSecondInf(
plur: T.ArrayOneOrMore<T.PsString> | T.PsString
): T.PluralInflectionSet {
if (!Array.isArray(plur)) {
return addSecondInf([plur]);
}
return [plur, plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
}
if (w.c && w.c.includes("pl.")) {
const plural = addSecondInf(makePsString(w.p, w.f));
// Typescript being dumb and not letting me do a typed variable for the key
// could try refactoring with an updated TypeScript dependency
if (w.c.includes("n. m.")) return { plural: { masc: plural } };
if (w.c.includes("n. f.")) return { plural: { fem: plural } };
}
// exception for mUláa
if (w.f === "mUláa" || w.f === "mUlaa") {
return {
plural: {
masc: [
[
{ p: "ملایان", f: "mUlaayáan" },
{ p: "ملاګان", f: "mUlaagáan" },
],
[
{ p: "ملایانو", f: "mUlaayáano" },
{ p: "ملاګانو", f: "mUlaagáano" },
],
],
},
};
}
const arabicPlural = makeArabicPlural(w);
const pashtoPlural = makePashtoPlural(w);
const bundledPlural = makeBundledPlural(w);
function addMascPluralSuffix(
animate?: boolean,
shortSquish?: boolean
): T.PluralInflectionSet {
if (shortSquish && (w.infap === undefined || w.infaf === undefined)) {
throw new Error(`no irregular inflection info for ${w.p} - ${w.ts}`);
}
const b = removeAccents(
shortSquish
? makePsString(
(w.infap as string).slice(0, -1),
(w.infaf as string).slice(0, -1)
)
: w
);
const base = hasShwaEnding(b)
? makePsString(b.p.slice(0, -1), b.f.slice(0, -1))
: b;
return addSecondInf(
concatPsString(
base,
animate && !shortSquish
? { p: "ان", f: "áan" }
: { p: "ونه", f: "óona" }
)
);
}
function addAnimUnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
const base = removeAccents(w);
return {
masc: addMascPluralSuffix(true),
fem: addSecondInf(concatPsString(base, { p: "انې", f: "áane" })),
};
}
function addEePluralSuffix(gender: T.Gender): T.PluralInflectionSet {
const b = removeAccents(w);
const base = {
p: b.p.slice(0, -1),
f: b.f.slice(0, -2),
};
const firstInf: T.ArrayOneOrMore<T.PsString> = [
concatPsString(
base,
{ p: "یان", f: "iyáan" },
gender === "fem" ? { p: "ې", f: "e" } : ""
),
];
return [
firstInf,
firstInf.flatMap(addOEnding),
// firstInf.map(addOEnding),
] as T.PluralInflectionSet;
}
function addAnimN3UnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
const b = removeAccents(w);
const base = {
p: b.p.slice(0, -1),
f: b.f.slice(0, -2),
};
return {
masc: [
[concatPsString(base, { p: "یان", f: "iyáan" })],
[concatPsString(base, { p: "یانو", f: "iyáano" })],
// TODO: or use addSecondInf method above?
],
fem: [
[concatPsString(base, { p: "یانې", f: "iyáane" })],
[concatPsString(base, { p: "یانو", f: "iyáano" })],
],
};
}
function addLongVowelSuffix(gender: "masc" | "fem"): T.PluralInflectionSet {
if (pashtoPlural) {
}
const base = removeEndTick(makePsString(w.p, w.f));
const baseWOutAccents = removeAccents(base);
const space =
w.p.slice(-1) === "ع" || w.p.slice(-1) === "ه" ? { p: " ", f: " " } : "";
if (gender === "fem") {
return addSecondInf([
concatPsString(base, space, { p: "وې", f: "we" }),
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" }),
]);
} else {
return addSecondInf([
concatPsString(baseWOutAccents, space, { p: "ګان", f: "gáan" }),
]);
}
}
// TODO: This should be possible for words like پلویان but not for words like ترورزامن 🤔
// function addFemToPashtoPlural(i: T.PluralInflections): T.UnisexSet<T.PluralInflectionSet> {
// if ("fem" in i && "masc" in i) return i;
// if (!("masc" in i)) throw new Error("bad pashto plural doesn't even have masculine");
// if (endsInConsonant(i.masc[0][0])) {
// return {
// ...i,
// fem: [
// i.masc[0].map((x) => concatPsString(x, { p: "ې", f: "e" })) as T.ArrayOneOrMore<T.PsString>,
// i.masc[0].map((x) => concatPsString(x, { p: "و", f: "o" })) as T.ArrayOneOrMore<T.PsString>,
// ],
// };
// }
// return {
// ...i,
// fem: i.masc,
// };
// }
const shortSquish = !!w.infap && !w.infap.includes("ا");
const anim = w.c?.includes("anim.");
const type = w.c?.includes("unisex")
? "unisex noun"
: w.c?.includes("n. m.")
? "masc noun"
: w.c?.includes("n. f.")
? "fem noun"
: "other";
if (pashtoPlural) {
return {
plural: pashtoPlural,
arabicPlural,
};
}
if (type === "unisex noun") {
// doesn't need to be labelled anim - because it's only with animate nouns that you get the unisex - I THINK
if (endsInConsonant(w) && !w.infap) {
return {
arabicPlural,
bundledPlural,
plural: addAnimUnisexPluralSuffix(),
};
}
if (shortSquish && !anim) {
return {
arabicPlural,
plural: { masc: addMascPluralSuffix(anim, shortSquish) },
};
}
if (endsWith([{ p: "ی", f: "áy" }, { p: "ي" }], w, true)) {
return { arabicPlural, plural: addAnimN3UnisexPluralSuffix() };
}
// usually shortSquish nouns would never have arabicPlurals -- so we don't have to worry about catching
// arabic plurals for the animat ones, right?
}
if (
type === "masc noun" &&
(shortSquish || ((endsInConsonant(w) || hasShwaEnding(w)) && !w.infap)) &&
w.p.slice(-3) !== "توب"
) {
return {
arabicPlural,
bundledPlural,
plural: {
masc: addMascPluralSuffix(anim, shortSquish),
},
};
}
if (type === "masc noun" && endsWith({ p: "ی", f: "áy" }, w, true) && anim) {
const { masc } = addAnimN3UnisexPluralSuffix();
return {
arabicPlural,
plural: {
masc,
},
};
}
if (type === "masc noun" && endsWith({ p: "ي" }, w)) {
const masc = addEePluralSuffix("masc");
return {
arabicPlural,
plural: { masc },
};
}
// TODO: What about endings in long ee / animate at inanimate
if (type === "masc noun" && endsInAaOrOo(w) && !w.infap) {
return {
arabicPlural,
plural: {
masc: addLongVowelSuffix("masc"),
},
};
}
// TODO: What about endings in long ee / animate at inanimate
if (type === "fem noun" && endsInAaOrOo(w) && !w.infap) {
return {
arabicPlural,
plural: {
fem: addLongVowelSuffix("fem"),
},
};
}
if (
type === "fem noun" &&
(endsWith({ p: "ي" }, w) || (endsWith({ p: "ۍ" }, w) && anim))
) {
return {
arabicPlural,
plural: {
fem: addEePluralSuffix("fem"),
},
};
}
if (arabicPlural) {
return { arabicPlural, plural: pashtoPlural, bundledPlural };
}
return undefined;
}

View File

@ -2114,7 +2114,8 @@ const others: T.DictionaryEntry[] = [
adjectives.forEach((word) => { adjectives.forEach((word) => {
test(`${word.in.p} should inflect properly`, () => { test(`${word.in.p} should inflect properly`, () => {
expect(inflectWord(word.in)).toEqual(word.out); const out = inflectWord(word.in);
expect(out).toEqual(word.out);
}); });
}); });

View File

@ -10,25 +10,14 @@ import {
concatInflections, concatInflections,
splitDoubleWord, splitDoubleWord,
ensureUnisexInflections, ensureUnisexInflections,
concatPsString,
endsInConsonant,
endsInAaOrOo,
addOEnding,
splitPsByVarients,
removeEndTick,
endsWith,
concatPlurals, concatPlurals,
hasShwaEnding,
} from "./p-text-helpers"; } from "./p-text-helpers";
import { makePsString, removeFVarients } from "./accent-and-ps-utils"; import { makePsString, removeFVarients } from "./accent-and-ps-utils";
import { import { removeAccents } from "./accent-helpers";
accentOnNFromEnd,
countSyllables,
removeAccents,
} from "./accent-helpers";
import * as T from "../../types"; import * as T from "../../types";
import { getInfsAndVocative } from "./inflections-and-vocative"; import { getInfsAndVocative } from "./inflections-and-vocative";
import { fmapSingleOrLengthOpts } from "./fp-ps"; import { fmapSingleOrLengthOpts } from "./fp-ps";
import { makePlural } from "./nouns-plural";
export function inflectWord(word: T.DictionaryEntry): T.InflectorOutput { export function inflectWord(word: T.DictionaryEntry): T.InflectorOutput {
// If it's a noun/adj, inflect accordingly // If it's a noun/adj, inflect accordingly
@ -131,309 +120,6 @@ export function inflectRegularShwaEndingUnisex(
}; };
} }
function makePashtoPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!(word.ppp && word.ppf)) return undefined;
const base = splitPsByVarients(makePsString(word.ppp, word.ppf));
function getBaseAndO(): T.PluralInflectionSet {
return [base, base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
}
if (word.c?.includes("n. m.")) {
return { masc: getBaseAndO() };
}
if (word.c?.includes("n. f.")) {
return { fem: getBaseAndO() };
}
// TODO: handle masculine and unisex
return undefined;
}
function makeBundledPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!endsInConsonant(word) || !word.c?.includes("n.")) {
return undefined;
}
const w = makePsString(word.p, word.f);
const base = countSyllables(w) === 1 ? accentOnNFromEnd(w, 0) : w;
return {
masc: [
[concatPsString(base, { p: "ه", f: "a" })],
[concatPsString(base, { p: "و", f: "o" })],
],
};
}
function makeArabicPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!(word.apf && word.app)) return undefined;
const w = makePsString(word.app, word.apf);
const plural = splitPsByVarients(w);
const end = removeAccents(removeEndTick(word.apf).slice(-1));
// again typescript being dumb and not letting me use a typed key here
const value = [
plural,
plural.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
] as T.PluralInflectionSet;
// feminine words that have arabic plurals stay feminine with the plural - ie مرجع - مراجع
// but masculine words that appear feminine in the plural aren't femening with the Arabic plural - ie. نبي - انبیا
if (["i", "e", "a"].includes(end) && word.c?.includes("n. f.")) {
return { fem: value };
}
return { masc: value };
}
function makePlural(
w: T.DictionaryEntryNoFVars
):
| { plural: T.PluralInflections; bundledPlural?: T.PluralInflections }
| { arabicPlural: T.PluralInflections; bundledPlural?: T.PluralInflections }
| undefined {
function addSecondInf(
plur: T.ArrayOneOrMore<T.PsString> | T.PsString
): T.PluralInflectionSet {
if (!Array.isArray(plur)) {
return addSecondInf([plur]);
}
return [plur, plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
}
if (w.c && w.c.includes("pl.")) {
const plural = addSecondInf(makePsString(w.p, w.f));
// Typescript being dumb and not letting me do a typed variable for the key
// could try refactoring with an updated TypeScript dependency
if (w.c.includes("n. m.")) return { plural: { masc: plural } };
if (w.c.includes("n. f.")) return { plural: { fem: plural } };
}
// exception for mUláa
if (w.f === "mUláa" || w.f === "mUlaa") {
return {
plural: {
masc: [
[
{ p: "ملایان", f: "mUlaayáan" },
{ p: "ملاګان", f: "mUlaagáan" },
],
[
{ p: "ملایانو", f: "mUlaayáano" },
{ p: "ملاګانو", f: "mUlaagáano" },
],
],
},
};
}
const arabicPlural = makeArabicPlural(w);
const pashtoPlural = makePashtoPlural(w);
const bundledPlural = makeBundledPlural(w);
function addMascPluralSuffix(
animate?: boolean,
shortSquish?: boolean
): T.PluralInflectionSet {
if (shortSquish && (w.infap === undefined || w.infaf === undefined)) {
throw new Error(`no irregular inflection info for ${w.p} - ${w.ts}`);
}
const b = removeAccents(
shortSquish
? makePsString(
(w.infap as string).slice(0, -1),
(w.infaf as string).slice(0, -1)
)
: w
);
const base = hasShwaEnding(b)
? makePsString(b.p.slice(0, -1), b.f.slice(0, -1))
: b;
return addSecondInf(
concatPsString(
base,
animate && !shortSquish
? { p: "ان", f: "áan" }
: { p: "ونه", f: "óona" }
)
);
}
function addAnimUnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
const base = removeAccents(w);
return {
masc: addMascPluralSuffix(true),
fem: addSecondInf(concatPsString(base, { p: "انې", f: "áane" })),
};
}
function addEePluralSuffix(gender: T.Gender): T.PluralInflectionSet {
const b = removeAccents(w);
const base = {
p: b.p.slice(0, -1),
f: b.f.slice(0, -2),
};
const firstInf: T.ArrayOneOrMore<T.PsString> = [
concatPsString(
base,
{ p: "یان", f: "iyáan" },
gender === "fem" ? { p: "ې", f: "e" } : ""
),
];
return [
firstInf,
firstInf.flatMap(addOEnding),
// firstInf.map(addOEnding),
] as T.PluralInflectionSet;
}
function addAnimN3UnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
const b = removeAccents(w);
const base = {
p: b.p.slice(0, -1),
f: b.f.slice(0, -2),
};
return {
masc: [
[concatPsString(base, { p: "یان", f: "iyáan" })],
[concatPsString(base, { p: "یانو", f: "iyáano" })],
// TODO: or use addSecondInf method above?
],
fem: [
[concatPsString(base, { p: "یانې", f: "iyáane" })],
[concatPsString(base, { p: "یانو", f: "iyáano" })],
],
};
}
function addLongVowelSuffix(gender: "masc" | "fem"): T.PluralInflectionSet {
if (pashtoPlural) {
}
const base = removeEndTick(makePsString(w.p, w.f));
const baseWOutAccents = removeAccents(base);
const space =
w.p.slice(-1) === "ع" || w.p.slice(-1) === "ه" ? { p: " ", f: " " } : "";
if (gender === "fem") {
return addSecondInf([
concatPsString(base, space, { p: "وې", f: "we" }),
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" }),
]);
} else {
return addSecondInf([
concatPsString(baseWOutAccents, space, { p: "ګان", f: "gáan" }),
]);
}
}
// TODO: This should be possible for words like پلویان but not for words like ترورزامن 🤔
// function addFemToPashtoPlural(i: T.PluralInflections): T.UnisexSet<T.PluralInflectionSet> {
// if ("fem" in i && "masc" in i) return i;
// if (!("masc" in i)) throw new Error("bad pashto plural doesn't even have masculine");
// if (endsInConsonant(i.masc[0][0])) {
// return {
// ...i,
// fem: [
// i.masc[0].map((x) => concatPsString(x, { p: "ې", f: "e" })) as T.ArrayOneOrMore<T.PsString>,
// i.masc[0].map((x) => concatPsString(x, { p: "و", f: "o" })) as T.ArrayOneOrMore<T.PsString>,
// ],
// };
// }
// return {
// ...i,
// fem: i.masc,
// };
// }
const shortSquish = !!w.infap && !w.infap.includes("ا");
const anim = w.c?.includes("anim.");
const type = w.c?.includes("unisex")
? "unisex noun"
: w.c?.includes("n. m.")
? "masc noun"
: w.c?.includes("n. f.")
? "fem noun"
: "other";
if (pashtoPlural) {
return {
plural: pashtoPlural,
arabicPlural,
};
}
if (type === "unisex noun") {
// doesn't need to be labelled anim - because it's only with animate nouns that you get the unisex - I THINK
if (endsInConsonant(w) && !w.infap) {
return {
arabicPlural,
bundledPlural,
plural: addAnimUnisexPluralSuffix(),
};
}
if (shortSquish && !anim) {
return {
arabicPlural,
plural: { masc: addMascPluralSuffix(anim, shortSquish) },
};
}
if (endsWith([{ p: "ی", f: "áy" }, { p: "ي" }], w, true)) {
return { arabicPlural, plural: addAnimN3UnisexPluralSuffix() };
}
// usually shortSquish nouns would never have arabicPlurals -- so we don't have to worry about catching
// arabic plurals for the animat ones, right?
}
if (
type === "masc noun" &&
(shortSquish || ((endsInConsonant(w) || hasShwaEnding(w)) && !w.infap)) &&
w.p.slice(-3) !== "توب"
) {
return {
arabicPlural,
bundledPlural,
plural: {
masc: addMascPluralSuffix(anim, shortSquish),
},
};
}
if (type === "masc noun" && endsWith({ p: "ی", f: "áy" }, w, true) && anim) {
const { masc } = addAnimN3UnisexPluralSuffix();
return {
arabicPlural,
plural: {
masc,
},
};
}
if (type === "masc noun" && endsWith({ p: "ي" }, w)) {
const masc = addEePluralSuffix("masc");
return {
arabicPlural,
plural: { masc },
};
}
// TODO: What about endings in long ee / animate at inanimate
if (type === "masc noun" && endsInAaOrOo(w) && !w.infap) {
return {
arabicPlural,
plural: {
masc: addLongVowelSuffix("masc"),
},
};
}
// TODO: What about endings in long ee / animate at inanimate
if (type === "fem noun" && endsInAaOrOo(w) && !w.infap) {
return {
arabicPlural,
plural: {
fem: addLongVowelSuffix("fem"),
},
};
}
if (
type === "fem noun" &&
(endsWith({ p: "ي" }, w) || (endsWith({ p: "ۍ" }, w) && anim))
) {
return {
arabicPlural,
plural: {
fem: addEePluralSuffix("fem"),
},
};
}
if (arabicPlural) {
return { arabicPlural, plural: pashtoPlural, bundledPlural };
}
return undefined;
}
export function inflectYay( export function inflectYay(
ps: T.SingleOrLengthOpts<T.PsString> ps: T.SingleOrLengthOpts<T.PsString>
): T.SingleOrLengthOpts<T.UnisexInflections> { ): T.SingleOrLengthOpts<T.UnisexInflections> {