/** * 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. * */ export type PsStringField = "p" | "f"; export type PsString = { [k in PsStringField]: string; } & { e?: string; }; export type PsJSX = { p: JSX.Element, f: JSX.Element, e?: JSX.Element | string }; export type DictionaryInfo = { title: string; license: string; release: number; numberOfEntries: number; url: string; infoUrl: string; } export type Dictionary = { info: DictionaryInfo; entries: DictionaryEntry[]; } // TODO: BETTER TYPING OF THIS WITH RECORD TO MAKE SURE THAT THE FIELDS LINE UP export type DictionaryEntry = { // BASE REQUIRED INFO /** timestamp - used for word id */ ts: number; /** Pashto alphabetical index */ i: number; /** entry in Pashto */ p: string; /** entry in Phonetics */ f: string; /** entry in simplified phonetics */ g: string; /** entry in English */ e: string; // PART OF SPEECH AND LINK INFO /** part of speech info */ c?: string; /** link - timestamp of related word */ l?: number; // INFLECTION INFO /** first masculine irregular inflection in Pashto */ infap?: string; /** first masculine irregular inflection in Phonetics */ infaf?: string; /** base for second masculine / feminine irregular inflection in Pashto */ infbp?: string; /** base for second masculine / feminine irregular inflection in Phonetics */ infbf?: string; /** entry does not inflect? */ noInf?: boolean; // PLURAL INFO /** Arabic plural in Pashto */ app?: string; /** Arabic plural in Phonetics */ apf?: string; /** Pashto irregular plural in Pashto */ ppp?: string; /** Pashto irregular plural in phonetics */ ppf?: string; // VERB INFO /** imperfective (present) stem in Pashto */ psp?: string; /** imperfective (present) stem in Phonetics */ psf?: string; /** perfective (subjunctive) stem in Pashto */ ssp?: string; /** perfective (subjunctive) stem in Phonetics */ ssf?: string; /** perfective root in Pashto */ prp?: string; /** perfective root in Phonetics */ prf?: string; /** past participle in Pashto */ pprtp?: string; /** past participle in Phonetics */ pprtf?: string; /** The idiosyncratic third person singular masc. short past in Pashto */ tppp?: string; /** The idiosyncratic third person singular masc. short past in Phonetics */ tppf?: string; /** intransitive short version is available like ګرځېږي and ګرځي */ shortIntrans?: boolean; /** does not take a و - oo perfective verb prefix? */ noOo?: boolean; /** takes a seperate و - oo perfective verb prefix? */ sepOo?: boolean; /** Pashto separation point for seperable verbs */ separationAtP?: number; /** Phonetics separation point for seperable verbs */ separationAtF?: number; // PHONETICS - PASHTO - DIACRITICS INFO /** Is an exception to the rules of diacritics for Pashto/Phonetics */ diacExcept?: boolean; /** the English conjugations of a verb comma seperated set of 5 ie. "see,sees,seeing,saw,seen" or single word ie. "walk" if regular - or the english singular version of a noun */ ec?: string; /** the English partical of a English phrasal verb - or the english irregular plural of a noun */ ep?: string; } export type DictionaryEntryNoFVars = DictionaryEntry & { __brand: "name for a dictionary entry with all the phonetics variations removed" }; export type PsStringNoFVars = PsString & { __brand: "name for a ps string with all the phonetics variations removed" }; export type FStringNoFVars = string & { __brand: "name for a phonetics string with all the phonetics variations removed" }; export type DictionaryEntryTextField = "p" | "f" | "e" | "c" | "infap" | "infaf" | "infbp" | "infbf" | "app" | "apf" | "ppp" | "ppf" | "psp" | "psf" | "ssp" | "ssf" | "prp" | "prf" | "pprtp" | "pprtf" | "tppp" | "tppf" | "ec" | "ep"; export type DictionaryEntryBooleanField = "noInf" | "shortIntrans" | "noOo" | "sepOo" | "diacExcept"; export type DictionaryEntryNumberField = "ts" | "i" | "l" | "separationAtP" | "separationAtF"; export type DictionaryEntryField = DictionaryEntryTextField | DictionaryEntryBooleanField | DictionaryEntryNumberField; export type DictionaryEntryError = { errors: string[], p: string, f: string, e: string, ts: number, erroneousFields: DictionaryEntryField[], } export type Spelling = "Afghan" | "Pakistani ی" | "Pakistani ي"; export type TextOptions = { pTextSize: "normal" | "larger" | "largest"; phonetics: "lingdocs" | "ipa" | "alalc" | "none"; dialect: "standard" | "peshawer" | "southern"; spelling: Spelling; diacritics: boolean; } export enum Person { FirstSingMale = 0, FirstSingFemale, SecondSingMale, SecondSingFemale, ThirdSingMale, ThirdSingFemale, FirstPlurMale, FirstPlurFemale, SecondPlurMale, SecondPlurFemale, ThirdPlurMale, ThirdPlurFemale, } // INPUT // all information to be passed to conjugating functions export type VerbInfoBase = { entry: VerbEntry, transitivity: Transitivity; yulEnding: boolean | null; stem: VerbStemSet; root: VerbRootSet; participle: ParticipleSet; idiosyncraticThirdMascSing?: ShortThirdPersFormSet; } export type PassiveRootsStems = { stem: VerbStemSet, root: VerbRootSet, participle: { past: FullForm, }, } export type SimpleVerbInfo = VerbInfoBase & { type: "simple"; } export type StativeCompoundVerbInfo = VerbInfoBase & { type: "stative compound" complement: UnisexInflections; } export type GenerativeStativeCompoundVerbInfo = VerbInfoBase & { type: "generative stative compound" objComplement: ObjComplement, singularForm?: GenerativeStativeCompoundVerbInfo, // TODO: Could add intransitive form 🤪 } export type DynamicCompoundVerbInfo = VerbInfoBase & { type: "dynamic compound"; objComplement: ObjComplement; auxVerb: DictionaryEntry; auxVerbComplement?: DictionaryEntry; singularForm?: DynamicCompoundVerbInfo; intransitiveForm?: DynamicCompoundVerbInfo; } export type ObjComplement = { entry: DictionaryEntry; plural?: PsString; person: Person; } export type NonComboVerbInfo = SimpleVerbInfo | StativeCompoundVerbInfo | DynamicCompoundVerbInfo | GenerativeStativeCompoundVerbInfo; export type VerbInfo = NonComboVerbInfo | { type: "transitive or grammatically transitive simple"; transitive: SimpleVerbInfo; grammaticallyTransitive: SimpleVerbInfo; } | { type: "dynamic or stative compound"; transitivity: Transitivity; stative: StativeCompoundVerbInfo; dynamic: DynamicCompoundVerbInfo; } | { type: "dynamic or generative stative compound"; transitivity: Transitivity; stative: GenerativeStativeCompoundVerbInfo; dynamic: DynamicCompoundVerbInfo; } export type Transitivity = "transitive" | "intransitive" | "grammatically transitive"; export type SplitInfo = FullForm<[PsString, PsString]>; export type VerbStemSet = { perfective: FullForm; imperfective: FullForm; perfectiveSplit?: SplitInfo; } export type VerbRootSet = { perfective: OptionalPersonInflections>; imperfective: OptionalPersonInflections>; perfectiveSplit?: SplitInfo; } export type ParticipleSet = { present: FullForm, past: FullForm, } export type ShortThirdPersFormSet = { [K in Aspect]: PsString; } export type Aspect = "perfective" | "imperfective"; export type Length = "short" | "long" | "mini"; export type LengthOptions = { long: T; short: T; mini?: T; } export type PersonInflectionsField = "mascSing" | "mascPlur" | "femSing" | "femPlur"; export type OptionalPersonInflections = { [K in PersonInflectionsField]: T; } | T; export type SingleOrLengthOpts = T | LengthOptions; export type VerbConjugation = { info: NonComboVerbInfo, // INFINITIVE = info.root.imperfective.long imperfective: AspectContent; // --╖ ASPECT = "imperfective" perfective: AspectContent; // --╜ ASPECT = "perfective" hypothetical: VerbForm; // INFINITIVE - ul + aay participle: ParticipleContent; perfect: PerfectContent; // PPART = PAST PARTICIPLE (plus spectial short forms) passive?: PassiveContent; // only on transitive verbs singularForm?: VerbConjugation; } export type VerbOutput = VerbConjugation | { info: VerbInfo, stative: VerbConjugation, dynamic: VerbConjugation, } | { info: VerbInfo, transitive: VerbConjugation, grammaticallyTransitive: VerbConjugation, }; export type PassiveContent = { imperfective: AspectContentPassive // --╖ ASPECT = "imperfective" perfective: AspectContentPassive // --╜ ASPECT = "perfective" perfect: PerfectContent; // PPART INFINITIVE + kedulStat perfect.pastParticiple // TODO: ADD PARTICIPLE } // ASPECT -> AspectContent export type AspectContent = { // STEM = info.stem[ASPECT] // ROOT = info.root[ASPECT] nonImperative: VerbForm; // STEM + pres ending future: VerbForm; // به + this.nonImperative imperative: ImperativeForm; // STEM + imperative ending past: VerbForm; // ROOT + past ending habitualPast: VerbForm; // ba + past modal: ModalContent; } // ASPECT -> AspectContentPssive export type AspectContentPassive = Omit & { imperative: undefined, }; export type ModalContent = { nonImperative: VerbForm; // ROOT + ey + kedulStat.perfective.nonImperative future: VerbForm; // به + this.nonImperative past: VerbForm; // ROOT + ey + kedulStat.perfective.past habitualPast: VerbForm; // ba + past hypotheticalPast: VerbForm; // ROOT + ey + shw + ey } export type ParticipleForm = SingleOrLengthOpts | SingleOrLengthOpts; export type ParticipleContent = { past: SingleOrLengthOpts | SingleOrLengthOpts, // TODO: Should this ever have an object matrix?? present: SingleOrLengthOpts, } // PPART -> PerfectContent export type PerfectContent = { halfPerfect: VerbForm; // PPART past: VerbForm; // PPART + equative.past present: VerbForm; // PPART + equative.prest habitual: VerbForm; // PPART + equative.habit subjunctive: VerbForm; // PPART + equative.subj future: VerbForm; // ba + PPART + equative.subj affirmational: VerbForm; // ba + PPART + equative.past pastSubjunctiveHypothetical: VerbForm; // PPART + waay } // Plain, 1st, and 2nd Inflection export type InflectionSet = ArrayFixed, 3>; // Plural and Second Inflection export type PluralInflectionSet = ArrayFixed, 2> export type Gender = "masc" | "fem"; export type UnisexSet = Record; export type GenderedSet = UnisexSet | Omit, "fem"> | Omit, "masc">; export type UnisexInflections = UnisexSet; export type Inflections = GenderedSet; export type PluralInflections = GenderedSet; export type InflectorOutput = { arabicPlural: PluralInflections, plural?: PluralInflections, inflections?: Inflections, } | { plural: PluralInflections, arabicPlural?: PluralInflections, inflections?: Inflections, } | { inflections: Inflections, } | false; export type PersonLine = [ /** singular form of person */ ArrayOneOrMore, /** plural form of person */ ArrayOneOrMore, ]; /** * The basic form of a verb conjugation * Each line representing one person (singular and plural) * 1st Person Male, 1st Person Female, 2nd Person Male etc... */ export type VerbBlock = [ PersonLine, // 1st Person Male PersonLine, // 1st Person Female PersonLine, // 2nd Person Male PersonLine, // 2nd Person Female PersonLine, // 3rd Person Male PersonLine, // 3rd Person Female ]; export type EnglishBlock = [ [string, string], [string, string], [string, string], [string, string], [string, string], [string, string], ]; export type ImperativeBlock = [ PersonLine, // 2nd Person Male PersonLine, // 2nd Person Female ]; export type FullForm = OptionalPersonInflections>; export type VerbForm = FullForm; export type ImperativeForm = FullForm; export type SentenceForm = SingleOrLengthOpts>; export interface ArrayFixed extends Array { 0: T; length: L; } export type Wrapper = T & { __brand: "wrapped" }; export type ArrayOneOrMore = { 0: T } & Array export type RootsOrStemsToHighlight = ("imperfective root" | "perfective root" | "imperfective stem" | "perfective stem" | "past participle")[]; /* i.e. ec: ["take", "takes", "taking", "took", "taken"], ep: out */ export type EnglishVerbConjugationEc = [string, string, string, string, string]; export type EnglishVerbConjugation = { ec: EnglishVerbConjugationEc, ep: string | undefined, }; export type DisplayFormItem = DisplayForm | DisplayFormSubgroup | DisplayFormForSentence; export type EnglishBuilder = (subject: Person, ec: EnglishVerbConjugationEc, neg: boolean) => string[]; export type DisplayForm = { label: string, aspect?: Aspect, form: VerbForm | ImperativeForm | ParticipleForm | SentenceForm, advanced?: boolean, englishBuilder?: EnglishBuilder, formula: React.ReactNode, explanation: React.ReactNode, sentence?: boolean, passive?: boolean, past?: boolean, reorderWithNegative?: boolean, } export type DisplayFormForSentence = Omit & { form: VerbForm, secondPronounNeeded?: boolean, } // { // label: string, // aspect?: Aspect, // form: VerbForm, // advanced?: boolean, // englishBuilder?: EnglishBuilder, // formula: React.ReactNode, // secondPronounNeeded?: boolean, // explanation: React.ReactNode, // sentence?: boolean, // passive?: boolean, // past?: boolean, // reorderWithNegative?: boolean, // } export type DisplayFormSubgroup = { label: string, subgroup: string, advanced?: boolean, content: DisplayFormItem[], } export type AayTail = "ey" | "aay"; export type NounEntry = DictionaryEntry & { c: string } & { __brand: "a noun entry" }; export type MascNounEntry = NounEntry & { __brand2: "a masc noun entry" }; export type FemNounEntry = NounEntry & { __brand2: "a fem noun entry" }; export type AnimNounEntry = NounEntry & { __brand3: "a anim noun entry" }; export type UnisexNounEntry = MascNounEntry & { __brand3: "a unisex noun entry" }; export type UnisexAnimNounEntry = UnisexNounEntry & { __brand4: "an anim unisex noun entry" }; export type AdverbEntry = DictionaryEntry & { c: string } & { __brand: "an adverb entry" }; export type LocativeAdverbEntry = AdverbEntry & { __brand2: "a locative adverb entry" }; export type AdjectiveEntry = DictionaryEntry & { c: string } & { __brand: "an adjective entry" }; export type VerbDictionaryEntry = DictionaryEntry & { __brand: "a verb entry" }; export type VerbEntry = { entry: VerbDictionaryEntry, // TODO: the compliment could also be typed? Maybe? complement?: DictionaryEntry, }; export type SingularEntry = T & { __brand7: "a singular noun - as opposed to an always plural noun" }; export type PluralNounEntry = T & { __brand7: "a noun that is always plural" }; export type Pattern1Entry = T & { __brand3: "basic inflection pattern" }; export type Pattern2Entry = T & { __brand3: "ending in unstressed ی pattern" }; export type Pattern3Entry = T & { __brand3: "ending in stressed ی pattern" }; export type Pattern4Entry = T & { __brand3: "Pashtoon pattern" }; export type Pattern5Entry = T & { __brand3: "short squish pattern" }; export type Pattern6FemEntry = T & { __brand3: "non anim. ending in ي" }; export type NonInflecting = T & { __brand3: "non-inflecting" }; export type Entry = NounEntry | AdjectiveEntry | AdverbEntry | VerbEntry; export type RenderedVPSBlock = (Rendered | Rendered | Rendered); // TODO: make this Rendered with recursive Rendered<> export type VPRendered = { type: "VPRendered", king: "subject" | "object", servant: "subject" | "object" | undefined, isPast: boolean, isTransitive: boolean, isCompound: "stative" | "dynamic" | false, blocks: RenderedVPSBlock[], verb: VerbRendered, englishBase?: string[], form: FormVersion, whatsAdjustable: "both" | "king" | "servant", } export type VerbTense = "presentVerb" | "subjunctiveVerb" | "perfectiveFuture" | "imperfectiveFuture" | "perfectivePast" | "imperfectivePast" | "habitualPerfectivePast" | "habitualImperfectivePast"; export type NounNumber = "singular" | "plural"; export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive"; export type PerfectTense = `${EquativeTense}Perfect`; export type ModalTense = `${VerbTense}Modal`; export type ImperativeTense = `${Aspect}Imperative`; export type Tense = EquativeTense | VerbTense | PerfectTense | ModalTense | ImperativeTense; export type SubjectSelection = { type: "subjectSelection", selection: NPSelection | undefined, }; export type ObjectSelection = { type: "objectSelection", selection: NPSelection | ObjectNP | undefined, }; export type SubjectSelectionComplete = { type: "subjectSelection", selection: NPSelection, }; export type ObjectSelectionComplete = { type: "objectSelection", selection: NPSelection | ObjectNP, }; export type VPSelectionState = { blocks: VPSBlock[] verb: VerbSelection, form: FormVersion, }; export type VPSelectionComplete = { blocks: VPSBlockComplete[] verb: VerbSelectionComplete, form: FormVersion, }; export type VerbSelectionComplete = Omit & { tense: VerbTense | PerfectTense | ModalTense | ImperativeTense, } export type VerbSelection = { type: "verb", verb: VerbEntry, dynAuxVerb?: VerbEntry, transitivity: Transitivity, canChangeTransitivity: boolean, canChangeStatDyn: boolean, isCompound: "stative" | "dynamic" | false, voice: "active" | "passive", canChangeVoice: boolean, negative: boolean, verbTense: VerbTense, perfectTense: PerfectTense, imperativeTense: ImperativeTense, tenseCategory: "basic" | "modal" | "perfect" | "imperative", }; export type VerbRendered = Omit & { ps: { head: PsString | undefined, rest: SingleOrLengthOpts< PsString[] >, }, hasBa: boolean, person: Person, }; export type VerbObject = // transitive verb - object not selected yet undefined | // transitive verb - obect selected NPSelection | // grammatically transitive verb with unspoken 3rd pers masc plur entity // or intransitive "none" ObjectNP; export type NPSelection = { type: "NP", selection: NounSelection | PronounSelection | ParticipleSelection, }; export type APSelection = { type: "AP", selection: AdverbSelection | SandwichSelection, }; export type NPType = "noun" | "pronoun" | "participle"; export type ObjectNP = "none" | Person.ThirdPlurMale; export type PossesorSelection = { shrunken: boolean, np: NPSelection, } // TODO require/import Person and PsString export type NounSelection = { type: "noun", entry: NounEntry, gender: Gender, genderCanChange: boolean, number: NounNumber, numberCanChange: boolean, dynamicComplement?: boolean, adjectives: AdjectiveSelection[], possesor: undefined | PossesorSelection, }; export type AdverbSelection = { type: "adverb", entry: AdverbEntry, } export type AdjectiveSelection = { type: "adjective", entry: AdjectiveEntry, sandwich: SandwichSelection | undefined, } export type LocativeAdverbSelection = { type: "loc. adv.", entry: LocativeAdverbEntry, } // take an argument for subject/object in rendering English export type PronounSelection = { type: "pronoun", person: Person, distance: "near" | "far", }; export type ParticipleSelection = { type: "participle", verb: VerbEntry, possesor: undefined | PossesorSelection, }; // not object // type Primitive = string | Function | number | boolean | Symbol | undefined | null; // If T has key K ("user"), replace it export type ReplaceKey = T extends Record ? (Omit & Record) : T; export type FormVersion = { removeKing: boolean, shrinkServant: boolean }; // TODO: rendered should would for rendering T.PossesorSelection etc // look recursively down on something export type RenderedPossesorSelection = { np: Rendered, shrunken: boolean, }; export type Rendered< T extends | NPSelection | NPSelection["selection"] | APSelection | APSelection["selection"] | EqCompSelection | EqCompSelection["selection"] | SubjectSelectionComplete | ObjectSelectionComplete | AdjectiveSelection | SandwichSelection > = T extends NPSelection ? { type: "NP", selection: Rendered } : T extends APSelection ? { type: "AP", selection: Rendered } : T extends EqCompSelection ? { type: "EQComp", selection: Rendered } : T extends SandwichSelection ? Omit, "inside"> & { inside: Rendered, } : T extends AdverbSelection ? { type: "adverb", entry: AdverbEntry, ps: PsString[], e?: string, } : T extends AdjectiveSelection ? { type: "adjective", entry: AdjectiveEntry, ps: PsString[], e?: string, sandwich: Rendered> | undefined, inflected: boolean, person: Person, } : T extends SubjectSelectionComplete ? { type: "subjectSelection", selection: Rendered, } : T extends ObjectSelectionComplete ? { type: "objectSelection", selection: Rendered | Person.ThirdPlurMale | "none", } : ReplaceKey< Omit, "e", string > & { ps: PsString[], e?: string, inflected: boolean, person: Person, role: "king" | "servant" | "none", // TODO: better recursive thing adjectives?: Rendered[], possesor?: { shrunken: boolean, np: Rendered, }, }; export type EPSelectionState = { blocks: EPSBlock[], predicate: { type: "NP" | "Complement", NP: NPSelection | undefined, Complement: EqCompSelection | undefined, }, equative: EquativeSelection, omitSubject: boolean, }; export type EPSBlock = { key: number, block: SubjectSelection | APSelection | undefined, }; export type EPSBlockComplete = { key: number, block: SubjectSelectionComplete | APSelection, }; export type VPSBlock = { key: number, // TODO: confusing use of APSelection / should be like APSelection s APSelection complete like the others block: SubjectSelection | ObjectSelection | (APSelection | undefined), }; export type VPSBlockComplete = { key: number, block: SubjectSelectionComplete | ObjectSelectionComplete | APSelection, }; export type EPSelectionComplete = Omit & { blocks: EPSBlockComplete[], predicate: { type: "NP", selection: NPSelection, } | { type: "Complement", selection: EqCompSelection, }, omitSubject: boolean, }; export type EqCompType = "adjective" | "loc. adv." | "sandwich" export type EqCompSelection = { type: "EQComp", selection: AdjectiveSelection | LocativeAdverbSelection | SandwichSelection, }; export type SandwichSelection = S & { inside: NPSelection, }; export type Sandwich = { type: "sandwich", before: PsString | undefined, after: PsString | undefined, e: string, }; export type EquativeSelection = { tense: EquativeTense, negative: boolean, }; export type EquativeRendered = EquativeSelection & { ps: SingleOrLengthOpts, person: Person, hasBa: boolean, } export type EPRendered = { type: "EPRendered", king: "subject" | "predicate", blocks: (Rendered | Rendered)[], predicate: Rendered | Rendered, equative: EquativeRendered, englishBase?: string[], omitSubject: boolean, } export type EntryFeeder = { nouns: EntryLookupPortal, verbs: EntryLookupPortal, adjectives: EntryLookupPortal, locativeAdverbs: EntryLookupPortal, adverbs: EntryLookupPortal, } | { nouns: NounEntry[], verbs: VerbEntry[], adjectives: AdjectiveEntry[], locativeAdverbs: LocativeAdverbEntry[], adverbs: AdverbEntry[], } export type EntryFeederSingleType = X[] | EntryLookupPortal; export type EntryLookupPortal = { search: (s: string) => X[], getByTs: (ts: number) => (X | undefined), }