pretty much working with new verb engine and verb explorer ... quiz doesn't seem to be working right now

This commit is contained in:
adueck 2023-07-22 18:13:52 +04:00
parent 5f8c4ba876
commit 3b6d013402
32 changed files with 39977 additions and 3698 deletions

11
package-lock.json generated
View File

@ -10,6 +10,7 @@
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"fp-ts": "^2.16.0",
"react-select": "^5.4.0"
},
"devDependencies": {
@ -10735,6 +10736,11 @@
"node": ">= 0.6"
}
},
"node_modules/fp-ts": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz",
"integrity": "sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ=="
},
"node_modules/fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@ -31006,6 +31012,11 @@
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"dev": true
},
"fp-ts": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz",
"integrity": "sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ=="
},
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",

View File

@ -77,7 +77,6 @@
},
"dependencies": {
"fp-ts": "^2.16.0",
"react-media-hook": "^0.5.0",
"react-select": "^5.4.0"
}
}
}

View File

@ -9,9 +9,7 @@
import { useEffect, useState } from "react";
import ButtonSelect from "./components/src/ButtonSelect";
import {
Modal
} from "react-bootstrap";
import { Modal } from "react-bootstrap";
import * as T from "./types";
import defualtTextOptions from "./lib/src/default-text-options";
import useStickyState from "./components/src/useStickyState";
@ -23,148 +21,196 @@ import InflectionDemo from "./demo-components/InflectionDemo";
import SpellingDemo from "./demo-components/SpellingDemo";
function App() {
const [showingTextOptions, setShowingTextOptions] = useStickyState<boolean>(false, "showTextOpts1");
const [textOptions, setTextOptions] = useStickyState<T.TextOptions>(defualtTextOptions, "textOpts1");
const [theme, setTheme] = useStickyState<"light" | "dark">("light", "theme1");
const [showing, setShowing] = useState<string>("");
function handleHiderClick(label: string) {
setShowing(os => os === label
? ""
: label);
}
useEffect(() => {
document.documentElement.setAttribute("data-theme", theme);
}, [theme]);
const [showingTextOptions, setShowingTextOptions] = useStickyState<boolean>(
false,
"showTextOpts1"
);
const [textOptions, setTextOptions] = useStickyState<T.TextOptions>(
defualtTextOptions,
"textOpts1"
);
const [theme, setTheme] = useStickyState<"light" | "dark">("light", "theme1");
const [showing, setShowing] = useState<string>("");
function handleHiderClick(label: string) {
setShowing((os) => (os === label ? "" : label));
}
useEffect(() => {
document.documentElement.setAttribute("data-theme", theme);
}, [theme]);
return <>
<main className="flex-shrink-0 mb-4">
<div className="container" style={{ maxWidth: "800px" }}>
<div style={{ position: "absolute", top: "1.5rem", right: "1.5rem", display: "flex", flexDirection: "row" }}>
<div
className="clickable mr-3"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<i className={`fa-lg fas fa-${theme === "light" ? "sun" : "moon"}`} />
</div>
<div
className="clickable"
onClick={() => setShowingTextOptions(true)}
>
<i className="fa-lg fas fa-cog" />
</div>
return (
<>
<main className="flex-shrink-0 mb-4">
<div className="container" style={{ maxWidth: "800px" }}>
<div
style={{
position: "absolute",
top: "1.5rem",
right: "1.5rem",
display: "flex",
flexDirection: "row",
}}
>
<div
className="clickable mr-3"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<i
className={`fa-lg fas fa-${theme === "light" ? "sun" : "moon"}`}
/>
</div>
<div className="text-center mb-4" style={{ marginTop: "3rem", marginBottom: "1rem" }}>
<h1 className="display-4 mt-2"><code>Pashto Inflector</code></h1>
<p className="lead my-3" style={{ maxWidth: "600px", margin: "0 auto" }}>
An open source TypeScript/React library for Pashto inflection, verb conjugation, phrase generation, text conversion, and more
</p>
<p>Used in the <a href="https://dictionary.lingdocs.com">LingDocs Pashto Dictionary</a> and <a href="https://grammar.lingdocs.com">LingDocs Pashto Grammar</a></p>
<p>by <a href="https://adueck.github.io">Adam Dueck</a> - GPLv3 licensed <a href="https://github.com/lingdocs/pashto-inflector">Source Code</a> on GitHub</p>
</div>
<h2 className="mb-3">Demos:</h2>
<Hider
label="Verb Conjugation / Verb Phrase Engine"
hLevel={3}
showing={showing === "verbs"}
handleChange={() => handleHiderClick("verbs")}
>
<VPBuilderDemo opts={textOptions} />
</Hider>
<Hider
label="Equative Phrase Engine"
hLevel={3}
showing={showing === "equatives"}
handleChange={() => handleHiderClick("equatives")}
>
<div className="mt-4" style={{ paddingBottom: "20px" }}>
<EPExplorer
opts={textOptions}
entryFeeder={entryFeeder}
/>
</div>
</Hider>
<Hider
label="Inflection Engine"
hLevel={3}
showing={showing === "inflection"}
handleChange={() => handleHiderClick("inflection")}
>
<InflectionDemo opts={textOptions} />
</Hider>
<Hider
label="Spelling Conversion / Diacritics Engine"
hLevel={3}
showing={showing === "spelling"}
handleChange={() => handleHiderClick("spelling")}
>
<SpellingDemo opts={textOptions} onChange={setTextOptions} />
</Hider>
<div
className="clickable"
onClick={() => setShowingTextOptions(true)}
>
<i className="fa-lg fas fa-cog" />
</div>
</main>
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>
<Modal.Header closeButton>
<Modal.Title>Settings</Modal.Title>
</Modal.Header>
<Modal.Body>
<h6>Pashto Spelling</h6>
<ButtonSelect
options={[
{ label: "Afghan", value: "Afghan" },
{ label: "Pakistani ي", value: "Pakistani ي" },
{ label: "Pakistani ی", value: "Pakistani ی" },
]}
value={textOptions.spelling}
handleChange={(p) => {
setTextOptions({
...textOptions,
spelling: p,
});
}}
/>
<h6 className="mt-3">Diacritics</h6>
<ButtonSelect
options={[
{ label: "On", value: "true" },
{ label: "Off", value: "false" },
]}
value={textOptions.diacritics.toString()}
handleChange={(p) => setTextOptions({ ...textOptions, diacritics: p === "true" })}
/>
<h6 className="mt-3">Pashto Text Size</h6>
<ButtonSelect
options={[
{ label: "Normal", value: "normal" },
{ label: "Large", value: "larger" },
{ label: "X-Large", value: "largest" },
]}
value={textOptions.pTextSize}
handleChange={(p) => setTextOptions({ ...textOptions, pTextSize: p })}
/>
<h6 className="mt-3">Phonetics</h6>
<ButtonSelect
options={[
{ label: "LingDocs", value: "lingdocs" },
{ label: "IPA", value: "ipa" },
{ label: "ALAC", value: "alalc" },
// { label: "None", value: "none" },
]}
value={textOptions.phonetics}
handleChange={(p) => setTextOptions({ ...textOptions, phonetics: p })}
/>
</Modal.Body>
<Modal.Footer>
<button type="button" className="btn btn-primary clb" onClick={() => setShowingTextOptions(false)}>
Close
</button>
</Modal.Footer>
</Modal>
{/* <footer className="footer mt-auto py-3" style={{ backgroundColor: "#f5f5f5" }}>
</div>
<div
className="text-center mb-4"
style={{ marginTop: "3rem", marginBottom: "1rem" }}
>
<h1 className="display-4 mt-2">
<code>Pashto Inflector</code>
</h1>
<p
className="lead my-3"
style={{ maxWidth: "600px", margin: "0 auto" }}
>
An open source TypeScript/React library for Pashto inflection,
verb conjugation, phrase generation, text conversion, and more
</p>
<p>
Used in the{" "}
<a href="https://dictionary.lingdocs.com">
LingDocs Pashto Dictionary
</a>{" "}
and{" "}
<a href="https://grammar.lingdocs.com">LingDocs Pashto Grammar</a>
</p>
<p>
by <a href="https://adueck.github.io">Adam Dueck</a> - GPLv3
licensed{" "}
<a href="https://github.com/lingdocs/pashto-inflector">
Source Code
</a>{" "}
on GitHub
</p>
</div>
<h2 className="mb-3">Demos:</h2>
<Hider
label="Verb Conjugation / Verb Phrase Engine"
hLevel={3}
showing={showing === "verbs"}
handleChange={() => handleHiderClick("verbs")}
>
<VPBuilderDemo opts={textOptions} />
</Hider>
<Hider
label="Equative Phrase Engine"
hLevel={3}
showing={showing === "equatives"}
handleChange={() => handleHiderClick("equatives")}
>
<div className="mt-4" style={{ paddingBottom: "20px" }}>
<EPExplorer opts={textOptions} entryFeeder={entryFeeder} />
</div>
</Hider>
<Hider
label="Inflection Engine"
hLevel={3}
showing={showing === "inflection"}
handleChange={() => handleHiderClick("inflection")}
>
<InflectionDemo opts={textOptions} />
</Hider>
<Hider
label="Spelling Conversion / Diacritics Engine"
hLevel={3}
showing={showing === "spelling"}
handleChange={() => handleHiderClick("spelling")}
>
<SpellingDemo opts={textOptions} onChange={setTextOptions} />
</Hider>
</div>
</main>
<Modal
show={showingTextOptions}
onHide={() => setShowingTextOptions(false)}
>
<Modal.Header closeButton>
<Modal.Title>Settings</Modal.Title>
</Modal.Header>
<Modal.Body>
<h6>Pashto Spelling</h6>
<ButtonSelect
options={[
{ label: "Afghan", value: "Afghan" },
{ label: "Pakistani ي", value: "Pakistani ي" },
{ label: "Pakistani ی", value: "Pakistani ی" },
]}
value={textOptions.spelling}
handleChange={(p) => {
setTextOptions({
...textOptions,
spelling: p,
});
}}
/>
<h6 className="mt-3">Diacritics</h6>
<ButtonSelect
options={[
{ label: "On", value: "true" },
{ label: "Off", value: "false" },
]}
value={textOptions.diacritics.toString()}
handleChange={(p) =>
setTextOptions({ ...textOptions, diacritics: p === "true" })
}
/>
<h6 className="mt-3">Pashto Text Size</h6>
<ButtonSelect
options={[
{ label: "Normal", value: "normal" },
{ label: "Large", value: "larger" },
{ label: "X-Large", value: "largest" },
]}
value={textOptions.pTextSize}
handleChange={(p) =>
setTextOptions({ ...textOptions, pTextSize: p })
}
/>
<h6 className="mt-3">Phonetics</h6>
<ButtonSelect
options={[
{ label: "LingDocs", value: "lingdocs" },
{ label: "IPA", value: "ipa" },
{ label: "ALAC", value: "alalc" },
// { label: "None", value: "none" },
]}
value={textOptions.phonetics}
handleChange={(p) =>
setTextOptions({ ...textOptions, phonetics: p })
}
/>
</Modal.Body>
<Modal.Footer>
<button
type="button"
className="btn btn-primary clb"
onClick={() => setShowingTextOptions(false)}
>
Close
</button>
</Modal.Footer>
</Modal>
{/* <footer className="footer mt-auto py-3" style={{ backgroundColor: "#f5f5f5" }}>
<div className="container">
<span className="text-muted">Copyright © 2022 <a href="https://www.lingdocs.com">lingdocs.com</a> - <a href="https://github.com/lingdocs/pashto-inflector/blob/master/LICENSE">MIT License</a></span>
</div>
</footer> */}
</>
);
}
export default App;

35162
src/components/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -47,4 +47,4 @@
"babel-loader": "^8.3.0",
"fs-extra": "^10.1.0"
}
}
}

View File

