From 0008f18e8512090d64f4ef34d438008b58efc183 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 27 Jul 2022 16:45:52 -0500 Subject: [PATCH] BIG IMPROVEMENT - passive and ability stems, simplified formulas, and avoiding picking passive ability verbs etc --- package.json | 2 +- src/components/verb-info/VerbInfo.tsx | 7 +- src/components/vp-explorer/TensePicker.tsx | 32 +++--- src/components/vp-explorer/VerbPicker.tsx | 20 +++- src/components/vp-explorer/vps-reducer.ts | 11 ++ src/lib/misc-helpers.ts | 14 ++- src/lib/verb-info.ts | 114 ++++++++++++++++++++- src/library.ts | 2 + src/types.ts | 4 +- 9 files changed, 179 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 69c3c0a..48458fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "3.5.9", + "version": "3.6.0", "author": "lingdocs.com", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "homepage": "https://verbs.lingdocs.com", diff --git a/src/components/verb-info/VerbInfo.tsx b/src/components/verb-info/VerbInfo.tsx index 15b416e..bf688ff 100644 --- a/src/components/verb-info/VerbInfo.tsx +++ b/src/components/verb-info/VerbInfo.tsx @@ -41,12 +41,13 @@ const title: CSSProperties = { export function RootsAndStems({ textOptions, info, hidePastParticiple, highlighted, noTails }: { textOptions: T.TextOptions, - info: T.NonComboVerbInfo | T.PassiveRootsStems, + info: T.NonComboVerbInfo | T.PassiveRootsAndStems | T.AbilityRootsAndStems, hidePastParticiple?: boolean, highlighted?: T.RootsOrStemsToHighlight, noTails?: boolean, }) { - const hasPerfectiveSplit = !!(info.root.perfectiveSplit || info.stem.perfectiveSplit); + const hasPerfectiveSplit = ("perfectiveSplit" in info.root && "perfectiveSplit" in info.stem) + && !!(info.root.perfectiveSplit || info.stem.perfectiveSplit); const showPersInf = hasPersInfs(info); const [persInf, setPersInf] = useState("mascSing"); const [split, setSplit] = useState(false); @@ -161,7 +162,7 @@ export function RootsAndStems({ textOptions, info, hidePastParticiple, highlight - {!hidePastParticiple &&
+ {!hidePastParticiple && "participle" in info &&
Past Participle
present
, value: "presentVerb", formula: "imperfective stem + present verb ending", - modalFormula: `imperfective root + tail + kedul "to become" subjunctive`, }, { label:
subjunctive
, value: "subjunctiveVerb", formula: "perfective stem + present verb ending", - modalFormula: `perfective root + tail + kedul "to become" subjunctive`, }, { label:
imperfective future
, value: "imperfectiveFuture", formula: "ba + present", - modalFormula: `ba + present modal`, }, { label:
perfective future
, value: "perfectiveFuture", formula: "ba + subjunctive", - modalFormula: `ba + subjunctive modal`, }, { label:
continuous past
, value: "imperfectivePast", formula: "imperfective root + past verb ending", - modalFormula: `imperfective root + tail + kedul "to become" simple past`, }, { label:
simple past
, value: "perfectivePast", formula: "perfective root + past verb ending", - modalFormula: `perfective root + tail + kedul "to become" simple past`, }, { label:
habitual continual past
, value: "habitualImperfectivePast", - formula: "ba + contiunous past", - modalFormula: `ba + simple past modal`, + formula: "ba + continuous past", }, { label:
habitual simple past
, value: "habitualPerfectivePast", formula: "ba + simple past", - modalFormula: `ba + continuous past modal`, }]; +function composeFormula(formula: string, prefix: "passive" | "ability"): string { + return formula.replace(/^perfective/, `${prefix} perfective`) + .replace(/^imperfective/, `${prefix} imperfective`) + .replace("continuous", `${prefix} continuous`) + .replace("simple", `${prefix} simple`) + .replace(/present$/, `${prefix} present`) + .replace(/subjunctive$/, `${prefix} subjunctive`) + .replace("past participle", `${prefix} past participle`); +} + const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense, formula: string }[] = [{ label: "Present Perfect", value: "presentPerfect", @@ -181,6 +183,7 @@ function TensePicker(props: ({ : verbTenseOptions; const showImperativeOption = ("vps" in props && props.vps.verb.voice === "active") || ("vpsComplete" in props && props.vpsComplete.verb.voice !== "active"); + const inPassiveVoice = ("vps" in props && props.vps.verb.voice === "passive") || ("vpsComplete" in props && props.vpsComplete.verb.voice === "passive");; const canHaveFormula = "vps" in props && props.mode !== "quiz"; return
@@ -196,6 +199,7 @@ function TensePicker(props: ({ value={"vpsComplete" in props ? getTenseCategory(props.vpsComplete.verb.tense) : props.vps.verb.tenseCategory} + // @ts-ignore options={showImperativeOption ? [{ label: "Basic", value: "basic", @@ -217,7 +221,7 @@ function TensePicker(props: ({ }, { label: "Ability", value: "modal", - }]} + }].filter(x => !(inPassiveVoice && x.value === "modal"))} handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null} />
} @@ -276,8 +280,10 @@ function TensePicker(props: ({ ]); const formula = !curr ? "" - : ("modalFormula" in curr && props.vps.verb.tenseCategory === "modal") - ? curr.modalFormula + : (props.vps.verb.tenseCategory === "modal") + ? composeFormula(curr.formula, "ability") + : (props.vps.verb.voice === "passive") + ? composeFormula(curr.formula, "passive") : curr.formula; if (curr && "formula" in curr) { return
diff --git a/src/components/vp-explorer/VerbPicker.tsx b/src/components/vp-explorer/VerbPicker.tsx index 95e140a..0903a5b 100644 --- a/src/components/vp-explorer/VerbPicker.tsx +++ b/src/components/vp-explorer/VerbPicker.tsx @@ -1,7 +1,7 @@ import * as T from "../../types"; import ButtonSelect from "../ButtonSelect"; import { RootsAndStems } from "../verb-info/VerbInfo"; -import { getPassiveRootsAndStems, getVerbInfo } from "../../lib/verb-info"; +import { getAbilityRootsAndStems, getPassiveRootsAndStems, getVerbInfo } from "../../lib/verb-info"; import Hider from "../Hider"; import useStickyState from "../../lib/useStickyState"; import CompoundDisplay from "./CompoundDisplay"; @@ -51,6 +51,14 @@ function VerbPicker(props: { }); } const passiveRootsAndStems = (info && props.vps.verb.voice === "passive") ? getPassiveRootsAndStems(info) : undefined; + const abilityRootsAndStems = (() => { + try { + return (info && props.vps.verb.tenseCategory === "modal") ? getAbilityRootsAndStems(info) : undefined; + } catch (e) { + console.log("error making ability roots and stems", e); + return undefined; + } + })(); return
{info && setShowRootsAndStems(p => !p)} hLevel={5} >
} @@ -89,7 +101,7 @@ function VerbPicker(props: { >, + helper: T.PsString, + ): T.OptionalPersonInflections> { + if ("mascSing" in r) { + return { + mascSing: addAbilityHelperToRoot(r.mascSing, helper) as T.LengthOptions, + mascPlur: addAbilityHelperToRoot(r.mascPlur, helper) as T.LengthOptions, + femSing: addAbilityHelperToRoot(r.femSing, helper) as T.LengthOptions, + femPlur: addAbilityHelperToRoot(r.femPlur, helper) as T.LengthOptions, + } + } + return { + long: concatPsString(r.long, " ", helper), + short: concatPsString(r.short, " ", helper), + }; + } + const stemHelper = getLong(noPersInfs(kedulStat.info.stem.perfective)); + const rootHelper = noPersInfs(kedulStat.info.root.perfective).long; + return { + stem: { + perfective: addAbilityHelperToRoot(roots.perfective, stemHelper), + imperfective: addAbilityHelperToRoot(roots.imperfective, stemHelper), + ...roots.perfectiveSplit ? { + perfectiveSplit: addAbilityHelperToPerfectiveSplit(roots.perfectiveSplit, stemHelper), + } : {}, + }, + root: { + perfective: addAbilityHelperToRoot(roots.perfective, rootHelper), + imperfective: addAbilityHelperToRoot(roots.imperfective, rootHelper), + ...roots.perfectiveSplit ? { + perfectiveSplit: addAbilityHelperToPerfectiveSplit(roots.perfectiveSplit, rootHelper), + } : {}, + }, + }; +} + +function addAbilityHelperToPerfectiveSplit(s: T.SplitInfo, helper: T.PsString): T.SplitInfo { + if ("mascSing" in s) { + return { + mascSing: addAbilityHelperToPerfectiveSplit(s.mascSing, helper) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, + mascPlur: addAbilityHelperToPerfectiveSplit(s.mascPlur, helper) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, + femSing: addAbilityHelperToPerfectiveSplit(s.femSing, helper) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, + femPlur: addAbilityHelperToPerfectiveSplit(s.femPlur, helper) as T.SingleOrLengthOpts<[T.PsString, T.PsString]>, + }; + } + return { + long: [ + getLong(s)[0], + concatPsString(getLong(s)[1], " ", helper), + ], + short: [ + getShort(s)[0], + concatPsString(getShort(s)[1], " ", helper), + ], + }; +} + +export function getPassiveRootsAndStems(info: T.NonComboVerbInfo, withTails?: boolean): T.PassiveRootsAndStems | undefined { if (info.transitivity === "intransitive") return undefined; return { stem: getPassiveStem(info.root, info.root.perfectiveSplit, withTails), @@ -1050,6 +1118,50 @@ function getPassiveRootPerfectiveSplit(root: T.OptionalPersonInflections> { + if ("mascSing" in root) { + return { + mascSing: getAspectAbilityRoot(root.mascSing, aspect) as T.LengthOptions, + mascPlur: getAspectAbilityRoot(root.mascPlur, aspect) as T.LengthOptions, + femSing: getAspectAbilityRoot(root.femSing, aspect) as T.LengthOptions, + femPlur: getAspectAbilityRoot(root.femPlur, aspect) as T.LengthOptions, + }; + } + return { + long: concatPsString(root.long, abilityTail) as T.PsString, + short: concatPsString(root.short, aspect === "imperfective" ? abilityTailAccented : abilityTail) as T.PsString, + } + } + function getAbilityRootPerfectiveSplit(s: T.SplitInfo): T.SplitInfo { + if ("mascSing" in s) { + return { + mascSing: getAbilityRootPerfectiveSplit(s.mascSing) as [T.PsString, T.PsString], + mascPlur: getAbilityRootPerfectiveSplit(s.mascPlur) as [T.PsString, T.PsString], + femSing: getAbilityRootPerfectiveSplit(s.femSing) as [T.PsString, T.PsString], + femPlur: getAbilityRootPerfectiveSplit(s.femPlur) as [T.PsString, T.PsString], + }; + } + return { + long: [getLong(s)[0], concatPsString(getLong(s)[1], abilityTail)], + short: [getShort(s)[0], concatPsString(getShort(s)[1], abilityTail)], + } + } + return { + perfective: getAspectAbilityRoot( + !isIntransitiveStativeCompound ? root.perfective : root.imperfective, + !isIntransitiveStativeCompound ? "perfective" : "imperfective", + ), + imperfective: getAspectAbilityRoot(root.imperfective, "imperfective"), + ...(root.perfectiveSplit && !isIntransitiveStativeCompound) ? { + perfectiveSplit: getAbilityRootPerfectiveSplit(root.perfectiveSplit), + } : {}, + }; +} + function getPassiveRoot(root: T.VerbRootSet, splitInfo: T.SplitInfo | undefined, withTails?: boolean): T.VerbRootSet { const perfectiveRoot = withTails ? concatPsString(root.perfective, passiveRootTail) : root.perfective; const imperfectiveRoot = withTails ? concatPsString(root.imperfective, passiveRootTail) : root.imperfective; diff --git a/src/library.ts b/src/library.ts index c947324..041260c 100644 --- a/src/library.ts +++ b/src/library.ts @@ -15,6 +15,7 @@ import { import { getVerbInfo, getPassiveRootsAndStems, + getAbilityRootsAndStems, } from "./lib/verb-info"; import InflectionsTable from "./components/InflectionsTable"; import Pashto from "./components/Pashto"; @@ -173,6 +174,7 @@ export { conjugateVerb, getVerbInfo, getPassiveRootsAndStems, + getAbilityRootsAndStems, inflectWord, addToForm, concatPsString, diff --git a/src/types.ts b/src/types.ts index 089e331..691f3f4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -169,7 +169,7 @@ export type VerbInfoBase = { idiosyncraticThirdMascSing?: ShortThirdPersFormSet; } -export type PassiveRootsStems = { +export type PassiveRootsAndStems = { stem: VerbStemSet, root: VerbRootSet, participle: { @@ -177,6 +177,8 @@ export type PassiveRootsStems = { }, } +export type AbilityRootsAndStems = Omit; + export type SimpleVerbInfo = VerbInfoBase & { type: "simple"; }