/** * Copyright (c) 2021 lingdocs.com * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { concatPsString, firstPhonetics, makePsString, psStringEquals, removeEndingL, yulEndingInfinitive, removeRetroflexR, inflectYey, unisexInfToObjectMatrix, complementInflects, beginsWithDirectionalPronoun, checkForOoPrefix, removeStartingTick, ensureShortWurShwaShift, choosePersInf, } from "./p-text-helpers"; import { accentOnFront, accentOnNFromEnd, removeAccents, } from "./accent-helpers"; import { inflectWord, } from "./pashto-inflector"; import { stativeAux, } from "./irregular-conjugations"; import { presentParticipleSuffix } from "./grammar-units"; import { dynamicAuxVerbs, } from "./dyn-comp-aux-verbs"; import { getPersonInflectionsKey, getPersonNumber, spaceInForm, getAuxTransitivity, chooseParticipleInflection, } from "./misc-helpers"; import * as T from "../types"; const eyEndingUnaccented: T.PsString = { p: "ی", f: "ey" }; /** * Compiles the base information (roots, stems etc.) needed in order * to make all the conjugations. This is the first step of creating * the conjugations. * * @param entry - the dictionary entry for the verb * @param complement - the dictioanry entry for the complement of the verb if compound */ export function getVerbInfo( entry: T.DictionaryEntry, complement?: T.DictionaryEntry, ): T.VerbInfo { const type = getType(entry); if (type === "transitive or grammatically transitive simple") { return { type: "transitive or grammatically transitive simple", transitive: getVerbInfo( // @ts-ignore (will have entry.c) { ...entry, c: entry.c.replace("trans./gramm. trans.", "trans.") }, ) as T.SimpleVerbInfo, grammaticallyTransitive: getVerbInfo( // @ts-ignore (will have entry.c) { ...entry, c: entry.c.replace("trans./gramm. trans.", "gramm. trans.") }, ) as T.SimpleVerbInfo, }; } const transitivity = getTransitivity(entry); if (type !== "simple") { if (!complement) { throw new Error("complement required for compound verb"); } if (type === "dynamic compound") { return getDynamicCompoundInfo(entry, complement) } if (type === "dynamic or stative compound") { return { type: "dynamic or stative compound", transitivity, dynamic: getDynamicCompoundInfo( // @ts-ignore (will have entry.c) { ...entry, c: entry.c.replace("dyn./stat.", "dyn.") }, complement, ), stative: getVerbInfo( // @ts-ignore (will have entry.c) { ...entry, c: entry.c.replace("dyn./stat.", "stat.") }, complement, ) as T.StativeCompoundVerbInfo, }; } if (type === "dynamic or generative stative compound") { return { type: "dynamic or generative stative compound", transitivity, dynamic: getDynamicCompoundInfo( // @ts-ignore (will have entry.c) { ...entry, c: entry.c.replace("gen. stat./dyn.", "dyn.") }, complement, ), stative: getGenerativeStativeCompoundVerbInfo( // @ts-ignore (will have entry.c) { ...entry, c: entry.c.replace("gen. stat./dyn.", "gen. stat.") }, complement, ), } } if (type === "generative stative compound") { return getGenerativeStativeCompoundVerbInfo(entry, complement as T.DictionaryEntry); } } const comp = complement ? ensureUnisexInflections(complement) : undefined; const root = getVerbRoots(entry, transitivity, comp); const stem = getVerbStems(entry, root, transitivity, comp); const infinitive = "mascSing" in root.imperfective ? root.imperfective.mascSing.long : root.imperfective.long; const yulEnding = yulEndingInfinitive(infinitive); const participle = getParticiple(entry, stem, infinitive, transitivity, comp); const idiosyncraticThirdMascSing = getIdiosyncraticThirdMascSing(entry); const baseInfo: T.VerbInfoBase = { transitivity, yulEnding, root, stem, participle, ...idiosyncraticThirdMascSing ? { idiosyncraticThirdMascSing, } : {}, }; if (type === "stative compound") { return { ...baseInfo, type, complement: comp as T.UnisexInflections, }; } return { ...baseInfo, type, }; } type Bases = { stem: { imperfective: T.FullForm, perfective: T.FullForm, perfectiveSplit?: T.SplitInfo, }, root: { imperfective: T.FullForm, perfective: T.FullForm, perfectiveSplit?: T.SplitInfo, }, participle: { present: T.FullForm, past: T.FullForm, }, } function getGenerativeStativeCompoundVerbInfo( entry: T.DictionaryEntry, comp: T.DictionaryEntry, forceSingular?: true, ): T.GenerativeStativeCompoundVerbInfo { const transitivity = getTransitivity(entry); const transitivityNoGrammTrans = transitivity === "grammatically transitive" ? "transitive" : transitivity; const yulEnding = null; const objComplement = getObjComplementInfo(entry, comp, forceSingular); const auxVerb = stativeAux[transitivityNoGrammTrans]; const compUsed = objComplement.plural ? objComplement.plural : makePsString( objComplement.entry.p, firstPhonetics(objComplement.entry.f), ); const bases: Bases = { stem: { imperfective: auxVerb.info.stem.imperfective, perfective: auxVerb.info.stem.perfective, }, root: { imperfective: auxVerb.info.root.imperfective, perfective: auxVerb.info.root.perfective, }, participle: { present: auxVerb.info.participle.present, past: chooseParticipleInflection( inflectYey( "mascSing" in auxVerb.info.participle.past // purely for type saftey, will not have mascSing // in a non stative compound verb /* istanbul ignore next */ ? auxVerb.info.participle.past.mascSing : auxVerb.info.participle.past ), objComplement.person, ), } } const perfectiveStem = concatPsString(compUsed, " ", bases.stem.perfective); const stem = { imperfective: concatPsString(compUsed, " ", bases.stem.imperfective), perfective: perfectiveStem, perfectiveSplit: splitPerfective(perfectiveStem, 0, 0, true), }; const perfectiveRoot = concatPsString(compUsed, " ", bases.root.perfective) as T.OptionalPersonInflections>; const root = { imperfective: concatPsString(compUsed, " ", bases.root.imperfective) as T.OptionalPersonInflections>, perfective: perfectiveRoot, perfectiveSplit: splitPerfective(perfectiveRoot, 0, 0, true), }; const participle = { present: concatPsString(compUsed, " ", auxVerb.info.participle.present), past: concatPsString(compUsed, " ", bases.participle.past), } return { type: "generative stative compound", transitivity, yulEnding, stem, root, participle, objComplement, ...objComplement.plural ? { singularForm: getGenerativeStativeCompoundVerbInfo(entry, comp, true), } : {}, }; } function getDynamicCompoundInfo(entry: T.DictionaryEntry, comp: T.DictionaryEntry, forceSingular?: true): T.DynamicCompoundVerbInfo { const transitivity = getTransitivity(entry); const yulEnding = null; const objComplement = getObjComplementInfo(entry, comp, forceSingular); const auxVerb = getDynamicAuxVerb(entry); const auxVerbInfo = getVerbInfo(auxVerb.entry, auxVerb.complement) as T.NonComboVerbInfo; const compUsed = objComplement.plural ? objComplement.plural : makePsString( objComplement.entry.p, firstPhonetics(objComplement.entry.f), ); const bases: Bases = (auxVerbInfo.type === "stative compound") ? getObjectMatchingBases(auxVerbInfo, objComplement.person) : { stem: { imperfective: auxVerbInfo.stem.imperfective, perfective: auxVerbInfo.stem.perfective, ...auxVerbInfo.stem.perfectiveSplit ? { perfectiveSplit: auxVerbInfo.stem.perfectiveSplit, } : {}, }, root: { imperfective: auxVerbInfo.root.imperfective, perfective: auxVerbInfo.root.perfective, ...auxVerbInfo.root.perfectiveSplit ? { perfectiveSplit: auxVerbInfo.root.perfectiveSplit, } : {}, }, participle: { present: auxVerbInfo.participle.present, past: chooseParticipleInflection( inflectYey( "mascSing" in auxVerbInfo.participle.past // purely for type saftey, will not have mascSing // in a non stative compound verb /* istanbul ignore next */ ? auxVerbInfo.participle.past.mascSing : auxVerbInfo.participle.past ), objComplement.person, ), } } const stem = { imperfective: concatPsString(compUsed, " ", bases.stem.imperfective), perfective: concatPsString(compUsed, " ", bases.stem.perfective), ...bases.stem.perfectiveSplit ? { perfectiveSplit: makeDynamicPerfectiveSplit(compUsed, bases.stem.perfectiveSplit), } : {}, }; const root = { imperfective: concatPsString(compUsed, " ", bases.root.imperfective) as T.OptionalPersonInflections>, perfective: concatPsString(compUsed, " ", bases.root.perfective) as T.OptionalPersonInflections>, ...bases.root.perfectiveSplit ? { perfectiveSplit: makeDynamicPerfectiveSplit(compUsed, bases.root.perfectiveSplit), } : {}, }; const participle = { present: concatPsString(compUsed, " ", auxVerbInfo.participle.present), past: concatPsString(compUsed, " ", bases.participle.past), }; const makeIntransitiveFormOfEntry = (e: T.DictionaryEntry): T.DictionaryEntry => ({ ...e, p: e.p.replace( "کول", "کېدل" ), e: e.e.replace("to do", "to become"), f: e.f.replace(/kaw[u|ú]l/, "kedul"), c: "v. intrans. dyn. comp.", }); const intransitiveFormEntry = (transitivity === "transitive" && auxVerb.entry.p === "کول") ? makeIntransitiveFormOfEntry(entry) : null; return { type: "dynamic compound", transitivity, yulEnding, stem, root, participle, objComplement, auxVerb: auxVerb.entry, ...auxVerb.complement ? { auxVerbComplement: auxVerb.complement, } : {}, ...objComplement.plural ? { singularForm: getDynamicCompoundInfo(entry, comp, true), } : {}, ...intransitiveFormEntry ? { intransitiveForm: getDynamicCompoundInfo(intransitiveFormEntry, comp), } : {}, }; } function getObjectMatchingBases(auxInfo: T.NonComboVerbInfo, person: T.Person): Bases { const key = getPersonInflectionsKey(person); const getBase = (x: T.FullForm): T.SingleOrLengthOpts => ( "mascSing" in x ? x[key] : x ); return { stem: { imperfective: getBase(auxInfo.stem.imperfective), perfective: getBase(auxInfo.stem.perfective), ...auxInfo.stem.perfectiveSplit ? { perfectiveSplit: choosePersInf(auxInfo.stem.perfectiveSplit, key), } : {}, }, root: { imperfective: getBase(auxInfo.root.imperfective), perfective: getBase(auxInfo.root.perfective), ...auxInfo.root.perfectiveSplit ? { perfectiveSplit: choosePersInf(auxInfo.root.perfectiveSplit, key), } : {}, }, participle: { present: getBase(auxInfo.participle.present), past: getBase(auxInfo.participle.past), }, }; } function getObjComplementInfo( entry: T.DictionaryEntry, complement: T.DictionaryEntry, forceSingular?: true ): T.ObjComplement { const complementInEntry = makePsString( entry.p.split(" ")[0], entry.f.split(" ")[0], ); const complementEntry: T.DictionaryEntry = { ...complement, f: firstPhonetics(complement.f) }; const usesSeperatePluralForm = !forceSingular && !psStringEquals( makePsString(complementInEntry.p, removeAccents(complementInEntry.f)), makePsString(complementEntry.p, removeAccents(complementEntry.f)), ); return { entry: complementEntry, ...usesSeperatePluralForm ? { plural: complementInEntry, } : {}, person: getComplementPerson(complement, usesSeperatePluralForm), }; } function getTransitivity(entry: T.DictionaryEntry): T.Transitivity { if (!entry.c) { throw new Error("No part of speech info"); } if (entry.c.includes("gramm. trans.")) { return "grammatically transitive"; } if (entry.c.includes("intrans.")) { return "intransitive"; } return "transitive"; } function getType(entry: T.DictionaryEntry): "simple" | "stative compound" | "dynamic compound" | "dynamic or stative compound" | "dynamic or generative stative compound" | "generative stative compound" | "transitive or grammatically transitive simple" { // error will have thrown before on the getTransitivity function if missing entry.c /* istanbul ignore if */ if (!entry.c) { throw new Error("No part of speech info"); } if (entry.c.includes(" trans./gramm. trans.")) { return "transitive or grammatically transitive simple"; } if (entry.c.includes(" gen. stat. comp.")) { return "generative stative compound"; } if (entry.c.includes(" stat. comp.")) { return "stative compound"; } if (entry.c.includes(" dyn. comp.")) { return "dynamic compound"; } if (entry.c.includes(" dyn./stat. comp.")) { return "dynamic or stative compound"; } if (entry.c.includes(" gen. stat./dyn. comp.")) { return "dynamic or generative stative compound"; } return "simple"; } function getIdiosyncraticThirdMascSing(entry: T.DictionaryEntry): T.ShortThirdPersFormSet | false { if (entry.tppp && entry.tppf) { const tpp = makePsString(entry.tppp, entry.tppf); const ooRes = addOoPrefix(tpp, entry) return { imperfective: tpp, perfective: ooRes.ps as T.PsString, }; } return false; } /** * Returns the roots (imperfective and perfective) of a given verb * * @param entry - the dictionary entry for the verb */ function getVerbRoots(entry: T.DictionaryEntry, transitivity: T.Transitivity, complement?: T.UnisexInflections): T.VerbRootSet { // each of the roots compes with a short and long version // with or without the ending ل - ul const isKawulAux = entry.p === "کول"; const shortAndLong = (root: T.PsString, perfective?: "perfective"): T.LengthOptions => { const long = perfective ? root : accentOnNFromEnd(root, yulEndingInfinitive(root) ? 1 : 0); const short = removeEndingL(root); return { long, short, ...(isKawulAux && perfective) ? { mini: removeRetroflexR(short) } : {}, }; }; const infinitive = makePsString(entry.p, firstPhonetics(entry.f)); // the imperfective root is the infinitive // TODO: CHECK THIS!! FOR PERSON INFLECTIONS?? const imperfective = ((): T.OptionalPersonInflections> => { // if stative compound if (complement && spaceInForm(infinitive)) { const comp = complementInflects(complement) ? unisexInfToObjectMatrix(complement) : complement.masc[0][0]; const t = getAuxTransitivity(transitivity); const aux = stativeAux[t].info.root.imperfective return concatPsString(comp, " ", aux) as T.OptionalPersonInflections>; } return shortAndLong(infinitive); })(); const { perfective, pSplit, fSplit } = ((): { perfective: T.OptionalPersonInflections> pSplit: number, fSplit: number, } => { // if stative compound if (complement) { const comp = complementInflects(complement) ? unisexInfToObjectMatrix(complement) : complement.masc[0][0]; const t = getAuxTransitivity(transitivity); const aux = stativeAux[t].info.root.perfective return { pSplit: 0, fSplit: 0, perfective: concatPsString(comp, " ", aux) as T.OptionalPersonInflections>, }; } // the perfective root is // - the special perfective root if it exists, or if (entry.prp && entry.prf) { const perfective = shortAndLong(makePsString(entry.prp, entry.prf), "perfective"); const hasOoPrefix = checkForOoPrefix(perfective.long); return { perfective, pSplit: entry.separationAtP || (hasOoPrefix ? 1 : 0), fSplit: entry.separationAtF || (hasOoPrefix ? 2 : 0), }; } // - the infinitive prefixed with oo const { ps, pSplit, fSplit } = addOoPrefix(infinitive, entry); return { perfective: shortAndLong(ps as T.PsString, "perfective"), pSplit, fSplit, }; })(); const perfectiveSplit = splitPerfective(perfective, pSplit, fSplit, !!complement); return { imperfective, perfective, perfectiveSplit, }; } /** * Returns the stems (imperfective and perfective) of a given verb * * @param entry - the dictionary entry for the verb */ function getVerbStems(entry: T.DictionaryEntry, root: T.VerbRootSet, transitivity: T.Transitivity, complement?: T.UnisexInflections): T.VerbStemSet { function isRegEdulTransitive(): boolean { /* istanbul ignore next */ if ("mascSing" in root.imperfective) { return false; } const lastPCharacters = root.imperfective.long.p.slice(-3); return ( // @ts-ignore - will always have a entry.c if we get to this point (entry.c.includes("intrans.")) && (lastPCharacters === "ېدل") ); } function makeIntransImperfectiveStem() { const long = { // @ts-ignore p: root.imperfective.long.p.slice(0, -2) + "ږ", // @ts-ignore f: root.imperfective.long.f.slice(0, -4) + "éG", }; if (entry.shortIntrans) { const short = makePsString( long.p.slice(0, -2), long.f.slice(0, -2), ); return { long, short }; } return long; } const imperfective = ((): T.FullForm => { const auxTransitivity = getAuxTransitivity(transitivity); if (complement && spaceInForm(root.imperfective)) { const comp = complementInflects(complement) ? unisexInfToObjectMatrix(complement) : complement.masc[0][0]; return concatPsString( comp, " ", stativeAux[auxTransitivity].info.stem.imperfective as T.PsString, ); } // the imperfective stem is // - the special present stem if it exists, or if (entry.psp && entry.psf) { return makePsString(entry.psp, entry.psf); } // - the eG form (and short form possibly) if regular transitive, or if (isRegEdulTransitive()) { return makeIntransImperfectiveStem() } // - the infinitive minus ل return "mascSing" in root.imperfective ? root.imperfective.mascSing.short : root.imperfective.short; })(); const { perfective, pSplit, fSplit } = ((): { perfective: T.FullForm, pSplit: number, fSplit: number } => { if (complement) { const comp = complementInflects(complement) ? unisexInfToObjectMatrix(complement) : complement.masc[0][0]; const t = getAuxTransitivity(transitivity); return { perfective: concatPsString(comp, " ", stativeAux[t].info.stem.perfective), pSplit: 0, fSplit: 0, }; } // the perfective stem is // - the special subjunctive stem if it exists, or if (entry.ssp && entry.ssf) { const isKawulAux = entry.p === "کول"; const perfective = makePsString(entry.ssp, entry.ssf); const hasOoPrefix = checkForOoPrefix(perfective); if (isKawulAux) { return { perfective: { long: perfective, short: removeRetroflexR(perfective), }, pSplit: hasOoPrefix ? 1 : 0, fSplit: hasOoPrefix ? 2 : 0, }; } return { perfective, pSplit: entry.separationAtP || (hasOoPrefix ? 1 : 0), fSplit: entry.separationAtF || (hasOoPrefix ? 2 : 0), }; } // - the perfective stem prefixed with oo (if possible) const res = addOoPrefix(imperfective as T.SingleOrLengthOpts, entry); return { perfective: res.ps, pSplit: res.pSplit, fSplit: res.fSplit, }; })(); const perfectiveSplit = splitPerfective(perfective, pSplit, fSplit, !!complement); return { imperfective, perfective, ...perfectiveSplit ? { perfectiveSplit, } : {}, }; } function splitPerfective(perfective: T.FullForm, pSplit: number, fSplit: number, isStativeComp: boolean): T.SplitInfo | undefined { if (!isStativeComp && pSplit === 0 && fSplit === 0) { return undefined; } if ("mascSing" in perfective) { // @ts-ignore return { mascSing: splitPerfective(perfective.mascSing, pSplit, fSplit, isStativeComp), mascPlur: splitPerfective(perfective.mascPlur, pSplit, fSplit, isStativeComp), femSing: splitPerfective(perfective.femSing, pSplit, fSplit, isStativeComp), femPlur: splitPerfective(perfective.femPlur, pSplit, fSplit, isStativeComp), }; } if ("long" in perfective) { return { // @ts-ignore short: splitPerfective(perfective.short, pSplit, fSplit, isStativeComp) as [T.PsString, T.PsString], long: splitPerfective(perfective.long, pSplit, fSplit, isStativeComp) as [T.PsString, T.PsString], ..."mini" in perfective ? { // @ts-ignore mini: splitPerfective(perfective.mini, pSplit, fSplit, isStativeComp) as [T.PsString, T.PsString], } : {}, }; } if (isStativeComp) { // if it's a stative, split whatever is before the aux verb with a trailing space const pWords = perfective.p.split(" "); const fWords = perfective.f.split(" "); const before = makePsString( pWords.slice(0, -1).join(" ") + " ", fWords.slice(0, -1).join(" ") + " ", ); const after = makePsString( pWords[pWords.length - 1], fWords[fWords.length - 1], ); return [before, after]; } const pBeg = perfective.p.slice(0, pSplit); const before = makePsString( pBeg.endsWith(" ") ? pBeg.slice(0, -1) : pBeg, perfective.f.slice(0, fSplit).replace("`", ""), ); const beforeAccented = beginsWithDirectionalPronoun(before) ? before : accentOnFront(before); const after = makePsString(perfective.p.slice(pSplit), removeAccents(removeStartingTick(perfective.f.slice(fSplit)))); return [beforeAccented, after] as T.SplitInfo; } function getParticiple(entry: T.DictionaryEntry, stem: T.VerbStemSet, infinitive: T.PsString, transitivity: T.Transitivity, complement?: T.UnisexInflections): T.ParticipleSet { const shortParticipleRoot = ((): T.PsString | null => { const shortenableEndings = ["ښتل", "ستل", "وتل"]; // special thing for اېښودل - پرېښودل if (infinitive.p.slice(-4) === "ښودل" && infinitive.p.length > 4 && infinitive.p !== "کېښودل" && infinitive.p !== "کښېښودل") { return makePsString( infinitive.p.slice(0, -3), infinitive.f.slice(0, -4), ); } const isOrulShortenable = ["وړل", "راوړل", "وروړل"].includes(infinitive.p); if (isOrulShortenable || (shortenableEndings.includes(infinitive.p.slice(-3)) && infinitive.p.slice(-4) !== "استل")) { return makePsString( infinitive.p.slice(0, -1), infinitive.f.slice(0, -2), ) } return null; })(); const makeSepStativePart = (complement: T.UnisexInflections, tense: "present" | "past"): T.FullForm => { const compInflects = complementInflects(complement); const comp = compInflects ? unisexInfToObjectMatrix(complement) : complement.masc[0][0]; const aux = stativeAux[auxTransitivity].info.participle[tense] as T.PsString; return concatPsString( comp, " ", compInflects ? unisexInfToObjectMatrix(inflectYey(aux) as T.UnisexInflections) : aux, ); }; const accentPastPart = (pp: T.PsString): T.PsString => ( accentOnNFromEnd(pp, yulEndingInfinitive(infinitive) ? 2 : 1) ); const auxTransitivity = getAuxTransitivity(transitivity); const past = (entry.pprtp && entry.pprtf) ? makePsString(entry.pprtp, entry.pprtf) : complement ? makeSepStativePart(complement, "past") : shortParticipleRoot ? { short: accentPastPart( concatPsString(ensureShortWurShwaShift(shortParticipleRoot), eyEndingUnaccented), ), long: accentPastPart( concatPsString(infinitive, eyEndingUnaccented), ), } : accentPastPart(concatPsString(infinitive, eyEndingUnaccented)); // TODO: make this into a rule? const shortImperfectiveRoot = (entry.p === "وتل") ? { p: "وتل", f: "watl" } : removeEndingL(infinitive); const accentPresPart = (pp: T.PsString): T.PsString => ( accentOnNFromEnd(pp, 1) ); const present = (complement && spaceInForm(infinitive)) ? makeSepStativePart(complement, "present") : (shortParticipleRoot && (!psStringEquals(shortParticipleRoot, shortImperfectiveRoot) || (entry.p === "وتل"))) ? { short: accentPresPart( concatPsString(shortParticipleRoot, presentParticipleSuffix), ), long: accentPresPart( concatPsString(shortImperfectiveRoot, presentParticipleSuffix), ), } : ("short" in stem.imperfective && entry.shortIntrans && entry.p !== "اوسېدل") ? { short: accentPresPart( concatPsString(stem.imperfective.short, presentParticipleSuffix), ), long: accentPresPart( concatPsString(shortImperfectiveRoot, presentParticipleSuffix), ), } : accentPresPart( concatPsString( shortImperfectiveRoot.p === "وړ" ? ensureShortWurShwaShift(shortImperfectiveRoot) : shortImperfectiveRoot, presentParticipleSuffix, ), ); return { past, present, }; } /** * Adds a perfective و - oo prefix to a verb * * @param entry - the dictionary entry for the verb */ function addOoPrefix( s: T.SingleOrLengthOpts, entry: T.DictionaryEntry, ): { ps: T.SingleOrLengthOpts, pSplit: number, fSplit: number } { let pSplit = 0; let fSplit = 0; // A bit of side effects in this function... sorry! function attachOo(ps: T.PsString): T.PsString; function attachOo(ps: T.SingleOrLengthOpts): T.SingleOrLengthOpts; function attachOo(ps: T.SingleOrLengthOpts): T.SingleOrLengthOpts { if ("long" in ps) { return { short: attachOo(ps.short), long: attachOo(ps.long), }; } if (entry.separationAtP && entry.separationAtF) { pSplit = entry.separationAtP; fSplit = entry.separationAtF; return ps; } if (entry.noOo) { return ps; } if (entry.sepOo) { pSplit = 2; fSplit = 3; return { p: `و ${ps.p}`, f: `oo\`${ps.f}`, }; } const startsWithA = ps.p.charAt(0) === "ا" && ps.f.charAt(0) === "a"; if (startsWithA) { pSplit = 2; fSplit = 3; return { p: `و${ps.p}`, f: `wa${ps.f}`, }; } const startsWithAa = ["آ", "ا"].includes(ps.p.charAt(0)) && ps.f.slice(0, 2) === "aa"; if (startsWithAa) { pSplit = 2; fSplit = 3; return { p: `وا${ps.p.substr(1)}`, f: `w${ps.f}`, }; } const startsWithOo = ["óo", "oo"].includes(ps.f.slice(0, 2)); if (startsWithOo) { pSplit = 1; fSplit = 2; return { p: `و${ps.p}`, f: `wU${ps.f}`, }; } const startsWithEe = ["ée", "ee"].includes(ps.f.slice(0, 2)) && ps.p.slice(0, 2) === "ای"; const startsWithE = ["e", "é"].includes(ps.f[0]) && ps.p.slice(0, 2) === "اې"; if (startsWithEe || startsWithE) { pSplit = 2; fSplit = startsWithEe ? 3 : 2; return { p: `و${ps.p.slice(1)}`, f: `w${ps.f}`, }; } const startsWithO = ["ó", "o"].includes(ps.f[0]) && ps.p.slice(0, 2) === "او"; if (startsWithO) { pSplit = 1; fSplit = 2; return { p: `و${ps.p}`, f: `oo\`${ps.f}`, }; } pSplit = 1; fSplit = 2; return { p: `و${ps.p}`, f: `oo${ps.f}`, }; } const attachedOo = attachOo(s); return { ps: accentOnFront(attachedOo), pSplit: entry.separationAtP ? entry.separationAtP : pSplit, fSplit: entry.separationAtF ? entry.separationAtF : fSplit, }; } function ensureUnisexInflections(complement: T.DictionaryEntry): T.UnisexInflections { const inflected = inflectWord(complement); const isUnisex = inflected && (("masc" in inflected) && ("fem" in inflected)); if (isUnisex) { return inflected as T.UnisexInflections; } const word = makePsString(complement.p, firstPhonetics(complement.f)); return { masc: [ [word], [word], [word], ], fem: [ [word], [word], [word], ], }; } function getDynamicAuxVerb(entry: T.DictionaryEntry): { entry: T.DictionaryEntry, complement?: T.DictionaryEntry, } { const auxWord = entry.p.trim().split(" ").slice(-1)[0]; const auxWordResult = dynamicAuxVerbs.find((a) => a.entry.p === auxWord); /* istanbul ignore next */ if (!auxWordResult) { throw new Error("unknown auxilary verb for dynamic compound"); } return { entry: auxWordResult.entry, ...("complement" in auxWordResult) ? { complement: auxWordResult.complement, } : {}, }; } function getComplementPerson( complement: T.DictionaryEntry, usesSeperatePluralForm?: boolean, ): T.Person { const number = ( (complement.c && complement.c.includes("pl.")) || usesSeperatePluralForm ) ? "plural" : "singular"; const gender = (complement.c && complement.c.includes("n. m.")) ? "masc" : "fem"; return getPersonNumber(gender, number); } function makeDynamicPerfectiveSplit(comp: T.PsString, auxSplit: T.SplitInfo): T.SplitInfo { if ("mascSing" in auxSplit) { return { mascSing: makeDynamicPerfectiveSplit(comp, auxSplit.mascSing) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, mascPlur: makeDynamicPerfectiveSplit(comp, auxSplit.mascPlur) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, femSing: makeDynamicPerfectiveSplit(comp, auxSplit.femSing) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, femPlur: makeDynamicPerfectiveSplit(comp, auxSplit.femPlur) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, }; } if ("long" in auxSplit) { return { long: makeDynamicPerfectiveSplit(comp, auxSplit.long) as [T.PsString, T.PsString], short: makeDynamicPerfectiveSplit(comp, auxSplit.short) as [T.PsString, T.PsString], ...auxSplit.mini ? { mini: makeDynamicPerfectiveSplit(comp, auxSplit.mini) as [T.PsString, T.PsString], } : {}, }; } return [ concatPsString(comp, " ", auxSplit[0]), auxSplit[1], ]; }