@ -1,6 +1,4 @@
import {
makeNounSelection,
} from "../../../lib/src/phrase-building/make-selections";
import { makeNounSelection } from "../../../lib/src/phrase-building/make-selections";
import * as T from "../../../types";
import ButtonSelect from "../ButtonSelect";
@ -57,45 +55,49 @@ import AdjectiveManager from "./AdjectiveManager";
// }
function NPNounPicker(props: {
entryFeeder: T.EntryFeeder,
noun: T.NounSelection | undefined,
onChange: (p: T.NounSelection | undefined) => void,
opts: T.TextOptions,
phraseIsComplete: boolean,
entryFeeder: T.EntryFeeder;
noun: T.NounSelection | undefined;
onChange: (p: T.NounSelection | undefined) => void;
opts: T.TextOptions;
phraseIsComplete: boolean;
}) {
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
// const [showFilter, setShowFilter] = useState<boolean>(false)
// const nounsFiltered = props.nouns
// .filter(nounFilter(patternFilter))
// .sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
function onEntrySelect(entry: T.NounEntry | undefined) {
if (!entry) {
return props.onChange(undefined);
}
props.onChange(makeNounSelection(entry, props.noun));
console.log({ noun: props.noun });
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
// const [showFilter, setShowFilter] = useState<boolean>(false)
// const nounsFiltered = props.nouns
// .filter(nounFilter(patternFilter))
// .sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
function onEntrySelect(entry: T.NounEntry | undefined) {
if (!entry) {
return props.onChange(undefined);
}
// function handleFilterClose() {
// setPatternFilter(undefined);
// setShowFilter(false);
// }
function handelAdjectivesUpdate(adjectives: T.AdjectiveSelection[]) {
if (props.noun) {
props.onChange({
...props.noun,
adjectives,
});
}
props.onChange(makeNounSelection(entry, props.noun));
}
// function handleFilterClose() {
// setPatternFilter(undefined);
// setShowFilter(false);
// }
function handelAdjectivesUpdate(adjectives: T.AdjectiveSelection[]) {
if (props.noun) {
props.onChange({
...props.noun,
adjectives,
});
}
function handleDemonstrativeUpdate(demonstrative: undefined | T.NounSelection["demonstrative"]) {
if (props.noun) {
props.onChange({
...props.noun,
demonstrative,
});
}
}
function handleDemonstrativeUpdate(
demonstrative: undefined | T.NounSelection["demonstrative"]
) {
if (props.noun) {
props.onChange({
...props.noun,
demonstrative,
});
}
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
{/* {showFilter && <div className="mb-2 text-center">
}
return (
<div style={{ maxWidth: "225px", minWidth: "125px" }}>
{/* {showFilter && <div className="mb-2 text-center">
<div className="d-flex flex-row justify-content-between">
<div className="text-small mb-1">Filter by inflection pattern</div>
<div className="clickable" onClick={handleFilterClose}>X</div>
@ -108,72 +110,102 @@ function NPNounPicker(props: {
handleChange={setPatternFilter}
/>
</div>} */}
{props.noun && <AdjectiveManager
phraseIsComplete={props.phraseIsComplete}
adjectives={props.noun?.adjectives}
demonstrative={props.noun.demonstrative}
entryFeeder={props.entryFeeder}
{props.noun && (
<AdjectiveManager
phraseIsComplete={props.phraseIsComplete}
adjectives={props.noun?.adjectives}
demonstrative={props.noun.demonstrative}
entryFeeder={props.entryFeeder}
opts={props.opts}
onChange={handelAdjectivesUpdate}
onDemonstrativeChange={handleDemonstrativeUpdate}
/>
)}
<div className="h6">Noun</div>
{!(
props.noun &&
(props.noun.dynamicComplement || props.noun.genStativeComplement)
) ? (
<div>
<EntrySelect
value={props.noun?.entry}
entryFeeder={props.entryFeeder.nouns}
onChange={onEntrySelect}
name="Noun"
opts={props.opts}
onChange={handelAdjectivesUpdate}
onDemonstrativeChange={handleDemonstrativeUpdate}
/>}
<div className="h6">Noun</div>
{!(props.noun && props.noun.dynamicComplement) ? <div>
<EntrySelect
value={props.noun?.entry}
entryFeeder={props.entryFeeder.nouns}
onChange={onEntrySelect}
name="Noun"
opts={props.opts}
/>
</div> : <div>
{props.noun && <div>
<div className="mb-2">Included in Dyn. Compound:</div>
<div className="mb-3 text-center">
<InlinePs opts={props.opts}>
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
</InlinePs>
<div className="text-muted">{props.noun.entry.e}</div>
</div>
</div>}
</div>}
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
/>
</div>
) : (
<div>
{props.noun && (
<div>
{props.noun.genderCanChange ? <ButtonSelect
small
options={[
{ label: "Masc", value: "masc" },
{ label: "Fem", value: "fem" },
]}
value={props.noun.gender}
handleChange={(gender) => {
if (!props.noun || !props.noun.genderCanChange) return;
props.onChange({
...props.noun,
gender,
});
}}
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
<div className="mb-2">
Included in{" "}
{props.noun.genStativeComplement ? "Gen. Stat." : "Dyn."}{" "}
Compound:
</div>
<div className="mb-3 text-center">
<InlinePs opts={props.opts}>
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
</InlinePs>
<div className="text-muted">{props.noun.entry.e}</div>
</div>
</div>
<div>
{props.noun.numberCanChange ? <ButtonSelect
small
options={[
{ label: "Sing.", value: "singular" },
{ label: "Plur.", value: "plural" },
]}
value={props.noun.number}
handleChange={(number) => {
if (!props.noun || !props.noun.numberCanChange) return;
props.onChange({
...props.noun,
number,
});
}}
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
</div>
</div>}
</div>;
)}
</div>
)}
{props.noun && (
<div className="my-2 d-flex flex-row justify-content-around align-items-center">
<div>
{props.noun.genderCanChange ? (
<ButtonSelect
small
options={[
{ label: "Masc", value: "masc" },
{ label: "Fem", value: "fem" },
]}
value={props.noun.gender}
handleChange={(gender) => {
if (!props.noun || !props.noun.genderCanChange) return;
props.onChange({
...props.noun,
gender,
});
}}
/>
) : props.noun.gender === "masc" ? (
"Masc."
) : (
"Fem."
)}
</div>
<div>
{props.noun.numberCanChange ? (
<ButtonSelect
small
options={[
{ label: "Sing.", value: "singular" },
{ label: "Plur.", value: "plural" },
]}
value={props.noun.number}
handleChange={(number) => {
if (!props.noun || !props.noun.numberCanChange) return;
props.onChange({
...props.noun,
number,
});
}}
/>
) : props.noun.number === "singular" ? (
"Sing."
) : (
"Plur."
)}
</div>
</div>
)}
</div>
);
}
export default NPNounPicker;
export default NPNounPicker;

View File

@ -9,13 +9,21 @@ import Hider from "../Hider";
import * as T from "../../../types";
import useStickyState from "../useStickyState";
import { isImperativeTense } from "../../../lib/src/type-predicates";
import ButtonSelect from "../ButtonSelect";
import { VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
import { useState } from "react";
import { statVerb } from "../../../lib/src/new-verb-engine/roots-and-stems";
// import { conjugateVerb } from "../../../lib/src/verb-conjugation";
function AllTensesDisplay({
VS,
opts,
onChange,
object,
}: {
onChange: (p: VpsReducerAction) => void;
VS: T.VerbSelection;
object: T.NPSelection | T.ObjectNP | undefined;
opts: T.TextOptions;
}) {
const [showing, setShowing] = useStickyState<string[]>([], "VPTensesShowing");
@ -23,6 +31,11 @@ function AllTensesDisplay({
false,
"showFormulasWithCharts"
);
const [objectNPNumber, setObjectNPNumber] = useState<T.NounNumber>(
object && typeof object === "object" && object.selection.type === "noun"
? object.selection.number
: "singular"
);
const adjustShowing = (v: string) => {
if (showing.includes(v)) {
setShowing((os) => os.filter((x) => x !== v));
@ -56,14 +69,69 @@ function AllTensesDisplay({
? (`${baseTense}Modal` as T.AbilityTense)
: baseTense;
}
const objectNP: T.NPSelection | undefined =
object && typeof object === "object" && object.selection.type === "noun"
? object
: undefined;
const verb =
VS.isCompound === "generative stative"
? statVerb[
VS.transitivity === "intransitive" ? "intransitive" : "transitive"
]
: VS.dynAuxVerb
? VS.dynAuxVerb
: VS.verb;
return (
<div>
<div
className="clickable mb-2 small text-center"
onClick={() => setShowFormulas((x) => !x)}
className="small clickable text-right mb-2"
>
🧪 {!showFormulas ? "Show" : "Hide"} Formulas
</div>
<div className="mb-2 d-flex flex-row justify-content-around align-items-center">
{objectNP?.selection.type === "noun" &&
objectNP.selection.numberCanChange && (
<div>
<span className="text-muted small mr-2">comp. noun:</span>
<ButtonSelect
xSmall
value={objectNPNumber}
options={[
{
label: "sing.",
value: "singular",
},
{
label: "plur.",
value: "plural",
},
]}
handleChange={(number) => {
setObjectNPNumber(number);
}}
/>
</div>
)}
<ButtonSelect
xSmall
value={VS.negative.toString() as "true" | "false"}
options={[
{
label: "Pos.",
value: "false",
},
{
label: "Neg.",
value: "true",
},
]}
handleChange={(payload) =>
onChange({ type: "set negativity", payload })
}
/>
</div>
{options.map((tense) => {
const t = getTense(tense.value);
return (
@ -81,7 +149,20 @@ function AllTensesDisplay({
)}
{showing && (
<ChartDisplay
verb={VS.verb}
verb={verb}
objectNP={
objectNP?.selection.type === "noun"
? {
...objectNP,
selection: {
...objectNP.selection,
number: objectNP.selection.numberCanChange
? objectNPNumber
: objectNP.selection.number,
},
}
: undefined
}
negative={VS.negative}
tense={t}
transitivity={VS.transitivity}

View File

@ -8,7 +8,13 @@ import { choosePersInf, getLength } from "../../../lib/src/p-text-helpers";
import genderColors from "../gender-colors";
import { eqPsStringWVars } from "../../../lib/src/fp-ps";
import PersInfsPicker from "../PersInfsPicker";
import { useMediaPredicate } from "react-media-hook";
import "./form-display.css";
import {
makeBlock,
makeKid,
} from "../../../lib/src/phrase-building/blocks-utils";
import InlinePs from "../InlinePs";
import { personToGenNum } from "../../../lib/src/misc-helpers";
export const roleIcon = {
king: <i className="mx-1 fas fa-crown" />,
@ -21,14 +27,21 @@ function VerbChartDisplay({
shortDefault,
transitivity,
past,
negative,
imperative,
}: {
chart: T.OptionalPersonInflections<
T.SingleOrLengthOpts<T.RenderVerbOutput[]>
>;
chart: {
objNP: T.Rendered<T.NPSelection> | undefined;
vbs: T.OptionalPersonInflections<
T.SingleOrLengthOpts<T.RenderVerbOutput[]>
>;
};
opts: T.TextOptions;
shortDefault?: boolean;
transitivity: T.Transitivity;
past: boolean;
negative: boolean;
imperative: boolean;
}) {
const [length, setLength] = useState<T.Length>(
shortDefault ? "short" : "long"
@ -37,13 +50,23 @@ function VerbChartDisplay({
useEffect(() => {
setLength("long");
}, [chart]);
const desktop = useMediaPredicate("(min-width: 600px)");
const chartWPers = choosePersInf(chart, persInf);
const chartWPers = choosePersInf(chart.vbs, persInf);
const chartWLength = getLength(chartWPers, length);
const x = chartWLength.map(renderVerbOutputToText(false));
const x = chartWLength.map(
renderVerbOutputToText({
objNP: chart.objNP,
negative,
hasBa: chartWLength[0].hasBa,
imperative,
intransitive: transitivity === "intransitive",
})
);
const verbBlock =
x.length === 12
x.length === 1
? // unchanging gramm trans or dynamic compound past transitive
[[[x[0]]]]
: x.length === 12
? [
// 1st pers
[
@ -83,10 +106,15 @@ function VerbChartDisplay({
</div>
<div className="row">
<div className="col">
<AgreementInfo transitivity={transitivity} past={past} />
<AgreementInfo
opts={opts}
transitivity={transitivity}
past={past}
objNP={chart.objNP}
/>
</div>
<div className="col">
{"long" in chartWPers && (
{"long" in chartWPers && lengthsMakeADiff(chartWPers) && (
<LengthSelection
hasMini={"mini" in chartWPers}
value={length}
@ -94,30 +122,36 @@ function VerbChartDisplay({
/>
)}
</div>
{desktop && <div className="col" />}
<div className="hide-on-mobile col" />
</div>
<table className="table mt-2" style={{ tableLayout: "fixed" }}>
<thead>
<tr>
<th scope="col" style={{ width: "3rem" }}>
Pers.
</th>
<th scope="col">Singular</th>
<th scope="col">Plural</th>
</tr>
</thead>
<tbody>
{verbBlock.map((personRow, i) => (
<PersonRow
key={Math.random()}
// get proper version for imperative blocks
person={verbBlock.length === 1 ? 1 : i}
item={personRow}
opts={opts}
/>
))}
</tbody>
</table>
{verbBlock.length === 1 ? (
<div className="d-flex flex-row justify-content-center mt-3 text-center">
<TableCell item={verbBlock[0][0][0]} textOptions={opts} />
</div>
) : (
<table className="table mt-2" style={{ tableLayout: "fixed" }}>
<thead>
<tr>
<th scope="col" style={{ width: "3rem" }}>
Pers.
</th>
<th scope="col">Singular</th>
<th scope="col">Plural</th>
</tr>
</thead>
<tbody>
{verbBlock.map((personRow, i) => (
<PersonRow
key={Math.random()}
// get proper version for imperative blocks
person={verbBlock.length === 1 ? 1 : i}
item={personRow}
opts={opts}
/>
))}
</tbody>
</table>
)}
</>
);
}
@ -224,32 +258,93 @@ function LengthSelection({
);
}
function renderVerbOutputToText(negative: boolean) {
function renderVerbOutputToText({
objNP,
negative,
hasBa,
imperative,
intransitive,
}: {
objNP: T.Rendered<T.NPSelection> | undefined;
negative: boolean;
hasBa: boolean;
imperative: boolean;
intransitive: boolean;
}) {
return function (v: T.RenderVerbOutput): T.PsString[] {
const blocks = insertNegative(
v.vbs,
negative,
false /* TODO: apply imperative */
const blocks: T.Block[][] = insertNegative(v.vbs, negative, imperative).map(
(b) => {
if (!objNP) return b;
return [
...(objNP
? [makeBlock({ type: "objectSelection", selection: objNP })]
: []),
...b,
];
}
);
return combineIntoText(blocks, 0 /* TODO: why is this needed */);
const b = hasBa
? blocks.flatMap((v) => [
[
{ p: " ... ", f: " ... " },
...[makeKid({ type: "ba" }), { p: " ... ", f: " ... " }],
...v,
],
...(v.length > 1 && intransitive
? [[v[0], makeKid({ type: "ba" }), ...v.slice(1)]]
: []),
])
: blocks;
return combineIntoText(b, 0 /* TODO: why is this needed */);
};
}
function AgreementInfo({
transitivity,
past,
objNP,
opts,
}: {
transitivity: T.Transitivity;
past: boolean;
objNP: T.Rendered<T.NPSelection> | undefined;
opts: T.TextOptions;
}) {
function printGenNum({ gender, number }: T.GenderNumber): string {
return `${gender === "masc" ? "m." : "f."} ${
number === "singular" ? "s." : "pl."
}`;
}
return (
<div className="text-muted small mt-1">
{roleIcon.king} agrees w/{" "}
<strong>
{transitivity !== "intransitive" && past ? "object" : "subject"}
</strong>
<div>
{roleIcon.king} agrees w/{" "}
<strong>
{transitivity !== "intransitive" && past ? "object" : "subject"}
</strong>
{transitivity === "transitive" && past && objNP ? " noun" : ""}
</div>
{transitivity === "transitive" && past && objNP && (
<div>
<InlinePs opts={opts}>{objNP.selection.ps[0]}</InlinePs>
{` `}({printGenNum(personToGenNum(objNP.selection.person))})
</div>
)}
{transitivity === "grammatically transitive" && past && (
<div>(implied 3rd pers. m. pl.)</div>
)}
</div>
);
}
function lengthsMakeADiff(v: T.LengthOptions<T.RenderVerbOutput[]>): boolean {
if (v.long.length > 1) {
return true;
}
const longSample = combineIntoText([[makeBlock(v.long[0].vbs[1][0])]], 0);
const shortSample = combineIntoText([[makeBlock(v.short[0].vbs[1][0])]], 0);
return !eqPsStringWVars.equals(longSample, shortSample);
}
export default VerbChartDisplay;

View File

@ -3,6 +3,8 @@ import * as T from "../../../types";
import { buildVerbChart } from "./chart-builder";
import { isPastTense } from "../../library";
// TODO - combine this with NewVerbFormDisplay
function ChartDisplay({
verb,
tense,
@ -11,6 +13,7 @@ function ChartDisplay({
imperative,
negative,
transitivity,
objectNP,
}: {
verb: T.VerbEntry;
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
@ -19,6 +22,7 @@ function ChartDisplay({
imperative: boolean;
negative: boolean;
transitivity: T.Transitivity;
objectNP: T.NPSelection | undefined;
}) {
const verbChart = buildVerbChart({
verb,
@ -27,10 +31,13 @@ function ChartDisplay({
negative,
transitivity,
imperative,
objectNP,
});
return (
<div className="mb-4">
<NewVerbFormDisplay
imperative={imperative}
negative={negative}
chart={verbChart}
opts={opts}
transitivity={transitivity}

View File

@ -28,213 +28,244 @@ export const vpPhraseURLParam = "vp";
// TODO: error handling on error with rendering etc
function VPExplorer(props: {
loaded?: T.VPSelectionState,
verb: T.VerbEntry,
opts: T.TextOptions,
handleLinkClick: ((ts: number) => void) | "none",
entryFeeder: T.EntryFeeder,
onlyPhrases?: boolean,
loaded?: T.VPSelectionState;
verb: T.VerbEntry;
opts: T.TextOptions;
handleLinkClick: ((ts: number) => void) | "none";
entryFeeder: T.EntryFeeder;
onlyPhrases?: boolean;
}) {
const [vps, adjustVps] = useStickyReducer(
vpsReducer,
props.loaded
? props.loaded
: savedVps => makeVPSelectionState(props.verb, savedVps),
"vpsState16",
flashMessage,
);
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
savedMode => {
if (!savedMode) return props.onlyPhrases ? "phrases" : "charts";
if (savedMode === "quiz") return "phrases";
return savedMode;
},
"verbExplorerMode2",
);
const [showClipped, setShowClipped] = useState<string>("");
const [
alertMsg,
// setAlertMsg,
] = useState<string | undefined>(undefined);
function flashMessage(msg: string) {
console.log(msg);
// for some crazy reason this causes it to go through with the state change
// we're trying to avoid when there's a potential errored state
// setAlertMsg(msg);
// setTimeout(() => {
// setAlertMsg(undefined);
// }, 2000);
const [vps, adjustVps] = useStickyReducer(
vpsReducer,
props.loaded
? props.loaded
: (savedVps) => makeVPSelectionState(props.verb, savedVps),
"vpsState16",
flashMessage
);
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
(savedMode) => {
if (!savedMode) return props.onlyPhrases ? "phrases" : "charts";
if (savedMode === "quiz") return "phrases";
return savedMode;
},
"verbExplorerMode2"
);
const [showClipped, setShowClipped] = useState<string>("");
const [
alertMsg,
// setAlertMsg,
] = useState<string | undefined>(undefined);
function flashMessage(msg: string) {
console.log(msg);
// for some crazy reason this causes it to go through with the state change
// we're trying to avoid when there's a potential errored state
// setAlertMsg(msg);
// setTimeout(() => {
// setAlertMsg(undefined);
// }, 2000);
}
useEffect(() => {
adjustVps({
type: "set verb",
payload: props.verb,
});
// eslint-disable-next-line
}, [props.verb]);
useEffect(() => {
if (props.loaded) {
adjustVps({
type: "load vps",
payload: props.loaded,
});
}
useEffect(() => {
adjustVps({
type: "set verb",
payload: props.verb,
});
// eslint-disable-next-line
}, [props.verb]);
useEffect(() => {
if (props.loaded) {
adjustVps({
type: "load vps",
payload: props.loaded,
});
}
// eslint-disable-next-line
}, [props.loaded]);
useEffect(() => {
const VPSFromUrl = getVPSFromUrl();
if (VPSFromUrl) {
setMode("phrases");
adjustVps({
type: "load vps",
payload: VPSFromUrl
});
}
// eslint-disable-next-line
}, []);
function handleSubjObjSwap() {
adjustVps({ type: "swap subj/obj" });
// eslint-disable-next-line
}, [props.loaded]);
useEffect(() => {
const VPSFromUrl = getVPSFromUrl();
if (VPSFromUrl) {
setMode("phrases");
adjustVps({
type: "load vps",
payload: VPSFromUrl,
});
}
function quizLock<T>(f: T) {
if (mode === "quiz") {
return () => {
flashMessage("to adjust this, get out of quiz mode");
return null;
};
}
return f;
// eslint-disable-next-line
}, []);
function handleSubjObjSwap() {
adjustVps({ type: "swap subj/obj" });
}
function quizLock<T>(f: T) {
if (mode === "quiz") {
return () => {
flashMessage("to adjust this, get out of quiz mode");
return null;
};
}
function handleSetForm(form: T.FormVersion) {
adjustVps({
type: "set form",
payload: form,
});
}
function flashClippedMessage(m: string) {
setShowClipped(m);
setTimeout(() => {
setShowClipped("");
}, 1250);
}
// for some crazy reason I can't get the URI share thing to encode and decode properly
function handleCopyShareLink() {
const shareUrl = getShareUrl(vps);
navigator.clipboard.writeText(shareUrl);
flashClippedMessage("Copied phrase URL to clipboard");
}
function handleCopyCode() {
const code = getCode(vps);
navigator.clipboard.writeText(code);
flashClippedMessage("Copied phrase code to clipboard");
}
const object = getObjectSelection(vps.blocks).selection;
const VPS = completeVPSelection(vps);
const phraseIsComplete = !!VPS;
return <div className="mt-3" style={{ maxWidth: "950px"}}>
<VerbPicker
vps={vps}
onChange={quizLock(adjustVps)}
opts={props.opts}
handleLinkClick={props.handleLinkClick}
return f;
}
function handleSetForm(form: T.FormVersion) {
adjustVps({
type: "set form",
payload: form,
});
}
function flashClippedMessage(m: string) {
setShowClipped(m);
setTimeout(() => {
setShowClipped("");
}, 1250);
}
// for some crazy reason I can't get the URI share thing to encode and decode properly
function handleCopyShareLink() {
const shareUrl = getShareUrl(vps);
navigator.clipboard.writeText(shareUrl);
flashClippedMessage("Copied phrase URL to clipboard");
}
function handleCopyCode() {
const code = getCode(vps);
navigator.clipboard.writeText(code);
flashClippedMessage("Copied phrase code to clipboard");
}
const object = getObjectSelection(vps.blocks).selection;
const VPS = completeVPSelection(vps);
const phraseIsComplete = !!VPS;
return (
<div className="mt-3" style={{ maxWidth: "950px" }}>
<VerbPicker
vps={vps}
onChange={quizLock(adjustVps)}
opts={props.opts}
handleLinkClick={props.handleLinkClick}
/>
{!props.onlyPhrases && (
<div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
<div style={{ width: "1rem" }}></div>
<ButtonSelect
value={mode}
options={[
{ label: "Charts", value: "charts" },
{ label: "Phrases", value: "phrases" },
{ label: "Quiz", value: "quiz" },
]}
handleChange={setMode}
/>
<div className="d-flex flex-row">
<div
className="clickable mr-4"
onClick={mode === "phrases" ? handleCopyCode : undefined}
style={{ width: "1rem" }}
>
{mode === "phrases" && phraseIsComplete ? (
<i className="fas fa-code" />
) : (
""
)}
</div>
<div
className="clickable"
onClick={mode === "phrases" ? handleCopyShareLink : undefined}
style={{ width: "1rem" }}
>
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
</div>
</div>
</div>
)}
{vps.verb &&
typeof object === "object" &&
vps.verb.isCompound !== "dynamic" &&
vps.verb.tenseCategory !== "imperative" &&
mode === "phrases" && (
<div className="text-center my-2">
<button
onClick={handleSubjObjSwap}
className="btn btn-sm btn-light"
>
<i className="fas fa-exchange-alt mr-2" /> subj/obj
</button>
</div>
)}
{mode === "phrases" && (
<VPPicker
opts={props.opts}
entryFeeder={props.entryFeeder}
onChange={(payload) => adjustVps({ type: "load vps", payload })}
vps={vps}
/>
{!props.onlyPhrases && <div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
<div style={{ width: "1rem" }}>
</div>
<ButtonSelect
value={mode}
options={[
{ label: "Charts", value: "charts" },
{ label: "Phrases", value: "phrases" },
{ label: "Quiz", value: "quiz" },
]}
handleChange={setMode}
/>
<div className="d-flex flex-row">
<div
className="clickable mr-4"
onClick={mode === "phrases" ? handleCopyCode : undefined}
style={{ width: "1rem" }}
>
{(mode === "phrases" && phraseIsComplete) ? <i className="fas fa-code" /> : ""}
</div>
<div
className="clickable"
onClick={mode === "phrases" ? handleCopyShareLink : undefined}
style={{ width: "1rem" }}
>
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
</div>
</div>
</div>}
{(vps.verb && (typeof object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
<div className="text-center my-2">
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
<i className="fas fa-exchange-alt mr-2" /> subj/obj
</button>
</div>}
{mode === "phrases" && <VPPicker
opts={props.opts}
entryFeeder={props.entryFeeder}
onChange={(payload) => adjustVps({ type: "load vps", payload })}
vps={vps}
/>}
{mode !== "phrases" && <div className="my-2">
<TensePicker
vps={vps}
onChange={adjustVps}
mode={mode}
/>
</div>}
{mode === "phrases" && <VPDisplay
VPS={vps}
opts={props.opts}
setForm={handleSetForm}
/>}
{mode === "charts" && <AllTensesDisplay VS={vps.verb} opts={props.opts} />}
{mode === "quiz" && <VPExplorerQuiz opts={props.opts} vps={vps} />}
{showClipped && <div className="alert alert-primary text-center" role="alert" style={{
)}
{mode !== "phrases" && (
<div className="my-2">
<TensePicker vps={vps} onChange={adjustVps} mode={mode} />
</div>
)}
{mode === "phrases" && (
<VPDisplay VPS={vps} opts={props.opts} setForm={handleSetForm} />
)}
{mode === "charts" && (
<AllTensesDisplay
object={object}
VS={vps.verb}
opts={props.opts}
onChange={adjustVps}
/>
)}
{mode === "quiz" && <VPExplorerQuiz opts={props.opts} vps={vps} />}
{showClipped && (
<div
className="alert alert-primary text-center"
role="alert"
style={{
position: "fixed",
top: "30%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 9999999999999,
}}>
{showClipped}
</div>}
{alertMsg && <div className="alert alert-warning text-center" role="alert" style={{
}}
>
{showClipped}
</div>
)}
{alertMsg && (
<div
className="alert alert-warning text-center"
role="alert"
style={{
position: "fixed",
top: "30%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 9999999999999,
}}>
{alertMsg}
</div>}
}}
>
{alertMsg}
</div>
)}
</div>
);
}
export default VPExplorer;
function getShareUrl(vps: T.VPSelectionState): string {
const code = getCode(vps);
const encoded = LZString.compressToEncodedURIComponent(code);
const url = new URL(window.location.href);
// need to delete or else you could just get a second param written after
// which gets ignored
url.searchParams.delete(vpPhraseURLParam);
url.searchParams.append(vpPhraseURLParam, encoded);
return url.toString();
const code = getCode(vps);
const encoded = LZString.compressToEncodedURIComponent(code);
const url = new URL(window.location.href);
// need to delete or else you could just get a second param written after
// which gets ignored
url.searchParams.delete(vpPhraseURLParam);
url.searchParams.append(vpPhraseURLParam, encoded);
return url.toString();
}
function getCode(vps: T.VPSelectionState): string {
return JSON.stringify(vps);
return JSON.stringify(vps);
}
function getVPSFromUrl(): T.VPSelectionState | undefined {
const params = new URLSearchParams(window.location.search);
const fromParams = params.get(vpPhraseURLParam);
if (!fromParams) return;
const decoded = LZString.decompressFromEncodedURIComponent(fromParams);
return JSON.parse(decoded) as T.VPSelectionState;
const params = new URLSearchParams(window.location.search);
const fromParams = params.get(vpPhraseURLParam);
if (!fromParams) return;
const decoded = LZString.decompressFromEncodedURIComponent(fromParams);
return JSON.parse(decoded) as T.VPSelectionState;
}

View File

@ -2,232 +2,435 @@ import NPPicker, { shrunkenBackground } from "../../src/np-picker/NPPicker";
import TensePicker from "./TensePicker";
import * as T from "../../../types";
import {
// useEffect,
useRef,
useState,
// useEffect,
useRef,
useState,
} from "react";
import { getKingAndServant, renderVP } from "../../../lib/src/phrase-building/render-vp";
import { completeVPSelection, isPastTense } from "../../../lib/src/phrase-building/vp-tools";
import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal";
import {
getKingAndServant,
renderVP,
} from "../../../lib/src/phrase-building/render-vp";
import {
completeVPSelection,
isPastTense,
} from "../../../lib/src/phrase-building/vp-tools";
import VPExplorerExplanationModal, {
roleIcon,
} from "./VPExplorerExplanationModal";
import APPicker from "../../src/ap-picker/APPicker";
// import autoAnimate from "@formkit/auto-animate";
import {
getObjectSelection,
getSubjectSelection,
includesShrunkenServant,
isNoObject,
getObjectSelection,
getSubjectSelection,
includesShrunkenServant,
isNoObject,
} from "../../../lib/src/phrase-building/blocks-utils";
import ComplementPicker from "../ComplementPicker";
import { vpsReducer, VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
import {
vpsReducer,
VpsReducerAction,
} from "../../../lib/src/phrase-building/vps-reducer";
function VPPicker({ opts, vps, onChange, entryFeeder }: {
opts: T.TextOptions,
vps: T.VPSelectionState,
onChange: (vps: T.VPSelectionState) => void,
entryFeeder: T.EntryFeeder,
function VPPicker({
opts,
vps,
onChange,
entryFeeder,
}: {
opts: T.TextOptions;
vps: T.VPSelectionState;
onChange: (vps: T.VPSelectionState) => void;
entryFeeder: T.EntryFeeder;
}) {
const parent = useRef<HTMLDivElement>(null);
// useEffect(() => {
// parent.current && autoAnimate(parent.current);
// }, [parent]);
const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false);
function adjustVps(action: VpsReducerAction) {
onChange(vpsReducer(vps, action));
}
function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) {
adjustVps({
type: "set subject",
payload: { subject, skipPronounConflictCheck },
});
}
function handleObjectChange(object: T.NPSelection | undefined) {
adjustVps({
type: "set object",
payload: object,
});
}
const object = getObjectSelection(vps.blocks).selection;
const subject = getSubjectSelection(vps.blocks).selection;
const VPS = completeVPSelection(vps);
const phraseIsComplete = !!VPS;
const rendered = VPS ? renderVP(VPS) : undefined;
const servantIsShrunk = includesShrunkenServant(rendered?.kids);
const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense);
const roles = getKingAndServant(
isPast,
vps.verb.transitivity !== "intransitive",
const parent = useRef<HTMLDivElement>(null);
// useEffect(() => {
// parent.current && autoAnimate(parent.current);
// }, [parent]);
const [showingExplanation, setShowingExplanation] =
useState<{ role: "servant" | "king"; item: "subject" | "object" } | false>(
false
);
return <div>
<div className="clickable h5" onClick={() => adjustVps({ type: "insert new AP" })}>+ AP</div>
<div ref={parent} className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
{vps.blocks.map(({ block, key }, i, blocks) => {
if (isNoObject(block)) return null;
return <div className="my-2 card block-card p-1 mx-1" key={key} style={{
background: (servantIsShrunk && (
(roles.servant === "subject" && block?.type === "subjectSelection")
||
(roles.servant === "object" && block?.type === "objectSelection")
)) ? shrunkenBackground : "inherit",
}}>
<div className="d-flex flex-row justify-content-between mb-1" style={{ height: "1rem" }}>
{(i > 0 && !isNoObject(blocks[i - 1].block)) ? <div
className="small clickable ml-1"
onClick={() => adjustVps({ type: "shift block", payload: { index: i, direction: "back" }})}
>
<i className="fas fa-chevron-left" />
</div> : <div/>}
{(i < vps.blocks.length - 1 && !isNoObject(blocks[i + 1].block)) ? <div
className="small clickable mr-1"
onClick={() => adjustVps({ type: "shift block", payload: { index: i, direction: "forward" }})}
>
<i className="fas fa-chevron-right" />
</div> : <div/>}
</div>
{(!block || block.type === "AP")
? <APPicker
phraseIsComplete={phraseIsComplete}
heading="AP"
entryFeeder={entryFeeder}
AP={block}
opts={opts}
onChange={AP => adjustVps({ type: "set AP", payload: { index: i, AP } })}
onRemove={() => adjustVps({ type: "remove AP", payload: i })}
/>
: (block?.type === "subjectSelection")
? <NPPicker
phraseIsComplete={phraseIsComplete}
heading={roles.king === "subject"
? <div className="h5 text-center">
Subj. <span onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>{roleIcon.king}</span>
{(rendered && rendered.whatsAdjustable !== "servant") &&
<KingRemover
onChange={() => adjustVps({ type: "toggle king remove" })}
showKing={!VPS?.form.removeKing}
/>
}
</div>
: <div className="h5 text-center">
Subj.
{` `}
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant}</span>
{` `}
{(rendered && rendered.whatsAdjustable !== "king") &&
<ServantShrinker
shrunk={servantIsShrunk}
onClick={() => adjustVps({ type: "toggle servant shrink" })}
/>
}
</div>}
entryFeeder={entryFeeder}
np={block.selection}
counterPart={vps.verb ? object : undefined}
role={(isPast && vps.verb.transitivity !== "intransitive")
? "ergative"
: "subject"
}
onChange={handleSubjectChange}
opts={opts}
isShrunk={(servantIsShrunk && roles.servant === "subject")}
isRemoved={roles.king === "subject" && VPS?.form.removeKing}
/>
: (vps.verb && block?.type === "objectSelection" && block.selection !== "none")
? <div className="my-2" style={{ background: (servantIsShrunk && roles.servant === "object") ? shrunkenBackground : "inherit" }}>
{(typeof block.selection === "number")
? <div>
{roles.king === "object"
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
: roles.servant === "object"
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>
: <div className="h5 text-center">Object</div>}
<div className="text-muted text-center">
<div className="mt-3 mb-1">Unspoken</div>
<div>3rd Pers. Masc. Plur.</div>
</div>
</div>
: <NPPicker
phraseIsComplete={phraseIsComplete}
heading={roles.king === "object"
? <div className="h5 text-center">
Obj. <span onClick={() => setShowingExplanation({ role: "king", item: "object" })}>{roleIcon.king}</span>
{(rendered && rendered.whatsAdjustable !== "servant") &&
<KingRemover
onChange={() => adjustVps({ type: "toggle king remove" })}
showKing={!VPS?.form.removeKing}
/>
}
</div>
: <div className="h5 text-center">
Obj.
{` `}
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant}</span>
{` `}
{(rendered && rendered.whatsAdjustable !== "king") &&
<ServantShrinker shrunk={servantIsShrunk} onClick={() => adjustVps({ type: "toggle servant shrink" })} />
}
</div>}
entryFeeder={entryFeeder}
role="object"
np={block.selection}
counterPart={subject}
onChange={handleObjectChange}
opts={opts}
isShrunk={(servantIsShrunk && roles.servant === "object")}
isRemoved={roles.king === "object" && VPS?.form.removeKing}
/>}
</div>
: null}
</div>;
})}
{vps.externalComplement && <div className="my-2 card block-card p-1 mr-1" key="complementPicker">
<div className="h5 text-center">Complement</div>
<ComplementPicker
phraseIsComplete={phraseIsComplete}
comp={vps.externalComplement.selection.type === "unselected"
? undefined
: vps.externalComplement as T.ComplementSelection // TODO: just typescript being dumb? - looks like it
function adjustVps(action: VpsReducerAction) {
onChange(vpsReducer(vps, action));
}
function handleSubjectChange(
subject: T.NPSelection | undefined,
skipPronounConflictCheck?: boolean
) {
adjustVps({
type: "set subject",
payload: { subject, skipPronounConflictCheck },
});
}
function handleObjectChange(object: T.NPSelection | undefined) {
adjustVps({
type: "set object",
payload: object,
});
}
const object = getObjectSelection(vps.blocks).selection;
const subject = getSubjectSelection(vps.blocks).selection;
const VPS = completeVPSelection(vps);
const phraseIsComplete = !!VPS;
const rendered = VPS ? renderVP(VPS) : undefined;
const servantIsShrunk = includesShrunkenServant(rendered?.kids);
const isPast = isPastTense(
vps.verb.tenseCategory === "perfect"
? vps.verb.perfectTense
: vps.verb.verbTense
);
const roles = getKingAndServant(
isPast,
vps.verb.transitivity !== "intransitive"
);
return (
<div>
<div
className="clickable h5"
onClick={() => adjustVps({ type: "insert new AP" })}
>
+ AP
</div>
<div
ref={parent}
className="d-flex flex-row justify-content-around flex-wrap"
style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}
>
{vps.blocks.map(({ block, key }, i, blocks) => {
if (isNoObject(block)) return null;
return (
<div
className="my-2 card block-card p-1 mx-1"
key={key}
style={{
background:
servantIsShrunk &&
((roles.servant === "subject" &&
block?.type === "subjectSelection") ||
(roles.servant === "object" &&
block?.type === "objectSelection"))
? shrunkenBackground
: "inherit",
}}
>
<div
className="d-flex flex-row justify-content-between mb-1"
style={{ height: "1rem" }}
>
{i > 0 &&
!isNoObject(blocks[i - 1].block) &&
!isGenStatCompNoun(block) ? (
<div
className="small clickable ml-1"
onClick={() =>
adjustVps({
type: "shift block",
payload: { index: i, direction: "back" },
})
}
onChange={payload => adjustVps({ type: "set externalComplement", payload })}
opts={opts}
entryFeeder={entryFeeder}
>
<i className="fas fa-chevron-left" />
</div>
) : (
<div />
)}
{i < vps.blocks.length - 1 &&
!isNoObject(blocks[i + 1].block) &&
!isGenStatCompNoun(block) ? (
<div
className="small clickable mr-1"
onClick={() =>
adjustVps({
type: "shift block",
payload: { index: i, direction: "forward" },
})
}
>
<i className="fas fa-chevron-right" />
</div>
) : (
<div />
)}
</div>
{!block || block.type === "AP" ? (
<APPicker
phraseIsComplete={phraseIsComplete}
heading="AP"
entryFeeder={entryFeeder}
AP={block}
opts={opts}
onChange={(AP) =>
adjustVps({ type: "set AP", payload: { index: i, AP } })
}
onRemove={() => adjustVps({ type: "remove AP", payload: i })}
/>
</div>}
<div className="my-2">
<TensePicker
vps={vps}
onChange={adjustVps}
mode="phrases"
) : block?.type === "subjectSelection" ? (
<NPPicker
phraseIsComplete={phraseIsComplete}
heading={
roles.king === "subject" ? (
<div className="h5 text-center">
Subj.{" "}
<span
onClick={() =>
setShowingExplanation({
role: "king",
item: "subject",
})
}
>
{roleIcon.king}
</span>
{rendered && rendered.whatsAdjustable !== "servant" && (
<KingRemover
onChange={() =>
adjustVps({ type: "toggle king remove" })
}
showKing={!VPS?.form.removeKing}
/>
)}
</div>
) : (
<div className="h5 text-center">
Subj.
{` `}
<span
className="clickable"
onClick={() =>
setShowingExplanation({
role: "servant",
item: "subject",
})
}
>
{roleIcon.servant}
</span>
{` `}
{rendered && rendered.whatsAdjustable !== "king" && (
<ServantShrinker
shrunk={servantIsShrunk}
onClick={() =>
adjustVps({ type: "toggle servant shrink" })
}
/>
)}
</div>
)
}
entryFeeder={entryFeeder}
np={block.selection}
counterPart={vps.verb ? object : undefined}
role={
isPast && vps.verb.transitivity !== "intransitive"
? "ergative"
: "subject"
}
onChange={handleSubjectChange}
opts={opts}
isShrunk={servantIsShrunk && roles.servant === "subject"}
isRemoved={roles.king === "subject" && VPS?.form.removeKing}
/>
) : vps.verb &&
block?.type === "objectSelection" &&
block.selection !== "none" ? (
<div
className="my-2"
style={{
background:
servantIsShrunk && roles.servant === "object"
? shrunkenBackground
: "inherit",
}}
>
{typeof block.selection === "number" ? (
<div>
{roles.king === "object" ? (
<div
className="h5 text-center clickable"
onClick={() =>
setShowingExplanation({
role: "king",
item: "object",
})
}
>
Object {roleIcon.king}
</div>
) : roles.servant === "object" ? (
<div
className="h5 text-center clickable"
onClick={() =>
setShowingExplanation({
role: "servant",
item: "object",
})
}
>
Object {roleIcon.servant}
</div>
) : (
<div className="h5 text-center">Object</div>
)}
<div className="text-muted text-center">
<div className="mt-3 mb-1">Unspoken</div>
<div>3rd Pers. Masc. Plur.</div>
</div>
</div>
) : (
<NPPicker
phraseIsComplete={phraseIsComplete}
heading={
roles.king === "object" ? (
<div className="h5 text-center">
Obj.{" "}
<span
onClick={() =>
setShowingExplanation({
role: "king",
item: "object",
})
}
>
{roleIcon.king}
</span>
{rendered &&
rendered.whatsAdjustable !== "servant" && (
<KingRemover
onChange={() =>
adjustVps({ type: "toggle king remove" })
}
showKing={!VPS?.form.removeKing}
/>
)}
</div>
) : (
<div className="h5 text-center">
Obj.
{` `}
<span
className="clickable"
onClick={() =>
setShowingExplanation({
role: "servant",
item: "object",
})
}
>
{roleIcon.servant}
</span>
{` `}
{rendered &&
rendered.whatsAdjustable !== "king" && (
<ServantShrinker
shrunk={servantIsShrunk}
onClick={() =>
adjustVps({ type: "toggle servant shrink" })
}
/>
)}
</div>
)
}
entryFeeder={entryFeeder}
role="object"
np={block.selection}
counterPart={subject}
onChange={handleObjectChange}
opts={opts}
isShrunk={servantIsShrunk && roles.servant === "object"}
isRemoved={
roles.king === "object" && VPS?.form.removeKing
}
/>
)}
</div>
) : null}
</div>
);
})}
{vps.externalComplement && (
<div className="my-2 card block-card p-1 mr-1" key="complementPicker">
<div className="h5 text-center">Complement</div>
<ComplementPicker
phraseIsComplete={phraseIsComplete}
comp={
vps.externalComplement.selection.type === "unselected"
? undefined
: (vps.externalComplement as T.ComplementSelection) // TODO: just typescript being dumb? - looks like it
}
onChange={(payload) =>
adjustVps({ type: "set externalComplement", payload })
}
opts={opts}
entryFeeder={entryFeeder}
/>
</div>
)}
<div className="my-2">
<TensePicker vps={vps} onChange={adjustVps} mode="phrases" />
</div>
<VPExplorerExplanationModal
showing={showingExplanation}
setShowing={setShowingExplanation}
/>
</div>;
</div>
<VPExplorerExplanationModal
showing={showingExplanation}
setShowing={setShowingExplanation}
/>
</div>
);
}
function ServantShrinker({ shrunk, onClick }: {
shrunk: boolean;
onClick: () => void;
function ServantShrinker({
shrunk,
onClick,
}: {
shrunk: boolean;
onClick: () => void;
}) {
return <span className="mx-2 clickable" onClick={onClick}>
{!shrunk ? "🪄" : "👶"}
</span>;
return (
<span className="mx-2 clickable" onClick={onClick}>
{!shrunk ? "🪄" : "👶"}
</span>
);
}
function KingRemover({ showKing, onChange }: {
showKing: boolean;
onChange: () => void;
function KingRemover({
showKing,
onChange,
}: {
showKing: boolean;
onChange: () => void;
}) {
return <span className="form-check form-check-inline ml-3">
<input
checked={showKing}
onChange={onChange}
className="form-check-input"
type="checkbox"
id="showKingCheck"
/>
</span>;
return (
<span className="form-check form-check-inline ml-3">
<input
checked={showKing}
onChange={onChange}
className="form-check-input"
type="checkbox"
id="showKingCheck"
/>
</span>
);
}
export default VPPicker;
function isGenStatCompNoun(
block:
| T.APSelection
| T.ComplementSelection
| T.SubjectSelection
| T.ObjectSelection
| undefined
) {
if (!block) return false;
console.log({ block });
if (
block.type === "objectSelection" &&
typeof block.selection === "object" &&
block.selection.selection.type === "noun" &&
block.selection.selection.genStativeComplement
) {
return true;
}
return false;
}
export default VPPicker;

View File

@ -1,141 +1,213 @@
import * as T from "../../../types";
import ButtonSelect from "../ButtonSelect";
import { RootsAndStems } from "../verb-info/VerbInfo";
import { getAbilityRootsAndStems, getPassiveRootsAndStems, getVerbInfo } from "../../../lib/src/verb-info";
import {
getAbilityRootsAndStems,
getPassiveRootsAndStems,
getVerbInfo,
} from "../../../lib/src/verb-info";
import Hider from "../Hider";
import useStickyState from "../useStickyState";
import CompoundDisplay from "./CompoundDisplay";
import {
VpsReducerAction
} from "../../../lib/src/phrase-building/vps-reducer";
import { VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
import { ensureNonComboVerbInfo } from "../../../lib/src/misc-helpers";
// TODO: dark on past tense selecitons
function VerbPicker(props: {
vps: T.VPSelectionState,
onChange: (a: VpsReducerAction) => void,
opts: T.TextOptions,
handleLinkClick: ((ts: number) => void) | "none",
vps: T.VPSelectionState;
onChange: (a: VpsReducerAction) => void;
opts: T.TextOptions;
handleLinkClick: ((ts: number) => void) | "none";
}) {
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
const infoRaw = props.vps.verb ? getVerbInfo(props.vps.verb.verb.entry, props.vps.verb.verb.complement) : undefined;
const info = (!infoRaw || !props.vps.verb)
? undefined
: ("stative" in infoRaw)
? infoRaw[props.vps.verb.isCompound === "stative" ? "stative" : "dynamic"]
: ("transitive" in infoRaw)
? infoRaw[props.vps.verb.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
: infoRaw;
if (info && ("stative" in info || "transitive" in info)) {
return <div>ERROR: Verb version should be select first</div>;
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(
false,
"showRootsAndStems"
);
const infoRaw = props.vps.verb
? getVerbInfo(props.vps.verb.verb.entry, props.vps.verb.verb.complement)
: undefined;
const info =
!infoRaw || !props.vps.verb
? undefined
: "stative" in infoRaw
? infoRaw[
props.vps.verb.isCompound === "stative" ||
props.vps.verb.isCompound === "generative stative"
? "stative"
: "dynamic"
]
: "transitive" in infoRaw
? infoRaw[
props.vps.verb.transitivity === "grammatically transitive"
? "grammaticallyTransitive"
: "transitive"
]
: infoRaw;
if (info && ("stative" in info || "transitive" in info)) {
return <div>ERROR: Verb version should be select first</div>;
}
function onVoiceSelect(value: "active" | "passive") {
props.onChange({
type: "set voice",
payload: value,
});
}
function notInstransitive(
t: "transitive" | "intransitive" | "grammatically transitive"
): "transitive" | "grammatically transitive" {
return t === "intransitive" ? "transitive" : t;
}
function handleChangeTransitivity(
payload: "transitive" | "grammatically transitive"
) {
props.onChange({
type: "set transitivity",
payload,
});
}
function handleChangeStatDyn(payload: "stative" | "dynamic") {
props.onChange({
type: "set statDyn",
payload,
});
}
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;
}
function onVoiceSelect(value: "active" | "passive") {
props.onChange({
type: "set voice",
payload: value,
});
}
function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" {
return t === "intransitive" ? "transitive" : t;
}
function handleChangeTransitivity(payload: "transitive" | "grammatically transitive") {
props.onChange({
type: "set transitivity",
payload,
});
}
function handleChangeStatDyn(payload: "stative" | "dynamic") {
props.onChange({
type: "set statDyn",
payload,
});
}
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}
opts={props.opts}
handleLinkClick={props.handleLinkClick}
/>}
{info && <div className="mt-3 mb-1 text-center">
<Hider
showing={showRootsAndStems}
label={`🌳 ${passiveRootsAndStems ? "Passive" : abilityRootsAndStems ? "Ability" : ""} Roots and Stems${info.type === "dynamic compound" ? " for Aux. Verb" : ""}`}
handleChange={() => setShowRootsAndStems(p => !p)}
hLevel={5}
>
<RootsAndStems
textOptions={props.opts}
info={passiveRootsAndStems
? passiveRootsAndStems
: abilityRootsAndStems
? abilityRootsAndStems
: info.type === "dynamic compound"
? ensureNonComboVerbInfo(getVerbInfo(info.auxVerb))
: info}
/>
</Hider>
</div>}
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ maxWidth: "400px", margin: "0 auto" }}>
{props.vps.verb && props.vps.verb.canChangeTransitivity && <div className="text-center my-2">
<ButtonSelect
small
options={[{
label: "gramm. trans.",
value: "grammatically transitive",
}, {
label: "trans.",
value: "transitive",
}]}
value={notInstransitive(props.vps.verb.transitivity)}
handleChange={handleChangeTransitivity}
/>
</div>}
{props.vps.verb && props.vps.verb.canChangeVoice && <div className="text-center my-2">
<ButtonSelect
small
value={props.vps.verb.voice}
options={(props.vps.verb.tenseCategory === "imperative") // || props.vps.verb.tenseCategory === "modal")
? [{
label: "Active",
value: "active",
}]
: [{
label: "Active",
value: "active",
}, {
label: "Passive",
value: "passive",
}]}
handleChange={onVoiceSelect}
/>
</div>}
{props.vps.verb && props.vps.verb.canChangeStatDyn && <div className="text-center my-2">
<ButtonSelect
small
options={[{
label: "stative",
value: "stative",
}, {
label: "dynamic",
value: "dynamic",
}]}
value={props.vps.verb.isCompound ? props.vps.verb.isCompound : "stative"}
handleChange={handleChangeStatDyn}
/>
</div>}
})();
return (
<div className="mb-3">
{info && (
<CompoundDisplay
info={info}
opts={props.opts}
handleLinkClick={props.handleLinkClick}
/>
)}
{info && (
<div className="mt-3 mb-1 text-center">
<Hider
showing={showRootsAndStems}
label={`🌳 ${
passiveRootsAndStems
? "Passive"
: abilityRootsAndStems
? "Ability"
: ""
} Roots and Stems${
info.type === "dynamic compound" ? " for Aux. Verb" : ""
}`}
handleChange={() => setShowRootsAndStems((p) => !p)}
hLevel={5}
>
<RootsAndStems
textOptions={props.opts}
info={
passiveRootsAndStems
? passiveRootsAndStems
: abilityRootsAndStems
? abilityRootsAndStems
: info.type === "dynamic compound"
? ensureNonComboVerbInfo(getVerbInfo(info.auxVerb))
: info
}
/>
</Hider>
</div>
</div>;
)}
<div
className="d-flex flex-row justify-content-around flex-wrap"
style={{ maxWidth: "400px", margin: "0 auto" }}
>
{props.vps.verb && props.vps.verb.canChangeTransitivity && (
<div className="text-center my-2">
<ButtonSelect
small
options={[
{
label: "gramm. trans.",
value: "grammatically transitive",
},
{
label: "trans.",
value: "transitive",
},
]}
value={notInstransitive(props.vps.verb.transitivity)}
handleChange={handleChangeTransitivity}
/>
</div>
)}
{props.vps.verb && props.vps.verb.canChangeVoice && (
<div className="text-center my-2">
<ButtonSelect
small
value={props.vps.verb.voice}
options={
props.vps.verb.tenseCategory === "imperative" // || props.vps.verb.tenseCategory === "modal")
? [
{
label: "Active",
value: "active",
},
]
: [
{
label: "Active",
value: "active",
},
{
label: "Passive",
value: "passive",
},
]
}
handleChange={onVoiceSelect}
/>
</div>
)}
{props.vps.verb && props.vps.verb.canChangeStatDyn && (
<div className="text-center my-2">
<ButtonSelect
small
options={[
{
label:
infoRaw?.type === "dynamic or generative stative compound"
? "gen. stative"
: "stative",
value: "stative",
},
{
label: "dynamic",
value: "dynamic",
},
]}
value={
props.vps.verb.isCompound === "generative stative"
? "stative"
: props.vps.verb.isCompound
? props.vps.verb.isCompound
: "stative"
}
handleChange={handleChangeStatDyn}
/>
</div>
)}
</div>
</div>
);
}
export default VerbPicker;
export default VerbPicker;

View File

@ -1,7 +1,8 @@
import { renderVerb } from "../../../lib/src/new-verb-engine/render-verb";
import * as T from "../../../types";
import { equals } from "rambda";
import { isPastTense } from "../../library";
import { isPastTense, renderNPSelection } from "../../library";
import { getPersonFromNP } from "../../../lib/src/phrase-building/vp-tools";
export function buildVerbChart({
verb,
@ -10,6 +11,7 @@ export function buildVerbChart({
voice,
imperative,
negative,
objectNP,
}: {
verb: T.VerbEntry;
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
@ -17,7 +19,11 @@ export function buildVerbChart({
imperative: boolean;
voice: T.VerbSelection["voice"];
negative: boolean;
}): T.OptionalPersonInflections<T.SingleOrLengthOpts<T.RenderVerbOutput[]>> {
objectNP: T.NPSelection | undefined;
}): {
objNP: T.Rendered<T.NPSelection> | undefined;
vbs: T.OptionalPersonInflections<T.SingleOrLengthOpts<T.RenderVerbOutput[]>>;
} {
const allPersons = imperative
? [
T.Person.SecondSingMale,
@ -27,6 +33,9 @@ export function buildVerbChart({
]
: ([...Array(12).keys()] as T.Person[]);
const isPast = isPastTense(tense);
const objNP: T.Rendered<T.NPSelection> | undefined = objectNP
? renderNPSelection(objectNP, false, false, "object", "none", false)
: undefined;
function conjugateAllPers(
p?: T.Person
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
@ -46,19 +55,51 @@ export function buildVerbChart({
negative,
});
});
const hasLengths = vIsLength("long")(ps[0]);
const hasMini = vIsLength("mini")(ps[0]);
return pullOutLengths(hasLengths, hasMini, ps);
return pullOutLengths(ps);
}
if (transitivity === "transitive" && !isPast) {
return conflateIfNoCompGenNumDiff({
mascSing: conjugateAllPers(T.Person.FirstSingMale),
mascPlur: conjugateAllPers(T.Person.FirstPlurMale),
femSing: conjugateAllPers(T.Person.FirstSingFemale),
femPlur: conjugateAllPers(T.Person.FirstPlurFemale),
});
return {
objNP,
vbs: conflateIfNoCompGenNumDiff({
mascSing: conjugateAllPers(T.Person.FirstSingMale),
mascPlur: conjugateAllPers(T.Person.FirstPlurMale),
femSing: conjugateAllPers(T.Person.FirstSingFemale),
femPlur: conjugateAllPers(T.Person.FirstPlurFemale),
}),
};
} else if (objNP && isPast) {
return {
objNP,
vbs: pullOutLengths([
renderVerb({
verb,
tense,
subject: 0,
object: getPersonFromNP(objNP),
voice,
negative,
}),
]),
};
} else if (isPast && transitivity === "grammatically transitive") {
return {
objNP,
vbs: pullOutLengths([
renderVerb({
verb,
tense,
subject: 0,
object: T.Person.ThirdPlurMale,
voice,
negative,
}),
]),
};
} else {
return conjugateAllPers();
return {
objNP: undefined,
vbs: conjugateAllPers(),
};
}
}
@ -106,23 +147,21 @@ function grabLength(
if (v.length === 2) {
const [vb, vbe] = v;
return {
objComp: undefined,
hasBa,
vbs: [ph, [grabVBLength(vb), vbe]],
};
}
return {
objComp: undefined,
hasBa,
vbs: [ph, [grabVBLength(v[0])]],
};
}
function pullOutLengths(
hasLengths: boolean,
hasMini: boolean,
ps: T.RenderVerbOutput[]
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
const hasLengths = vIsLength("long")(ps[0]);
const hasMini = vIsLength("mini")(ps[0]);
if (!hasLengths) {
return ps;
}

View File

@ -0,0 +1,5 @@
@media screen and (max-width: 600px) {
.hide-on-mobile {
display: none;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +0,0 @@
import * as T from "../../types";
export function fmapSingleOrLengthOpts<A extends object, B extends object>(f: (x: A) => B, x: T.SingleOrLengthOpts<A>): T.SingleOrLengthOpts<B> {
if ("long" in x) {
return {
long: f(x.long),
short: f(x.short),
..."mini" in x && x.mini ? {
mini: f(x.mini),
} : {},
};
} else {
return f(x);
}
}
export function mapInflections(f: (x: T.PsString) => T.PsString, inf: T.UnisexInflections): T.UnisexInflections {
function handleSide(inf: T.InflectionSet): T.InflectionSet {
return inf.map(x => x.map(f)) as T.ArrayFixed<T.ArrayOneOrMore<T.PsString>, 3>;
}
return {
masc: handleSide(inf.masc),
fem: handleSide(inf.fem),
};
}
export function mapVerbRenderedOutput(f: (a: T.PsString) => T.PsString, [a, b]: T.VerbRenderedOutput): T.VerbRenderedOutput {
return [
fmapVHead(a),
fmapV(b),
];
function fmapVHead([v]: [T.VHead] | []): [T.VHead] | [] {
if (v === undefined) {
return [];
}
if (v.type === "PH") {
return [{
...v,
ps: f(v.ps),
}];
}
return [{
...v,
comp: fmapComp(v.comp),
}];
}
function fmapComp(comp: T.Comp): T.Comp {
return {
...comp,
ps: f(comp.ps),
};
}
function fmapV(v: [T.VB, T.VBE] | [T.VBE]): [T.VB, T.VBE]| [T.VBE] {
return v.map(fmapVB) as [T.VB, T.VBE]| [T.VBE];
}
function fmapVB<V extends T.VB | T.VBE>(v: V): V {
if (v.type === "welded") {
return {
...v,
left: fmapWeldedLeft(v.left),
right: fmapVB(v.right),
};
}
return {
...v,
ps: fmapSingleOrLengthOpts((x) => x.map(f), v.ps),
};
}
function fmapWeldedLeft(v: T.NComp | T.VBBasic | T.Welded) {
if (v.type === "NComp") {
return {
...v,
comp: fmapComp(v.comp),
};
}
return fmapVB(v);
}
}

View File

@ -41,3 +41,95 @@ export const monoidPsStringWVars: Monoid<T.PsString[]> = {
concat: semigroupPsStringWVars.concat,
empty: [monoidPsString.empty],
};
export function fmapSingleOrLengthOpts<A extends object, B extends object>(
f: (x: A) => B,
x: T.SingleOrLengthOpts<A>
): T.SingleOrLengthOpts<B> {
if ("long" in x) {
return {
long: f(x.long),
short: f(x.short),
...("mini" in x && x.mini
? {
mini: f(x.mini),
}
: {}),
};
} else {
return f(x);
}
}
export function mapInflections(
f: (x: T.PsString) => T.PsString,
inf: T.UnisexInflections
): T.UnisexInflections {
function handleSide(inf: T.InflectionSet): T.InflectionSet {
return inf.map((x) => x.map(f)) as T.ArrayFixed<
T.ArrayOneOrMore<T.PsString>,
3
>;
}
return {
masc: handleSide(inf.masc),
fem: handleSide(inf.fem),
};
}
export function mapVerbRenderedOutput(
f: (a: T.PsString) => T.PsString,
[a, b]: T.VerbRenderedOutput
): T.VerbRenderedOutput {
return [fmapVHead(a), fmapV(b)];
function fmapVHead([v]: [T.VHead] | []): [T.VHead] | [] {
if (v === undefined) {
return [];
}
if (v.type === "PH") {
return [
{
...v,
ps: f(v.ps),
},
];
}
return [
{
...v,
comp: fmapComp(v.comp),
},
];
}
function fmapComp(comp: T.Comp): T.Comp {
return {
...comp,
ps: f(comp.ps),
};
}
function fmapV(v: [T.VB, T.VBE] | [T.VBE]): [T.VB, T.VBE] | [T.VBE] {
return v.map(fmapVB) as [T.VB, T.VBE] | [T.VBE];
}
function fmapVB<V extends T.VB | T.VBE>(v: V): V {
if (v.type === "welded") {
return {
...v,
left: fmapWeldedLeft(v.left),
right: fmapVB(v.right),
};
}
return {
...v,
ps: fmapSingleOrLengthOpts((x) => x.map(f), v.ps),
};
}
function fmapWeldedLeft(v: T.NComp | T.VBBasic | T.Welded) {
if (v.type === "NComp") {
return {
...v,
comp: fmapComp(v.comp),
};
}
return fmapVB(v);
}
}

View File

@ -7,7 +7,7 @@
*/
import * as T from "../../types";
import { fmapSingleOrLengthOpts } from "./fmaps";
import { fmapSingleOrLengthOpts } from "./fp-ps";
export const blank: T.PsString = {
p: "_____",

View File

@ -5,7 +5,7 @@ import {
personNumber,
personToGenNum,
} from "../misc-helpers";
import { fmapSingleOrLengthOpts } from "../fmaps";
import { fmapSingleOrLengthOpts } from "../fp-ps";
import { concatPsString, getLength } from "../p-text-helpers";
import {
presentEndings,
@ -18,6 +18,7 @@ import {
isAbilityTense,
isPerfectTense,
isTlulVerb,
isImperativeTense,
} from "../type-predicates";
import { perfectTenseHasBa } from "../phrase-building/vp-tools";
import { makePsString, removeFVarients } from "../accent-and-ps-utils";
@ -100,6 +101,7 @@ export function renderVerb({
subject,
object,
voice,
negative,
}: {
verb: T.VerbEntry;
negative: boolean;
@ -126,7 +128,7 @@ export function renderVerb({
const [vHead, rest] = getRootStem({
verb,
rs: isPast ? "root" : "stem",
aspect,
aspect: negative && isImperativeTense(tense) ? "imperfective" : aspect,
voice,
type,
genderNumber: personToGenNum(transitive ? object : subject),
@ -136,7 +138,6 @@ export function renderVerb({
const ending = getEnding(king, tenseC, aspect);
return {
hasBa,
objComp: undefined,
vbs: [
vHead,
addEnding({

View File

@ -31,9 +31,9 @@ import {
isKedul,
} from "./rs-helpers";
import { inflectPattern3 } from "./new-inflectors";
import { fmapSingleOrLengthOpts } from "../fmaps";
import { fmapSingleOrLengthOpts } from "../fp-ps";
const statVerb = {
export const statVerb = {
intransitive: vEntry({
ts: 1581086654898,
i: 11100,

View File

@ -30,7 +30,7 @@ import {
splitUpSyllables,
} from "./accent-helpers";
import * as T from "../../types";
import { fmapSingleOrLengthOpts } from "./fmaps";
import { fmapSingleOrLengthOpts } from "./fp-ps";
const endingInSingleARegex = /[^a]'??[aá]'??$/;
const endingInHeyOrAynRegex = /[^ا][هع]$/;
@ -42,24 +42,29 @@ export function inflectWord(word: T.DictionaryEntry): T.InflectorOutput {
const w = removeFVarients(word);
if (w.c?.includes("doub.")) {
const words = splitDoubleWord(w);
const inflected = words.map((x) => ensureUnisexInflections(inflectWord(x), x));
const inflected = words.map((x) =>
ensureUnisexInflections(inflectWord(x), x)
);
return {
inflections: concatInflections(
inflected[0].inflections,
inflected[1].inflections,
inflected[1].inflections
) as T.UnisexInflections,
};
}
if (w.c && w.c.includes("pl.")) {
return handlePluralNounOrAdj(w);
}
if (w.c && (w.c.includes("adj.") || w.c.includes("unisex") || w.c.includes("num"))) {
if (
w.c &&
(w.c.includes("adj.") || w.c.includes("unisex") || w.c.includes("num"))
) {
return handleUnisexWord(w);
}
if (w.c && (w.c.includes("n. m."))) {
if (w.c && w.c.includes("n. m.")) {
return handleMascNoun(w);
}
if (w.c && (w.c.includes("n. f."))) {
if (w.c && w.c.includes("n. f.")) {
return handleFemNoun(w);
}
// It's not a noun/adj
@ -78,8 +83,8 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
if (word.infap && word.infaf && word.infbp && word.infbf) {
return {
inflections: inflectIrregularUnisex(word.p, word.f, [
{p: word.infap, f: word.infaf},
{p: word.infbp, f: word.infbf},
{ p: word.infap, f: word.infaf },
{ p: word.infbp, f: word.infbf },
]),
...plurals,
};
@ -88,10 +93,16 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
return { inflections: inflectRegularYeyUnisex(word.p, word.f), ...plurals };
}
if (pEnd === "ه" && word.g.slice(-1) === "u") {
return { inflections: inflectRegularShwaEndingUnisex(word.p, word.f), ...plurals };
return {
inflections: inflectRegularShwaEndingUnisex(word.p, word.f),
...plurals,
};
}
if (pEnd === "ی" && word.f.slice(-2) === "éy") {
return { inflections: inflectEmphasizedYeyUnisex(word.p, word.f), ...plurals };
return {
inflections: inflectEmphasizedYeyUnisex(word.p, word.f),
...plurals,
};
}
if (
pashtoConsonants.includes(pEnd) ||
@ -100,7 +111,10 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
word.f.slice(-1) === "w" ||
(word.p.slice(-1) === "ه" && word.f.slice(-1) === "h")
) {
return { inflections: inflectConsonantEndingUnisex(word.p, word.f), ...plurals };
return {
inflections: inflectConsonantEndingUnisex(word.p, word.f),
...plurals,
};
}
if (plurals) return plurals;
return false;
@ -128,13 +142,16 @@ function handleMascNoun(w: T.DictionaryEntryNoFVars): T.InflectorOutput {
if (w.infap && w.infaf && w.infbp && w.infbf) {
return {
inflections: inflectIrregularMasc(w.p, w.f, [
{p: w.infap, f: w.infaf},
{p: w.infbp, f: w.infbf},
{ p: w.infap, f: w.infaf },
{ p: w.infbp, f: w.infbf },
]),
...plurals,
};
}
const isTobEnding = (w.p.slice(-3) === "توب" && ["tób", "tob"].includes(w.f.slice(-3)) && w.p.length > 3);
const isTobEnding =
w.p.slice(-3) === "توب" &&
["tób", "tob"].includes(w.f.slice(-3)) &&
w.p.length > 3;
if (isTobEnding) {
return { inflections: inflectTobMasc(w.p, w.f), ...plurals };
}
@ -142,9 +159,12 @@ function handleMascNoun(w: T.DictionaryEntryNoFVars): T.InflectorOutput {
return { inflections: inflectRegularYeyMasc(w.p, w.f), ...plurals };
}
if (pEnd === "ی" && fEnd === "éy") {
return { inflections: inflectRegularEmphasizedYeyMasc(w.p, w.f), ...plurals };
return {
inflections: inflectRegularEmphasizedYeyMasc(w.p, w.f),
...plurals,
};
}
return plurals ? { ...plurals } : false
return plurals ? { ...plurals } : false;
}
function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
@ -163,13 +183,22 @@ function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
return { inflections: inflectRegularAFem(word.p, word.f), ...plurals };
}
if (word.p.slice(-1) === "ح" && endingInSingleARegex.test(word.f)) {
return { inflections: inflectRegularAWithHimPEnding(word.p, word.f), ...plurals };
return {
inflections: inflectRegularAWithHimPEnding(word.p, word.f),
...plurals,
};
}
// TODO: better reusable function to check if something ends with a consonant
if ((pashtoConsonants.includes(pEnd) || word.f.slice(-1) === "w") && !animate) {
return { inflections: inflectRegularInanMissingAFem(word.p, word.f), ...plurals };
if (
(pashtoConsonants.includes(pEnd) || word.f.slice(-1) === "w") &&
!animate
) {
return {
inflections: inflectRegularInanMissingAFem(word.p, word.f),
...plurals,
};
}
if (pEnd === "ي" && (!animate)) {
if (pEnd === "ي" && !animate) {
return { inflections: inflectRegularInanEeFem(word.p, word.f), ...plurals };
}
if (pEnd === "ۍ") {
@ -182,59 +211,74 @@ function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
}
// LEVEL 3 FUNCTIONS
function inflectIrregularUnisex(p: string, f: string, inflections: Array<{p: string, f: string}>): T.Inflections {
function inflectIrregularUnisex(
p: string,
f: string,
inflections: Array<{ p: string; f: string }>
): T.Inflections {
const inf1 = removeAccents(inflections[1]);
const inf0 = removeAccents(inflections[0]);
const inf0fSyls = splitUpSyllables(inf0.f).length;
return {
masc: [
[{p, f}],
[{p: inflections[0].p, f: `${inf0.f.slice(0, -1)}${inf0fSyls === 1 ? "u" : "ú"}` }],
[{p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}`}],
[{ p, f }],
[
{
p: inflections[0].p,
f: `${inf0.f.slice(0, -1)}${inf0fSyls === 1 ? "u" : "ú"}`,
},
],
[{ p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}` }],
],
fem: [
[{p: `${inf1.p}ه`, f: `${inf1.f}${inf0fSyls === 1 ? "a" : "á"}`}],
[{p: `${inf1.p}ې`, f: `${inf1.f}${inf0fSyls === 1 ? "e" : "é"}`}],
[{p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}`}],
[{ p: `${inf1.p}ه`, f: `${inf1.f}${inf0fSyls === 1 ? "a" : "á"}` }],
[{ p: `${inf1.p}ې`, f: `${inf1.f}${inf0fSyls === 1 ? "e" : "é"}` }],
[{ p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}` }],
],
};
}
export function inflectRegularYeyUnisex(p: string, f: string): T.UnisexInflections {
export function inflectRegularYeyUnisex(
p: string,
f: string
): T.UnisexInflections {
const baseP = p.slice(0, -1);
const baseF = f.slice(0, -2);
return {
masc: [
[{p, f}],
[{p: `${baseP}ي`, f: `${baseF}ee`}],
[{ p, f }],
[{ p: `${baseP}ي`, f: `${baseF}ee` }],
[
{p: `${baseP}یو`, f: `${baseF}iyo`},
{p: `${baseP}و`, f: `${baseF}o`},
{ p: `${baseP}یو`, f: `${baseF}iyo` },
{ p: `${baseP}و`, f: `${baseF}o` },
],
],
fem: [
[{p: `${baseP}ې`, f: `${baseF}e`}],
[{p: `${baseP}ې`, f: `${baseF}e`}],
[{p: `${baseP}و`, f: `${baseF}o`}],
[{ p: `${baseP}ې`, f: `${baseF}e` }],
[{ p: `${baseP}ې`, f: `${baseF}e` }],
[{ p: `${baseP}و`, f: `${baseF}o` }],
],
};
}
export function inflectRegularShwaEndingUnisex(pr: string, fr: string): T.UnisexInflections {
export function inflectRegularShwaEndingUnisex(
pr: string,
fr: string
): T.UnisexInflections {
const { p, f } = removeAccents(makePsString(pr, fr));
const accented = fr.slice(-1) === "ú";
const baseP = p.slice(0, -1);
const baseF = f.slice(0, -1);
return {
masc: [
[{p: `${baseP}ه`, f: `${baseF}${accented ? "ú" : "u"}`}],
[{p: `${baseP}ه`, f: `${baseF}${accented ? "ú" : "u"}`}],
[{p: `${baseP}و`, f: `${baseF}${accented ? "ó" : "o"}`}],
[{ p: `${baseP}ه`, f: `${baseF}${accented ? "ú" : "u"}` }],
[{ p: `${baseP}ه`, f: `${baseF}${accented ? "ú" : "u"}` }],
[{ p: `${baseP}و`, f: `${baseF}${accented ? "ó" : "o"}` }],
],
fem: [
[{p: `${baseP}ه`, f: `${baseF}${accented ? "á" : "a"}`}],
[{p: `${baseP}ې`, f: `${baseF}${accented ? "é" : "e"}`}],
[{p: `${baseP}و`, f: `${baseF}${accented ? "ó" : "o"}`}],
[{ p: `${baseP}ه`, f: `${baseF}${accented ? "á" : "a"}` }],
[{ p: `${baseP}ې`, f: `${baseF}${accented ? "é" : "e"}` }],
[{ p: `${baseP}و`, f: `${baseF}${accented ? "ó" : "o"}` }],
],
};
}
@ -244,39 +288,39 @@ function inflectEmphasizedYeyUnisex(p: string, f: string): T.UnisexInflections {
const baseF = f.slice(0, -2);
return {
masc: [
[{p, f}],
[{p: `${baseP}ي`, f: `${baseF}ée`}],
[{ p, f }],
[{ p: `${baseP}ي`, f: `${baseF}ée` }],
[
{p: `${baseP}یو`, f: `${baseF}iyo`},
{p: `${baseP}و`, f: `${baseF}ó`},
{ p: `${baseP}یو`, f: `${baseF}iyo` },
{ p: `${baseP}و`, f: `${baseF}ó` },
],
],
fem: [
[{p: `${baseP}ۍ`, f: `${baseF}úy`}],
[{p: `${baseP}ۍ`, f: `${baseF}úy`}],
[{ p: `${baseP}ۍ`, f: `${baseF}úy` }],
[{ p: `${baseP}ۍ`, f: `${baseF}úy` }],
[
{ p: `${baseP}یو`, f: `${baseF}úyo` },
{ p: `${baseP}و`, f: `${baseF}ó`, },
{ p: `${baseP}و`, f: `${baseF}ó` },
],
],
};
}
function inflectConsonantEndingUnisex(p: string, f: string): T.UnisexInflections {
function inflectConsonantEndingUnisex(
p: string,
f: string
): T.UnisexInflections {
const fSyls = splitUpSyllables(removeAccents(f));
const iBase = fSyls.length === 1
? makePsString(p, accentFSylsOnNFromEnd(fSyls, 0))
: makePsString(p, f);
const iBase =
fSyls.length === 1
? makePsString(p, accentFSylsOnNFromEnd(fSyls, 0))
: makePsString(p, f);
return {
masc: [
[{p, f}],
[{p, f}],
[{p: `${iBase.p}و`, f: `${iBase.f}o`}],
],
masc: [[{ p, f }], [{ p, f }], [{ p: `${iBase.p}و`, f: `${iBase.f}o` }]],
fem: [
[{p: `${iBase.p}ه`, f: `${iBase.f}a`}],
[{p: `${iBase.p}ې`, f: `${iBase.f}e`}],
[{p: `${iBase.p}و`, f: `${iBase.f}o`}],
[{ p: `${iBase.p}ه`, f: `${iBase.f}a` }],
[{ p: `${iBase.p}ې`, f: `${iBase.f}e` }],
[{ p: `${iBase.p}و`, f: `${iBase.f}o` }],
],
};
}
@ -286,11 +330,11 @@ function inflectRegularYeyMasc(p: string, f: string): T.Inflections {
const baseF = f.slice(0, -2);
return {
masc: [
[{p, f}],
[{p: `${baseP}ي`, f: `${baseF}ee`}],
[{ p, f }],
[{ p: `${baseP}ي`, f: `${baseF}ee` }],
[
{p: `${baseP}یو`, f: `${baseF}iyo`},
{p: `${baseP}و`, f: `${baseF}o`},
{ p: `${baseP}یو`, f: `${baseF}iyo` },
{ p: `${baseP}و`, f: `${baseF}o` },
],
],
};
@ -301,9 +345,9 @@ function inflectTobMasc(p: string, f: string): T.Inflections {
const baseF = f.slice(0, -3);
return {
masc: [
[{p, f}],
[{p: `${baseP}تابه`, f: `${baseF}taabu`}],
[{p: `${baseP}تبو`, f: `${baseF}tabo`}],
[{ p, f }],
[{ p: `${baseP}تابه`, f: `${baseF}taabu` }],
[{ p: `${baseP}تبو`, f: `${baseF}tabo` }],
],
};
}
@ -313,39 +357,55 @@ function inflectRegularEmphasizedYeyMasc(p: string, f: string): T.Inflections {
const baseF = f.slice(0, -2);
return {
masc: [
[{p, f}],
[{p: `${baseP}ي`, f: `${baseF}ée`}],
[{ p, f }],
[{ p: `${baseP}ي`, f: `${baseF}ée` }],
[
{p: `${baseP}یو`, f: `${baseF}iyo`},
{p: `${baseP}و`, f: `${baseF}o`},
{ p: `${baseP}یو`, f: `${baseF}iyo` },
{ p: `${baseP}و`, f: `${baseF}o` },
],
],
};
}
function inflectIrregularMasc(p: string, f: string, inflections: Array<{p: string, f: string}>): T.Inflections {
function inflectIrregularMasc(
p: string,
f: string,
inflections: Array<{ p: string; f: string }>
): T.Inflections {
let inf0f = removeAccents(inflections[0].f);
const inf0syls = splitUpSyllables(f).length;
const inf1f = removeAccents(inflections[1].f);
return {
masc: [
[{p, f}],
[{p: inflections[0].p, f: `${inf0f.slice(0, -1)}${inf0syls === 1 ? "u" : "ú"}`}],
[{p: `${inflections[1].p}و`, f: `${inf1f}${inf0syls === 1 ? "o" : "ó"}`}],
[{ p, f }],
[
{
p: inflections[0].p,
f: `${inf0f.slice(0, -1)}${inf0syls === 1 ? "u" : "ú"}`,
},
],
[
{
p: `${inflections[1].p}و`,
f: `${inf1f}${inf0syls === 1 ? "o" : "ó"}`,
},
],
],
};
}
function inflectRegularAFem(p: string, f: string): T.Inflections {
const withoutTrailingComma = ["'", ""].includes(f.slice(-1)) ? f.slice(0, -1) : f;
const withoutTrailingComma = ["'", ""].includes(f.slice(-1))
? f.slice(0, -1)
: f;
const accentLast = hasAccents(withoutTrailingComma.slice(-1));
const baseF = withoutTrailingComma.slice(0, -1);
const baseP = p.slice(-1) === "ع" ? p : p.slice(0, -1);
return {
fem: [
[{p, f}],
[{p: `${baseP}ې`, f: `${baseF}${accentLast ? "é" : "e"}`}],
[{p: `${baseP}و`, f: `${baseF}${accentLast ? "ó" : "o"}`}],
[{ p, f }],
[{ p: `${baseP}ې`, f: `${baseF}${accentLast ? "é" : "e"}` }],
[{ p: `${baseP}و`, f: `${baseF}${accentLast ? "ó" : "o"}` }],
],
};
}
@ -354,22 +414,21 @@ function inflectRegularAWithHimPEnding(p: string, f: string): T.Inflections {
const baseF = f.slice(0, -1);
return {
fem: [
[{p, f}],
[{p: `${p}ې`, f: `${baseF}e`}],
[{p: `${p}و`, f: `${baseF}o`}],
[{ p, f }],
[{ p: `${p}ې`, f: `${baseF}e` }],
[{ p: `${p}و`, f: `${baseF}o` }],
],
};
}
function inflectRegularInanMissingAFem(p: string, f: string): T.Inflections {
const fBase = splitUpSyllables(f).length === 1
? accentFSylsOnNFromEnd(f, 0)
: f;
return {
const fBase =
splitUpSyllables(f).length === 1 ? accentFSylsOnNFromEnd(f, 0) : f;
return {
fem: [
[{p, f}],
[{p: `${p}ې`, f: `${fBase}e`}],
[{p: `${p}و`, f: `${fBase}o`}],
[{ p, f }],
[{ p: `${p}ې`, f: `${fBase}e` }],
[{ p: `${p}و`, f: `${fBase}o` }],
],
};
}
@ -379,9 +438,9 @@ function inflectRegularInanEeFem(p: string, f: string): T.Inflections {
const baseF = f.slice(0, -2);
return {
fem: [
[{p, f}],
[{p: `${baseP}ۍ`, f: `${baseF}úy`}],
[{p: `${baseP}یو`, f: `${baseF}úyo`}],
[{ p, f }],
[{ p: `${baseP}ۍ`, f: `${baseF}úy` }],
[{ p: `${baseP}یو`, f: `${baseF}úyo` }],
],
};
}
@ -391,26 +450,23 @@ function inflectRegularUyFem(p: string, f: string): T.Inflections {
const baseF = removeAccents(f.slice(0, -2));
return {
fem: [
[{p, f: `${baseF}úy`}],
[{p, f: `${baseF}úy`}],
[{ p, f: `${baseF}úy` }],
[{ p, f: `${baseF}úy` }],
[
{p: `${baseP}یو`, f: `${baseF}úyo`},
{p: `${baseP}و`, f: `${baseF}o`},
{ p: `${baseP}یو`, f: `${baseF}úyo` },
{ p: `${baseP}و`, f: `${baseF}o` },
],
],
};
}
function makePashtoPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
function makePashtoPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!(word.ppp && word.ppf)) return undefined;
const base = splitPsByVarients(
makePsString(word.ppp, word.ppf)
);
const base = splitPsByVarients(makePsString(word.ppp, word.ppf));
function getBaseAndO(): T.PluralInflectionSet {
return [
base,
base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
];
return [base, base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
}
if (word.c?.includes("n. m.")) {
return { masc: getBaseAndO() };
@ -422,14 +478,14 @@ function makePashtoPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections |
return undefined;
}
function makeBundledPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
function makeBundledPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!endsInConsonant(word) || !word.c?.includes("n.")) {
return undefined;
}
const w = makePsString(word.p, word.f);
const base = countSyllables(w) === 1
? accentOnNFromEnd(w, 0)
: w;
const base = countSyllables(w) === 1 ? accentOnNFromEnd(w, 0) : w;
return {
masc: [
[concatPsString(base, { p: "ه", f: "a" })],
@ -438,7 +494,9 @@ function makeBundledPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections
};
}
function makeArabicPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
function makeArabicPlural(
word: T.DictionaryEntryNoFVars
): T.PluralInflections | undefined {
if (!(word.apf && word.app)) return undefined;
const w = makePsString(word.app, word.apf);
const plural = splitPsByVarients(w);
@ -456,39 +514,55 @@ function makeArabicPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections |
return { masc: value };
}
function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections, bundledPlural?: T.PluralInflections } | { arabicPlural: T.PluralInflections, bundledPlural?: T.PluralInflections } | undefined {
function addSecondInf(plur: T.ArrayOneOrMore<T.PsString> | T.PsString): T.PluralInflectionSet {
function makePlural(
w: T.DictionaryEntryNoFVars
):
| { plural: T.PluralInflections; bundledPlural?: T.PluralInflections }
| { arabicPlural: T.PluralInflections; bundledPlural?: T.PluralInflections }
| undefined {
function addSecondInf(
plur: T.ArrayOneOrMore<T.PsString> | T.PsString
): T.PluralInflectionSet {
if (!Array.isArray(plur)) {
return addSecondInf([plur]);
}
return [
plur,
plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
];
return [plur, plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
}
if (w.c && w.c.includes("pl.")) {
const plural = addSecondInf(makePsString(w.p, w.f));
// Typescript being dumb and not letting me do a typed variable for the key
// could try refactoring with an updated TypeScript dependency
if (w.c.includes("n. m.")) return { plural: { masc: plural }};
if (w.c.includes("n. f.")) return { plural: { fem: plural }};
if (w.c.includes("n. m.")) return { plural: { masc: plural } };
if (w.c.includes("n. f.")) return { plural: { fem: plural } };
}
const arabicPlural = makeArabicPlural(w);
const pashtoPlural = makePashtoPlural(w);
const bundledPlural = makeBundledPlural(w);
function addMascPluralSuffix(animate?: boolean, shortSquish?: boolean): T.PluralInflectionSet {
function addMascPluralSuffix(
animate?: boolean,
shortSquish?: boolean
): T.PluralInflectionSet {
if (shortSquish && (w.infap === undefined || w.infaf === undefined)) {
throw new Error(`no irregular inflection info for ${w.p} - ${w.ts}`);
}
const b = removeAccents(shortSquish
? makePsString((w.infap as string).slice(0, -1), (w.infaf as string).slice(0, -1))
: w
const b = removeAccents(
shortSquish
? makePsString(
(w.infap as string).slice(0, -1),
(w.infaf as string).slice(0, -1)
)
: w
);
const base = endsInShwa(b)
? makePsString(b.p.slice(0, -1), b.f.slice(0, -1))
: b;
return addSecondInf(
concatPsString(base, (animate && !shortSquish) ? { p: "ان", f: "áan" } : { p: "ونه", f: "óona" }),
concatPsString(
base,
animate && !shortSquish
? { p: "ان", f: "áan" }
: { p: "ونه", f: "óona" }
)
);
}
function addAnimUnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
@ -505,10 +579,14 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
f: b.f.slice(0, -2),
};
const firstInf: T.ArrayOneOrMore<T.PsString> = [
concatPsString(base, { p: "یان", f: "iyáan" }, gender === "fem" ? { p: "ې", f: "e" } : ""),
...gender === "fem"
concatPsString(
base,
{ p: "یان", f: "iyáan" },
gender === "fem" ? { p: "ې", f: "e" } : ""
),
...(gender === "fem"
? [concatPsString(base, { p: "یګانې", f: "eegáane" })]
: [],
: []),
];
return [
firstInf,
@ -537,11 +615,12 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
function addLongVowelSuffix(gender: "masc" | "fem"): T.PluralInflectionSet {
const base = removeEndTick(makePsString(w.p, w.f));
const baseWOutAccents = removeAccents(base);
const space = (w.p.slice(-1) === "ع" || w.p.slice(-1) === "ه") ? { p: " ", f: " " } : "";
const space =
w.p.slice(-1) === "ع" || w.p.slice(-1) === "ه" ? { p: " ", f: " " } : "";
if (gender === "fem") {
return addSecondInf([
concatPsString(base, space, { p: "وې", f: "we" }),
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" })
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" }),
]);
} else {
return addSecondInf([
@ -571,24 +650,32 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
const shortSquish = !!w.infap && !w.infap.includes("ا");
const anim = w.c?.includes("anim.");
const type = (w.c?.includes("unisex"))
const type = w.c?.includes("unisex")
? "unisex noun"
: (w.c?.includes("n. m."))
: w.c?.includes("n. m.")
? "masc noun"
: (w.c?.includes("n. f."))
: w.c?.includes("n. f.")
? "fem noun"
: "other";
if (pashtoPlural) return {
plural: pashtoPlural,
arabicPlural,
};
if (pashtoPlural)
return {
plural: pashtoPlural,
arabicPlural,
};
if (type === "unisex noun") {
// doesn't need to be labelled anim - because it's only with animate nouns that you get the unisex - I THINK
if (endsInConsonant(w) && (!w.infap)) {
return { arabicPlural, bundledPlural, plural: addAnimUnisexPluralSuffix() };
if (endsInConsonant(w) && !w.infap) {
return {
arabicPlural,
bundledPlural,
plural: addAnimUnisexPluralSuffix(),
};
}
if (shortSquish && !anim) {
return { arabicPlural, plural: { masc: addMascPluralSuffix(anim, shortSquish) }};
return {
arabicPlural,
plural: { masc: addMascPluralSuffix(anim, shortSquish) },
};
}
if (endsWith([{ p: "ی", f: "éy" }, { p: "ي" }], w, true)) {
return { arabicPlural, plural: addAnimN3UnisexPluralSuffix() };
@ -597,10 +684,10 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
// arabic plurals for the animat ones, right?
}
if (
type === "masc noun" &&
(shortSquish || ((endsInConsonant(w) || endsInShwa(w)) && (!w.infap))) &&
(w.p.slice(-3) !== "توب")
) {
type === "masc noun" &&
(shortSquish || ((endsInConsonant(w) || endsInShwa(w)) && !w.infap)) &&
w.p.slice(-3) !== "توب"
) {
return {
arabicPlural,
bundledPlural,
@ -609,11 +696,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
},
};
}
if (
type === "masc noun" &&
endsWith({ p: "ی", f: "éy" }, w, true) &&
anim
) {
if (type === "masc noun" && endsWith({ p: "ی", f: "éy" }, w, true) && anim) {
const { masc } = addAnimN3UnisexPluralSuffix();
return {
arabicPlural,
@ -630,7 +713,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
};
}
// TODO: What about endings in long ee / animate at inanimate
if (type === "masc noun" && endsInAaOrOo(w) && (!w.infap)) {
if (type === "masc noun" && endsInAaOrOo(w) && !w.infap) {
return {
arabicPlural,
plural: {
@ -639,7 +722,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
};
}
// TODO: What about endings in long ee / animate at inanimate
if (type === "fem noun" && endsInAaOrOo(w) && (!w.infap)) {
if (type === "fem noun" && endsInAaOrOo(w) && !w.infap) {
return {
arabicPlural,
plural: {
@ -661,6 +744,8 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
return undefined;
}
export function inflectYey(ps: T.SingleOrLengthOpts<T.PsString>): T.SingleOrLengthOpts<T.UnisexInflections> {
export function inflectYey(
ps: T.SingleOrLengthOpts<T.PsString>
): T.SingleOrLengthOpts<T.UnisexInflections> {
return fmapSingleOrLengthOpts((x) => inflectRegularYeyUnisex(x.p, x.f), ps);
}

View File

@ -2,289 +2,403 @@ import * as T from "../../../types";
import { getLength } from "../p-text-helpers";
export function makeBlock(block: T.Block["block"], key?: number): T.Block {
return {
key: key === undefined ? Math.random() : key,
block,
};
return {
key: key === undefined ? Math.random() : key,
block,
};
}
export function makeKid(kid: T.Kid["kid"], key?: number): T.Kid {
return {
key: key === undefined ? Math.random() : key,
kid,
};
return {
key: key === undefined ? Math.random() : key,
kid,
};
}
export function getSubjectSelection(blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]): T.SubjectSelectionComplete;
export function getSubjectSelection(blocks: T.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection;
export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[] | T.VPSBlockComplete[] | T.VPSBlock[]): T.SubjectSelection | T.SubjectSelectionComplete {
const b = blocks.find(f => f.block?.type === "subjectSelection");
if (!b || !b.block || b.block.type !== "subjectSelection") {
throw new Error("subjectSelection not found in blocks");
}
return b.block;
export function getSubjectSelection(
blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]
): T.SubjectSelectionComplete;
export function getSubjectSelection(
blocks: T.EPSBlock[] | T.VPSBlock[]
): T.SubjectSelection;
export function getSubjectSelection(
blocks:
| T.EPSBlock[]
| T.EPSBlockComplete[]
| T.VPSBlockComplete[]
| T.VPSBlock[]
): T.SubjectSelection | T.SubjectSelectionComplete {
const b = blocks.find((f) => f.block?.type === "subjectSelection");
if (!b || !b.block || b.block.type !== "subjectSelection") {
throw new Error("subjectSelection not found in blocks");
}
return b.block;
}
export function getComplementFromBlocks(blocks: T.Block[][]): T.Rendered<T.ComplementSelection> | T.UnselectedComplementSelection | undefined {
const b = blocks[0].find(f => f.block.type === "complement");
return b?.block as T.Rendered<T.ComplementSelection> | T.UnselectedComplementSelection | undefined;
export function getComplementFromBlocks(
blocks: T.Block[][]
):
| T.Rendered<T.ComplementSelection>
| T.UnselectedComplementSelection
| undefined {
const b = blocks[0].find((f) => f.block.type === "complement");
return b?.block as
| T.Rendered<T.ComplementSelection>
| T.UnselectedComplementSelection
| undefined;
}
export function getSubjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.SubjectSelectionComplete> {
const b = blocks[0].find(f => f.block.type === "subjectSelection");
if (!b || b.block.type !== "subjectSelection") {
throw new Error("subjectSelection not found in blocks");
}
return b.block;
export function getSubjectSelectionFromBlocks(
blocks: T.Block[][]
): T.Rendered<T.SubjectSelectionComplete> {
const b = blocks[0].find((f) => f.block.type === "subjectSelection");
if (!b || b.block.type !== "subjectSelection") {
throw new Error("subjectSelection not found in blocks");
}
return b.block;
}
export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.ObjectSelectionComplete> {
const b = blocks[0].find(f => f.block.type === "objectSelection");
if (!b || b.block.type !== "objectSelection") {
throw new Error("objectSelection not found in blocks");
}
return b.block;
export function getObjectSelectionFromBlocks(
blocks: T.Block[][]
): T.Rendered<T.ObjectSelectionComplete> {
const b = blocks[0].find((f) => f.block.type === "objectSelection");
if (!b || b.block.type !== "objectSelection") {
throw new Error("objectSelection not found in blocks");
}
return b.block;
}
export function includesShrunkenServant(kids?: T.Kid[]): boolean {
if (!kids) return false;
return kids.some(k => (
k.kid.type === "mini-pronoun" && k.kid.source === "servant"
));
if (!kids) return false;
return kids.some(
(k) => k.kid.type === "mini-pronoun" && k.kid.source === "servant"
);
}
export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.PredicateSelectionComplete> {
const b = blocks[0].find(f => f.block.type === "predicateSelection");
if (!b || b.block.type !== "predicateSelection") {
throw new Error("predicateSelection not found in blocks");
}
return b.block;
export function getPredicateSelectionFromBlocks(
blocks: T.Block[][]
): T.Rendered<T.PredicateSelectionComplete> {
const b = blocks[0].find((f) => f.block.type === "predicateSelection");
if (!b || b.block.type !== "predicateSelection") {
throw new Error("predicateSelection not found in blocks");
}
return b.block;
}
export function getAPsFromBlocks(blocks: T.Block[][]): T.Rendered<T.APSelection>[] {
return blocks[0].filter(b => b.block.type === "AP").map(b => b.block) as T.Rendered<T.APSelection>[];
export function getAPsFromBlocks(
blocks: T.Block[][]
): T.Rendered<T.APSelection>[] {
return blocks[0]
.filter((b) => b.block.type === "AP")
.map((b) => b.block) as T.Rendered<T.APSelection>[];
}
export function getObjectSelection(blocks: T.VPSBlockComplete[]): T.ObjectSelectionComplete;
export function getObjectSelection(
blocks: T.VPSBlockComplete[]
): T.ObjectSelectionComplete;
export function getObjectSelection(blocks: T.VPSBlock[]): T.ObjectSelection;
export function getObjectSelection(blocks: T.VPSBlock[] | T.VPSBlockComplete[]): T.ObjectSelection | T.ObjectSelectionComplete {
const b = blocks.find(f => f.block?.type === "objectSelection");
if (!b || !b.block || b.block.type !== "objectSelection") {
throw new Error("objectSelection not found in blocks");
}
return b.block;
export function getObjectSelection(
blocks: T.VPSBlock[] | T.VPSBlockComplete[]
): T.ObjectSelection | T.ObjectSelectionComplete {
const b = blocks.find((f) => f.block?.type === "objectSelection");
if (!b || !b.block || b.block.type !== "objectSelection") {
throw new Error("objectSelection not found in blocks");
}
return b.block;
}
export function makeEPSBlocks(): T.EPSBlock[] {
return [
{
key: Math.random(),
block: {
type: "subjectSelection",
selection: undefined,
},
}
];
}
export function makeAPBlock(): { key: number, block: undefined } {
return {
key: Math.random(),
block: undefined,
};
}
export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelection | T.NPSelection["selection"] | undefined): T.SubjectSelection {
if (!selection) {
return {
type: "subjectSelection",
selection: undefined,
};
}
if (selection.type === "subjectSelection") {
return selection;
}
if (selection.type === "NP") {
return {
type: "subjectSelection",
selection,
};
}
return {
return [
{
key: Math.random(),
block: {
type: "subjectSelection",
selection: {
type: "NP",
selection,
}
};
selection: undefined,
},
},
];
}
export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP | T.NPSelection | T.NPSelection["selection"] | undefined): T.ObjectSelection {
if (!selection) {
return {
type: "objectSelection",
selection: undefined,
}
}
if (typeof selection !== "object") {
return {
type: "objectSelection",
selection,
};
}
if (selection.type === "objectSelection") {
return selection;
}
if (selection.type === "NP") {
return {
type: "objectSelection",
selection,
};
}
export function makeAPBlock(): { key: number; block: undefined } {
return {
key: Math.random(),
block: undefined,
};
}
export function makeSubjectSelection(
selection:
| T.SubjectSelection
| T.NPSelection
| T.NPSelection["selection"]
| undefined
): T.SubjectSelection {
if (!selection) {
return {
type: "objectSelection",
selection: {
type: "NP",
selection,
},
type: "subjectSelection",
selection: undefined,
};
}
if (selection.type === "subjectSelection") {
return selection;
}
if (selection.type === "NP") {
return {
type: "subjectSelection",
selection,
};
}
return {
type: "subjectSelection",
selection: {
type: "NP",
selection,
},
};
}
export function EPSBlocksAreComplete(blocks: T.EPSBlock[]): blocks is T.EPSBlockComplete[] {
if (blocks.some(block => block.block === undefined)) {
return false;
}
const subject = getSubjectSelection(blocks);
return !!subject.selection;
export function makeObjectSelection(
selection:
| T.ObjectSelection
| T.ObjectNP
| T.NPSelection
| T.NPSelection["selection"]
| undefined
): T.ObjectSelection {
if (!selection) {
return {
type: "objectSelection",
selection: undefined,
};
}
if (typeof selection !== "object") {
return {
type: "objectSelection",
selection,
};
}
if (selection.type === "objectSelection") {
return selection;
}
if (selection.type === "NP") {
return {
type: "objectSelection",
selection,
};
}
return {
type: "objectSelection",
selection: {
type: "NP",
selection,
},
};
}
export function VPSBlocksAreComplete(blocks: T.VPSBlock[]): blocks is T.VPSBlockComplete[] {
if (blocks.some(block => block.block === undefined)) {
return false;
}
const subject = getSubjectSelection(blocks);
if (!subject.selection) return false;
const object = getObjectSelection(blocks);
if (!object.selection) return false;
return true;
export function EPSBlocksAreComplete(
blocks: T.EPSBlock[]
): blocks is T.EPSBlockComplete[] {
if (blocks.some((block) => block.block === undefined)) {
return false;
}
const subject = getSubjectSelection(blocks);
return !!subject.selection;
}
export function adjustSubjectSelection(blocks: T.EPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.EPSBlock[];
export function adjustSubjectSelection(blocks: T.VPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.VPSBlock[];
export function adjustSubjectSelection(blocks: T.VPSBlock[] | T.EPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.VPSBlock[] | T.EPSBlock[] {
const nb = [...blocks];
const i = nb.findIndex(b => b.block && b.block.type === "subjectSelection");
if (i === -1) {
throw new Error("couldn't find subjectSelection to modify");
}
nb[i].block = subject?.type === "subjectSelection" ? subject : makeSubjectSelection(subject);
return nb;
export function VPSBlocksAreComplete(
blocks: T.VPSBlock[]
): blocks is T.VPSBlockComplete[] {
if (blocks.some((block) => block.block === undefined)) {
return false;
}
const subject = getSubjectSelection(blocks);
if (!subject.selection) return false;
const object = getObjectSelection(blocks);
if (!object.selection) return false;
return true;
}
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelectionComplete | T.NPSelection | T.VerbObject | T.ObjectSelectionComplete): T.VPSBlockComplete[];
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelection | T.NPSelection | T.VerbObject | T.ObjectSelection | undefined): T.EPSBlock[];
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelection | T.ObjectSelectionComplete | T.VerbObject | T.NPSelection | undefined): T.VPSBlock[] | T.VPSBlockComplete[] {
const nb = [...blocks];
const i = nb.findIndex(b => b.block && b.block.type === "objectSelection");
if (i === -1) {
throw new Error("couldn't find objectSelection to modify");
}
nb[i].block = typeof object === "object" && object?.type === "objectSelection"
? object
: makeObjectSelection(object);
return nb;
export function adjustSubjectSelection(
blocks: T.EPSBlock[],
subject: T.SubjectSelection | T.NPSelection | undefined
): T.EPSBlock[];
export function adjustSubjectSelection(
blocks: T.VPSBlock[],
subject: T.SubjectSelection | T.NPSelection | undefined
): T.VPSBlock[];
export function adjustSubjectSelection(
blocks: T.VPSBlock[] | T.EPSBlock[],
subject: T.SubjectSelection | T.NPSelection | undefined
): T.VPSBlock[] | T.EPSBlock[] {
const nb = [...blocks];
const i = nb.findIndex((b) => b.block && b.block.type === "subjectSelection");
if (i === -1) {
throw new Error("couldn't find subjectSelection to modify");
}
nb[i].block =
subject?.type === "subjectSelection"
? subject
: makeSubjectSelection(subject);
return nb;
}
export function shiftBlock<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number, direction: "back" | "forward"): B {
const newIndex = index + (direction === "forward"
? 1 // (isNoObject(blocks[index + 1].block) ? 2 : 1)
: -1 // (isNoObject(blocks[index - 1].block) ? -2 : -2)
);
return arrayMove(blocks, index, newIndex) as B;
export function adjustObjectSelection(
blocks: Readonly<T.VPSBlock[]>,
object:
| T.ObjectSelectionComplete
| T.NPSelection
| T.VerbObject
| T.ObjectSelectionComplete
): T.VPSBlockComplete[];
export function adjustObjectSelection(
blocks: Readonly<T.VPSBlock[]>,
object:
| T.ObjectSelection
| T.NPSelection
| T.VerbObject
| T.ObjectSelection
| undefined
): T.EPSBlock[];
export function adjustObjectSelection(
blocks: Readonly<T.VPSBlock[]>,
object:
| T.ObjectSelection
| T.ObjectSelectionComplete
| T.VerbObject
| T.NPSelection
| undefined
): T.VPSBlock[] | T.VPSBlockComplete[] {
const nb = [...blocks];
const i = nb.findIndex((b) => b.block && b.block.type === "objectSelection");
if (i === -1) {
throw new Error("couldn't find objectSelection to modify");
}
nb[i].block =
typeof object === "object" && object?.type === "objectSelection"
? object
: makeObjectSelection(object);
return nb;
}
export function insertNewAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B): B {
return [makeAPBlock(), ...blocks] as B;
export function moveObjectToEnd(
blocks: T.VPSBlockComplete[]
): T.VPSBlockComplete[] {
const i = blocks.findIndex(
(b) => b.block && b.block.type === "objectSelection"
);
if (i === -1) {
throw new Error("couldn't find objectSelection to move");
}
if (i === blocks.length - 1) {
return blocks;
}
return arrayMove(blocks, i, blocks.length - 1);
}
export function setAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number, AP: T.APSelection | undefined): B {
const nBlocks = [...blocks] as B;
nBlocks[index].block = AP;
return nBlocks;
export function shiftBlock<B extends T.VPSBlock[] | T.EPSBlock[]>(
blocks: B,
index: number,
direction: "back" | "forward"
): B {
const newIndex =
index +
(direction === "forward"
? 1 // (isNoObject(blocks[index + 1].block) ? 2 : 1)
: -1); // (isNoObject(blocks[index - 1].block) ? -2 : -2)
return arrayMove(blocks, index, newIndex) as B;
}
export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number): B {
const nBlocks = [...blocks] as B;
nBlocks.splice(index, 1);
return nBlocks;
export function insertNewAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
blocks: B
): B {
return [makeAPBlock(), ...blocks] as B;
}
export function isNoObject(b: T.VPSBlock["block"] | T.EPSBlock["block"]): b is { type: "objectSelection", selection: "none" } {
return !!(
b
&&
(b.type === "objectSelection" && b.selection === "none")
);
export function setAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
blocks: B,
index: number,
AP: T.APSelection | undefined
): B {
const nBlocks = [...blocks] as B;
nBlocks[index].block = AP;
return nBlocks;
}
export function specifyEquativeLength(blocksWVars: T.Block[][], length: "long" | "short"): T.Block[][] {
function specify(blocks: T.Block[]): T.Block[] {
const i = blocks.findIndex(b => b.block.type === "equative");
if (i === -1) throw new Error("equative block not found in EPRendered");
const eq = blocks[i];
if (eq.block.type !== "equative") throw new Error("error searching for equative block");
const adjusted = [...blocks];
adjusted[i] = {
...eq,
block: {
...eq.block,
equative: {
...eq.block.equative,
ps: getLength(eq.block.equative.ps, length),
},
},
};
return adjusted;
}
return blocksWVars.map(specify);
export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
blocks: B,
index: number
): B {
const nBlocks = [...blocks] as B;
nBlocks.splice(index, 1);
return nBlocks;
}
export function isNoObject(
b: T.VPSBlock["block"] | T.EPSBlock["block"]
): b is { type: "objectSelection"; selection: "none" } {
return !!(b && b.type === "objectSelection" && b.selection === "none");
}
export function specifyEquativeLength(
blocksWVars: T.Block[][],
length: "long" | "short"
): T.Block[][] {
function specify(blocks: T.Block[]): T.Block[] {
const i = blocks.findIndex((b) => b.block.type === "equative");
if (i === -1) throw new Error("equative block not found in EPRendered");
const eq = blocks[i];
if (eq.block.type !== "equative")
throw new Error("error searching for equative block");
const adjusted = [...blocks];
adjusted[i] = {
...eq,
block: {
...eq.block,
equative: {
...eq.block.equative,
ps: getLength(eq.block.equative.ps, length),
},
},
};
return adjusted;
}
return blocksWVars.map(specify);
}
export function isRenderedVerbB({ block }: T.Block): boolean {
if (block.type === "equative") {
return true;
}
if (block.type === "VB") {
return true;
}
if (block.type === "PH") {
return true;
}
if (block.type === "NComp") {
return true;
}
if (block.type === "welded") {
return true;
}
if (block.type === "complement") {
return true;
}
return false
if (block.type === "equative") {
return true;
}
if (block.type === "VB") {
return true;
}
if (block.type === "PH") {
return true;
}
if (block.type === "NComp") {
return true;
}
if (block.type === "welded") {
return true;
}
if (block.type === "complement") {
return true;
}
return false;
}
export function hasEquativeWithLengths(blocks: T.Block[][]): boolean {
const equative = blocks[0].find(x => x.block.type === "equative");
if (!equative) throw new Error("equative not found in blocks");
if (equative.block.type !== "equative") throw new Error("error finding equative in blocks");
return "long" in equative.block.equative.ps;
const equative = blocks[0].find((x) => x.block.type === "equative");
if (!equative) throw new Error("equative not found in blocks");
if (equative.block.type !== "equative")
throw new Error("error finding equative in blocks");
return "long" in equative.block.equative.ps;
}
function arrayMove<X>(ar: X[], old_index: number, new_index: number): X[] {
const arr = [...ar];
const new_i = (new_index >= arr.length)
? (arr.length - 1)
: (new_index < 0)
? 0
: new_index;
arr.splice(new_i, 0, arr.splice(old_index, 1)[0]);
return arr;
};
const arr = [...ar];
const new_i =
new_index >= arr.length ? arr.length - 1 : new_index < 0 ? 0 : new_index;
arr.splice(new_i, 0, arr.splice(old_index, 1)[0]);
return arr;
}

View File

@ -22,6 +22,8 @@ import {
specifyEquativeLength,
} from "./blocks-utils";
import { blank, kidsBlank } from "../misc-helpers";
import { monoidPsStringWVars } from "../fp-ps";
import { concatAll } from "fp-ts/lib/Monoid";
type BlankoutOptions = {
equative?: boolean;
@ -215,64 +217,66 @@ export function combineIntoText(
subjectPerson: T.Person,
blankOut?: BlankoutOptions
): T.PsString[] {
function removeDoubleBlanks(x: T.PsString): T.PsString {
return {
p: x.p.replace(blank.p + blank.p, blank.p),
f: x.f.replace(blank.f + blank.f, blank.f),
};
}
function combine(pieces: (T.Block | T.Kid | T.PsString)[]): T.PsString[] {
const first = pieces[0];
const next = pieces[1];
const rest = pieces.slice(1);
// better to do map-reduce
// map the blocks into monoids [T.PsString] (with appropriate space blocks) and then concat them all together
const firstPs =
"p" in first
? [first]
: (blankOut?.equative &&
"block" in first &&
first.block.type === "equative") ||
(blankOut?.verb && "block" in first && isRenderedVerbB(first)) ||
(blankOut?.predicate &&
"block" in first &&
first.block.type === "predicateSelection")
? [blank]
: blankOut?.ba && "kid" in first && first.kid.type === "ba"
? [kidsBlank]
: blankOut?.negative &&
"block" in first &&
first.block.type === "negative"
? [{ p: "", f: "" }]
: getPsFromPiece(first, subjectPerson);
if (!rest.length) {
return firstPs;
return piecesWVars
.map((pieces) => {
const psVarsBlocks = getPsVarsBlocks(
applyBlankOut(pieces, blankOut),
subjectPerson
);
return concatAll(monoidPsStringWVars)(psVarsBlocks);
})
.flat();
}
function getPsVarsBlocks(
pieces: (T.Block | T.Kid | T.PsString)[],
subjectPerson: T.Person
): T.PsString[][] {
const space = [{ p: " ", f: " " }];
const phToCliticNegSpace = [{ p: "", f: "-" }];
const endIndex = pieces.length - 1;
return pieces.reduce<T.PsString[][]>((acc, x, i) => {
const next = pieces[i + 1];
if ("p" in x) {
return [...acc, [x]];
}
return combine(rest)
.flatMap((r) =>
firstPs.map((fPs) =>
concatPsString(
fPs,
// TODO: this spacing is a mess and not accurate
!("p" in first) &&
"block" in first &&
first.block.type === "PH" &&
!("p" in next) &&
(("block" in next &&
(isRenderedVerbB(next) || next.block.type === "negative")) ||
("kid" in next && next.kid.type === "mini-pronoun"))
? ("block" in next && next.block.type === "negative") ||
("kid" in next && next.kid.type === "mini-pronoun")
? { p: "", f: " " }
: ""
: " ",
r
)
)
)
.map(removeDoubleBlanks);
}
return piecesWVars.flatMap(combine);
const ps = getPsFromPiece(x, subjectPerson);
return [
...acc,
ps,
...(i === endIndex
? []
: "block" in x && x.block.type === "PH"
? "kid" in next || ("block" in next && next.block.type === "negative")
? [phToCliticNegSpace]
: []
: [space]),
];
}, []);
}
function applyBlankOut(
pieces: (T.Block | T.Kid | T.PsString)[],
blankOut: BlankoutOptions | undefined
): (T.Block | T.Kid | T.PsString)[] {
if (!blankOut) return pieces;
return pieces.map((x) => {
if (
(blankOut.equative && "block" in x && x.block.type === "equative") ||
(blankOut.verb && "block" in x && isRenderedVerbB(x)) ||
(blankOut?.predicate &&
"block" in x &&
x.block.type === "predicateSelection")
) {
return blank;
}
if (blankOut?.ba && "kid" in x && x.kid.type === "ba") {
return kidsBlank;
}
if (blankOut?.negative && "block" in x && x.block.type === "negative") {
return { p: "", f: "" };
}
return x;
});
}
function getPsFromPiece(

View File

@ -1,52 +1,63 @@
import {
isPluralNounEntry,
isMascNounEntry,
isUnisexNounEntry,
isPluralNounEntry,
isMascNounEntry,
isUnisexNounEntry,
} from "../type-predicates";
import * as T from "../../../types";
export function makeAdverbSelection(entry: T.AdverbEntry): T.AdverbSelection {
return {
type: "adverb",
entry: entry,
};
return {
type: "adverb",
entry: entry,
};
}
export function makeLocativeAdverbSelection(entry: T.LocativeAdverbEntry): T.LocativeAdverbSelection {
return {
type: "loc. adv.",
entry: entry,
};
export function makeLocativeAdverbSelection(
entry: T.LocativeAdverbEntry
): T.LocativeAdverbSelection {
return {
type: "loc. adv.",
entry: entry,
};
}
export function makeAdjectiveSelection(entry: T.AdjectiveEntry): T.AdjectiveSelection {
return {
type: "adjective",
entry: entry,
sandwich: undefined,
};
export function makeAdjectiveSelection(
entry: T.AdjectiveEntry
): T.AdjectiveSelection {
return {
type: "adjective",
entry: entry,
sandwich: undefined,
};
}
export function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelection {
return {
type: "participle",
verb,
possesor: undefined,
};
export function makeParticipleSelection(
verb: T.VerbEntry
): T.ParticipleSelection {
return {
type: "participle",
verb,
possesor: undefined,
};
}
export function makeNounSelection(entry: T.NounEntry, old: T.NounSelection | undefined, dynamicComplement?: true): T.NounSelection {
const number = isPluralNounEntry(entry) ? "plural" : "singular";
return {
type: "noun",
entry,
gender: isMascNounEntry(entry) ? "masc" : "fem",
genderCanChange: isUnisexNounEntry(entry),
number,
numberCanChange: number === "singular",
adjectives: (!dynamicComplement && old) ? old.adjectives : [],
possesor: !dynamicComplement ? old?.possesor : undefined,
dynamicComplement,
demonstrative: undefined,
};
}
export function makeNounSelection(
entry: T.NounEntry,
old: T.NounSelection | undefined,
complementType?: "dynamic" | "generative stative"
): T.NounSelection {
const number = isPluralNounEntry(entry) ? "plural" : "singular";
return {
type: "noun",
entry,
gender: isMascNounEntry(entry) ? "masc" : "fem",
genderCanChange: isUnisexNounEntry(entry),
number,
numberCanChange: number === "singular",
adjectives: !complementType && old ? old.adjectives : [],
possesor: !complementType ? old?.possesor : undefined,
dynamicComplement: complementType === "dynamic",
genStativeComplement: complementType === "generative stative",
demonstrative: undefined,
};
}

View File

@ -1,5 +1,5 @@
import * as T from "../../../types";
import { mapVerbRenderedOutput } from "../fmaps";
import { mapVerbRenderedOutput } from "../fp-ps";
import { removeAccents } from "../accent-helpers";
import { getPersonFromNP, isPastTense } from "./vp-tools";
import { isImperativeTense, isPattern4Entry } from "../type-predicates";
@ -19,6 +19,7 @@ import {
getMiniPronounPs,
} from "./render-common";
import { renderComplementSelection } from "./render-complement";
import { statVerb } from "../new-verb-engine/roots-and-stems";
export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
const subject = getSubjectSelection(VP.blocks).selection;
@ -45,8 +46,18 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
king,
complementPerson,
});
// TODO: for dynamic -
const { vbs, hasBa } = renderVerb({
verb: VP.verb.verb,
verb:
VP.verb.isCompound === "generative stative"
? statVerb[
VP.verb.transitivity === "intransitive"
? "intransitive"
: "transitive"
]
: VP.verb.dynAuxVerb
? VP.verb.dynAuxVerb
: VP.verb.verb,
tense: VP.verb.tense,
subject: subjectPerson,
object: objectPerson,
@ -128,7 +139,6 @@ export function insertNegative(
if (!negative) {
return [blocks.flat().map(makeBlock)];
}
const blocksA = blocks.flat().map(makeBlock);
const blocksNoAccentA = mapVerbRenderedOutput(removeAccents, blocks)
.flat()
.map(makeBlock);
@ -138,13 +148,13 @@ export function insertNegative(
// swapped ending with negative for ability and perfect verb forms
if (nonStandPerfectiveSplit) {
return [
insertFromEnd(swapEndingBlocks(blocksA), neg, 2),
insertFromEnd(swapEndingBlocks(blocksA, 2), neg, 3),
insertFromEnd(swapEndingBlocks(blocksNoAccentA), neg, 2),
insertFromEnd(swapEndingBlocks(blocksNoAccentA, 2), neg, 3),
insertFromEnd(blocksNoAccentA, neg, 1),
];
}
return [
insertFromEnd(swapEndingBlocks(blocksA), neg, 2),
insertFromEnd(swapEndingBlocks(blocksNoAccentA), neg, 2),
insertFromEnd(blocksNoAccentA, neg, 1),
];
}
@ -280,8 +290,9 @@ function whatsAdjustable(
VP: T.VPSelectionComplete
): "both" | "king" | "servant" {
// TODO: intransitive dynamic compounds?
return VP.verb.isCompound === "dynamic" &&
VP.verb.transitivity === "transitive"
return VP.verb.isCompound === "dynamic" ||
(VP.verb.isCompound === "generative stative" &&
VP.verb.transitivity === "transitive")
? isPastTense(VP.verb.tense)
? "servant"
: "king"

View File

@ -1,131 +1,186 @@
import {
makeNounSelection,
} from "./make-selections";
import { makeNounSelection } from "./make-selections";
import * as T from "../../../types";
import { getVerbInfo } from "../verb-info";
import {
adjustObjectSelection,
getObjectSelection,
getSubjectSelection,
makeObjectSelection,
makeSubjectSelection,
adjustObjectSelection,
getObjectSelection,
getSubjectSelection,
makeObjectSelection,
makeSubjectSelection,
moveObjectToEnd,
} from "./blocks-utils";
export function makeVPSelectionState(
verb: T.VerbEntry,
os?: T.VPSelectionState,
verb: T.VerbEntry,
os?: T.VPSelectionState
): T.VPSelectionState {
const info = getVerbInfo(verb.entry, verb.complement);
const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound")
? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true)
: (os?.blocks ? getSubjectSelection(os.blocks).selection : undefined);
function getTransObjFromos() {
const osObj = os ? getObjectSelection(os.blocks).selection : undefined;
if (
!os ||
osObj === "none" ||
typeof osObj === "number" ||
os.verb.isCompound === "dynamic" ||
(osObj?.selection.type === "noun" && osObj.selection.dynamicComplement)
) return undefined;
return osObj;
}
const transitivity: T.Transitivity = "grammaticallyTransitive" in info
? "transitive"
: info.transitivity;
const object = (transitivity === "grammatically transitive")
? T.Person.ThirdPlurMale
: (info.type === "dynamic compound" && os?.verb.voice !== "passive")
? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true)
: (transitivity === "transitive" && os?.verb.voice !== "passive")
? getTransObjFromos()
: "none";
const isCompound = ("stative" in info || info.type === "stative compound")
? "stative"
: info.type === "dynamic compound"
? "dynamic"
: false;
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
const dynAuxVerb: T.VerbEntry | undefined = isCompound !== "dynamic"
? undefined
: info.type === "dynamic compound"
? { entry: info.auxVerb } as T.VerbEntry
: "dynamic" in info
? { entry: info.dynamic.auxVerb } as T.VerbEntry
: undefined;
const blocks = [
{ key: Math.random(), block: makeSubjectSelection(subject) },
{ key: Math.random(), block: makeObjectSelection(object) },
];
return {
blocks,
verb: {
type: "verb",
verb: verb,
dynAuxVerb,
verbTense: os ? os.verb.verbTense : "presentVerb",
perfectTense: os ? os.verb.perfectTense : "presentPerfect",
imperativeTense: os ? os.verb.imperativeTense : "imperfectiveImperative",
tenseCategory: os ? os.verb.tenseCategory : "basic",
transitivity,
isCompound,
voice: transitivity === "transitive"
? (os?.verb.voice || "active")
: "active",
negative: os ? os.verb.negative : false,
canChangeTransitivity: "grammaticallyTransitive" in info,
canChangeVoice: transitivity === "transitive",
canChangeStatDyn: "stative" in info,
},
externalComplement: takesExternalComplement(verb)
? { type: "complement", selection: { type: "unselected" }}
: undefined,
form: (os && info.type !== "dynamic compound")
? os.form
: { removeKing: false, shrinkServant: false },
};
const info = getVerbInfo(verb.entry, verb.complement);
const subject =
os?.verb.voice === "passive" && info.type === "dynamic compound"
? makeNounSelection(
info.objComplement.entry as T.NounEntry,
undefined,
"dynamic"
)
: os?.blocks
? getSubjectSelection(os.blocks).selection
: undefined;
function getTransObjFromos() {
const osObj = os ? getObjectSelection(os.blocks).selection : undefined;
if (
!os ||
osObj === "none" ||
typeof osObj === "number" ||
os.verb.isCompound === "dynamic" ||
(osObj?.selection.type === "noun" &&
(osObj.selection.dynamicComplement ||
osObj.selection.genStativeComplement))
)
return undefined;
return osObj;
}
const transitivity: T.Transitivity =
"grammaticallyTransitive" in info ? "transitive" : info.transitivity;
const object =
transitivity === "grammatically transitive"
? T.Person.ThirdPlurMale
: (info.type === "dynamic compound" ||
info.type === "generative stative compound") &&
os?.verb.voice !== "passive"
? makeNounSelection(
info.objComplement.entry as T.NounEntry,
undefined,
info.type === "dynamic compound" ? "dynamic" : "generative stative"
)
: info.type === "dynamic or generative stative compound" &&
os?.verb.voice !== "passive"
? makeNounSelection(
info.dynamic.objComplement.entry as T.NounEntry,
undefined,
"generative stative"
)
: transitivity === "transitive" && os?.verb.voice !== "passive"
? getTransObjFromos()
: "none";
const isCompound =
"stative" in info && info.type === "dynamic or generative stative compound"
? "generative stative"
: "stative" in info || info.type === "stative compound"
? "stative"
: info.type === "dynamic compound"
? "dynamic"
: false;
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
const dynAuxVerb: T.VerbEntry | undefined =
isCompound !== "dynamic"
? undefined
: info.type === "dynamic compound"
? ({ entry: info.auxVerb } as T.VerbEntry)
: "dynamic" in info
? ({ entry: info.dynamic.auxVerb } as T.VerbEntry)
: undefined;
const blocks = [
{ key: Math.random(), block: makeSubjectSelection(subject) },
{ key: Math.random(), block: makeObjectSelection(object) },
];
return {
blocks,
verb: {
type: "verb",
verb: verb,
dynAuxVerb,
verbTense: os ? os.verb.verbTense : "presentVerb",
perfectTense: os ? os.verb.perfectTense : "presentPerfect",
imperativeTense: os ? os.verb.imperativeTense : "imperfectiveImperative",
tenseCategory: os ? os.verb.tenseCategory : "basic",
transitivity,
isCompound,
voice:
transitivity === "transitive" ? os?.verb.voice || "active" : "active",
negative: os ? os.verb.negative : false,
canChangeTransitivity: "grammaticallyTransitive" in info,
canChangeVoice: transitivity === "transitive",
canChangeStatDyn: "stative" in info,
},
externalComplement: takesExternalComplement(verb)
? { type: "complement", selection: { type: "unselected" } }
: undefined,
form:
os && info.type !== "dynamic compound"
? os.form
: { removeKing: false, shrinkServant: false },
};
}
function takesExternalComplement(v: T.VerbEntry): boolean {
if (v.entry.p === "کول" && v.entry.e.includes("to make")) {
return true;
}
if (v.entry.p === "کېدل" && v.entry.e.includes("to become")) {
return true;
}
return false;
if (v.entry.p === "کول" && v.entry.e.includes("to make")) {
return true;
}
if (v.entry.p === "کېدل" && v.entry.e.includes("to become")) {
return true;
}
return false;
}
export function changeStatDyn(v: T.VPSelectionState, s: "dynamic" | "stative"): T.VPSelectionState {
const info = getVerbInfo(v.verb.verb.entry, v.verb.verb.complement);
if (!("stative" in info)) {
return v;
}
return {
...v,
blocks: adjustObjectSelection(
v.blocks,
s === "dynamic"
? { type: "NP", selection: makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, undefined, true) }
: undefined,
),
verb: {
...v.verb,
isCompound: s,
dynAuxVerb: s === "dynamic"
? { entry: info.dynamic.auxVerb } as T.VerbEntry
: undefined,
},
};
export function changeStatDyn(
v: T.VPSelectionState,
s: "dynamic" | "stative"
): T.VPSelectionState {
const info = getVerbInfo(v.verb.verb.entry, v.verb.verb.complement);
if (!("stative" in info)) {
return v;
}
const newBlocks = adjustObjectSelection(
v.blocks,
s === "dynamic" ||
(s === "stative" &&
info.type === "dynamic or generative stative compound")
? {
type: "NP",
selection: makeNounSelection(
info.dynamic.objComplement.entry as T.NounEntry,
undefined,
s === "dynamic" ? "dynamic" : "generative stative"
),
}
: undefined
);
return {
...v,
blocks:
s === "stative" && info.type === "dynamic or generative stative compound"
? moveObjectToEnd(newBlocks)
: newBlocks,
verb: {
...v.verb,
isCompound:
info.type === "dynamic or generative stative compound" &&
s === "stative"
? "generative stative"
: s,
dynAuxVerb:
s === "dynamic"
? ({ entry: info.dynamic.auxVerb } as T.VerbEntry)
: undefined,
},
};
}
export function changeTransitivity(v: T.VPSelectionState, transitivity: "transitive" | "grammatically transitive"): T.VPSelectionState {
return {
...v,
blocks: adjustObjectSelection(v.blocks, transitivity === "grammatically transitive" ? T.Person.ThirdPlurMale : undefined),
verb: {
...v.verb,
transitivity,
},
};
export function changeTransitivity(
v: T.VPSelectionState,
transitivity: "transitive" | "grammatically transitive"
): T.VPSelectionState {
return {
...v,
blocks: adjustObjectSelection(
v.blocks,
transitivity === "grammatically transitive"
? T.Person.ThirdPlurMale
: undefined
),
verb: {
...v.verb,
transitivity,
},
};
}

View File

@ -132,12 +132,14 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
// throw new Error("unknown tense");
// }
export function getPersonFromNP(np: T.NPSelection): T.Person;
export function getPersonFromNP(
np: T.NPSelection | T.ObjectNP
np: T.NPSelection | T.Rendered<T.NPSelection>
): T.Person;
export function getPersonFromNP(
np: T.NPSelection | T.Rendered<T.NPSelection> | T.ObjectNP
): T.Person | undefined;
export function getPersonFromNP(
np: T.NPSelection | T.ObjectNP
np: T.NPSelection | T.Rendered<T.NPSelection> | T.ObjectNP
): T.Person | undefined {
if (np === "none") {
return undefined;

File diff suppressed because it is too large Load Diff

View File

@ -693,7 +693,7 @@ export type VPRendered = {
servant: "subject" | "object" | undefined;
isPast: boolean;
isTransitive: boolean;
isCompound: "stative" | "dynamic" | false;
isCompound: "stative" | "dynamic" | "generative stative" | false;
blocks: Block[][];
kids: Kid[];
englishBase?: string[];
@ -811,7 +811,7 @@ export type VerbSelection = {
transitivity: Transitivity;
canChangeTransitivity: boolean;
canChangeStatDyn: boolean;
isCompound: "stative" | "dynamic" | false;
isCompound: "stative" | "dynamic" | "generative stative" | false;
voice: Voice;
canChangeVoice: boolean;
negative: boolean;
@ -867,6 +867,7 @@ export type NounSelection = {
number: NounNumber;
numberCanChange: boolean;
dynamicComplement?: boolean;
genStativeComplement?: boolean;
adjectives: AdjectiveSelection[];
possesor: undefined | PossesorSelection;
demonstrative: undefined | DemonstrativeSelection;
@ -1199,7 +1200,6 @@ export type MiniPronoun = {
export type RenderVerbOutput = {
hasBa: boolean;
vbs: VerbRenderedOutput;
objComp: Rendered<NPSelection> | undefined;
};
export type VerbRenderedOutput = [[VHead] | [], [VB, VBE] | [VBE]];
export type RootsStemsOutput = [[VHead] | [], [VB, VBA] | [VBA]]; // or perfect / equative

View File

@ -7,136 +7,138 @@
*/
module.exports = [
1527816643, // استعفا کول - to resign, to quit (a job or position)
1527817823, // اصرار کول - to insist, persist, demand
1591002320547, // امر کول - to order, command
1527821339, // انتظار کول - to wait
1527817226, // اندازه لګول - to guess, to estimate
1527812167, // انکار کول - to deny, to renounce, to not recognize
1527812598, // ایمان راوړل - to beileve, have faith (du chaa baande / د چا باندې)
1527812002, // برخه اخستل - to take part in, to participate, to join in
1527813489, // پرهېز کول - to abstain, fast
1577390517316, // پرېکړه کول - to decide
1527820710, // پناه اړول - to take/seek refuge
1527817312, // پوښتنه کول - to ask
1527818188, // پیروي کول - to follow, obey (usually a religious teacher or leader)
1527811863, // تاوان رسول - to harm, damage
1527816383, // تپوس کول - to ask, to question, to request
1527822770, // ترپکې وهل - to stamp (feet), to tread, to tap ones foot
1527821587, // ترحم کول - to feel pity, to have sympathy, to feel sorry for someone
1527818390, // تشریف راوړل - to come (when speaking about someone w/ respect)
1527818391, // تشریف وړل - to go (when speaking about someone w/ respect)
1527814726, // تصمیم نیول - to make a decision
1579394718033, // تصور کول - to imagine, suppose
1527815968, // تکیه کول - to rely on, to depend on
1592303372377, // تلاوت کول - to read (relgious, usually the Quran)
1577551342853, // تمرکز کول - to concentrate, focus (په يوه شي باندې)
1527815351, // توبه ایستل - to repent
1586452103064, // توجه کول - to pay attention to, to consider
1527816822, // توکل کول - to count on, hope for, depend on
1527812186, // تیاري نیول - to prepare
1527814870, // ټوپونه وهل - to jump
1527815355, // ټوکې کول - to joke, tease, make fun of
1527815867, // ټینګار کول - to emphasize, to insist
1527822741, // جیټکه خوړل - to be jolted, surprised
1527814864, // ځان وژل - to commit suicide
1527819607, // چرت وهل - to think about something, reflect on something, worry about something
1527821070, // چکر وهل - to stroll, walk around
1577812269585, // چمچه ګیري کول - to suck up to, to flatter
1573768865232, // چنې وهل - to barter, bargain (for a price)
1527822814, // حسد کول - to be envious, to be jealous
1527823161, // حفاظت کول - to protect, guard
1527821042, // حمایه کول - to support, aid, protect, back
1527818810, // حیا کول - to be bashful, modest, observing of Islamic rules of modesty
1577823792516, // خدمت کول - to serve (د چا خدمت کول)
1588858155947, // خېز وهل - to jump, leap, bob up and down
1589024311021, // دافع کول - to defend (د ځان دفاع کول - to defend oneself)
1527816916, // دفاع کول - to defend, protect
1527820291, // ډغره وهل - to challenge, invite to engage in a contest, confront, provoke
1527813125, // ذکر کول - to mention, refernce, remark, refer to
1527813937, // روژه نیول - to fast
1591804639647, // روغه کول - to reconcile, to make peace
1527813212, // زاري کول - to plea, ask, request, beg
1584529741244, // زړه ساتل - to hold back and not say what you're really thinking
1575128717139, // زړه وهل - to feel hesitancy about some action or thing (د دې کار څخه زړه وهي); to satiate
1527813319, // زنګ وهل - to ring, phone, call (Afghanistan)
1527822368, // زیاتي کول - to do injustice, oppression (to someone) (د چا سرس زياتي کول)
1527819178, // زیان رسول - to damage, to cause harm
1594129207239, // سا اخستل - to breathe
1594129204513, // سا اخیستل - to breathe
1527815309, // سبق وایل - to study, go to school
1527814102, // ست کول - to invite, to make an offer out of politeness (د ډوډۍ ست مې ورته وکړ)
1527818975, // سترګه وهل - to wink, to blink
1578326320888, // سجده لګول - to bowing down to the ground, to prostrating (in religion)
1527816152, // سر ټکول - complain, gripe
1527816463, // سوله کول - to make peace, to reconcile
1527818094, // سیل کول - to stroll through, go on a walk or tour through, to see, watch, examine, survey, visit, tour
1527814855, // شپېلۍ وهل - to play the flute, fife, reed, to whistle
1527819033, // شکایت کول - to complain, to express a grievance
1577817988469, // شکست خوړل - to be defeated, to experience defeat
1527819185, // صبر کول - to be patient, to bear up and endure under difficult or painful circumstances
1527814887, // صفت کول - to praise; admire, glorify
1527818217, // طرفداري کول - to support, adhere to, pick a side, stand up for something or someone
1571946107980, // ظلم کول - to be cruel to, to oppress, to do voilence against, to persecute (د چا باندې ظلم کول)
1581610643511, // عبادت کول - to worship, pray
1527811674, // عمل کول - to act, to put into practice; to do something addicting (like smoking), to do out of habit
1581610659810, // غچ اخیستل - to take revenge
1527818401, // غرض کول - to interfere, to meddle, to step in
1592303194144, // غږ کول - to call out, to say something, make a sound
1578607689918, // غلا کول - to steal
1527818341, // غمرازي کول - to share in someones sorrow, to show sympathy or give condolences
1527818425, // غوټه اچول - to tie, fasten, hitch
1527818422, // غوټه وهل - to dive, dip, go into water
1527812633, // غوږ نیول - to listen
1527816328, // غیبت کول - to gossip
1588784260692, // فال اچول - to do fortune telling, divination
1527812607, // فکر کول - to think
1527822096, // قدم وهل - to take a step, to walk
1588152878869, // قرباني کول - to make a sacrifice
1527817624, // قسم خوړل - to take an oath, vow, to swear
1527812732, // کار کول - to work
1527811600, // کوشش کول - to try, to attempt, to put in effort
1527819661, // ګپ لګول - to talk, converse; to joke
1527814357, // ګډون کول - to participate, join, be involved
1582146016627, // ګذاره کول - to get by, make ends meet, deal with something, handle or get some task done (with difficulty or not quite in the ideal way), to bear with, to be tolerant or forgiving
1527819872, // ګمان کول - to think, to suppose
1579034883717, // لاړې تېرول - to spit ?? (other fluids too??)
1527817357, // لاس وړل - to touch
1527818937, // لامبو وهل - to swim, bathe
1527813950, // لحاظ کول - to be considerate of, pay attention to someone or something, to be polite, to show deference or respect to someone
1527813888, // لغته وهل - to kick
1527822099, // لمس کول - to touch, motivate, instigate
1588760636420, // لوظ کول - to promise, give one's word
1527819089, // ماته خوړل - to be defeated, beaten by someone
1527817361, // مخ اړول - to turn (ones face), to face, (when turning from someone or people) to neglect, (when turning to someone or people) to pay attention to
1527812934, // مخه نیول - to prevent, hold back
1588161314887, // مرسته کول - to help, assist
1527817165, // مزدوري کول - to do labour, to work
1609162269829, // مزې کول - to be enjoyable, to have good taste (the thing that gives enjoyment/taste "does maza"), to have fun
1579295606403, // ملاتړ کول - to support (ie. a political party etc.)
1589031340746, // موټر چلول - to drive a car
1527812902, // مینه کول - to love
1527817369, // ناره وهل - to cry out, to yell, to yell a chant or slogan
1527819687, // نارې کول - to cry out, shout (ناره)
1527821254, // نافرماني کول - to disobey, to not comply, to rebel
1527817709, // نجات موندل - to be saved, to find salvation
1527823208, // نفرت کول - to hate, abhor
1527811827, // نفس ایستل - breath in, inhale; kill
1579459605988, // نقصان کول - to suffer loss
1527815991, // ننداره کول - to behold, to spectate, to watch, to take in
1527823707, // نیالګی کېنول - to plant a sapling, young tree
1527811729, // نیوکه کول - to criticize
1527823733, // هجرت کول - to migrate, resettle
1527820620, // هجوم کول - to swarm, rush, attack
1527811599, // هڅه کول - to try, to attempt, to put in effort
1604431102462, // هدایت کول - to guide, show the true path, give revelation leading to truth
1527818092, // همکاري کول - to collaborate, to work together, to aid/help
1527816106, // وده کول - to grow, develop, improve, rise
1579723460957, // ورزش کول - to de exercise, athletics
1527814910, // وعده کول - to promise
1527816263, // وفا کول - to be faithful, to keep one's promise
1609162463793, // واده کول - to marry, get married
1609599425410, // دعا کول - to pray
1527812939, // منډې وهل - to run
1614602054303, // بدله اخیستل - to take revenge
]
1527818320, // جارو کول - to sweep
1658796089458, // استري کول - to iron
1527816643, // استعفا کول - to resign, to quit (a job or position)
1527817823, // اصرار کول - to insist, persist, demand
1591002320547, // امر کول - to order, command
1527821339, // انتظار کول - to wait
1527817226, // اندازه لګول - to guess, to estimate
1527812167, // انکار کول - to deny, to renounce, to not recognize
1527812598, // ایمان راوړل - to beileve, have faith (du chaa baande / د چا باندې)
1527812002, // برخه اخستل - to take part in, to participate, to join in
1527813489, // پرهېز کول - to abstain, fast
1577390517316, // پرېکړه کول - to decide
1527820710, // پناه اړول - to take/seek refuge
1527817312, // پوښتنه کول - to ask
1527818188, // پیروي کول - to follow, obey (usually a religious teacher or leader)
1527811863, // تاوان رسول - to harm, damage
1527816383, // تپوس کول - to ask, to question, to request
1527822770, // ترپکې وهل - to stamp (feet), to tread, to tap ones foot
1527821587, // ترحم کول - to feel pity, to have sympathy, to feel sorry for someone
1527818390, // تشریف راوړل - to come (when speaking about someone w/ respect)
1527818391, // تشریف وړل - to go (when speaking about someone w/ respect)
1527814726, // تصمیم نیول - to make a decision
1579394718033, // تصور کول - to imagine, suppose
1527815968, // تکیه کول - to rely on, to depend on
1592303372377, // تلاوت کول - to read (relgious, usually the Quran)
1577551342853, // تمرکز کول - to concentrate, focus (په يوه شي باندې)
1527815351, // توبه ایستل - to repent
1586452103064, // توجه کول - to pay attention to, to consider
1527816822, // توکل کول - to count on, hope for, depend on
1527812186, // تیاري نیول - to prepare
1527814870, // ټوپونه وهل - to jump
1527815355, // ټوکې کول - to joke, tease, make fun of
1527815867, // ټینګار کول - to emphasize, to insist
1527822741, // جیټکه خوړل - to be jolted, surprised
1527814864, // ځان وژل - to commit suicide
1527819607, // چرت وهل - to think about something, reflect on something, worry about something
1527821070, // چکر وهل - to stroll, walk around
1577812269585, // چمچه ګیري کول - to suck up to, to flatter
1573768865232, // چنې وهل - to barter, bargain (for a price)
1527822814, // حسد کول - to be envious, to be jealous
1527823161, // حفاظت کول - to protect, guard
1527821042, // حمایه کول - to support, aid, protect, back
1527818810, // حیا کول - to be bashful, modest, observing of Islamic rules of modesty
1577823792516, // خدمت کول - to serve (د چا خدمت کول)
1588858155947, // خېز وهل - to jump, leap, bob up and down
1589024311021, // دافع کول - to defend (د ځان دفاع کول - to defend oneself)
1527816916, // دفاع کول - to defend, protect
1527820291, // ډغره وهل - to challenge, invite to engage in a contest, confront, provoke
1527813125, // ذکر کول - to mention, refernce, remark, refer to
1527813937, // روژه نیول - to fast
1591804639647, // روغه کول - to reconcile, to make peace
1527813212, // زاري کول - to plea, ask, request, beg
1584529741244, // زړه ساتل - to hold back and not say what you're really thinking
1575128717139, // زړه وهل - to feel hesitancy about some action or thing (د دې کار څخه زړه وهي); to satiate
1527813319, // زنګ وهل - to ring, phone, call (Afghanistan)
1527822368, // زیاتي کول - to do injustice, oppression (to someone) (د چا سرس زياتي کول)
1527819178, // زیان رسول - to damage, to cause harm
1594129207239, // سا اخستل - to breathe
1594129204513, // سا اخیستل - to breathe
1527815309, // سبق وایل - to study, go to school
1527814102, // ست کول - to invite, to make an offer out of politeness (د ډوډۍ ست مې ورته وکړ)
1527818975, // سترګه وهل - to wink, to blink
1578326320888, // سجده لګول - to bowing down to the ground, to prostrating (in religion)
1527816152, // سر ټکول - complain, gripe
1527816463, // سوله کول - to make peace, to reconcile
1527818094, // سیل کول - to stroll through, go on a walk or tour through, to see, watch, examine, survey, visit, tour
1527814855, // شپېلۍ وهل - to play the flute, fife, reed, to whistle
1527819033, // شکایت کول - to complain, to express a grievance
1577817988469, // شکست خوړل - to be defeated, to experience defeat
1527819185, // صبر کول - to be patient, to bear up and endure under difficult or painful circumstances
1527814887, // صفت کول - to praise; admire, glorify
1527818217, // طرفداري کول - to support, adhere to, pick a side, stand up for something or someone
1571946107980, // ظلم کول - to be cruel to, to oppress, to do voilence against, to persecute (د چا باندې ظلم کول)
1581610643511, // عبادت کول - to worship, pray
1527811674, // عمل کول - to act, to put into practice; to do something addicting (like smoking), to do out of habit
1581610659810, // غچ اخیستل - to take revenge
1527818401, // غرض کول - to interfere, to meddle, to step in
1592303194144, // غږ کول - to call out, to say something, make a sound
1578607689918, // غلا کول - to steal
1527818341, // غمرازي کول - to share in someones sorrow, to show sympathy or give condolences
1527818425, // غوټه اچول - to tie, fasten, hitch
1527818422, // غوټه وهل - to dive, dip, go into water
1527812633, // غوږ نیول - to listen
1527816328, // غیبت کول - to gossip
1588784260692, // فال اچول - to do fortune telling, divination
1527812607, // فکر کول - to think
1527822096, // قدم وهل - to take a step, to walk
1588152878869, // قرباني کول - to make a sacrifice
1527817624, // قسم خوړل - to take an oath, vow, to swear
1527812732, // کار کول - to work
1527811600, // کوشش کول - to try, to attempt, to put in effort
1527819661, // ګپ لګول - to talk, converse; to joke
1527814357, // ګډون کول - to participate, join, be involved
1582146016627, // ګذاره کول - to get by, make ends meet, deal with something, handle or get some task done (with difficulty or not quite in the ideal way), to bear with, to be tolerant or forgiving
1527819872, // ګمان کول - to think, to suppose
1579034883717, // لاړې تېرول - to spit ?? (other fluids too??)
1527817357, // لاس وړل - to touch
1527818937, // لامبو وهل - to swim, bathe
1527813950, // لحاظ کول - to be considerate of, pay attention to someone or something, to be polite, to show deference or respect to someone
1527813888, // لغته وهل - to kick
1527822099, // لمس کول - to touch, motivate, instigate
1588760636420, // لوظ کول - to promise, give one's word
1527819089, // ماته خوړل - to be defeated, beaten by someone
1527817361, // مخ اړول - to turn (ones face), to face, (when turning from someone or people) to neglect, (when turning to someone or people) to pay attention to
1527812934, // مخه نیول - to prevent, hold back
1588161314887, // مرسته کول - to help, assist
1527817165, // مزدوري کول - to do labour, to work
1609162269829, // مزې کول - to be enjoyable, to have good taste (the thing that gives enjoyment/taste "does maza"), to have fun
1579295606403, // ملاتړ کول - to support (ie. a political party etc.)
1589031340746, // موټر چلول - to drive a car
1527812902, // مینه کول - to love
1527817369, // ناره وهل - to cry out, to yell, to yell a chant or slogan
1527819687, // نارې کول - to cry out, shout (ناره)
1527821254, // نافرماني کول - to disobey, to not comply, to rebel
1527817709, // نجات موندل - to be saved, to find salvation
1527823208, // نفرت کول - to hate, abhor
1527811827, // نفس ایستل - breath in, inhale; kill
1579459605988, // نقصان کول - to suffer loss
1527815991, // ننداره کول - to behold, to spectate, to watch, to take in
1527823707, // نیالګی کېنول - to plant a sapling, young tree
1527811729, // نیوکه کول - to criticize
1527823733, // هجرت کول - to migrate, resettle
1527820620, // هجوم کول - to swarm, rush, attack
1527811599, // هڅه کول - to try, to attempt, to put in effort
1604431102462, // هدایت کول - to guide, show the true path, give revelation leading to truth
1527818092, // همکاري کول - to collaborate, to work together, to aid/help
1527816106, // وده کول - to grow, develop, improve, rise
1579723460957, // ورزش کول - to de exercise, athletics
1527814910, // وعده کول - to promise
1527816263, // وفا کول - to be faithful, to keep one's promise
1609162463793, // واده کول - to marry, get married
1609599425410, // دعا کول - to pray
1527812939, // منډې وهل - to run
1614602054303, // بدله اخیستل - to take revenge
];

View File

@ -7,80 +7,81 @@
*/
module.exports = [
1658537998960, // لېونی کول
1527812403, // بچ کول - to save, protect, guard, spare, rescue, economize
1577299232429, // بدلول - to change, to adapt, exchange, replace
1527815728, // بلدول - to familiarize with, to acquaint, orient, to train
1527821309, // بندول - to close, block, stop
1527821309, // بندول - to close, barricade, cut off, restrain, hold back
1527815843, // بېلول - to separate
1588073727998, // پاکول - to clean, cleanse, purify
1527812010, // پخلا کول - to reconcile, to bring to an agreement
1527820144, // پستول - to soften, knead, pulverize, dig over again
1584689306281, // پستول - to make soft, tender, gentle, loosened
1583269391864, // پورته کول - to raise up, lift up, bring up
1577394118297, // پوهول - to make understand (to bring someone to the state of understanding)
1571859113828, // پخول - to cook
1527812385, // پیدا کول - to find, birth, create
1581189437955, // پېش کول - to bring forward, present, deliver
1527820021, // پېښول - to cause, provoke, bring on
1591872434020, // پیلول - to start, begin
1527815323, // تاوول - to turn, to twist (active, causative), to rotate (causative) to wrap up, wind up
1527812388, // تباه کول - to destroy, ruin
1580754885011, // ترکول - to abandon, leave, refuse
1527821357, // تصدیق کول - to confirm, affirm, attest
1577501129214, // تکرار کول - to repeat
1527822697, // تولول - to weigh
1579908304357, // تولول - to balance
1579644522321, // تویول - to pour, shed, spill, scatter, knock down (fruit)
1527815731, // ټولول - to gather, collect
1589019863017, // ټیک کول - to correct, make right
1527816201, // ثبتول - to enter, save, record, register
1527821167, // جارول - to clean (with a brush), to warp (textiles); to sacrifice
1527816945, // جوتول - to make clear, evident, apparent, explained, established
1527816947, // جوتول - to harness, hitch up
1527812712, // جوړول - to make, form, build, mend, fix
1527817455, // ځایول - to place, put, accommodate, make room for, to make fit
1527815074, // چاپول - to print, publish
1527811693, // چاغول - to fatten up, to fatten, to make stout, plump
1527816239, // خبرول - to inform, communicate, make known, notify
1527811395, // خپرول - to spread, disperse, open, unfold, publicize, distribute
1527812222, // ختمول - to finish, complete, end, use up, destroy, kill
1527814183, // خرڅول - to sell, to spend, (fig.) to betray
1577898915919, // خفه کول - to make sad, to grieve, to annoy; to choke, to make suffocate
1592303701516, // خوږول - to sweeten, to make sweet, to delight, to give pleasure
1527814174, // خوږول - to cause hurt, pain
1527812811, // خوښول - to like, to choose, to select; to make happy
1527813502, // درنول - to make heavier; to make serious, respectable, reliable
1527811432, // دفن کول - to bury
1527813665, // ډکول - to fill
1527817258, // ډوبول - to cause to drown, to make sing, to submerge
1527823503, // ډېرول - to increase, make more
1527818347, // راپورته کول - to raise up
1527823277, // رنګول - to paint, color
1527813179, // ړنګول - to destroy, wreck, ruin, demolish, mess up, liquidate, disband
1591033078746, // ستړی کول - to make tired, wear out
1527813065, // ستنول - to return, to give back; to delay someone or something, to direct, to turn, to fix on
1527811949, // شریکول - to make a participant or involved, to share, to bring someone or something in, to include
1589883890933, // شړمول - to attach loosely, to cause to be loose, lazy, flabby
1527814493, // غرقول - to sink, plunge, submerge, immerse
1527823133, // غلطول - confuse, mix up, make a mistake; to go wrong, to stray from; to deceive, to lead into error; to distract, to be distracted
1527823366, // قبلول - to accept, to approve
1527820386, // کلکول - to make firm, hard solid, to fasten, to secure, to lock, to staunchly defend
1527814819, // ګرمول - to warm, to heat up, to heat
1579034597012, // ګیرول - to seize, catch, trap, confine, imprison, beseige, make stuck
1588152253147, // لرې کول - to remove, put far away
1527817121, // لندول - to make wet, moisten, to make damp, to soak
1527817118, // لنډول - to shorten, to make short, abbreviate
1527814350, // لویول - to raise, bring up (children)
1527816012, // ماتول - to break, split, defeat
1579387733916, // مینول - to cause to fall in love, to make to fall in love
1527817762, // هېرول - to forget
1589640176788, // ورکول - to lose/make lost, to misplace, to make dissapear, get rid off
1527812004, // وقفول - to devote, dedicate, give, donate
1579724723019, // ویدول - to put to sleep
1579822065104, // ویښول - to wake up, to make awake, to make alert
1527816559, // یادول - to remember, to recall, to think on, to call
1527813556, // یو ځای کول - to gather, bring together
1527815444, // زده کول - to learn, to teach
]
1608137130992, // چیغه کول
1658537998960, // لېونی کول
1527812403, // بچ کول - to save, protect, guard, spare, rescue, economize
1577299232429, // بدلول - to change, to adapt, exchange, replace
1527815728, // بلدول - to familiarize with, to acquaint, orient, to train
1527821309, // بندول - to close, block, stop
1527821309, // بندول - to close, barricade, cut off, restrain, hold back
1527815843, // بېلول - to separate
1588073727998, // پاکول - to clean, cleanse, purify
1527812010, // پخلا کول - to reconcile, to bring to an agreement
1527820144, // پستول - to soften, knead, pulverize, dig over again
1584689306281, // پستول - to make soft, tender, gentle, loosened
1583269391864, // پورته کول - to raise up, lift up, bring up
1577394118297, // پوهول - to make understand (to bring someone to the state of understanding)
1571859113828, // پخول - to cook
1527812385, // پیدا کول - to find, birth, create
1581189437955, // پېش کول - to bring forward, present, deliver
1527820021, // پېښول - to cause, provoke, bring on
1591872434020, // پیلول - to start, begin
1527815323, // تاوول - to turn, to twist (active, causative), to rotate (causative) to wrap up, wind up
1527812388, // تباه کول - to destroy, ruin
1580754885011, // ترکول - to abandon, leave, refuse
1527821357, // تصدیق کول - to confirm, affirm, attest
1577501129214, // تکرار کول - to repeat
1527822697, // تولول - to weigh
1579908304357, // تولول - to balance
1579644522321, // تویول - to pour, shed, spill, scatter, knock down (fruit)
1527815731, // ټولول - to gather, collect
1589019863017, // ټیک کول - to correct, make right
1527816201, // ثبتول - to enter, save, record, register
1527821167, // جارول - to clean (with a brush), to warp (textiles); to sacrifice
1527816945, // جوتول - to make clear, evident, apparent, explained, established
1527816947, // جوتول - to harness, hitch up
1527812712, // جوړول - to make, form, build, mend, fix
1527817455, // ځایول - to place, put, accommodate, make room for, to make fit
1527815074, // چاپول - to print, publish
1527811693, // چاغول - to fatten up, to fatten, to make stout, plump
1527816239, // خبرول - to inform, communicate, make known, notify
1527811395, // خپرول - to spread, disperse, open, unfold, publicize, distribute
1527812222, // ختمول - to finish, complete, end, use up, destroy, kill
1527814183, // خرڅول - to sell, to spend, (fig.) to betray
1577898915919, // خفه کول - to make sad, to grieve, to annoy; to choke, to make suffocate
1592303701516, // خوږول - to sweeten, to make sweet, to delight, to give pleasure
1527814174, // خوږول - to cause hurt, pain
1527812811, // خوښول - to like, to choose, to select; to make happy
1527813502, // درنول - to make heavier; to make serious, respectable, reliable
1527811432, // دفن کول - to bury
1527813665, // ډکول - to fill
1527817258, // ډوبول - to cause to drown, to make sing, to submerge
1527823503, // ډېرول - to increase, make more
1527818347, // راپورته کول - to raise up
1527823277, // رنګول - to paint, color
1527813179, // ړنګول - to destroy, wreck, ruin, demolish, mess up, liquidate, disband
1591033078746, // ستړی کول - to make tired, wear out
1527813065, // ستنول - to return, to give back; to delay someone or something, to direct, to turn, to fix on
1527811949, // شریکول - to make a participant or involved, to share, to bring someone or something in, to include
1589883890933, // شړمول - to attach loosely, to cause to be loose, lazy, flabby
1527814493, // غرقول - to sink, plunge, submerge, immerse
1527823133, // غلطول - confuse, mix up, make a mistake; to go wrong, to stray from; to deceive, to lead into error; to distract, to be distracted
1527823366, // قبلول - to accept, to approve
1527820386, // کلکول - to make firm, hard solid, to fasten, to secure, to lock, to staunchly defend
1527814819, // ګرمول - to warm, to heat up, to heat
1579034597012, // ګیرول - to seize, catch, trap, confine, imprison, beseige, make stuck
1588152253147, // لرې کول - to remove, put far away
1527817121, // لندول - to make wet, moisten, to make damp, to soak
1527817118, // لنډول - to shorten, to make short, abbreviate
1527814350, // لویول - to raise, bring up (children)
1527816012, // ماتول - to break, split, defeat
1579387733916, // مینول - to cause to fall in love, to make to fall in love
1527817762, // هېرول - to forget
1589640176788, // ورکول - to lose/make lost, to misplace, to make dissapear, get rid off
1527812004, // وقفول - to devote, dedicate, give, donate
1579724723019, // ویدول - to put to sleep
1579822065104, // ویښول - to wake up, to make awake, to make alert
1527816559, // یادول - to remember, to recall, to think on, to call
1527813556, // یو ځای کول - to gather, bring together
1527815444, // زده کول - to learn, to teach
];

View File

@ -5427,7 +5427,7 @@ forwarded@0.2.0:
fp-ts@^2.16.0:
version "2.16.0"
resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.0.tgz#64e03314dfc1c7ce5e975d3496ac14bc3eb7f92e"
resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz"
integrity sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==
fragment-cache@^0.2.1:
@ -9544,11 +9544,6 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-media-hook@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/react-media-hook/-/react-media-hook-0.5.0.tgz#f830231f31ea80049f8cbaf8058da90ab71e7150"
integrity sha512-OupDgOSCjUUWPiXq3HMoRwpsQry4cGf4vKzh2E984Xtm4I01ZFbq8JwCG/RPqXB9h0qxgzoYLbABC+LIZH8deQ==
react-overlays@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/react-overlays/-/react-overlays-5.1.1.tgz"