pretty much working with new verb engine and verb explorer ... quiz doesn't seem to be working right now
This commit is contained in:
parent
5f8c4ba876
commit
3b6d013402
|
@ -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",
|
||||
|
|
|
@ -77,7 +77,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"fp-ts": "^2.16.0",
|
||||
"react-media-hook": "^0.5.0",
|
||||
"react-select": "^5.4.0"
|
||||
}
|
||||
}
|
||||
}
|
320
src/App.tsx
320
src/App.tsx
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -47,4 +47,4 @@
|
|||
"babel-loader": "^8.3.0",
|
||||
"fs-extra": "^10.1.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import * as T from "../../types";
|
||||
import { fmapSingleOrLengthOpts } from "./fmaps";
|
||||
import { fmapSingleOrLengthOpts } from "./fp-ps";
|
||||
|
||||
export const blank: T.PsString = {
|
||||
p: "_____",
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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 one’s 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 someone’s 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 (one’s 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 one’s 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 someone’s 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 (one’s 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
|
||||
];
|
||||
|
|
|
@ -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
|
||||
];
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue