include imperative
This commit is contained in:
parent
875237439b
commit
10532cb3bb
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@lingdocs/pashto-inflector",
|
"name": "@lingdocs/pashto-inflector",
|
||||||
"version": "2.1.2",
|
"version": "2.1.3",
|
||||||
"author": "lingdocs.com",
|
"author": "lingdocs.com",
|
||||||
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
||||||
"homepage": "https://verbs.lingdocs.com",
|
"homepage": "https://verbs.lingdocs.com",
|
||||||
|
|
|
@ -69,7 +69,6 @@ function App() {
|
||||||
}, [theme])
|
}, [theme])
|
||||||
|
|
||||||
const handleVerbIndexChange = (e: any) => {
|
const handleVerbIndexChange = (e: any) => {
|
||||||
console.log("changing to", e.target.value);
|
|
||||||
setVerbTs(parseInt(e.target.value));
|
setVerbTs(parseInt(e.target.value));
|
||||||
}
|
}
|
||||||
const handleTypeSelection = (e: any) => {
|
const handleTypeSelection = (e: any) => {
|
||||||
|
|
|
@ -14,7 +14,6 @@ type PsStringWSub = T.PsString & { sub?: any };
|
||||||
|
|
||||||
function EnglishContent({ children }: { children: (string | JSX.Element)[] | (string | JSX.Element) }) {
|
function EnglishContent({ children }: { children: (string | JSX.Element)[] | (string | JSX.Element) }) {
|
||||||
if (Array.isArray(children)) {
|
if (Array.isArray(children)) {
|
||||||
console.log(children);
|
|
||||||
return <>
|
return <>
|
||||||
{children.map((x) => <EnglishContent>{x}</EnglishContent>)}
|
{children.map((x) => <EnglishContent>{x}</EnglishContent>)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -40,7 +40,7 @@ function agreementInfo(info: T.NonComboVerbInfo, displayForm: T.DisplayForm): Re
|
||||||
}
|
}
|
||||||
|
|
||||||
function VerbFormDisplay({ displayForm, textOptions, info, showingFormInfo, english, shortDefault }: {
|
function VerbFormDisplay({ displayForm, textOptions, info, showingFormInfo, english, shortDefault }: {
|
||||||
displayForm: T.DisplayForm | T.VerbForm,
|
displayForm: T.DisplayForm | T.VerbForm | T.ImperativeForm,
|
||||||
english?: T.EnglishBlock | string,
|
english?: T.EnglishBlock | string,
|
||||||
textOptions: T.TextOptions,
|
textOptions: T.TextOptions,
|
||||||
showingFormInfo: boolean,
|
showingFormInfo: boolean,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
} from "../../lib/np-tools";
|
} from "../../lib/np-tools";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
|
import { isSecondPerson } from "../../lib/phrase-building/vp-tools";
|
||||||
// import { capitalizeFirstLetter } from "../../lib/text-tools";
|
// import { capitalizeFirstLetter } from "../../lib/text-tools";
|
||||||
|
|
||||||
const npTypes: T.NPType[] = ["pronoun", "noun", "participle"];
|
const npTypes: T.NPType[] = ["pronoun", "noun", "participle"];
|
||||||
|
@ -19,6 +20,7 @@ function NPPicker(props: {
|
||||||
asObject?: boolean,
|
asObject?: boolean,
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions,
|
||||||
cantClear?: boolean,
|
cantClear?: boolean,
|
||||||
|
is2ndPersonPicker?: boolean,
|
||||||
} & ({
|
} & ({
|
||||||
nouns: (s: string) => T.NounEntry[],
|
nouns: (s: string) => T.NounEntry[],
|
||||||
verbs: (s: string) => T.VerbEntry[],
|
verbs: (s: string) => T.VerbEntry[],
|
||||||
|
@ -28,6 +30,9 @@ function NPPicker(props: {
|
||||||
nouns: T.NounEntry[],
|
nouns: T.NounEntry[],
|
||||||
verbs: T.VerbEntry[],
|
verbs: T.VerbEntry[],
|
||||||
})) {
|
})) {
|
||||||
|
if (props.is2ndPersonPicker && ((props.np?.type !== "pronoun") || !isSecondPerson(props.np.person))) {
|
||||||
|
throw new Error("can't use 2ndPerson NPPicker without a pronoun");
|
||||||
|
}
|
||||||
const [npType, setNpType] = useState<T.NPType | undefined>(props.np ? props.np.type : undefined);
|
const [npType, setNpType] = useState<T.NPType | undefined>(props.np ? props.np.type : undefined);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNpType(props.np ? props.np.type : undefined);
|
setNpType(props.np ? props.np.type : undefined);
|
||||||
|
@ -78,6 +83,7 @@ function NPPicker(props: {
|
||||||
pronoun={props.np}
|
pronoun={props.np}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
clearButton={clearButton}
|
clearButton={clearButton}
|
||||||
|
is2ndPersonPicker={props.is2ndPersonPicker}
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
/>
|
/>
|
||||||
: npType === "noun"
|
: npType === "noun"
|
||||||
|
|
|
@ -2,6 +2,9 @@ import * as T from "../../types";
|
||||||
import ButtonSelect from "../ButtonSelect";
|
import ButtonSelect from "../ButtonSelect";
|
||||||
import useStickyState from "../../lib/useStickyState";
|
import useStickyState from "../../lib/useStickyState";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
import {
|
||||||
|
isSecondPerson, isThirdPerson,
|
||||||
|
} from "../../lib/phrase-building/vp-tools";
|
||||||
|
|
||||||
const gColors = {
|
const gColors = {
|
||||||
masc: "LightSkyBlue",
|
masc: "LightSkyBlue",
|
||||||
|
@ -53,15 +56,18 @@ function pickerStateToPerson(s: PickerState): T.Person {
|
||||||
+ (6 * s.col);
|
+ (6 * s.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
|
function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2ndPersonPicker }: {
|
||||||
pronoun: T.PronounSelection,
|
pronoun: T.PronounSelection,
|
||||||
onChange: (p: T.PronounSelection) => void,
|
onChange: (p: T.PronounSelection) => void,
|
||||||
asObject?: boolean,
|
asObject?: boolean,
|
||||||
clearButton?: JSX.Element,
|
clearButton?: JSX.Element,
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions,
|
||||||
|
is2ndPersonPicker?: boolean,
|
||||||
}) {
|
}) {
|
||||||
|
if (is2ndPersonPicker && !isSecondPerson(pronoun.person)) {
|
||||||
|
throw new Error("can't use 2ndPerson NPProunounPicker without a pronoun");
|
||||||
|
}
|
||||||
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("e", "prounoun-picker-display");
|
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("e", "prounoun-picker-display");
|
||||||
|
|
||||||
const p = personToPickerState(pronoun.person);
|
const p = personToPickerState(pronoun.person);
|
||||||
function handleClick(row: number, col: number) {
|
function handleClick(row: number, col: number) {
|
||||||
const person = pickerStateToPerson({ ...p, row, col });
|
const person = pickerStateToPerson({ ...p, row, col });
|
||||||
|
@ -92,11 +98,14 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
|
||||||
setDisplay(newPerson);
|
setDisplay(newPerson);
|
||||||
}
|
}
|
||||||
const prs = labels(!!asObject)[display];
|
const prs = labels(!!asObject)[display];
|
||||||
const pSpec = "near" in prs ? prs[pronoun.distance] : prs;
|
const pSpecA = "near" in prs ? prs[pronoun.distance] : prs;
|
||||||
|
const pSpec = is2ndPersonPicker
|
||||||
|
? [pSpecA[1]]
|
||||||
|
: pSpecA;
|
||||||
return <div style={{ maxWidth: "145px", padding: 0 }}>
|
return <div style={{ maxWidth: "145px", padding: 0 }}>
|
||||||
{clearButton}
|
{clearButton}
|
||||||
<div className="d-flex flex-row justify-content-around mb-3">
|
<div className="d-flex flex-row justify-content-between mb-3">
|
||||||
<ButtonSelect
|
{isThirdPerson(pronoun.person) ? <ButtonSelect
|
||||||
xSmall
|
xSmall
|
||||||
options={[
|
options={[
|
||||||
{ label: "Far", value: "far" },
|
{ label: "Far", value: "far" },
|
||||||
|
@ -104,7 +113,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
|
||||||
]}
|
]}
|
||||||
value={pronoun.distance}
|
value={pronoun.distance}
|
||||||
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
|
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
|
||||||
/>
|
/> : <div>{` `}</div>}
|
||||||
<button className="btn btn-sm btn-outline-secondary" onClick={handleDisplayChange}>
|
<button className="btn btn-sm btn-outline-secondary" onClick={handleDisplayChange}>
|
||||||
{display === "persons" ? "#" : display === "p" ? "PS" : "EN"}
|
{display === "persons" ? "#" : display === "p" ? "PS" : "EN"}
|
||||||
</button>
|
</button>
|
||||||
|
@ -114,9 +123,13 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
|
||||||
{pSpec.map((rw, i) => (
|
{pSpec.map((rw, i) => (
|
||||||
<tr>
|
<tr>
|
||||||
{rw.map((r, j) => {
|
{rw.map((r, j) => {
|
||||||
const active = (p.row === i && p.col === j)
|
const active = is2ndPersonPicker
|
||||||
|
? (p.col === j)
|
||||||
|
: (p.row === i && p.col === j);
|
||||||
return <td
|
return <td
|
||||||
onClick={() => handleClick(i, j)}
|
onClick={() => {
|
||||||
|
handleClick(is2ndPersonPicker ? 1 : i, j);
|
||||||
|
}}
|
||||||
className={classNames({ "table-active": active, "text-on-gender-color": active })}
|
className={classNames({ "table-active": active, "text-on-gender-color": active })}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: active ? gColors[p.gender] : "inherit",
|
backgroundColor: active ? gColors[p.gender] : "inherit",
|
||||||
|
|
|
@ -16,7 +16,7 @@ function ChartDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptions }
|
||||||
: ("transitive" in rawConjugations)
|
: ("transitive" in rawConjugations)
|
||||||
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
||||||
: rawConjugations;
|
: rawConjugations;
|
||||||
const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice);
|
const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice, VS.negative);
|
||||||
return <div className="mb-4">
|
return <div className="mb-4">
|
||||||
<VerbFormDisplay
|
<VerbFormDisplay
|
||||||
displayForm={form}
|
displayForm={form}
|
||||||
|
|
|
@ -4,7 +4,8 @@ import {
|
||||||
} from "../np-picker/picker-tools";
|
} from "../np-picker/picker-tools";
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
import ButtonSelect from "../ButtonSelect";
|
import ButtonSelect from "../ButtonSelect";
|
||||||
import { isModalTense, isPerfectTense, isVerbTense } from "../../lib/type-predicates";
|
import { isImperativeTense, isModalTense, isPerfectTense, isVerbTense } from "../../lib/type-predicates";
|
||||||
|
import { ensure2ndPersSubjPronounAndNoConflict } from "../../lib/phrase-building/vp-tools";
|
||||||
|
|
||||||
const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] = [{
|
const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] = [{
|
||||||
label: <div><i className="fas fa-video mr-2" />present</div>,
|
label: <div><i className="fas fa-video mr-2" />present</div>,
|
||||||
|
@ -55,8 +56,16 @@ const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense
|
||||||
value: "pastSubjunctivePerfect",
|
value: "pastSubjunctivePerfect",
|
||||||
}];
|
}];
|
||||||
|
|
||||||
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense): T.PerfectTense | T.VerbTense | T.ModalTense {
|
const imperativeTenseOptions: { label: string | JSX.Element, value: T.ImperativeTense }[] = [{
|
||||||
let tns: T.PerfectTense | T.VerbTense | T.ModalTense;
|
label: <div><i className="fas fa-video mr-2" />imperfective imp.</div>,
|
||||||
|
value: "imperfectiveImperative",
|
||||||
|
}, {
|
||||||
|
label: <div><i className="fas fa-camera mr-2" />perfective imp.</div>,
|
||||||
|
value: "perfectiveImperative",
|
||||||
|
}];
|
||||||
|
|
||||||
|
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense): T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense {
|
||||||
|
let tns: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense;
|
||||||
const oldTenseCategory = !o
|
const oldTenseCategory = !o
|
||||||
? undefined
|
? undefined
|
||||||
: getTenseCategory(o);
|
: getTenseCategory(o);
|
||||||
|
@ -64,6 +73,8 @@ export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense):
|
||||||
? perfectTenseOptions
|
? perfectTenseOptions
|
||||||
: oldTenseCategory === "modal"
|
: oldTenseCategory === "modal"
|
||||||
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense }))
|
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense }))
|
||||||
|
: oldTenseCategory === "imperative"
|
||||||
|
? imperativeTenseOptions
|
||||||
: verbTenseOptions;
|
: verbTenseOptions;
|
||||||
do {
|
do {
|
||||||
tns = tenseOptions[
|
tns = tenseOptions[
|
||||||
|
@ -81,7 +92,7 @@ function TensePicker(props: ({
|
||||||
onChange: (p: T.VPSelection) => void,
|
onChange: (p: T.VPSelection) => void,
|
||||||
mode: "charts" | "phrases" | "quiz",
|
mode: "charts" | "phrases" | "quiz",
|
||||||
}) {
|
}) {
|
||||||
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) {
|
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense | T.ImperativeTense } | null) {
|
||||||
if ("vpsComplete" in props) return;
|
if ("vpsComplete" in props) return;
|
||||||
const value = o?.value ? o.value : undefined;
|
const value = o?.value ? o.value : undefined;
|
||||||
if (props.vps.verb && value) {
|
if (props.vps.verb && value) {
|
||||||
|
@ -94,6 +105,15 @@ function TensePicker(props: ({
|
||||||
tenseCategory: "perfect",
|
tenseCategory: "perfect",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else if (isImperativeTense(value)) {
|
||||||
|
props.onChange({
|
||||||
|
...props.vps,
|
||||||
|
verb: {
|
||||||
|
...props.vps.verb,
|
||||||
|
imperativeTense: value,
|
||||||
|
tenseCategory: "imperative",
|
||||||
|
},
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
props.onChange({
|
props.onChange({
|
||||||
...props.vps,
|
...props.vps,
|
||||||
|
@ -112,9 +132,19 @@ function TensePicker(props: ({
|
||||||
if ("vpsComplete" in props) return;
|
if ("vpsComplete" in props) return;
|
||||||
if (!props.vps.verb) return;
|
if (!props.vps.verb) return;
|
||||||
return () => {
|
return () => {
|
||||||
const tenses = props.vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions;
|
// TODO: ABSTRACT THIS - SAFER
|
||||||
|
const tenses = props.vps.verb.tenseCategory === "perfect"
|
||||||
|
? perfectTenseOptions
|
||||||
|
: props.vps.verb.tenseCategory === "imperative"
|
||||||
|
? imperativeTenseOptions
|
||||||
|
: verbTenseOptions;
|
||||||
const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[
|
const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[
|
||||||
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense"
|
// TODO: ABSTRACT THIS? - SAFER
|
||||||
|
props.vps.verb.tenseCategory === "perfect"
|
||||||
|
? "perfectTense"
|
||||||
|
: props.vps.verb.tenseCategory === "imperative"
|
||||||
|
? "imperativeTense"
|
||||||
|
: "verbTense"
|
||||||
]);
|
]);
|
||||||
if (currIndex === -1) {
|
if (currIndex === -1) {
|
||||||
console.error("error moving tense", dir);
|
console.error("error moving tense", dir);
|
||||||
|
@ -139,9 +169,19 @@ function TensePicker(props: ({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") {
|
function onTenseCategorySelect(value: "basic" | "modal" | "perfect" | "imperative") {
|
||||||
if ("vpsComplete" in props) return;
|
if ("vpsComplete" in props) return;
|
||||||
if (props.vps.verb) {
|
if (props.vps.verb) {
|
||||||
|
if (value === "imperative") {
|
||||||
|
props.onChange(ensure2ndPersSubjPronounAndNoConflict({
|
||||||
|
...props.vps,
|
||||||
|
verb: {
|
||||||
|
...props.vps.verb,
|
||||||
|
tenseCategory: value,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
props.onChange({
|
props.onChange({
|
||||||
...props.vps,
|
...props.vps,
|
||||||
verb: {
|
verb: {
|
||||||
|
@ -153,40 +193,47 @@ function TensePicker(props: ({
|
||||||
}
|
}
|
||||||
const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect"))
|
const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect"))
|
||||||
? perfectTenseOptions
|
? perfectTenseOptions
|
||||||
|
: ("vps" in props && (props.vps.verb?.tenseCategory === "imperative"))
|
||||||
|
? imperativeTenseOptions
|
||||||
: verbTenseOptions;
|
: verbTenseOptions;
|
||||||
return <div>
|
return <div>
|
||||||
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
|
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
|
||||||
<div className="d-flex flex-row justify-content-between align-items-center">
|
<div className="h5">Tense:</div>
|
||||||
<div className="h5">Tense:</div>
|
{("vpsComplete" in props || props.vps.verb) && <div className="mb-2">
|
||||||
{("vpsComplete" in props || props.vps.verb) && <div className="mb-2">
|
<ButtonSelect
|
||||||
<ButtonSelect
|
small
|
||||||
small
|
value={"vpsComplete" in props
|
||||||
value={"vpsComplete" in props
|
? getTenseCategory(props.vpsComplete.verb.tense)
|
||||||
? getTenseCategory(props.vpsComplete.verb.tense)
|
: props.vps.verb.tenseCategory}
|
||||||
: props.vps.verb.tenseCategory}
|
options={[{
|
||||||
options={[{
|
label: "Basic",
|
||||||
label: "Basic",
|
value: "basic",
|
||||||
value: "basic",
|
}, {
|
||||||
}, {
|
label: "Perfect",
|
||||||
label: "Perfect",
|
value: "perfect",
|
||||||
value: "perfect",
|
}, {
|
||||||
}, {
|
label: "Modal",
|
||||||
label: "Modal",
|
value: "modal",
|
||||||
value: "modal",
|
}, {
|
||||||
}]}
|
label: "Imperative",
|
||||||
handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null}
|
value: "imperative",
|
||||||
/>
|
}]}
|
||||||
</div>}
|
handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null}
|
||||||
</div>
|
/>
|
||||||
|
</div>}
|
||||||
{"vpsComplete" in props
|
{"vpsComplete" in props
|
||||||
? <div style={{ fontSize: "larger" }} className="mb-3">
|
? <div style={{ fontSize: "larger" }} className="mb-3">
|
||||||
{[...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label}
|
{[...verbTenseOptions, ...perfectTenseOptions, ...imperativeTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label}
|
||||||
</div>
|
</div>
|
||||||
: <Select
|
: <Select
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
// for some reason can't use tOptions with find here;
|
// for some reason can't use tOptions with find here;
|
||||||
value={props.vps.verb && ([...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vps.verb[
|
value={props.vps.verb && ([...verbTenseOptions, ...perfectTenseOptions, ...imperativeTenseOptions].find(o => o.value === props.vps.verb[
|
||||||
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense"
|
props.vps.verb.tenseCategory === "perfect"
|
||||||
|
? "perfectTense"
|
||||||
|
: props.vps.verb.tenseCategory === "imperative"
|
||||||
|
? "imperativeTense"
|
||||||
|
: "verbTense"
|
||||||
]))}
|
]))}
|
||||||
onChange={onTenseSelect}
|
onChange={onTenseSelect}
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
|
@ -219,7 +266,7 @@ function TensePicker(props: ({
|
||||||
|
|
||||||
export default TensePicker;
|
export default TensePicker;
|
||||||
|
|
||||||
function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense): "basic" | "perfect" | "modal" {
|
function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense): "basic" | "perfect" | "modal" | "imperative" {
|
||||||
if (isPerfectTense(tense)) {
|
if (isPerfectTense(tense)) {
|
||||||
return "perfect";
|
return "perfect";
|
||||||
}
|
}
|
||||||
|
@ -229,5 +276,8 @@ function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense): "
|
||||||
if (isModalTense(tense)) {
|
if (isModalTense(tense)) {
|
||||||
return "modal";
|
return "modal";
|
||||||
}
|
}
|
||||||
|
if (isImperativeTense(tense)) {
|
||||||
|
return "imperative";
|
||||||
|
}
|
||||||
throw new Error("can't catagorize tense");
|
throw new Error("can't catagorize tense");
|
||||||
}
|
}
|
|
@ -17,6 +17,10 @@ import VPExplorerQuiz from "./VPExplorerQuiz";
|
||||||
import { switchSubjObj } from "../../lib/phrase-building/vp-tools";
|
import { switchSubjObj } from "../../lib/phrase-building/vp-tools";
|
||||||
import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal";
|
import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal";
|
||||||
|
|
||||||
|
// TO FINISH IMPERATIVE STUFF!!
|
||||||
|
// TODO: English Builders for imperatives
|
||||||
|
// TODO: Quiz with imperatives
|
||||||
|
|
||||||
// TODO: make answerFeedback emojis appear at random translate angles a little bit
|
// TODO: make answerFeedback emojis appear at random translate angles a little bit
|
||||||
// add energy drinks?
|
// add energy drinks?
|
||||||
|
|
||||||
|
@ -48,7 +52,7 @@ export function VPExplorer(props: {
|
||||||
})) {
|
})) {
|
||||||
const [vps, setVps] = useStickyState<T.VPSelection>(
|
const [vps, setVps] = useStickyState<T.VPSelection>(
|
||||||
savedVps => makeVPSelectionState(props.verb, savedVps),
|
savedVps => makeVPSelectionState(props.verb, savedVps),
|
||||||
"vpsState2",
|
"vpsState5",
|
||||||
);
|
);
|
||||||
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
||||||
savedMode => {
|
savedMode => {
|
||||||
|
@ -129,10 +133,16 @@ export function VPExplorer(props: {
|
||||||
{ label: "Phrases", value: "phrases" },
|
{ label: "Phrases", value: "phrases" },
|
||||||
{ label: "Quiz", value: "quiz" },
|
{ label: "Quiz", value: "quiz" },
|
||||||
]}
|
]}
|
||||||
handleChange={setMode}
|
handleChange={(x) => {
|
||||||
|
// TODO: remove this and implement the imperative in quiz
|
||||||
|
// if (x === "quiz") {
|
||||||
|
|
||||||
|
// }
|
||||||
|
setMode(x);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{(vps.verb && (typeof vps.verb.object === "object") && (vps.verb.isCompound !== "dynamic") && (mode === "phrases")) &&
|
{(vps.verb && (typeof vps.verb.object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
|
||||||
<div className="text-center mt-4">
|
<div className="text-center mt-4">
|
||||||
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
||||||
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
||||||
|
@ -154,6 +164,7 @@ export function VPExplorer(props: {
|
||||||
nouns: props.nouns,
|
nouns: props.nouns,
|
||||||
verbs: props.verbs,
|
verbs: props.verbs,
|
||||||
}}
|
}}
|
||||||
|
is2ndPersonPicker={vps.verb.tenseCategory === "imperative"}
|
||||||
np={vps.subject}
|
np={vps.subject}
|
||||||
counterPart={vps.verb ? vps.verb.object : undefined}
|
counterPart={vps.verb ? vps.verb.object : undefined}
|
||||||
onChange={handleSubjectChange}
|
onChange={handleSubjectChange}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import Keyframes from "../Keyframes";
|
||||||
import energyDrink from "./energy-drink.jpg";
|
import energyDrink from "./energy-drink.jpg";
|
||||||
import { flattenLengths } from "../../lib/phrase-building/compile-vp";
|
import { flattenLengths } from "../../lib/phrase-building/compile-vp";
|
||||||
import { concatPsString } from "../../lib/p-text-helpers";
|
import { concatPsString } from "../../lib/p-text-helpers";
|
||||||
|
import { isImperativeTense } from "../../lib/type-predicates";
|
||||||
|
|
||||||
const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"];
|
const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"];
|
||||||
|
|
||||||
|
@ -384,6 +385,7 @@ function completeVPs(vps: T.VPSelection): T.VPSelectionComplete {
|
||||||
obj: oldObj,
|
obj: oldObj,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const t = getTenseFromVerbSelection(vps.verb);
|
||||||
const verb: T.VerbSelectionComplete = {
|
const verb: T.VerbSelectionComplete = {
|
||||||
...vps.verb,
|
...vps.verb,
|
||||||
object: (
|
object: (
|
||||||
|
@ -397,7 +399,7 @@ function completeVPs(vps: T.VPSelection): T.VPSelectionComplete {
|
||||||
person: obj,
|
person: obj,
|
||||||
}
|
}
|
||||||
: vps.verb.object,
|
: vps.verb.object,
|
||||||
tense: getTenseFromVerbSelection(vps.verb),
|
tense: isImperativeTense(t) ? "presentVerb" : t,
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
...vps,
|
...vps,
|
||||||
|
|
|
@ -53,6 +53,7 @@ export function makeVPSelectionState(
|
||||||
dynAuxVerb,
|
dynAuxVerb,
|
||||||
verbTense: os ? os.verb.verbTense : "presentVerb",
|
verbTense: os ? os.verb.verbTense : "presentVerb",
|
||||||
perfectTense: os ? os.verb.perfectTense : "presentPerfect",
|
perfectTense: os ? os.verb.perfectTense : "presentPerfect",
|
||||||
|
imperativeTense: os ? os.verb.imperativeTense : "imperfectiveImperative",
|
||||||
tenseCategory: os ? os.verb.tenseCategory : "basic",
|
tenseCategory: os ? os.verb.tenseCategory : "basic",
|
||||||
object,
|
object,
|
||||||
transitivity,
|
transitivity,
|
||||||
|
|
|
@ -103,6 +103,7 @@ const kedulStatModal: T.ModalContent = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const kawulStatOrDynImperfectivePassive: T.AspectContentPassive = {
|
const kawulStatOrDynImperfectivePassive: T.AspectContentPassive = {
|
||||||
|
imperative: undefined,
|
||||||
nonImperative: [
|
nonImperative: [
|
||||||
[[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]],
|
[[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]],
|
||||||
[[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]],
|
[[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]],
|
||||||
|
@ -1303,6 +1304,7 @@ export const kawulStat: T.VerbConjugation = {
|
||||||
passive: {
|
passive: {
|
||||||
imperfective: kawulStatOrDynImperfectivePassive,
|
imperfective: kawulStatOrDynImperfectivePassive,
|
||||||
perfective: {
|
perfective: {
|
||||||
|
imperative: undefined,
|
||||||
nonImperative: [
|
nonImperative: [
|
||||||
[[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]],
|
[[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]],
|
||||||
[[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]],
|
[[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]],
|
||||||
|
@ -1808,6 +1810,7 @@ export const kawulDyn: T.VerbConjugation = {
|
||||||
passive: {
|
passive: {
|
||||||
imperfective: kawulStatOrDynImperfectivePassive,
|
imperfective: kawulStatOrDynImperfectivePassive,
|
||||||
perfective: {
|
perfective: {
|
||||||
|
imperative: undefined,
|
||||||
nonImperative: [
|
nonImperative: [
|
||||||
[[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]],
|
[[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]],
|
||||||
[[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]],
|
[[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]],
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
removeBa,
|
removeBa,
|
||||||
removeDuplicates,
|
removeDuplicates,
|
||||||
} from "./vp-tools";
|
} from "./vp-tools";
|
||||||
import { isModalTense, isPerfectTense } from "../type-predicates";
|
import { isImperativeTense, isModalTense, isPerfectTense } from "../type-predicates";
|
||||||
|
|
||||||
type Form = T.FormVersion & { OSV?: boolean };
|
type Form = T.FormVersion & { OSV?: boolean };
|
||||||
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
||||||
|
@ -159,7 +159,9 @@ function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[
|
||||||
headSegment ? [headSegment, rest] : [rest],
|
headSegment ? [headSegment, rest] : [rest],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
const nu: T.PsString = { p: "نه", f: "nú" };
|
const nu: T.PsString = isImperativeTense(V.tense)
|
||||||
|
? { p: "مه", f: "mú" }
|
||||||
|
: { p: "نه", f: "nú" };
|
||||||
if (!headSegment) {
|
if (!headSegment) {
|
||||||
if ("front" in rest) {
|
if ("front" in rest) {
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as T from "../../types";
|
||||||
import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers";
|
import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers";
|
||||||
import * as grammarUnits from "../grammar-units";
|
import * as grammarUnits from "../grammar-units";
|
||||||
import {
|
import {
|
||||||
|
isImperativeTense,
|
||||||
isPerfectTense,
|
isPerfectTense,
|
||||||
isVerbTense,
|
isVerbTense,
|
||||||
// isModalTense,
|
// isModalTense,
|
||||||
|
@ -232,11 +233,24 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
|
||||||
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
|
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
const imperativeBuilders: Record<
|
||||||
|
T.ImperativeTense,
|
||||||
|
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||||
|
> = {
|
||||||
|
imperfectiveImperative: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||||
|
`${n ? "don't " : ""}${ec[0]}`,
|
||||||
|
]),
|
||||||
|
perfectiveImperative: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||||
|
`${n ? "don't " : ""}${ec[0]}`,
|
||||||
|
]),
|
||||||
|
};
|
||||||
const base = (
|
const base = (
|
||||||
isPerfectTense(vs.tense)
|
isPerfectTense(vs.tense)
|
||||||
? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense]
|
? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense]
|
||||||
: isVerbTense(vs.tense)
|
: isVerbTense(vs.tense)
|
||||||
? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense]
|
? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense]
|
||||||
|
: isImperativeTense(vs.tense)
|
||||||
|
? imperativeBuilders[vs.tense]
|
||||||
: (vs.voice === "active" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative);
|
: (vs.voice === "active" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative);
|
||||||
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
|
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
hasBaParticle,
|
hasBaParticle,
|
||||||
psStringFromEntry,
|
psStringFromEntry,
|
||||||
getLong,
|
getLong,
|
||||||
|
isImperativeBlock,
|
||||||
} from "../p-text-helpers";
|
} from "../p-text-helpers";
|
||||||
import { removeAccents } from "../accent-helpers";
|
import { removeAccents } from "../accent-helpers";
|
||||||
import {
|
import {
|
||||||
|
@ -26,6 +27,7 @@ import {
|
||||||
isPerfectTense,
|
isPerfectTense,
|
||||||
} from "../type-predicates";
|
} from "../type-predicates";
|
||||||
import { renderEnglishVPBase } from "./english-vp-rendering";
|
import { renderEnglishVPBase } from "./english-vp-rendering";
|
||||||
|
import { personGender } from "../../library";
|
||||||
|
|
||||||
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
|
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
|
||||||
|
|
||||||
|
@ -157,7 +159,8 @@ function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComple
|
||||||
},
|
},
|
||||||
hasBa: boolean,
|
hasBa: boolean,
|
||||||
} {
|
} {
|
||||||
const f = getTenseVerbForm(conj, vs.tense, vs.voice);
|
// TODO: handle the imperative form here
|
||||||
|
const f = getTenseVerbForm(conj, vs.tense, vs.voice, vs.negative);
|
||||||
const block = getMatrixBlock(f, objectPerson, person);
|
const block = getMatrixBlock(f, objectPerson, person);
|
||||||
const perfective = isPerfective(vs.tense);
|
const perfective = isPerfective(vs.tense);
|
||||||
const verbForm = getVerbFromBlock(block, person);
|
const verbForm = getVerbFromBlock(block, person);
|
||||||
|
@ -178,8 +181,11 @@ function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComple
|
||||||
return { hasBa, ps: { head: undefined, rest: verbForm }};
|
return { hasBa, ps: { head: undefined, rest: verbForm }};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVerbFromBlock(block: T.SingleOrLengthOpts<T.VerbBlock>, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
|
function getVerbFromBlock(block: T.SingleOrLengthOpts<T.VerbBlock | T.ImperativeBlock>, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
|
||||||
function grabFromBlock(b: T.VerbBlock, [row, col]: [ row: number, col: number ]): T.PsString[] {
|
function grabFromBlock(b: T.VerbBlock | T.ImperativeBlock, [row, col]: [ row: number, col: number ]): T.PsString[] {
|
||||||
|
if (isImperativeBlock(b)) {
|
||||||
|
return b[personGender(person) === "masc" ? 0 : 1][col];
|
||||||
|
}
|
||||||
return b[row][col];
|
return b[row][col];
|
||||||
}
|
}
|
||||||
const pos = getVerbBlockPosFromPerson(person);
|
const pos = getVerbBlockPosFromPerson(person);
|
||||||
|
@ -326,7 +332,7 @@ function isFirstOrSecondPersPronoun(o: "none" | T.NPSelection | T.Person.ThirdPl
|
||||||
return [0,1,2,3,6,7,8,9].includes(o.person);
|
return [0,1,2,3,6,7,8,9].includes(o.person);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPerfective(t: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
|
function isPerfective(t: T.Tense): boolean {
|
||||||
if (isPerfectTense(t)) return false;
|
if (isPerfectTense(t)) return false;
|
||||||
if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") {
|
if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") {
|
||||||
return false;
|
return false;
|
||||||
|
@ -337,7 +343,10 @@ function isPerfective(t: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
|
||||||
if (t === "perfectiveFutureModal" || t === "subjunctiveVerbModal" || t === "perfectivePastModal" || t === "habitualPerfectivePastModal") {
|
if (t === "perfectiveFutureModal" || t === "subjunctiveVerbModal" || t === "perfectivePastModal" || t === "habitualPerfectivePastModal") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw new Error("tense not implemented yet");
|
if (t === "perfectiveImperative") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMascSingAnimatePattern4(np: T.NPSelection): boolean {
|
function isMascSingAnimatePattern4(np: T.NPSelection): boolean {
|
||||||
|
|
|
@ -4,8 +4,9 @@ import {
|
||||||
psRemove,
|
psRemove,
|
||||||
psStringEquals,
|
psStringEquals,
|
||||||
} from "../../lib/p-text-helpers";
|
} from "../../lib/p-text-helpers";
|
||||||
import { isPerfectTense } from "../type-predicates";
|
import { isImperativeTense, isPerfectTense } from "../type-predicates";
|
||||||
import * as grammarUnits from "../../lib/grammar-units";
|
import * as grammarUnits from "../../lib/grammar-units";
|
||||||
|
import { randomNumber } from "../../lib/misc-helpers";
|
||||||
|
|
||||||
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||||
const firstPeople = [
|
const firstPeople = [
|
||||||
|
@ -27,8 +28,23 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense | T.PerfectTense | T.ModalTense, voice: "active" | "passive"): T.VerbForm {
|
export function getTenseVerbForm(
|
||||||
|
conjR: T.VerbConjugation,
|
||||||
|
tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense,
|
||||||
|
voice: "active" | "passive",
|
||||||
|
negative: boolean,
|
||||||
|
): T.VerbForm | T.ImperativeForm {
|
||||||
const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR;
|
const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR;
|
||||||
|
if (isImperativeTense(tense)) {
|
||||||
|
const impPassError = new Error("can't use imperative tenses with passive voice")
|
||||||
|
if (voice === "passive") {
|
||||||
|
throw impPassError;
|
||||||
|
}
|
||||||
|
if (!conj.imperfective.imperative || !conj.perfective.imperative) throw impPassError;
|
||||||
|
return (tense === "perfectiveImperative" && !negative)
|
||||||
|
? conj.perfective.imperative
|
||||||
|
: conj.imperfective.imperative;
|
||||||
|
}
|
||||||
if (tense === "presentVerb") {
|
if (tense === "presentVerb") {
|
||||||
return conj.imperfective.nonImperative;
|
return conj.imperfective.nonImperative;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +139,7 @@ export function removeBa(ps: T.PsString): T.PsString {
|
||||||
return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
|
return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense {
|
export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense {
|
||||||
function verbTenseToModalTense(tn: T.VerbTense): T.ModalTense {
|
function verbTenseToModalTense(tn: T.VerbTense): T.ModalTense {
|
||||||
if (tn === "presentVerb") {
|
if (tn === "presentVerb") {
|
||||||
return "presentVerbModal";
|
return "presentVerbModal";
|
||||||
|
@ -157,11 +173,14 @@ export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.
|
||||||
if (vs.tenseCategory === "perfect") {
|
if (vs.tenseCategory === "perfect") {
|
||||||
return vs.perfectTense;
|
return vs.perfectTense;
|
||||||
}
|
}
|
||||||
|
if (vs.tenseCategory === "imperative") {
|
||||||
|
return vs.imperativeTense;
|
||||||
|
}
|
||||||
// vs.tenseCategory === "modal"
|
// vs.tenseCategory === "modal"
|
||||||
return verbTenseToModalTense(vs.verbTense);
|
return verbTenseToModalTense(vs.verbTense);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPastTense(tense: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
|
export function isPastTense(tense: T.Tense): boolean {
|
||||||
if (isPerfectTense(tense)) return true;
|
if (isPerfectTense(tense)) return true;
|
||||||
return tense.toLowerCase().includes("past");
|
return tense.toLowerCase().includes("past");
|
||||||
}
|
}
|
||||||
|
@ -178,7 +197,7 @@ export function switchSubjObj(vps: T.VPSelection): T.VPSelection;
|
||||||
export function switchSubjObj(vps: T.VPSelectionComplete): T.VPSelectionComplete;
|
export function switchSubjObj(vps: T.VPSelectionComplete): T.VPSelectionComplete;
|
||||||
export function switchSubjObj(vps: T.VPSelection | T.VPSelectionComplete): T.VPSelection | T.VPSelectionComplete {
|
export function switchSubjObj(vps: T.VPSelection | T.VPSelectionComplete): T.VPSelection | T.VPSelectionComplete {
|
||||||
if ("tenseCategory" in vps.verb) {
|
if ("tenseCategory" in vps.verb) {
|
||||||
if (!vps.subject || !(typeof vps.verb.object === "object")) {
|
if (!vps.subject || !(typeof vps.verb.object === "object") || (vps.verb.tenseCategory === "imperative")) {
|
||||||
return vps;
|
return vps;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -223,3 +242,90 @@ export function completeVPSelection(vps: T.VPSelection): T.VPSelectionComplete |
|
||||||
verb,
|
verb,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isSecondPerson(p: T.Person): boolean {
|
||||||
|
return (
|
||||||
|
p === T.Person.SecondSingMale ||
|
||||||
|
p === T.Person.SecondSingFemale ||
|
||||||
|
p === T.Person.SecondPlurMale ||
|
||||||
|
p === T.Person.SecondPlurFemale
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isThirdPerson(p: T.Person): boolean {
|
||||||
|
return (
|
||||||
|
p === T.Person.ThirdSingMale ||
|
||||||
|
p === T.Person.ThirdSingFemale ||
|
||||||
|
p === T.Person.ThirdPlurMale ||
|
||||||
|
p === T.Person.ThirdPlurFemale
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ensure2ndPersSubjPronounAndNoConflict(vps: T.VPSelection): T.VPSelection {
|
||||||
|
console.log("checking more...", vps);
|
||||||
|
const subjIs2ndPerson = (vps.subject?.type === "pronoun") && isSecondPerson(vps.subject.person);
|
||||||
|
const objIs2ndPerson = (typeof vps.verb.object === "object")
|
||||||
|
&& (vps.verb.object.type === "pronoun")
|
||||||
|
&& isSecondPerson(vps.verb.object.person);
|
||||||
|
console.log({ subjIs2ndPerson, objIs2ndPerson });
|
||||||
|
const default2ndPersSubject: T.PronounSelection = {
|
||||||
|
type: "pronoun",
|
||||||
|
distance: "far",
|
||||||
|
person: T.Person.SecondSingMale,
|
||||||
|
};
|
||||||
|
function getNon2ndPersPronoun() {
|
||||||
|
let newObjPerson: T.Person;
|
||||||
|
do {
|
||||||
|
newObjPerson = randomNumber(0, 12);
|
||||||
|
} while(isSecondPerson(newObjPerson));
|
||||||
|
return newObjPerson;
|
||||||
|
}
|
||||||
|
if (subjIs2ndPerson && !objIs2ndPerson) {
|
||||||
|
return vps;
|
||||||
|
}
|
||||||
|
if (subjIs2ndPerson && objIs2ndPerson) {
|
||||||
|
if (typeof vps.verb.object !== "object" || vps.verb.object.type !== "pronoun") {
|
||||||
|
return vps;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...vps,
|
||||||
|
verb: {
|
||||||
|
...vps.verb,
|
||||||
|
object: {
|
||||||
|
...vps.verb.object,
|
||||||
|
person: getNon2ndPersPronoun(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!subjIs2ndPerson && objIs2ndPerson) {
|
||||||
|
if (typeof vps.verb.object !== "object" || vps.verb.object.type !== "pronoun") {
|
||||||
|
return {
|
||||||
|
...vps,
|
||||||
|
subject: default2ndPersSubject,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...vps,
|
||||||
|
subject: default2ndPersSubject,
|
||||||
|
verb: {
|
||||||
|
...vps.verb,
|
||||||
|
object: {
|
||||||
|
...vps.verb.object,
|
||||||
|
person: getNon2ndPersPronoun(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!subjIs2ndPerson && !objIs2ndPerson) {
|
||||||
|
console.log("returning last");
|
||||||
|
return {
|
||||||
|
...vps,
|
||||||
|
subject: default2ndPersSubject,
|
||||||
|
verb: {
|
||||||
|
...vps.verb,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error("error ensuring compatible VPSelection for imperative verb");
|
||||||
|
}
|
|
@ -160,11 +160,11 @@ export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> {
|
||||||
return a.length > 0;
|
return a.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPerfectTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.PerfectTense {
|
export function isPerfectTense(tense: T.Tense): tense is T.PerfectTense {
|
||||||
return tense.endsWith("Perfect");
|
return tense.endsWith("Perfect");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isVerbTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.VerbTense {
|
export function isVerbTense(tense: T.Tense): tense is T.VerbTense {
|
||||||
const verbTenses: T.VerbTense[] = [
|
const verbTenses: T.VerbTense[] = [
|
||||||
"presentVerb",
|
"presentVerb",
|
||||||
"subjunctiveVerb",
|
"subjunctiveVerb",
|
||||||
|
@ -178,12 +178,15 @@ export function isVerbTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense
|
||||||
return verbTenses.some(x => x === tense);
|
return verbTenses.some(x => x === tense);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isModalTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.ModalTense {
|
export function isModalTense(tense: T.Tense): tense is T.ModalTense {
|
||||||
return tense.endsWith("Modal");
|
return tense.endsWith("Modal");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense | T.ModalTense): t is T.EquativeTense {
|
export function isEquativeTense(t: T.Tense): t is T.EquativeTense {
|
||||||
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
|
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isImperativeTense(tense: T.Tense): tense is T.ImperativeTense {
|
||||||
|
return tense === "imperfectiveImperative" || tense === "perfectiveImperative";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,11 +106,11 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
||||||
}
|
}
|
||||||
|
|
||||||
function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation {
|
function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation {
|
||||||
const willUseImperative = !(
|
// const willUseImperative = !(
|
||||||
info.type === "dynamic compound"
|
// info.type === "dynamic compound"
|
||||||
&& info.transitivity === "intransitive"
|
// && info.transitivity === "intransitive"
|
||||||
&& info.auxVerb.p === "کېدل"
|
// && info.auxVerb.p === "کېدل"
|
||||||
);
|
// );
|
||||||
const auxConj = enforceObject(
|
const auxConj = enforceObject(
|
||||||
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
|
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
|
||||||
info.objComplement.person,
|
info.objComplement.person,
|
||||||
|
@ -136,18 +136,14 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
const ac = auxConj[aspect];
|
const ac = auxConj[aspect];
|
||||||
const nonImperative = addToForm([complement, " "], ac.nonImperative);
|
const nonImperative = addToForm([complement, " "], ac.nonImperative);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const imperative = (ac.imperative && willUseImperative)
|
const imperative = addToForm([complement, " "], ac.imperative);
|
||||||
? addToForm([complement, " "], ac.imperative)
|
|
||||||
: null;
|
|
||||||
const past = addToForm([complement, " "], auxConj[aspect].past);
|
const past = addToForm([complement, " "], auxConj[aspect].past);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
const modal = makeDynamicModalContent();
|
const modal = makeDynamicModalContent();
|
||||||
return {
|
return {
|
||||||
nonImperative,
|
nonImperative,
|
||||||
future,
|
future,
|
||||||
...imperative ? {
|
imperative,
|
||||||
imperative,
|
|
||||||
} : {},
|
|
||||||
past,
|
past,
|
||||||
habitualPast,
|
habitualPast,
|
||||||
modal,
|
modal,
|
||||||
|
@ -183,6 +179,7 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal);
|
const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal);
|
||||||
return {
|
return {
|
||||||
|
imperative: undefined,
|
||||||
nonImperative,
|
nonImperative,
|
||||||
future,
|
future,
|
||||||
past,
|
past,
|
||||||
|
@ -317,9 +314,7 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
|
||||||
stativeAux[transitivity][aspect].nonImperative,
|
stativeAux[transitivity][aspect].nonImperative,
|
||||||
);
|
);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const imperative = aux.imperative
|
const imperative = addToForm([presentComplement, " "], aux.imperative);
|
||||||
? addToForm([presentComplement, " "], aux.imperative)
|
|
||||||
: null;
|
|
||||||
const past = addToForm([info.complement, " "], aux.past);
|
const past = addToForm([info.complement, " "], aux.past);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
return {
|
return {
|
||||||
|
@ -327,9 +322,7 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
|
||||||
future,
|
future,
|
||||||
past,
|
past,
|
||||||
habitualPast,
|
habitualPast,
|
||||||
...imperative ? {
|
imperative,
|
||||||
imperative,
|
|
||||||
} : {},
|
|
||||||
modal: info.transitivity === "transitive"
|
modal: info.transitivity === "transitive"
|
||||||
? makeTransitiveStativeModalContent()
|
? makeTransitiveStativeModalContent()
|
||||||
: makeJoinedModalContent(info, "imperfective"),
|
: makeJoinedModalContent(info, "imperfective"),
|
||||||
|
@ -458,6 +451,7 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
noPersInfs(info.root.imperfective).long, " ",
|
noPersInfs(info.root.imperfective).long, " ",
|
||||||
], stativeAux.intransitive.imperfective.modal);
|
], stativeAux.intransitive.imperfective.modal);
|
||||||
return {
|
return {
|
||||||
|
imperative: undefined,
|
||||||
nonImperative,
|
nonImperative,
|
||||||
future,
|
future,
|
||||||
past,
|
past,
|
||||||
|
@ -474,6 +468,7 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
const auxModal = aux.modal;
|
const auxModal = aux.modal;
|
||||||
const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal);
|
const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal);
|
||||||
return {
|
return {
|
||||||
|
imperative: undefined,
|
||||||
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
|
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
|
||||||
future, // به ba + ROOT LONG + this.nonImperative
|
future, // به ba + ROOT LONG + this.nonImperative
|
||||||
past, // ROOT LONG + kedulStat[aspect].past
|
past, // ROOT LONG + kedulStat[aspect].past
|
||||||
|
@ -560,9 +555,7 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
||||||
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
|
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
|
||||||
nonImperative: allOnePersonInflection(as.nonImperative, person),
|
nonImperative: allOnePersonInflection(as.nonImperative, person),
|
||||||
future: allOnePersonInflection(as.future, person),
|
future: allOnePersonInflection(as.future, person),
|
||||||
...as.imperative ? {
|
imperative: allOnePersonInflection(as.imperative, person),
|
||||||
imperative: allOnePersonInflection(as.imperative, person),
|
|
||||||
} : {},
|
|
||||||
past: allOnePersonVerbForm(as.past, person),
|
past: allOnePersonVerbForm(as.past, person),
|
||||||
habitualPast: allOnePersonInflection(as.habitualPast, person),
|
habitualPast: allOnePersonInflection(as.habitualPast, person),
|
||||||
modal: {
|
modal: {
|
||||||
|
@ -586,6 +579,7 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
||||||
pastSubjunctiveHypothetical: allOnePersonVerbForm(perf.pastSubjunctiveHypothetical, person),
|
pastSubjunctiveHypothetical: allOnePersonVerbForm(perf.pastSubjunctiveHypothetical, person),
|
||||||
});
|
});
|
||||||
const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({
|
const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({
|
||||||
|
imperative: undefined,
|
||||||
nonImperative: allOnePersonVerbForm(as.nonImperative, person),
|
nonImperative: allOnePersonVerbForm(as.nonImperative, person),
|
||||||
future: allOnePersonVerbForm(as.future, person),
|
future: allOnePersonVerbForm(as.future, person),
|
||||||
past: allOnePersonVerbForm(as.past, person),
|
past: allOnePersonVerbForm(as.past, person),
|
||||||
|
|
28
src/types.ts
28
src/types.ts
|
@ -296,13 +296,17 @@ export type AspectContent = {
|
||||||
// ROOT = info.root[ASPECT]
|
// ROOT = info.root[ASPECT]
|
||||||
nonImperative: VerbForm; // STEM + pres ending
|
nonImperative: VerbForm; // STEM + pres ending
|
||||||
future: VerbForm; // به + this.nonImperative
|
future: VerbForm; // به + this.nonImperative
|
||||||
imperative?: ImperativeForm; // STEM + imperative ending
|
imperative: ImperativeForm; // STEM + imperative ending
|
||||||
// -- optional because not used for intransitive verison of kawul dynamic compounds
|
|
||||||
past: VerbForm; // ROOT + past ending
|
past: VerbForm; // ROOT + past ending
|
||||||
habitualPast: VerbForm; // ba + past
|
habitualPast: VerbForm; // ba + past
|
||||||
modal: ModalContent;
|
modal: ModalContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ASPECT -> AspectContentPssive
|
||||||
|
export type AspectContentPassive = Omit<AspectContent, "imperative"> & {
|
||||||
|
imperative: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
export type ModalContent = {
|
export type ModalContent = {
|
||||||
nonImperative: VerbForm; // ROOT + ey + kedulStat.perfective.nonImperative
|
nonImperative: VerbForm; // ROOT + ey + kedulStat.perfective.nonImperative
|
||||||
future: VerbForm; // به + this.nonImperative
|
future: VerbForm; // به + this.nonImperative
|
||||||
|
@ -311,16 +315,6 @@ export type ModalContent = {
|
||||||
hypotheticalPast: VerbForm; // ROOT + ey + shw + ey
|
hypotheticalPast: VerbForm; // ROOT + ey + shw + ey
|
||||||
}
|
}
|
||||||
|
|
||||||
// ASPECT -> AspectContentPssive
|
|
||||||
export type AspectContentPassive = {
|
|
||||||
// ROOT = info.root[ASPECT]
|
|
||||||
nonImperative: VerbForm; // ROOT LONG + kedulStat[ASPECT].nonImperative
|
|
||||||
future: VerbForm; // ba + this.nonImperative
|
|
||||||
past: VerbForm; // ROOT LONG + kedulStat[ASPECT].past
|
|
||||||
habitualPast: VerbForm;
|
|
||||||
modal: ModalContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ParticipleForm = SingleOrLengthOpts<UnisexInflections> | SingleOrLengthOpts<PsString>;
|
export type ParticipleForm = SingleOrLengthOpts<UnisexInflections> | SingleOrLengthOpts<PsString>;
|
||||||
|
|
||||||
export type ParticipleContent = {
|
export type ParticipleContent = {
|
||||||
|
@ -531,12 +525,13 @@ export type VerbTense = "presentVerb"
|
||||||
| "imperfectivePast"
|
| "imperfectivePast"
|
||||||
| "habitualPerfectivePast"
|
| "habitualPerfectivePast"
|
||||||
| "habitualImperfectivePast";
|
| "habitualImperfectivePast";
|
||||||
|
|
||||||
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
|
|
||||||
export type NounNumber = "singular" | "plural";
|
export type NounNumber = "singular" | "plural";
|
||||||
|
|
||||||
|
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
|
||||||
export type PerfectTense = `${EquativeTense}Perfect`;
|
export type PerfectTense = `${EquativeTense}Perfect`;
|
||||||
export type ModalTense = `${VerbTense}Modal`;
|
export type ModalTense = `${VerbTense}Modal`;
|
||||||
|
export type ImperativeTense = `${Aspect}Imperative`;
|
||||||
|
export type Tense = EquativeTense | VerbTense | PerfectTense | ModalTense | ImperativeTense;
|
||||||
|
|
||||||
export type VPSelection = {
|
export type VPSelection = {
|
||||||
subject: NPSelection | undefined,
|
subject: NPSelection | undefined,
|
||||||
|
@ -550,7 +545,7 @@ export type VPSelectionComplete = {
|
||||||
|
|
||||||
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "tenseCategory"> & {
|
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "tenseCategory"> & {
|
||||||
object: Exclude<VerbObject, undefined>,
|
object: Exclude<VerbObject, undefined>,
|
||||||
tense: VerbTense | PerfectTense | ModalTense,
|
tense: VerbTense | PerfectTense | ModalTense | ImperativeTense,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VerbSelection = {
|
export type VerbSelection = {
|
||||||
|
@ -569,7 +564,8 @@ export type VerbSelection = {
|
||||||
negative: boolean,
|
negative: boolean,
|
||||||
verbTense: VerbTense,
|
verbTense: VerbTense,
|
||||||
perfectTense: PerfectTense,
|
perfectTense: PerfectTense,
|
||||||
tenseCategory: "basic" | "modal" | "perfect",
|
imperativeTense: ImperativeTense,
|
||||||
|
tenseCategory: "basic" | "modal" | "perfect" | "imperative",
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VerbRendered = Omit<VerbSelectionComplete, "object"> & {
|
export type VerbRendered = Omit<VerbSelectionComplete, "object"> & {
|
||||||
|
|
Loading…
Reference in New Issue