BIG IMPROVEMENT - passive and ability stems, simplified formulas, and avoiding picking passive ability verbs etc
This commit is contained in:
parent
8f559e0665
commit
0008f18e85
|
@ -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",
|
||||
|
|
|
@ -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<T.PersonInflectionsField>("mascSing");
|
||||
const [split, setSplit] = useState<boolean>(false);
|
||||
|
@ -161,7 +162,7 @@ export function RootsAndStems({ textOptions, info, hidePastParticiple, highlight
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!hidePastParticiple && <div className="text-center" style={highlighted?.includes("past participle") ? highlight : {}}>
|
||||
{!hidePastParticiple && "participle" in info &&<div className="text-center" style={highlighted?.includes("past participle") ? highlight : {}}>
|
||||
<div style={title}>Past Participle</div>
|
||||
<VerbInfoItemDisplay
|
||||
item={pickPersInf(info.participle.past, persInf)}
|
||||
|
|
|
@ -8,48 +8,50 @@ import {
|
|||
VpsReducerAction
|
||||
} from "./vps-reducer";
|
||||
|
||||
const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense, formula: string, modalFormula: string, }[] = [{
|
||||
const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense, formula: string }[] = [{
|
||||
label: <div><i className="fas fa-video mr-2" />present</div>,
|
||||
value: "presentVerb",
|
||||
formula: "imperfective stem + present verb ending",
|
||||
modalFormula: `imperfective root + tail + kedul "to become" subjunctive`,
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />subjunctive</div>,
|
||||
value: "subjunctiveVerb",
|
||||
formula: "perfective stem + present verb ending",
|
||||
modalFormula: `perfective root + tail + kedul "to become" subjunctive`,
|
||||
}, {
|
||||
label: <div><i className="fas fa-video mr-2" />imperfective future</div>,
|
||||
value: "imperfectiveFuture",
|
||||
formula: "ba + present",
|
||||
modalFormula: `ba + present modal`,
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />perfective future</div>,
|
||||
value: "perfectiveFuture",
|
||||
formula: "ba + subjunctive",
|
||||
modalFormula: `ba + subjunctive modal`,
|
||||
}, {
|
||||
label: <div><i className="fas fa-video mr-2" />continuous past</div>,
|
||||
value: "imperfectivePast",
|
||||
formula: "imperfective root + past verb ending",
|
||||
modalFormula: `imperfective root + tail + kedul "to become" simple past`,
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />simple past</div>,
|
||||
value: "perfectivePast",
|
||||
formula: "perfective root + past verb ending",
|
||||
modalFormula: `perfective root + tail + kedul "to become" simple past`,
|
||||
}, {
|
||||
label: <div><i className="fas fa-video mr-2" />habitual continual past</div>,
|
||||
value: "habitualImperfectivePast",
|
||||
formula: "ba + contiunous past",
|
||||
modalFormula: `ba + simple past modal`,
|
||||
formula: "ba + continuous past",
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />habitual simple past</div>,
|
||||
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 <div>
|
||||
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
|
||||
|
@ -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}
|
||||
/>
|
||||
</div>}
|
||||
|
@ -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 <div className="mb-2" style={{ width: "250px", overflowY: "auto" }}>
|
||||
|
|
|
@ -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 <div className="mb-3">
|
||||
{info && <CompoundDisplay
|
||||
info={info}
|
||||
|
@ -60,13 +68,17 @@ function VerbPicker(props: {
|
|||
{info && <div className="mt-3 mb-1 text-center">
|
||||
<Hider
|
||||
showing={showRootsAndStems}
|
||||
label="🌳 Roots and Stems"
|
||||
label={`🌳 ${passiveRootsAndStems ? "Passive" : abilityRootsAndStems ? "Ability" : ""} Roots and Stems`}
|
||||
handleChange={() => setShowRootsAndStems(p => !p)}
|
||||
hLevel={5}
|
||||
>
|
||||
<RootsAndStems
|
||||
textOptions={props.opts}
|
||||
info={passiveRootsAndStems ? passiveRootsAndStems : info}
|
||||
info={passiveRootsAndStems
|
||||
? passiveRootsAndStems
|
||||
: abilityRootsAndStems
|
||||
? abilityRootsAndStems
|
||||
: info}
|
||||
/>
|
||||
</Hider>
|
||||
</div>}
|
||||
|
@ -89,7 +101,7 @@ function VerbPicker(props: {
|
|||
<ButtonSelect
|
||||
small
|
||||
value={props.vps.verb.voice}
|
||||
options={props.vps.verb.tenseCategory === "imperative"
|
||||
options={(props.vps.verb.tenseCategory === "imperative" || props.vps.verb.tenseCategory === "modal")
|
||||
? [{
|
||||
label: "Active",
|
||||
value: "active",
|
||||
|
|
|
@ -155,6 +155,7 @@ export function vpsReducer(vps: T.VPSelectionState, action: VpsReducerAction, se
|
|||
verb: {
|
||||
...vps.verb,
|
||||
voice,
|
||||
tenseCategory: vps.verb.tenseCategory === "modal" ? "basic" : vps.verb.tenseCategory,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
|
@ -239,6 +240,16 @@ export function vpsReducer(vps: T.VPSelectionState, action: VpsReducerAction, se
|
|||
},
|
||||
});
|
||||
}
|
||||
if (category === "modal") {
|
||||
return {
|
||||
...vps,
|
||||
verb: {
|
||||
...vps.verb,
|
||||
tenseCategory: category,
|
||||
voice: "active",
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
...vps,
|
||||
verb: {
|
||||
|
|
|
@ -60,12 +60,18 @@ export function getFirstSecThird(p: T.Person): 1 | 2 | 3 {
|
|||
// return s;
|
||||
// }
|
||||
|
||||
export function hasPersInfs(info: T.NonComboVerbInfo | T.PassiveRootsStems): boolean {
|
||||
export function hasPersInfs(info: T.NonComboVerbInfo | T.PassiveRootsAndStems | T.AbilityRootsAndStems): boolean {
|
||||
if ("participle" in info) {
|
||||
return (
|
||||
"mascSing" in info.root.perfective ||
|
||||
"mascSing" in info.stem.perfective ||
|
||||
("present" in info.participle && "mascSing" in info.participle.present) ||
|
||||
"mascSing" in info.participle.past
|
||||
);
|
||||
}
|
||||
return (
|
||||
"mascSing" in info.root.perfective ||
|
||||
"mascSing" in info.stem.perfective ||
|
||||
("present" in info.participle && "mascSing" in info.participle.present) ||
|
||||
"mascSing" in info.participle.past
|
||||
"mascSing" in info.stem.perfective
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
choosePersInf,
|
||||
isUnisexSet,
|
||||
getLong,
|
||||
getShort,
|
||||
} from "./p-text-helpers";
|
||||
import {
|
||||
makePsString,
|
||||
|
@ -39,6 +40,7 @@ import {
|
|||
} from "./pashto-inflector";
|
||||
import {
|
||||
checkForIrregularConjugation,
|
||||
kedulStat,
|
||||
stativeAux,
|
||||
} from "./irregular-conjugations";
|
||||
import {
|
||||
|
@ -53,6 +55,7 @@ import {
|
|||
spaceInForm,
|
||||
getAuxTransitivity,
|
||||
chooseParticipleInflection,
|
||||
noPersInfs,
|
||||
} from "./misc-helpers";
|
||||
import * as T from "../types";
|
||||
|
||||
|
@ -982,7 +985,72 @@ function makeDynamicPerfectiveSplit(comp: T.PsString, auxSplit: T.SplitInfo): T.
|
|||
];
|
||||
}
|
||||
|
||||
export function getPassiveRootsAndStems(info: T.NonComboVerbInfo, withTails?: boolean): T.PassiveRootsStems | undefined {
|
||||
export function getAbilityRootsAndStems(info: T.NonComboVerbInfo): T.AbilityRootsAndStems {
|
||||
const isIntransitiveStativeCompound = info.type === "stative compound" && info.transitivity === "intransitive"
|
||||
const roots = getAbilityRoots(info.root, isIntransitiveStativeCompound);
|
||||
return addAbilityHelperRootsAndStems(roots, isIntransitiveStativeCompound);
|
||||
}
|
||||
|
||||
function addAbilityHelperRootsAndStems(roots: T.VerbRootSet, isIntransitiveStativeCompound: boolean): T.AbilityRootsAndStems {
|
||||
function addAbilityHelperToRoot(
|
||||
r: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>,
|
||||
helper: T.PsString,
|
||||
): T.OptionalPersonInflections<T.LengthOptions<T.PsString>> {
|
||||
if ("mascSing" in r) {
|
||||
return {
|
||||
mascSing: addAbilityHelperToRoot(r.mascSing, helper) as T.LengthOptions<T.PsString>,
|
||||
mascPlur: addAbilityHelperToRoot(r.mascPlur, helper) as T.LengthOptions<T.PsString>,
|
||||
femSing: addAbilityHelperToRoot(r.femSing, helper) as T.LengthOptions<T.PsString>,
|
||||
femPlur: addAbilityHelperToRoot(r.femPlur, helper) as T.LengthOptions<T.PsString>,
|
||||
}
|
||||
}
|
||||
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<T.Lengt
|
|||
};
|
||||
}
|
||||
|
||||
const abilityTail = { p: "ی", f: "ey" };
|
||||
const abilityTailAccented = { p: "ی", f: "éy" };
|
||||
|
||||
function getAbilityRoots(root: T.VerbRootSet, isIntransitiveStativeCompound: boolean): T.VerbRootSet {
|
||||
function getAspectAbilityRoot(root: T.VerbRootSet[T.Aspect], aspect: T.Aspect): T.OptionalPersonInflections<T.LengthOptions<T.PsString>> {
|
||||
if ("mascSing" in root) {
|
||||
return {
|
||||
mascSing: getAspectAbilityRoot(root.mascSing, aspect) as T.LengthOptions<T.PsString>,
|
||||
mascPlur: getAspectAbilityRoot(root.mascPlur, aspect) as T.LengthOptions<T.PsString>,
|
||||
femSing: getAspectAbilityRoot(root.femSing, aspect) as T.LengthOptions<T.PsString>,
|
||||
femPlur: getAspectAbilityRoot(root.femPlur, aspect) as T.LengthOptions<T.PsString>,
|
||||
};
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<PassiveRootsAndStems, "participle">;
|
||||
|
||||
export type SimpleVerbInfo = VerbInfoBase & {
|
||||
type: "simple";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue