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,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"fp-ts": "^2.16.0",
|
||||||
"react-select": "^5.4.0"
|
"react-select": "^5.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -10735,6 +10736,11 @@
|
||||||
"node": ">= 0.6"
|
"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": {
|
"node_modules/fragment-cache": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||||
|
@ -31006,6 +31012,11 @@
|
||||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||||
"dev": true
|
"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": {
|
"fragment-cache": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||||
|
|
|
@ -77,7 +77,6 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fp-ts": "^2.16.0",
|
"fp-ts": "^2.16.0",
|
||||||
"react-media-hook": "^0.5.0",
|
|
||||||
"react-select": "^5.4.0"
|
"react-select": "^5.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
100
src/App.tsx
100
src/App.tsx
|
@ -9,9 +9,7 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import ButtonSelect from "./components/src/ButtonSelect";
|
import ButtonSelect from "./components/src/ButtonSelect";
|
||||||
import {
|
import { Modal } from "react-bootstrap";
|
||||||
Modal
|
|
||||||
} from "react-bootstrap";
|
|
||||||
import * as T from "./types";
|
import * as T from "./types";
|
||||||
import defualtTextOptions from "./lib/src/default-text-options";
|
import defualtTextOptions from "./lib/src/default-text-options";
|
||||||
import useStickyState from "./components/src/useStickyState";
|
import useStickyState from "./components/src/useStickyState";
|
||||||
|
@ -23,28 +21,43 @@ import InflectionDemo from "./demo-components/InflectionDemo";
|
||||||
import SpellingDemo from "./demo-components/SpellingDemo";
|
import SpellingDemo from "./demo-components/SpellingDemo";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [showingTextOptions, setShowingTextOptions] = useStickyState<boolean>(false, "showTextOpts1");
|
const [showingTextOptions, setShowingTextOptions] = useStickyState<boolean>(
|
||||||
const [textOptions, setTextOptions] = useStickyState<T.TextOptions>(defualtTextOptions, "textOpts1");
|
false,
|
||||||
|
"showTextOpts1"
|
||||||
|
);
|
||||||
|
const [textOptions, setTextOptions] = useStickyState<T.TextOptions>(
|
||||||
|
defualtTextOptions,
|
||||||
|
"textOpts1"
|
||||||
|
);
|
||||||
const [theme, setTheme] = useStickyState<"light" | "dark">("light", "theme1");
|
const [theme, setTheme] = useStickyState<"light" | "dark">("light", "theme1");
|
||||||
const [showing, setShowing] = useState<string>("");
|
const [showing, setShowing] = useState<string>("");
|
||||||
function handleHiderClick(label: string) {
|
function handleHiderClick(label: string) {
|
||||||
setShowing(os => os === label
|
setShowing((os) => (os === label ? "" : label));
|
||||||
? ""
|
|
||||||
: label);
|
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.documentElement.setAttribute("data-theme", theme);
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<main className="flex-shrink-0 mb-4">
|
<main className="flex-shrink-0 mb-4">
|
||||||
<div className="container" style={{ maxWidth: "800px" }}>
|
<div className="container" style={{ maxWidth: "800px" }}>
|
||||||
<div style={{ position: "absolute", top: "1.5rem", right: "1.5rem", display: "flex", flexDirection: "row" }}>
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "1.5rem",
|
||||||
|
right: "1.5rem",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className="clickable mr-3"
|
className="clickable mr-3"
|
||||||
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
|
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
|
||||||
>
|
>
|
||||||
<i className={`fa-lg fas fa-${theme === "light" ? "sun" : "moon"}`} />
|
<i
|
||||||
|
className={`fa-lg fas fa-${theme === "light" ? "sun" : "moon"}`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="clickable"
|
className="clickable"
|
||||||
|
@ -53,14 +66,36 @@ function App() {
|
||||||
<i className="fa-lg fas fa-cog" />
|
<i className="fa-lg fas fa-cog" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center mb-4" style={{ marginTop: "3rem", marginBottom: "1rem" }}>
|
<div
|
||||||
<h1 className="display-4 mt-2"><code>Pashto Inflector</code></h1>
|
className="text-center mb-4"
|
||||||
<p className="lead my-3" style={{ maxWidth: "600px", margin: "0 auto" }}>
|
style={{ marginTop: "3rem", marginBottom: "1rem" }}
|
||||||
An open source TypeScript/React library for Pashto inflection, verb conjugation, phrase generation, text conversion, and more
|
>
|
||||||
|
<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>
|
</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>
|
</div>
|
||||||
<h2 className="mb-3">Demos:</h2>
|
<h2 className="mb-3">Demos:</h2>
|
||||||
<Hider
|
<Hider
|
||||||
|
@ -78,10 +113,7 @@ function App() {
|
||||||
handleChange={() => handleHiderClick("equatives")}
|
handleChange={() => handleHiderClick("equatives")}
|
||||||
>
|
>
|
||||||
<div className="mt-4" style={{ paddingBottom: "20px" }}>
|
<div className="mt-4" style={{ paddingBottom: "20px" }}>
|
||||||
<EPExplorer
|
<EPExplorer opts={textOptions} entryFeeder={entryFeeder} />
|
||||||
opts={textOptions}
|
|
||||||
entryFeeder={entryFeeder}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Hider>
|
</Hider>
|
||||||
<Hider
|
<Hider
|
||||||
|
@ -102,7 +134,10 @@ function App() {
|
||||||
</Hider>
|
</Hider>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>
|
<Modal
|
||||||
|
show={showingTextOptions}
|
||||||
|
onHide={() => setShowingTextOptions(false)}
|
||||||
|
>
|
||||||
<Modal.Header closeButton>
|
<Modal.Header closeButton>
|
||||||
<Modal.Title>Settings</Modal.Title>
|
<Modal.Title>Settings</Modal.Title>
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
|
@ -129,7 +164,9 @@ function App() {
|
||||||
{ label: "Off", value: "false" },
|
{ label: "Off", value: "false" },
|
||||||
]}
|
]}
|
||||||
value={textOptions.diacritics.toString()}
|
value={textOptions.diacritics.toString()}
|
||||||
handleChange={(p) => setTextOptions({ ...textOptions, diacritics: p === "true" })}
|
handleChange={(p) =>
|
||||||
|
setTextOptions({ ...textOptions, diacritics: p === "true" })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<h6 className="mt-3">Pashto Text Size</h6>
|
<h6 className="mt-3">Pashto Text Size</h6>
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
|
@ -139,7 +176,9 @@ function App() {
|
||||||
{ label: "X-Large", value: "largest" },
|
{ label: "X-Large", value: "largest" },
|
||||||
]}
|
]}
|
||||||
value={textOptions.pTextSize}
|
value={textOptions.pTextSize}
|
||||||
handleChange={(p) => setTextOptions({ ...textOptions, pTextSize: p })}
|
handleChange={(p) =>
|
||||||
|
setTextOptions({ ...textOptions, pTextSize: p })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<h6 className="mt-3">Phonetics</h6>
|
<h6 className="mt-3">Phonetics</h6>
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
|
@ -150,11 +189,17 @@ function App() {
|
||||||
// { label: "None", value: "none" },
|
// { label: "None", value: "none" },
|
||||||
]}
|
]}
|
||||||
value={textOptions.phonetics}
|
value={textOptions.phonetics}
|
||||||
handleChange={(p) => setTextOptions({ ...textOptions, phonetics: p })}
|
handleChange={(p) =>
|
||||||
|
setTextOptions({ ...textOptions, phonetics: p })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<button type="button" className="btn btn-primary clb" onClick={() => setShowingTextOptions(false)}>
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-primary clb"
|
||||||
|
onClick={() => setShowingTextOptions(false)}
|
||||||
|
>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
|
@ -165,6 +210,7 @@ function App() {
|
||||||
</div>
|
</div>
|
||||||
</footer> */}
|
</footer> */}
|
||||||
</>
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,4 @@
|
||||||
import {
|
import { makeNounSelection } from "../../../lib/src/phrase-building/make-selections";
|
||||||
makeNounSelection,
|
|
||||||
} from "../../../lib/src/phrase-building/make-selections";
|
|
||||||
|
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import ButtonSelect from "../ButtonSelect";
|
import ButtonSelect from "../ButtonSelect";
|
||||||
|
@ -57,12 +55,13 @@ import AdjectiveManager from "./AdjectiveManager";
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function NPNounPicker(props: {
|
function NPNounPicker(props: {
|
||||||
entryFeeder: T.EntryFeeder,
|
entryFeeder: T.EntryFeeder;
|
||||||
noun: T.NounSelection | undefined,
|
noun: T.NounSelection | undefined;
|
||||||
onChange: (p: T.NounSelection | undefined) => void,
|
onChange: (p: T.NounSelection | undefined) => void;
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions;
|
||||||
phraseIsComplete: boolean,
|
phraseIsComplete: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
console.log({ noun: props.noun });
|
||||||
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
||||||
// const [showFilter, setShowFilter] = useState<boolean>(false)
|
// const [showFilter, setShowFilter] = useState<boolean>(false)
|
||||||
// const nounsFiltered = props.nouns
|
// const nounsFiltered = props.nouns
|
||||||
|
@ -86,7 +85,9 @@ function NPNounPicker(props: {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handleDemonstrativeUpdate(demonstrative: undefined | T.NounSelection["demonstrative"]) {
|
function handleDemonstrativeUpdate(
|
||||||
|
demonstrative: undefined | T.NounSelection["demonstrative"]
|
||||||
|
) {
|
||||||
if (props.noun) {
|
if (props.noun) {
|
||||||
props.onChange({
|
props.onChange({
|
||||||
...props.noun,
|
...props.noun,
|
||||||
|
@ -94,7 +95,8 @@ function NPNounPicker(props: {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
return (
|
||||||
|
<div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||||
{/* {showFilter && <div className="mb-2 text-center">
|
{/* {showFilter && <div className="mb-2 text-center">
|
||||||
<div className="d-flex flex-row justify-content-between">
|
<div className="d-flex flex-row justify-content-between">
|
||||||
<div className="text-small mb-1">Filter by inflection pattern</div>
|
<div className="text-small mb-1">Filter by inflection pattern</div>
|
||||||
|
@ -108,7 +110,8 @@ function NPNounPicker(props: {
|
||||||
handleChange={setPatternFilter}
|
handleChange={setPatternFilter}
|
||||||
/>
|
/>
|
||||||
</div>} */}
|
</div>} */}
|
||||||
{props.noun && <AdjectiveManager
|
{props.noun && (
|
||||||
|
<AdjectiveManager
|
||||||
phraseIsComplete={props.phraseIsComplete}
|
phraseIsComplete={props.phraseIsComplete}
|
||||||
adjectives={props.noun?.adjectives}
|
adjectives={props.noun?.adjectives}
|
||||||
demonstrative={props.noun.demonstrative}
|
demonstrative={props.noun.demonstrative}
|
||||||
|
@ -116,9 +119,14 @@ function NPNounPicker(props: {
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
onChange={handelAdjectivesUpdate}
|
onChange={handelAdjectivesUpdate}
|
||||||
onDemonstrativeChange={handleDemonstrativeUpdate}
|
onDemonstrativeChange={handleDemonstrativeUpdate}
|
||||||
/>}
|
/>
|
||||||
|
)}
|
||||||
<div className="h6">Noun</div>
|
<div className="h6">Noun</div>
|
||||||
{!(props.noun && props.noun.dynamicComplement) ? <div>
|
{!(
|
||||||
|
props.noun &&
|
||||||
|
(props.noun.dynamicComplement || props.noun.genStativeComplement)
|
||||||
|
) ? (
|
||||||
|
<div>
|
||||||
<EntrySelect
|
<EntrySelect
|
||||||
value={props.noun?.entry}
|
value={props.noun?.entry}
|
||||||
entryFeeder={props.entryFeeder.nouns}
|
entryFeeder={props.entryFeeder.nouns}
|
||||||
|
@ -126,20 +134,31 @@ function NPNounPicker(props: {
|
||||||
name="Noun"
|
name="Noun"
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
/>
|
/>
|
||||||
</div> : <div>
|
</div>
|
||||||
{props.noun && <div>
|
) : (
|
||||||
<div className="mb-2">Included in Dyn. Compound:</div>
|
<div>
|
||||||
|
{props.noun && (
|
||||||
|
<div>
|
||||||
|
<div className="mb-2">
|
||||||
|
Included in{" "}
|
||||||
|
{props.noun.genStativeComplement ? "Gen. Stat." : "Dyn."}{" "}
|
||||||
|
Compound:
|
||||||
|
</div>
|
||||||
<div className="mb-3 text-center">
|
<div className="mb-3 text-center">
|
||||||
<InlinePs opts={props.opts}>
|
<InlinePs opts={props.opts}>
|
||||||
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
|
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
|
||||||
</InlinePs>
|
</InlinePs>
|
||||||
<div className="text-muted">{props.noun.entry.e}</div>
|
<div className="text-muted">{props.noun.entry.e}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>
|
||||||
</div>}
|
)}
|
||||||
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
</div>
|
||||||
|
)}
|
||||||
|
{props.noun && (
|
||||||
|
<div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||||
<div>
|
<div>
|
||||||
{props.noun.genderCanChange ? <ButtonSelect
|
{props.noun.genderCanChange ? (
|
||||||
|
<ButtonSelect
|
||||||
small
|
small
|
||||||
options={[
|
options={[
|
||||||
{ label: "Masc", value: "masc" },
|
{ label: "Masc", value: "masc" },
|
||||||
|
@ -153,10 +172,16 @@ function NPNounPicker(props: {
|
||||||
gender,
|
gender,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
|
/>
|
||||||
|
) : props.noun.gender === "masc" ? (
|
||||||
|
"Masc."
|
||||||
|
) : (
|
||||||
|
"Fem."
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{props.noun.numberCanChange ? <ButtonSelect
|
{props.noun.numberCanChange ? (
|
||||||
|
<ButtonSelect
|
||||||
small
|
small
|
||||||
options={[
|
options={[
|
||||||
{ label: "Sing.", value: "singular" },
|
{ label: "Sing.", value: "singular" },
|
||||||
|
@ -170,10 +195,17 @@ function NPNounPicker(props: {
|
||||||
number,
|
number,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
|
/>
|
||||||
|
) : props.noun.number === "singular" ? (
|
||||||
|
"Sing."
|
||||||
|
) : (
|
||||||
|
"Plur."
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>
|
||||||
</div>;
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NPNounPicker;
|
export default NPNounPicker;
|
|
@ -9,13 +9,21 @@ import Hider from "../Hider";
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import useStickyState from "../useStickyState";
|
import useStickyState from "../useStickyState";
|
||||||
import { isImperativeTense } from "../../../lib/src/type-predicates";
|
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";
|
// import { conjugateVerb } from "../../../lib/src/verb-conjugation";
|
||||||
|
|
||||||
function AllTensesDisplay({
|
function AllTensesDisplay({
|
||||||
VS,
|
VS,
|
||||||
opts,
|
opts,
|
||||||
|
onChange,
|
||||||
|
object,
|
||||||
}: {
|
}: {
|
||||||
|
onChange: (p: VpsReducerAction) => void;
|
||||||
VS: T.VerbSelection;
|
VS: T.VerbSelection;
|
||||||
|
object: T.NPSelection | T.ObjectNP | undefined;
|
||||||
opts: T.TextOptions;
|
opts: T.TextOptions;
|
||||||
}) {
|
}) {
|
||||||
const [showing, setShowing] = useStickyState<string[]>([], "VPTensesShowing");
|
const [showing, setShowing] = useStickyState<string[]>([], "VPTensesShowing");
|
||||||
|
@ -23,6 +31,11 @@ function AllTensesDisplay({
|
||||||
false,
|
false,
|
||||||
"showFormulasWithCharts"
|
"showFormulasWithCharts"
|
||||||
);
|
);
|
||||||
|
const [objectNPNumber, setObjectNPNumber] = useState<T.NounNumber>(
|
||||||
|
object && typeof object === "object" && object.selection.type === "noun"
|
||||||
|
? object.selection.number
|
||||||
|
: "singular"
|
||||||
|
);
|
||||||
const adjustShowing = (v: string) => {
|
const adjustShowing = (v: string) => {
|
||||||
if (showing.includes(v)) {
|
if (showing.includes(v)) {
|
||||||
setShowing((os) => os.filter((x) => x !== v));
|
setShowing((os) => os.filter((x) => x !== v));
|
||||||
|
@ -56,14 +69,69 @@ function AllTensesDisplay({
|
||||||
? (`${baseTense}Modal` as T.AbilityTense)
|
? (`${baseTense}Modal` as T.AbilityTense)
|
||||||
: baseTense;
|
: 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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
className="clickable mb-2 small text-center"
|
|
||||||
onClick={() => setShowFormulas((x) => !x)}
|
onClick={() => setShowFormulas((x) => !x)}
|
||||||
|
className="small clickable text-right mb-2"
|
||||||
>
|
>
|
||||||
🧪 {!showFormulas ? "Show" : "Hide"} Formulas
|
🧪 {!showFormulas ? "Show" : "Hide"} Formulas
|
||||||
</div>
|
</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) => {
|
{options.map((tense) => {
|
||||||
const t = getTense(tense.value);
|
const t = getTense(tense.value);
|
||||||
return (
|
return (
|
||||||
|
@ -81,7 +149,20 @@ function AllTensesDisplay({
|
||||||
)}
|
)}
|
||||||
{showing && (
|
{showing && (
|
||||||
<ChartDisplay
|
<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}
|
negative={VS.negative}
|
||||||
tense={t}
|
tense={t}
|
||||||
transitivity={VS.transitivity}
|
transitivity={VS.transitivity}
|
||||||
|
|
|
@ -8,7 +8,13 @@ import { choosePersInf, getLength } from "../../../lib/src/p-text-helpers";
|
||||||
import genderColors from "../gender-colors";
|
import genderColors from "../gender-colors";
|
||||||
import { eqPsStringWVars } from "../../../lib/src/fp-ps";
|
import { eqPsStringWVars } from "../../../lib/src/fp-ps";
|
||||||
import PersInfsPicker from "../PersInfsPicker";
|
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 = {
|
export const roleIcon = {
|
||||||
king: <i className="mx-1 fas fa-crown" />,
|
king: <i className="mx-1 fas fa-crown" />,
|
||||||
|
@ -21,14 +27,21 @@ function VerbChartDisplay({
|
||||||
shortDefault,
|
shortDefault,
|
||||||
transitivity,
|
transitivity,
|
||||||
past,
|
past,
|
||||||
|
negative,
|
||||||
|
imperative,
|
||||||
}: {
|
}: {
|
||||||
chart: T.OptionalPersonInflections<
|
chart: {
|
||||||
|
objNP: T.Rendered<T.NPSelection> | undefined;
|
||||||
|
vbs: T.OptionalPersonInflections<
|
||||||
T.SingleOrLengthOpts<T.RenderVerbOutput[]>
|
T.SingleOrLengthOpts<T.RenderVerbOutput[]>
|
||||||
>;
|
>;
|
||||||
|
};
|
||||||
opts: T.TextOptions;
|
opts: T.TextOptions;
|
||||||
shortDefault?: boolean;
|
shortDefault?: boolean;
|
||||||
transitivity: T.Transitivity;
|
transitivity: T.Transitivity;
|
||||||
past: boolean;
|
past: boolean;
|
||||||
|
negative: boolean;
|
||||||
|
imperative: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [length, setLength] = useState<T.Length>(
|
const [length, setLength] = useState<T.Length>(
|
||||||
shortDefault ? "short" : "long"
|
shortDefault ? "short" : "long"
|
||||||
|
@ -37,13 +50,23 @@ function VerbChartDisplay({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLength("long");
|
setLength("long");
|
||||||
}, [chart]);
|
}, [chart]);
|
||||||
const desktop = useMediaPredicate("(min-width: 600px)");
|
const chartWPers = choosePersInf(chart.vbs, persInf);
|
||||||
const chartWPers = choosePersInf(chart, persInf);
|
|
||||||
const chartWLength = getLength(chartWPers, length);
|
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 =
|
const verbBlock =
|
||||||
x.length === 12
|
x.length === 1
|
||||||
|
? // unchanging gramm trans or dynamic compound past transitive
|
||||||
|
[[[x[0]]]]
|
||||||
|
: x.length === 12
|
||||||
? [
|
? [
|
||||||
// 1st pers
|
// 1st pers
|
||||||
[
|
[
|
||||||
|
@ -83,10 +106,15 @@ function VerbChartDisplay({
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col">
|
<div className="col">
|
||||||
<AgreementInfo transitivity={transitivity} past={past} />
|
<AgreementInfo
|
||||||
|
opts={opts}
|
||||||
|
transitivity={transitivity}
|
||||||
|
past={past}
|
||||||
|
objNP={chart.objNP}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col">
|
<div className="col">
|
||||||
{"long" in chartWPers && (
|
{"long" in chartWPers && lengthsMakeADiff(chartWPers) && (
|
||||||
<LengthSelection
|
<LengthSelection
|
||||||
hasMini={"mini" in chartWPers}
|
hasMini={"mini" in chartWPers}
|
||||||
value={length}
|
value={length}
|
||||||
|
@ -94,8 +122,13 @@ function VerbChartDisplay({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{desktop && <div className="col" />}
|
<div className="hide-on-mobile col" />
|
||||||
</div>
|
</div>
|
||||||
|
{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" }}>
|
<table className="table mt-2" style={{ tableLayout: "fixed" }}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -118,6 +151,7 @@ function VerbChartDisplay({
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -224,32 +258,93 @@ function LengthSelection({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderVerbOutputToText(negative: boolean) {
|
function renderVerbOutputToText({
|
||||||
return function (v: T.RenderVerbOutput): T.PsString[] {
|
objNP,
|
||||||
const blocks = insertNegative(
|
|
||||||
v.vbs,
|
|
||||||
negative,
|
negative,
|
||||||
false /* TODO: apply imperative */
|
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: 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({
|
function AgreementInfo({
|
||||||
transitivity,
|
transitivity,
|
||||||
past,
|
past,
|
||||||
|
objNP,
|
||||||
|
opts,
|
||||||
}: {
|
}: {
|
||||||
transitivity: T.Transitivity;
|
transitivity: T.Transitivity;
|
||||||
past: boolean;
|
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 (
|
return (
|
||||||
<div className="text-muted small mt-1">
|
<div className="text-muted small mt-1">
|
||||||
|
<div>
|
||||||
{roleIcon.king} agrees w/{" "}
|
{roleIcon.king} agrees w/{" "}
|
||||||
<strong>
|
<strong>
|
||||||
{transitivity !== "intransitive" && past ? "object" : "subject"}
|
{transitivity !== "intransitive" && past ? "object" : "subject"}
|
||||||
</strong>
|
</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>
|
</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;
|
export default VerbChartDisplay;
|
||||||
|
|
|
@ -3,6 +3,8 @@ import * as T from "../../../types";
|
||||||
import { buildVerbChart } from "./chart-builder";
|
import { buildVerbChart } from "./chart-builder";
|
||||||
import { isPastTense } from "../../library";
|
import { isPastTense } from "../../library";
|
||||||
|
|
||||||
|
// TODO - combine this with NewVerbFormDisplay
|
||||||
|
|
||||||
function ChartDisplay({
|
function ChartDisplay({
|
||||||
verb,
|
verb,
|
||||||
tense,
|
tense,
|
||||||
|
@ -11,6 +13,7 @@ function ChartDisplay({
|
||||||
imperative,
|
imperative,
|
||||||
negative,
|
negative,
|
||||||
transitivity,
|
transitivity,
|
||||||
|
objectNP,
|
||||||
}: {
|
}: {
|
||||||
verb: T.VerbEntry;
|
verb: T.VerbEntry;
|
||||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
|
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
|
||||||
|
@ -19,6 +22,7 @@ function ChartDisplay({
|
||||||
imperative: boolean;
|
imperative: boolean;
|
||||||
negative: boolean;
|
negative: boolean;
|
||||||
transitivity: T.Transitivity;
|
transitivity: T.Transitivity;
|
||||||
|
objectNP: T.NPSelection | undefined;
|
||||||
}) {
|
}) {
|
||||||
const verbChart = buildVerbChart({
|
const verbChart = buildVerbChart({
|
||||||
verb,
|
verb,
|
||||||
|
@ -27,10 +31,13 @@ function ChartDisplay({
|
||||||
negative,
|
negative,
|
||||||
transitivity,
|
transitivity,
|
||||||
imperative,
|
imperative,
|
||||||
|
objectNP,
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<NewVerbFormDisplay
|
<NewVerbFormDisplay
|
||||||
|
imperative={imperative}
|
||||||
|
negative={negative}
|
||||||
chart={verbChart}
|
chart={verbChart}
|
||||||
opts={opts}
|
opts={opts}
|
||||||
transitivity={transitivity}
|
transitivity={transitivity}
|
||||||
|
|
|
@ -28,28 +28,28 @@ export const vpPhraseURLParam = "vp";
|
||||||
// TODO: error handling on error with rendering etc
|
// TODO: error handling on error with rendering etc
|
||||||
|
|
||||||
function VPExplorer(props: {
|
function VPExplorer(props: {
|
||||||
loaded?: T.VPSelectionState,
|
loaded?: T.VPSelectionState;
|
||||||
verb: T.VerbEntry,
|
verb: T.VerbEntry;
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions;
|
||||||
handleLinkClick: ((ts: number) => void) | "none",
|
handleLinkClick: ((ts: number) => void) | "none";
|
||||||
entryFeeder: T.EntryFeeder,
|
entryFeeder: T.EntryFeeder;
|
||||||
onlyPhrases?: boolean,
|
onlyPhrases?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [vps, adjustVps] = useStickyReducer(
|
const [vps, adjustVps] = useStickyReducer(
|
||||||
vpsReducer,
|
vpsReducer,
|
||||||
props.loaded
|
props.loaded
|
||||||
? props.loaded
|
? props.loaded
|
||||||
: savedVps => makeVPSelectionState(props.verb, savedVps),
|
: (savedVps) => makeVPSelectionState(props.verb, savedVps),
|
||||||
"vpsState16",
|
"vpsState16",
|
||||||
flashMessage,
|
flashMessage
|
||||||
);
|
);
|
||||||
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
||||||
savedMode => {
|
(savedMode) => {
|
||||||
if (!savedMode) return props.onlyPhrases ? "phrases" : "charts";
|
if (!savedMode) return props.onlyPhrases ? "phrases" : "charts";
|
||||||
if (savedMode === "quiz") return "phrases";
|
if (savedMode === "quiz") return "phrases";
|
||||||
return savedMode;
|
return savedMode;
|
||||||
},
|
},
|
||||||
"verbExplorerMode2",
|
"verbExplorerMode2"
|
||||||
);
|
);
|
||||||
const [showClipped, setShowClipped] = useState<string>("");
|
const [showClipped, setShowClipped] = useState<string>("");
|
||||||
const [
|
const [
|
||||||
|
@ -87,7 +87,7 @@ function VPExplorer(props: {
|
||||||
setMode("phrases");
|
setMode("phrases");
|
||||||
adjustVps({
|
adjustVps({
|
||||||
type: "load vps",
|
type: "load vps",
|
||||||
payload: VPSFromUrl
|
payload: VPSFromUrl,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
@ -130,16 +130,17 @@ function VPExplorer(props: {
|
||||||
const object = getObjectSelection(vps.blocks).selection;
|
const object = getObjectSelection(vps.blocks).selection;
|
||||||
const VPS = completeVPSelection(vps);
|
const VPS = completeVPSelection(vps);
|
||||||
const phraseIsComplete = !!VPS;
|
const phraseIsComplete = !!VPS;
|
||||||
return <div className="mt-3" style={{ maxWidth: "950px"}}>
|
return (
|
||||||
|
<div className="mt-3" style={{ maxWidth: "950px" }}>
|
||||||
<VerbPicker
|
<VerbPicker
|
||||||
vps={vps}
|
vps={vps}
|
||||||
onChange={quizLock(adjustVps)}
|
onChange={quizLock(adjustVps)}
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
handleLinkClick={props.handleLinkClick}
|
handleLinkClick={props.handleLinkClick}
|
||||||
/>
|
/>
|
||||||
{!props.onlyPhrases && <div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
|
{!props.onlyPhrases && (
|
||||||
<div style={{ width: "1rem" }}>
|
<div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
|
||||||
</div>
|
<div style={{ width: "1rem" }}></div>
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
value={mode}
|
value={mode}
|
||||||
options={[
|
options={[
|
||||||
|
@ -155,7 +156,11 @@ function VPExplorer(props: {
|
||||||
onClick={mode === "phrases" ? handleCopyCode : undefined}
|
onClick={mode === "phrases" ? handleCopyCode : undefined}
|
||||||
style={{ width: "1rem" }}
|
style={{ width: "1rem" }}
|
||||||
>
|
>
|
||||||
{(mode === "phrases" && phraseIsComplete) ? <i className="fas fa-code" /> : ""}
|
{mode === "phrases" && phraseIsComplete ? (
|
||||||
|
<i className="fas fa-code" />
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="clickable"
|
className="clickable"
|
||||||
|
@ -165,52 +170,79 @@ function VPExplorer(props: {
|
||||||
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
|
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>
|
||||||
{(vps.verb && (typeof object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
|
)}
|
||||||
|
{vps.verb &&
|
||||||
|
typeof object === "object" &&
|
||||||
|
vps.verb.isCompound !== "dynamic" &&
|
||||||
|
vps.verb.tenseCategory !== "imperative" &&
|
||||||
|
mode === "phrases" && (
|
||||||
<div className="text-center my-2">
|
<div className="text-center my-2">
|
||||||
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
<button
|
||||||
|
onClick={handleSubjObjSwap}
|
||||||
|
className="btn btn-sm btn-light"
|
||||||
|
>
|
||||||
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
||||||
</button>
|
</button>
|
||||||
</div>}
|
</div>
|
||||||
{mode === "phrases" && <VPPicker
|
)}
|
||||||
|
{mode === "phrases" && (
|
||||||
|
<VPPicker
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
entryFeeder={props.entryFeeder}
|
entryFeeder={props.entryFeeder}
|
||||||
onChange={(payload) => adjustVps({ type: "load vps", payload })}
|
onChange={(payload) => adjustVps({ type: "load vps", payload })}
|
||||||
vps={vps}
|
vps={vps}
|
||||||
/>}
|
|
||||||
{mode !== "phrases" && <div className="my-2">
|
|
||||||
<TensePicker
|
|
||||||
vps={vps}
|
|
||||||
onChange={adjustVps}
|
|
||||||
mode={mode}
|
|
||||||
/>
|
/>
|
||||||
</div>}
|
)}
|
||||||
{mode === "phrases" && <VPDisplay
|
{mode !== "phrases" && (
|
||||||
VPS={vps}
|
<div className="my-2">
|
||||||
opts={props.opts}
|
<TensePicker vps={vps} onChange={adjustVps} mode={mode} />
|
||||||
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={{
|
|
||||||
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={{
|
|
||||||
position: "fixed",
|
|
||||||
top: "30%",
|
|
||||||
left: "50%",
|
|
||||||
transform: "translate(-50%, -50%)",
|
|
||||||
zIndex: 9999999999999,
|
|
||||||
}}>
|
|
||||||
{alertMsg}
|
|
||||||
</div>}
|
|
||||||
</div>
|
</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={{
|
||||||
|
position: "fixed",
|
||||||
|
top: "30%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
zIndex: 9999999999999,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{alertMsg}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VPExplorer;
|
export default VPExplorer;
|
||||||
|
@ -237,4 +269,3 @@ function getVPSFromUrl(): T.VPSelectionState | undefined {
|
||||||
const decoded = LZString.decompressFromEncodedURIComponent(fromParams);
|
const decoded = LZString.decompressFromEncodedURIComponent(fromParams);
|
||||||
return JSON.parse(decoded) as T.VPSelectionState;
|
return JSON.parse(decoded) as T.VPSelectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,17 @@ import {
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { getKingAndServant, renderVP } from "../../../lib/src/phrase-building/render-vp";
|
import {
|
||||||
import { completeVPSelection, isPastTense } from "../../../lib/src/phrase-building/vp-tools";
|
getKingAndServant,
|
||||||
import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal";
|
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 APPicker from "../../src/ap-picker/APPicker";
|
||||||
// import autoAnimate from "@formkit/auto-animate";
|
// import autoAnimate from "@formkit/auto-animate";
|
||||||
import {
|
import {
|
||||||
|
@ -18,23 +26,37 @@ import {
|
||||||
isNoObject,
|
isNoObject,
|
||||||
} from "../../../lib/src/phrase-building/blocks-utils";
|
} from "../../../lib/src/phrase-building/blocks-utils";
|
||||||
import ComplementPicker from "../ComplementPicker";
|
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 }: {
|
function VPPicker({
|
||||||
opts: T.TextOptions,
|
opts,
|
||||||
vps: T.VPSelectionState,
|
vps,
|
||||||
onChange: (vps: T.VPSelectionState) => void,
|
onChange,
|
||||||
entryFeeder: T.EntryFeeder,
|
entryFeeder,
|
||||||
|
}: {
|
||||||
|
opts: T.TextOptions;
|
||||||
|
vps: T.VPSelectionState;
|
||||||
|
onChange: (vps: T.VPSelectionState) => void;
|
||||||
|
entryFeeder: T.EntryFeeder;
|
||||||
}) {
|
}) {
|
||||||
const parent = useRef<HTMLDivElement>(null);
|
const parent = useRef<HTMLDivElement>(null);
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// parent.current && autoAnimate(parent.current);
|
// parent.current && autoAnimate(parent.current);
|
||||||
// }, [parent]);
|
// }, [parent]);
|
||||||
const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false);
|
const [showingExplanation, setShowingExplanation] =
|
||||||
|
useState<{ role: "servant" | "king"; item: "subject" | "object" } | false>(
|
||||||
|
false
|
||||||
|
);
|
||||||
function adjustVps(action: VpsReducerAction) {
|
function adjustVps(action: VpsReducerAction) {
|
||||||
onChange(vpsReducer(vps, action));
|
onChange(vpsReducer(vps, action));
|
||||||
}
|
}
|
||||||
function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) {
|
function handleSubjectChange(
|
||||||
|
subject: T.NPSelection | undefined,
|
||||||
|
skipPronounConflictCheck?: boolean
|
||||||
|
) {
|
||||||
adjustVps({
|
adjustVps({
|
||||||
type: "set subject",
|
type: "set subject",
|
||||||
payload: { subject, skipPronounConflictCheck },
|
payload: { subject, skipPronounConflictCheck },
|
||||||
|
@ -52,174 +74,333 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
|
||||||
const phraseIsComplete = !!VPS;
|
const phraseIsComplete = !!VPS;
|
||||||
const rendered = VPS ? renderVP(VPS) : undefined;
|
const rendered = VPS ? renderVP(VPS) : undefined;
|
||||||
const servantIsShrunk = includesShrunkenServant(rendered?.kids);
|
const servantIsShrunk = includesShrunkenServant(rendered?.kids);
|
||||||
const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense);
|
const isPast = isPastTense(
|
||||||
|
vps.verb.tenseCategory === "perfect"
|
||||||
|
? vps.verb.perfectTense
|
||||||
|
: vps.verb.verbTense
|
||||||
|
);
|
||||||
const roles = getKingAndServant(
|
const roles = getKingAndServant(
|
||||||
isPast,
|
isPast,
|
||||||
vps.verb.transitivity !== "intransitive",
|
vps.verb.transitivity !== "intransitive"
|
||||||
);
|
);
|
||||||
return <div>
|
return (
|
||||||
<div className="clickable h5" onClick={() => adjustVps({ type: "insert new AP" })}>+ AP</div>
|
<div>
|
||||||
<div ref={parent} className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
|
<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) => {
|
{vps.blocks.map(({ block, key }, i, blocks) => {
|
||||||
if (isNoObject(block)) return null;
|
if (isNoObject(block)) return null;
|
||||||
return <div className="my-2 card block-card p-1 mx-1" key={key} style={{
|
return (
|
||||||
background: (servantIsShrunk && (
|
<div
|
||||||
(roles.servant === "subject" && block?.type === "subjectSelection")
|
className="my-2 card block-card p-1 mx-1"
|
||||||
||
|
key={key}
|
||||||
(roles.servant === "object" && block?.type === "objectSelection")
|
style={{
|
||||||
)) ? shrunkenBackground : "inherit",
|
background:
|
||||||
}}>
|
servantIsShrunk &&
|
||||||
<div className="d-flex flex-row justify-content-between mb-1" style={{ height: "1rem" }}>
|
((roles.servant === "subject" &&
|
||||||
{(i > 0 && !isNoObject(blocks[i - 1].block)) ? <div
|
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"
|
className="small clickable ml-1"
|
||||||
onClick={() => adjustVps({ type: "shift block", payload: { index: i, direction: "back" }})}
|
onClick={() =>
|
||||||
|
adjustVps({
|
||||||
|
type: "shift block",
|
||||||
|
payload: { index: i, direction: "back" },
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<i className="fas fa-chevron-left" />
|
<i className="fas fa-chevron-left" />
|
||||||
</div> : <div/>}
|
</div>
|
||||||
{(i < vps.blocks.length - 1 && !isNoObject(blocks[i + 1].block)) ? <div
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
{i < vps.blocks.length - 1 &&
|
||||||
|
!isNoObject(blocks[i + 1].block) &&
|
||||||
|
!isGenStatCompNoun(block) ? (
|
||||||
|
<div
|
||||||
className="small clickable mr-1"
|
className="small clickable mr-1"
|
||||||
onClick={() => adjustVps({ type: "shift block", payload: { index: i, direction: "forward" }})}
|
onClick={() =>
|
||||||
|
adjustVps({
|
||||||
|
type: "shift block",
|
||||||
|
payload: { index: i, direction: "forward" },
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<i className="fas fa-chevron-right" />
|
<i className="fas fa-chevron-right" />
|
||||||
</div> : <div/>}
|
|
||||||
</div>
|
</div>
|
||||||
{(!block || block.type === "AP")
|
) : (
|
||||||
? <APPicker
|
<div />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!block || block.type === "AP" ? (
|
||||||
|
<APPicker
|
||||||
phraseIsComplete={phraseIsComplete}
|
phraseIsComplete={phraseIsComplete}
|
||||||
heading="AP"
|
heading="AP"
|
||||||
entryFeeder={entryFeeder}
|
entryFeeder={entryFeeder}
|
||||||
AP={block}
|
AP={block}
|
||||||
opts={opts}
|
opts={opts}
|
||||||
onChange={AP => adjustVps({ type: "set AP", payload: { index: i, AP } })}
|
onChange={(AP) =>
|
||||||
|
adjustVps({ type: "set AP", payload: { index: i, AP } })
|
||||||
|
}
|
||||||
onRemove={() => adjustVps({ type: "remove AP", payload: i })}
|
onRemove={() => adjustVps({ type: "remove AP", payload: i })}
|
||||||
/>
|
/>
|
||||||
: (block?.type === "subjectSelection")
|
) : block?.type === "subjectSelection" ? (
|
||||||
? <NPPicker
|
<NPPicker
|
||||||
phraseIsComplete={phraseIsComplete}
|
phraseIsComplete={phraseIsComplete}
|
||||||
heading={roles.king === "subject"
|
heading={
|
||||||
? <div className="h5 text-center">
|
roles.king === "subject" ? (
|
||||||
Subj. <span onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>{roleIcon.king}</span>
|
<div className="h5 text-center">
|
||||||
{(rendered && rendered.whatsAdjustable !== "servant") &&
|
Subj.{" "}
|
||||||
|
<span
|
||||||
|
onClick={() =>
|
||||||
|
setShowingExplanation({
|
||||||
|
role: "king",
|
||||||
|
item: "subject",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{roleIcon.king}
|
||||||
|
</span>
|
||||||
|
{rendered && rendered.whatsAdjustable !== "servant" && (
|
||||||
<KingRemover
|
<KingRemover
|
||||||
onChange={() => adjustVps({ type: "toggle king remove" })}
|
onChange={() =>
|
||||||
|
adjustVps({ type: "toggle king remove" })
|
||||||
|
}
|
||||||
showKing={!VPS?.form.removeKing}
|
showKing={!VPS?.form.removeKing}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
: <div className="h5 text-center">
|
) : (
|
||||||
|
<div className="h5 text-center">
|
||||||
Subj.
|
Subj.
|
||||||
{` `}
|
{` `}
|
||||||
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant}</span>
|
<span
|
||||||
|
className="clickable"
|
||||||
|
onClick={() =>
|
||||||
|
setShowingExplanation({
|
||||||
|
role: "servant",
|
||||||
|
item: "subject",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{roleIcon.servant}
|
||||||
|
</span>
|
||||||
{` `}
|
{` `}
|
||||||
{(rendered && rendered.whatsAdjustable !== "king") &&
|
{rendered && rendered.whatsAdjustable !== "king" && (
|
||||||
<ServantShrinker
|
<ServantShrinker
|
||||||
shrunk={servantIsShrunk}
|
shrunk={servantIsShrunk}
|
||||||
onClick={() => adjustVps({ type: "toggle servant shrink" })}
|
onClick={() =>
|
||||||
/>
|
adjustVps({ type: "toggle servant shrink" })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>}
|
|
||||||
entryFeeder={entryFeeder}
|
entryFeeder={entryFeeder}
|
||||||
np={block.selection}
|
np={block.selection}
|
||||||
counterPart={vps.verb ? object : undefined}
|
counterPart={vps.verb ? object : undefined}
|
||||||
role={(isPast && vps.verb.transitivity !== "intransitive")
|
role={
|
||||||
|
isPast && vps.verb.transitivity !== "intransitive"
|
||||||
? "ergative"
|
? "ergative"
|
||||||
: "subject"
|
: "subject"
|
||||||
}
|
}
|
||||||
onChange={handleSubjectChange}
|
onChange={handleSubjectChange}
|
||||||
opts={opts}
|
opts={opts}
|
||||||
isShrunk={(servantIsShrunk && roles.servant === "subject")}
|
isShrunk={servantIsShrunk && roles.servant === "subject"}
|
||||||
isRemoved={roles.king === "subject" && VPS?.form.removeKing}
|
isRemoved={roles.king === "subject" && VPS?.form.removeKing}
|
||||||
/>
|
/>
|
||||||
: (vps.verb && block?.type === "objectSelection" && block.selection !== "none")
|
) : vps.verb &&
|
||||||
? <div className="my-2" style={{ background: (servantIsShrunk && roles.servant === "object") ? shrunkenBackground : "inherit" }}>
|
block?.type === "objectSelection" &&
|
||||||
{(typeof block.selection === "number")
|
block.selection !== "none" ? (
|
||||||
? <div>
|
<div
|
||||||
{roles.king === "object"
|
className="my-2"
|
||||||
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
|
style={{
|
||||||
: roles.servant === "object"
|
background:
|
||||||
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>
|
servantIsShrunk && roles.servant === "object"
|
||||||
: <div className="h5 text-center">Object</div>}
|
? 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="text-muted text-center">
|
||||||
<div className="mt-3 mb-1">Unspoken</div>
|
<div className="mt-3 mb-1">Unspoken</div>
|
||||||
<div>3rd Pers. Masc. Plur.</div>
|
<div>3rd Pers. Masc. Plur.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
: <NPPicker
|
) : (
|
||||||
|
<NPPicker
|
||||||
phraseIsComplete={phraseIsComplete}
|
phraseIsComplete={phraseIsComplete}
|
||||||
heading={roles.king === "object"
|
heading={
|
||||||
? <div className="h5 text-center">
|
roles.king === "object" ? (
|
||||||
Obj. <span onClick={() => setShowingExplanation({ role: "king", item: "object" })}>{roleIcon.king}</span>
|
<div className="h5 text-center">
|
||||||
{(rendered && rendered.whatsAdjustable !== "servant") &&
|
Obj.{" "}
|
||||||
|
<span
|
||||||
|
onClick={() =>
|
||||||
|
setShowingExplanation({
|
||||||
|
role: "king",
|
||||||
|
item: "object",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{roleIcon.king}
|
||||||
|
</span>
|
||||||
|
{rendered &&
|
||||||
|
rendered.whatsAdjustable !== "servant" && (
|
||||||
<KingRemover
|
<KingRemover
|
||||||
onChange={() => adjustVps({ type: "toggle king remove" })}
|
onChange={() =>
|
||||||
|
adjustVps({ type: "toggle king remove" })
|
||||||
|
}
|
||||||
showKing={!VPS?.form.removeKing}
|
showKing={!VPS?.form.removeKing}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
: <div className="h5 text-center">
|
) : (
|
||||||
|
<div className="h5 text-center">
|
||||||
Obj.
|
Obj.
|
||||||
{` `}
|
{` `}
|
||||||
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant}</span>
|
<span
|
||||||
{` `}
|
className="clickable"
|
||||||
{(rendered && rendered.whatsAdjustable !== "king") &&
|
onClick={() =>
|
||||||
<ServantShrinker shrunk={servantIsShrunk} onClick={() => adjustVps({ type: "toggle servant shrink" })} />
|
setShowingExplanation({
|
||||||
|
role: "servant",
|
||||||
|
item: "object",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{roleIcon.servant}
|
||||||
|
</span>
|
||||||
|
{` `}
|
||||||
|
{rendered &&
|
||||||
|
rendered.whatsAdjustable !== "king" && (
|
||||||
|
<ServantShrinker
|
||||||
|
shrunk={servantIsShrunk}
|
||||||
|
onClick={() =>
|
||||||
|
adjustVps({ type: "toggle servant shrink" })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>}
|
|
||||||
entryFeeder={entryFeeder}
|
entryFeeder={entryFeeder}
|
||||||
role="object"
|
role="object"
|
||||||
np={block.selection}
|
np={block.selection}
|
||||||
counterPart={subject}
|
counterPart={subject}
|
||||||
onChange={handleObjectChange}
|
onChange={handleObjectChange}
|
||||||
opts={opts}
|
opts={opts}
|
||||||
isShrunk={(servantIsShrunk && roles.servant === "object")}
|
isShrunk={servantIsShrunk && roles.servant === "object"}
|
||||||
isRemoved={roles.king === "object" && VPS?.form.removeKing}
|
isRemoved={
|
||||||
/>}
|
roles.king === "object" && VPS?.form.removeKing
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
: null}
|
) : null}
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
{vps.externalComplement && <div className="my-2 card block-card p-1 mr-1" key="complementPicker">
|
{vps.externalComplement && (
|
||||||
|
<div className="my-2 card block-card p-1 mr-1" key="complementPicker">
|
||||||
<div className="h5 text-center">Complement</div>
|
<div className="h5 text-center">Complement</div>
|
||||||
<ComplementPicker
|
<ComplementPicker
|
||||||
phraseIsComplete={phraseIsComplete}
|
phraseIsComplete={phraseIsComplete}
|
||||||
comp={vps.externalComplement.selection.type === "unselected"
|
comp={
|
||||||
|
vps.externalComplement.selection.type === "unselected"
|
||||||
? undefined
|
? undefined
|
||||||
: vps.externalComplement as T.ComplementSelection // TODO: just typescript being dumb? - looks like it
|
: (vps.externalComplement as T.ComplementSelection) // TODO: just typescript being dumb? - looks like it
|
||||||
|
}
|
||||||
|
onChange={(payload) =>
|
||||||
|
adjustVps({ type: "set externalComplement", payload })
|
||||||
}
|
}
|
||||||
onChange={payload => adjustVps({ type: "set externalComplement", payload })}
|
|
||||||
opts={opts}
|
opts={opts}
|
||||||
entryFeeder={entryFeeder}
|
entryFeeder={entryFeeder}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>
|
||||||
|
)}
|
||||||
<div className="my-2">
|
<div className="my-2">
|
||||||
<TensePicker
|
<TensePicker vps={vps} onChange={adjustVps} mode="phrases" />
|
||||||
vps={vps}
|
|
||||||
onChange={adjustVps}
|
|
||||||
mode="phrases"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<VPExplorerExplanationModal
|
<VPExplorerExplanationModal
|
||||||
showing={showingExplanation}
|
showing={showingExplanation}
|
||||||
setShowing={setShowingExplanation}
|
setShowing={setShowingExplanation}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ServantShrinker({ shrunk, onClick }: {
|
function ServantShrinker({
|
||||||
|
shrunk,
|
||||||
|
onClick,
|
||||||
|
}: {
|
||||||
shrunk: boolean;
|
shrunk: boolean;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}) {
|
}) {
|
||||||
return <span className="mx-2 clickable" onClick={onClick}>
|
return (
|
||||||
|
<span className="mx-2 clickable" onClick={onClick}>
|
||||||
{!shrunk ? "🪄" : "👶"}
|
{!shrunk ? "🪄" : "👶"}
|
||||||
</span>;
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function KingRemover({ showKing, onChange }: {
|
function KingRemover({
|
||||||
|
showKing,
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
showKing: boolean;
|
showKing: boolean;
|
||||||
onChange: () => void;
|
onChange: () => void;
|
||||||
}) {
|
}) {
|
||||||
return <span className="form-check form-check-inline ml-3">
|
return (
|
||||||
|
<span className="form-check form-check-inline ml-3">
|
||||||
<input
|
<input
|
||||||
checked={showKing}
|
checked={showKing}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@ -227,7 +408,29 @@ function KingRemover({ showKing, onChange }: {
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="showKingCheck"
|
id="showKingCheck"
|
||||||
/>
|
/>
|
||||||
</span>;
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
export default VPPicker;
|
|
@ -1,31 +1,48 @@
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import ButtonSelect from "../ButtonSelect";
|
import ButtonSelect from "../ButtonSelect";
|
||||||
import { RootsAndStems } from "../verb-info/VerbInfo";
|
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 Hider from "../Hider";
|
||||||
import useStickyState from "../useStickyState";
|
import useStickyState from "../useStickyState";
|
||||||
import CompoundDisplay from "./CompoundDisplay";
|
import CompoundDisplay from "./CompoundDisplay";
|
||||||
import {
|
import { VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
|
||||||
VpsReducerAction
|
|
||||||
} from "../../../lib/src/phrase-building/vps-reducer";
|
|
||||||
import { ensureNonComboVerbInfo } from "../../../lib/src/misc-helpers";
|
import { ensureNonComboVerbInfo } from "../../../lib/src/misc-helpers";
|
||||||
|
|
||||||
// TODO: dark on past tense selecitons
|
// TODO: dark on past tense selecitons
|
||||||
|
|
||||||
function VerbPicker(props: {
|
function VerbPicker(props: {
|
||||||
vps: T.VPSelectionState,
|
vps: T.VPSelectionState;
|
||||||
onChange: (a: VpsReducerAction) => void,
|
onChange: (a: VpsReducerAction) => void;
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions;
|
||||||
handleLinkClick: ((ts: number) => void) | "none",
|
handleLinkClick: ((ts: number) => void) | "none";
|
||||||
}) {
|
}) {
|
||||||
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
|
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(
|
||||||
const infoRaw = props.vps.verb ? getVerbInfo(props.vps.verb.verb.entry, props.vps.verb.verb.complement) : undefined;
|
false,
|
||||||
const info = (!infoRaw || !props.vps.verb)
|
"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
|
? undefined
|
||||||
: ("stative" in infoRaw)
|
: "stative" in infoRaw
|
||||||
? infoRaw[props.vps.verb.isCompound === "stative" ? "stative" : "dynamic"]
|
? infoRaw[
|
||||||
: ("transitive" in infoRaw)
|
props.vps.verb.isCompound === "stative" ||
|
||||||
? infoRaw[props.vps.verb.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
props.vps.verb.isCompound === "generative stative"
|
||||||
|
? "stative"
|
||||||
|
: "dynamic"
|
||||||
|
]
|
||||||
|
: "transitive" in infoRaw
|
||||||
|
? infoRaw[
|
||||||
|
props.vps.verb.transitivity === "grammatically transitive"
|
||||||
|
? "grammaticallyTransitive"
|
||||||
|
: "transitive"
|
||||||
|
]
|
||||||
: infoRaw;
|
: infoRaw;
|
||||||
if (info && ("stative" in info || "transitive" in info)) {
|
if (info && ("stative" in info || "transitive" in info)) {
|
||||||
return <div>ERROR: Verb version should be select first</div>;
|
return <div>ERROR: Verb version should be select first</div>;
|
||||||
|
@ -36,10 +53,14 @@ function VerbPicker(props: {
|
||||||
payload: value,
|
payload: value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" {
|
function notInstransitive(
|
||||||
|
t: "transitive" | "intransitive" | "grammatically transitive"
|
||||||
|
): "transitive" | "grammatically transitive" {
|
||||||
return t === "intransitive" ? "transitive" : t;
|
return t === "intransitive" ? "transitive" : t;
|
||||||
}
|
}
|
||||||
function handleChangeTransitivity(payload: "transitive" | "grammatically transitive") {
|
function handleChangeTransitivity(
|
||||||
|
payload: "transitive" | "grammatically transitive"
|
||||||
|
) {
|
||||||
props.onChange({
|
props.onChange({
|
||||||
type: "set transitivity",
|
type: "set transitivity",
|
||||||
payload,
|
payload,
|
||||||
|
@ -51,91 +72,142 @@ function VerbPicker(props: {
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const passiveRootsAndStems = (info && props.vps.verb.voice === "passive") ? getPassiveRootsAndStems(info) : undefined;
|
const passiveRootsAndStems =
|
||||||
|
info && props.vps.verb.voice === "passive"
|
||||||
|
? getPassiveRootsAndStems(info)
|
||||||
|
: undefined;
|
||||||
const abilityRootsAndStems = (() => {
|
const abilityRootsAndStems = (() => {
|
||||||
try {
|
try {
|
||||||
return (info && props.vps.verb.tenseCategory === "modal") ? getAbilityRootsAndStems(info) : undefined;
|
return info && props.vps.verb.tenseCategory === "modal"
|
||||||
|
? getAbilityRootsAndStems(info)
|
||||||
|
: undefined;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("error making ability roots and stems", e);
|
console.log("error making ability roots and stems", e);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return <div className="mb-3">
|
return (
|
||||||
{info && <CompoundDisplay
|
<div className="mb-3">
|
||||||
|
{info && (
|
||||||
|
<CompoundDisplay
|
||||||
info={info}
|
info={info}
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
handleLinkClick={props.handleLinkClick}
|
handleLinkClick={props.handleLinkClick}
|
||||||
/>}
|
/>
|
||||||
{info && <div className="mt-3 mb-1 text-center">
|
)}
|
||||||
|
{info && (
|
||||||
|
<div className="mt-3 mb-1 text-center">
|
||||||
<Hider
|
<Hider
|
||||||
showing={showRootsAndStems}
|
showing={showRootsAndStems}
|
||||||
label={`🌳 ${passiveRootsAndStems ? "Passive" : abilityRootsAndStems ? "Ability" : ""} Roots and Stems${info.type === "dynamic compound" ? " for Aux. Verb" : ""}`}
|
label={`🌳 ${
|
||||||
handleChange={() => setShowRootsAndStems(p => !p)}
|
passiveRootsAndStems
|
||||||
|
? "Passive"
|
||||||
|
: abilityRootsAndStems
|
||||||
|
? "Ability"
|
||||||
|
: ""
|
||||||
|
} Roots and Stems${
|
||||||
|
info.type === "dynamic compound" ? " for Aux. Verb" : ""
|
||||||
|
}`}
|
||||||
|
handleChange={() => setShowRootsAndStems((p) => !p)}
|
||||||
hLevel={5}
|
hLevel={5}
|
||||||
>
|
>
|
||||||
<RootsAndStems
|
<RootsAndStems
|
||||||
textOptions={props.opts}
|
textOptions={props.opts}
|
||||||
info={passiveRootsAndStems
|
info={
|
||||||
|
passiveRootsAndStems
|
||||||
? passiveRootsAndStems
|
? passiveRootsAndStems
|
||||||
: abilityRootsAndStems
|
: abilityRootsAndStems
|
||||||
? abilityRootsAndStems
|
? abilityRootsAndStems
|
||||||
: info.type === "dynamic compound"
|
: info.type === "dynamic compound"
|
||||||
? ensureNonComboVerbInfo(getVerbInfo(info.auxVerb))
|
? ensureNonComboVerbInfo(getVerbInfo(info.auxVerb))
|
||||||
: info}
|
: info
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Hider>
|
</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">
|
<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
|
<ButtonSelect
|
||||||
small
|
small
|
||||||
options={[{
|
options={[
|
||||||
|
{
|
||||||
label: "gramm. trans.",
|
label: "gramm. trans.",
|
||||||
value: "grammatically transitive",
|
value: "grammatically transitive",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
label: "trans.",
|
label: "trans.",
|
||||||
value: "transitive",
|
value: "transitive",
|
||||||
}]}
|
},
|
||||||
|
]}
|
||||||
value={notInstransitive(props.vps.verb.transitivity)}
|
value={notInstransitive(props.vps.verb.transitivity)}
|
||||||
handleChange={handleChangeTransitivity}
|
handleChange={handleChangeTransitivity}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>
|
||||||
{props.vps.verb && props.vps.verb.canChangeVoice && <div className="text-center my-2">
|
)}
|
||||||
|
{props.vps.verb && props.vps.verb.canChangeVoice && (
|
||||||
|
<div className="text-center my-2">
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
small
|
small
|
||||||
value={props.vps.verb.voice}
|
value={props.vps.verb.voice}
|
||||||
options={(props.vps.verb.tenseCategory === "imperative") // || props.vps.verb.tenseCategory === "modal")
|
options={
|
||||||
? [{
|
props.vps.verb.tenseCategory === "imperative" // || props.vps.verb.tenseCategory === "modal")
|
||||||
|
? [
|
||||||
|
{
|
||||||
label: "Active",
|
label: "Active",
|
||||||
value: "active",
|
value: "active",
|
||||||
}]
|
},
|
||||||
: [{
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
label: "Active",
|
label: "Active",
|
||||||
value: "active",
|
value: "active",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
label: "Passive",
|
label: "Passive",
|
||||||
value: "passive",
|
value: "passive",
|
||||||
}]}
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
handleChange={onVoiceSelect}
|
handleChange={onVoiceSelect}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>
|
||||||
{props.vps.verb && props.vps.verb.canChangeStatDyn && <div className="text-center my-2">
|
)}
|
||||||
|
{props.vps.verb && props.vps.verb.canChangeStatDyn && (
|
||||||
|
<div className="text-center my-2">
|
||||||
<ButtonSelect
|
<ButtonSelect
|
||||||
small
|
small
|
||||||
options={[{
|
options={[
|
||||||
label: "stative",
|
{
|
||||||
|
label:
|
||||||
|
infoRaw?.type === "dynamic or generative stative compound"
|
||||||
|
? "gen. stative"
|
||||||
|
: "stative",
|
||||||
value: "stative",
|
value: "stative",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
label: "dynamic",
|
label: "dynamic",
|
||||||
value: "dynamic",
|
value: "dynamic",
|
||||||
}]}
|
},
|
||||||
value={props.vps.verb.isCompound ? props.vps.verb.isCompound : "stative"}
|
]}
|
||||||
|
value={
|
||||||
|
props.vps.verb.isCompound === "generative stative"
|
||||||
|
? "stative"
|
||||||
|
: props.vps.verb.isCompound
|
||||||
|
? props.vps.verb.isCompound
|
||||||
|
: "stative"
|
||||||
|
}
|
||||||
handleChange={handleChangeStatDyn}
|
handleChange={handleChangeStatDyn}
|
||||||
/>
|
/>
|
||||||
</div>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default VerbPicker;
|
export default VerbPicker;
|
|
@ -1,7 +1,8 @@
|
||||||
import { renderVerb } from "../../../lib/src/new-verb-engine/render-verb";
|
import { renderVerb } from "../../../lib/src/new-verb-engine/render-verb";
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import { equals } from "rambda";
|
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({
|
export function buildVerbChart({
|
||||||
verb,
|
verb,
|
||||||
|
@ -10,6 +11,7 @@ export function buildVerbChart({
|
||||||
voice,
|
voice,
|
||||||
imperative,
|
imperative,
|
||||||
negative,
|
negative,
|
||||||
|
objectNP,
|
||||||
}: {
|
}: {
|
||||||
verb: T.VerbEntry;
|
verb: T.VerbEntry;
|
||||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
|
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
|
||||||
|
@ -17,7 +19,11 @@ export function buildVerbChart({
|
||||||
imperative: boolean;
|
imperative: boolean;
|
||||||
voice: T.VerbSelection["voice"];
|
voice: T.VerbSelection["voice"];
|
||||||
negative: boolean;
|
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
|
const allPersons = imperative
|
||||||
? [
|
? [
|
||||||
T.Person.SecondSingMale,
|
T.Person.SecondSingMale,
|
||||||
|
@ -27,6 +33,9 @@ export function buildVerbChart({
|
||||||
]
|
]
|
||||||
: ([...Array(12).keys()] as T.Person[]);
|
: ([...Array(12).keys()] as T.Person[]);
|
||||||
const isPast = isPastTense(tense);
|
const isPast = isPastTense(tense);
|
||||||
|
const objNP: T.Rendered<T.NPSelection> | undefined = objectNP
|
||||||
|
? renderNPSelection(objectNP, false, false, "object", "none", false)
|
||||||
|
: undefined;
|
||||||
function conjugateAllPers(
|
function conjugateAllPers(
|
||||||
p?: T.Person
|
p?: T.Person
|
||||||
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
|
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
|
||||||
|
@ -46,19 +55,51 @@ export function buildVerbChart({
|
||||||
negative,
|
negative,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const hasLengths = vIsLength("long")(ps[0]);
|
return pullOutLengths(ps);
|
||||||
const hasMini = vIsLength("mini")(ps[0]);
|
|
||||||
return pullOutLengths(hasLengths, hasMini, ps);
|
|
||||||
}
|
}
|
||||||
if (transitivity === "transitive" && !isPast) {
|
if (transitivity === "transitive" && !isPast) {
|
||||||
return conflateIfNoCompGenNumDiff({
|
return {
|
||||||
|
objNP,
|
||||||
|
vbs: conflateIfNoCompGenNumDiff({
|
||||||
mascSing: conjugateAllPers(T.Person.FirstSingMale),
|
mascSing: conjugateAllPers(T.Person.FirstSingMale),
|
||||||
mascPlur: conjugateAllPers(T.Person.FirstPlurMale),
|
mascPlur: conjugateAllPers(T.Person.FirstPlurMale),
|
||||||
femSing: conjugateAllPers(T.Person.FirstSingFemale),
|
femSing: conjugateAllPers(T.Person.FirstSingFemale),
|
||||||
femPlur: conjugateAllPers(T.Person.FirstPlurFemale),
|
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 {
|
} else {
|
||||||
return conjugateAllPers();
|
return {
|
||||||
|
objNP: undefined,
|
||||||
|
vbs: conjugateAllPers(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,23 +147,21 @@ function grabLength(
|
||||||
if (v.length === 2) {
|
if (v.length === 2) {
|
||||||
const [vb, vbe] = v;
|
const [vb, vbe] = v;
|
||||||
return {
|
return {
|
||||||
objComp: undefined,
|
|
||||||
hasBa,
|
hasBa,
|
||||||
vbs: [ph, [grabVBLength(vb), vbe]],
|
vbs: [ph, [grabVBLength(vb), vbe]],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
objComp: undefined,
|
|
||||||
hasBa,
|
hasBa,
|
||||||
vbs: [ph, [grabVBLength(v[0])]],
|
vbs: [ph, [grabVBLength(v[0])]],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function pullOutLengths(
|
function pullOutLengths(
|
||||||
hasLengths: boolean,
|
|
||||||
hasMini: boolean,
|
|
||||||
ps: T.RenderVerbOutput[]
|
ps: T.RenderVerbOutput[]
|
||||||
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
|
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
|
||||||
|
const hasLengths = vIsLength("long")(ps[0]);
|
||||||
|
const hasMini = vIsLength("mini")(ps[0]);
|
||||||
if (!hasLengths) {
|
if (!hasLengths) {
|
||||||
return ps;
|
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,
|
concat: semigroupPsStringWVars.concat,
|
||||||
empty: [monoidPsString.empty],
|
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 * as T from "../../types";
|
||||||
import { fmapSingleOrLengthOpts } from "./fmaps";
|
import { fmapSingleOrLengthOpts } from "./fp-ps";
|
||||||
|
|
||||||
export const blank: T.PsString = {
|
export const blank: T.PsString = {
|
||||||
p: "_____",
|
p: "_____",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
personNumber,
|
personNumber,
|
||||||
personToGenNum,
|
personToGenNum,
|
||||||
} from "../misc-helpers";
|
} from "../misc-helpers";
|
||||||
import { fmapSingleOrLengthOpts } from "../fmaps";
|
import { fmapSingleOrLengthOpts } from "../fp-ps";
|
||||||
import { concatPsString, getLength } from "../p-text-helpers";
|
import { concatPsString, getLength } from "../p-text-helpers";
|
||||||
import {
|
import {
|
||||||
presentEndings,
|
presentEndings,
|
||||||
|
@ -18,6 +18,7 @@ import {
|
||||||
isAbilityTense,
|
isAbilityTense,
|
||||||
isPerfectTense,
|
isPerfectTense,
|
||||||
isTlulVerb,
|
isTlulVerb,
|
||||||
|
isImperativeTense,
|
||||||
} from "../type-predicates";
|
} from "../type-predicates";
|
||||||
import { perfectTenseHasBa } from "../phrase-building/vp-tools";
|
import { perfectTenseHasBa } from "../phrase-building/vp-tools";
|
||||||
import { makePsString, removeFVarients } from "../accent-and-ps-utils";
|
import { makePsString, removeFVarients } from "../accent-and-ps-utils";
|
||||||
|
@ -100,6 +101,7 @@ export function renderVerb({
|
||||||
subject,
|
subject,
|
||||||
object,
|
object,
|
||||||
voice,
|
voice,
|
||||||
|
negative,
|
||||||
}: {
|
}: {
|
||||||
verb: T.VerbEntry;
|
verb: T.VerbEntry;
|
||||||
negative: boolean;
|
negative: boolean;
|
||||||
|
@ -126,7 +128,7 @@ export function renderVerb({
|
||||||
const [vHead, rest] = getRootStem({
|
const [vHead, rest] = getRootStem({
|
||||||
verb,
|
verb,
|
||||||
rs: isPast ? "root" : "stem",
|
rs: isPast ? "root" : "stem",
|
||||||
aspect,
|
aspect: negative && isImperativeTense(tense) ? "imperfective" : aspect,
|
||||||
voice,
|
voice,
|
||||||
type,
|
type,
|
||||||
genderNumber: personToGenNum(transitive ? object : subject),
|
genderNumber: personToGenNum(transitive ? object : subject),
|
||||||
|
@ -136,7 +138,6 @@ export function renderVerb({
|
||||||
const ending = getEnding(king, tenseC, aspect);
|
const ending = getEnding(king, tenseC, aspect);
|
||||||
return {
|
return {
|
||||||
hasBa,
|
hasBa,
|
||||||
objComp: undefined,
|
|
||||||
vbs: [
|
vbs: [
|
||||||
vHead,
|
vHead,
|
||||||
addEnding({
|
addEnding({
|
||||||
|
|
|
@ -31,9 +31,9 @@ import {
|
||||||
isKedul,
|
isKedul,
|
||||||
} from "./rs-helpers";
|
} from "./rs-helpers";
|
||||||
import { inflectPattern3 } from "./new-inflectors";
|
import { inflectPattern3 } from "./new-inflectors";
|
||||||
import { fmapSingleOrLengthOpts } from "../fmaps";
|
import { fmapSingleOrLengthOpts } from "../fp-ps";
|
||||||
|
|
||||||
const statVerb = {
|
export const statVerb = {
|
||||||
intransitive: vEntry({
|
intransitive: vEntry({
|
||||||
ts: 1581086654898,
|
ts: 1581086654898,
|
||||||
i: 11100,
|
i: 11100,
|
||||||
|
|
|
@ -30,7 +30,7 @@ import {
|
||||||
splitUpSyllables,
|
splitUpSyllables,
|
||||||
} from "./accent-helpers";
|
} from "./accent-helpers";
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
import { fmapSingleOrLengthOpts } from "./fmaps";
|
import { fmapSingleOrLengthOpts } from "./fp-ps";
|
||||||
|
|
||||||
const endingInSingleARegex = /[^a]'?’?[aá]'?’?$/;
|
const endingInSingleARegex = /[^a]'?’?[aá]'?’?$/;
|
||||||
const endingInHeyOrAynRegex = /[^ا][هع]$/;
|
const endingInHeyOrAynRegex = /[^ا][هع]$/;
|
||||||
|
@ -42,24 +42,29 @@ export function inflectWord(word: T.DictionaryEntry): T.InflectorOutput {
|
||||||
const w = removeFVarients(word);
|
const w = removeFVarients(word);
|
||||||
if (w.c?.includes("doub.")) {
|
if (w.c?.includes("doub.")) {
|
||||||
const words = splitDoubleWord(w);
|
const words = splitDoubleWord(w);
|
||||||
const inflected = words.map((x) => ensureUnisexInflections(inflectWord(x), x));
|
const inflected = words.map((x) =>
|
||||||
|
ensureUnisexInflections(inflectWord(x), x)
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
inflections: concatInflections(
|
inflections: concatInflections(
|
||||||
inflected[0].inflections,
|
inflected[0].inflections,
|
||||||
inflected[1].inflections,
|
inflected[1].inflections
|
||||||
) as T.UnisexInflections,
|
) as T.UnisexInflections,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (w.c && w.c.includes("pl.")) {
|
if (w.c && w.c.includes("pl.")) {
|
||||||
return handlePluralNounOrAdj(w);
|
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);
|
return handleUnisexWord(w);
|
||||||
}
|
}
|
||||||
if (w.c && (w.c.includes("n. m."))) {
|
if (w.c && w.c.includes("n. m.")) {
|
||||||
return handleMascNoun(w);
|
return handleMascNoun(w);
|
||||||
}
|
}
|
||||||
if (w.c && (w.c.includes("n. f."))) {
|
if (w.c && w.c.includes("n. f.")) {
|
||||||
return handleFemNoun(w);
|
return handleFemNoun(w);
|
||||||
}
|
}
|
||||||
// It's not a noun/adj
|
// It's not a noun/adj
|
||||||
|
@ -88,10 +93,16 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
||||||
return { inflections: inflectRegularYeyUnisex(word.p, word.f), ...plurals };
|
return { inflections: inflectRegularYeyUnisex(word.p, word.f), ...plurals };
|
||||||
}
|
}
|
||||||
if (pEnd === "ه" && word.g.slice(-1) === "u") {
|
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") {
|
if (pEnd === "ی" && word.f.slice(-2) === "éy") {
|
||||||
return { inflections: inflectEmphasizedYeyUnisex(word.p, word.f), ...plurals };
|
return {
|
||||||
|
inflections: inflectEmphasizedYeyUnisex(word.p, word.f),
|
||||||
|
...plurals,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
pashtoConsonants.includes(pEnd) ||
|
pashtoConsonants.includes(pEnd) ||
|
||||||
|
@ -100,7 +111,10 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
||||||
word.f.slice(-1) === "w" ||
|
word.f.slice(-1) === "w" ||
|
||||||
(word.p.slice(-1) === "ه" && word.f.slice(-1) === "h")
|
(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;
|
if (plurals) return plurals;
|
||||||
return false;
|
return false;
|
||||||
|
@ -134,7 +148,10 @@ function handleMascNoun(w: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
||||||
...plurals,
|
...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) {
|
if (isTobEnding) {
|
||||||
return { inflections: inflectTobMasc(w.p, w.f), ...plurals };
|
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 };
|
return { inflections: inflectRegularYeyMasc(w.p, w.f), ...plurals };
|
||||||
}
|
}
|
||||||
if (pEnd === "ی" && fEnd === "éy") {
|
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 {
|
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 };
|
return { inflections: inflectRegularAFem(word.p, word.f), ...plurals };
|
||||||
}
|
}
|
||||||
if (word.p.slice(-1) === "ح" && endingInSingleARegex.test(word.f)) {
|
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
|
// TODO: better reusable function to check if something ends with a consonant
|
||||||
if ((pashtoConsonants.includes(pEnd) || word.f.slice(-1) === "w") && !animate) {
|
if (
|
||||||
return { inflections: inflectRegularInanMissingAFem(word.p, word.f), ...plurals };
|
(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 };
|
return { inflections: inflectRegularInanEeFem(word.p, word.f), ...plurals };
|
||||||
}
|
}
|
||||||
if (pEnd === "ۍ") {
|
if (pEnd === "ۍ") {
|
||||||
|
@ -182,14 +211,23 @@ function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LEVEL 3 FUNCTIONS
|
// 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 inf1 = removeAccents(inflections[1]);
|
||||||
const inf0 = removeAccents(inflections[0]);
|
const inf0 = removeAccents(inflections[0]);
|
||||||
const inf0fSyls = splitUpSyllables(inf0.f).length;
|
const inf0fSyls = splitUpSyllables(inf0.f).length;
|
||||||
return {
|
return {
|
||||||
masc: [
|
masc: [
|
||||||
[{ p, f }],
|
[{ p, f }],
|
||||||
[{p: inflections[0].p, f: `${inf0.f.slice(0, -1)}${inf0fSyls === 1 ? "u" : "ú"}` }],
|
[
|
||||||
|
{
|
||||||
|
p: inflections[0].p,
|
||||||
|
f: `${inf0.f.slice(0, -1)}${inf0fSyls === 1 ? "u" : "ú"}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
[{ p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}` }],
|
[{ p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}` }],
|
||||||
],
|
],
|
||||||
fem: [
|
fem: [
|
||||||
|
@ -200,7 +238,10 @@ function inflectIrregularUnisex(p: string, f: string, inflections: Array<{p: str
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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 baseP = p.slice(0, -1);
|
||||||
const baseF = f.slice(0, -2);
|
const baseF = f.slice(0, -2);
|
||||||
return {
|
return {
|
||||||
|
@ -220,7 +261,10 @@ export function inflectRegularYeyUnisex(p: string, f: string): T.UnisexInflectio
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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 { p, f } = removeAccents(makePsString(pr, fr));
|
||||||
const accented = fr.slice(-1) === "ú";
|
const accented = fr.slice(-1) === "ú";
|
||||||
const baseP = p.slice(0, -1);
|
const baseP = p.slice(0, -1);
|
||||||
|
@ -256,23 +300,23 @@ function inflectEmphasizedYeyUnisex(p: string, f: string): T.UnisexInflections {
|
||||||
[{ p: `${baseP}ۍ`, f: `${baseF}úy` }],
|
[{ p: `${baseP}ۍ`, f: `${baseF}úy` }],
|
||||||
[
|
[
|
||||||
{ p: `${baseP}یو`, f: `${baseF}úyo` },
|
{ 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 fSyls = splitUpSyllables(removeAccents(f));
|
||||||
const iBase = fSyls.length === 1
|
const iBase =
|
||||||
|
fSyls.length === 1
|
||||||
? makePsString(p, accentFSylsOnNFromEnd(fSyls, 0))
|
? makePsString(p, accentFSylsOnNFromEnd(fSyls, 0))
|
||||||
: makePsString(p, f);
|
: makePsString(p, f);
|
||||||
return {
|
return {
|
||||||
masc: [
|
masc: [[{ p, f }], [{ p, f }], [{ p: `${iBase.p}و`, f: `${iBase.f}o` }]],
|
||||||
[{p, f}],
|
|
||||||
[{p, f}],
|
|
||||||
[{p: `${iBase.p}و`, f: `${iBase.f}o`}],
|
|
||||||
],
|
|
||||||
fem: [
|
fem: [
|
||||||
[{ p: `${iBase.p}ه`, f: `${iBase.f}a` }],
|
[{ p: `${iBase.p}ه`, f: `${iBase.f}a` }],
|
||||||
[{ p: `${iBase.p}ې`, f: `${iBase.f}e` }],
|
[{ p: `${iBase.p}ې`, f: `${iBase.f}e` }],
|
||||||
|
@ -323,21 +367,37 @@ function inflectRegularEmphasizedYeyMasc(p: string, f: string): T.Inflections {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
let inf0f = removeAccents(inflections[0].f);
|
||||||
const inf0syls = splitUpSyllables(f).length;
|
const inf0syls = splitUpSyllables(f).length;
|
||||||
const inf1f = removeAccents(inflections[1].f);
|
const inf1f = removeAccents(inflections[1].f);
|
||||||
return {
|
return {
|
||||||
masc: [
|
masc: [
|
||||||
[{ p, f }],
|
[{ p, f }],
|
||||||
[{p: inflections[0].p, f: `${inf0f.slice(0, -1)}${inf0syls === 1 ? "u" : "ú"}`}],
|
[
|
||||||
[{p: `${inflections[1].p}و`, f: `${inf1f}${inf0syls === 1 ? "o" : "ó"}`}],
|
{
|
||||||
|
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 {
|
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 accentLast = hasAccents(withoutTrailingComma.slice(-1));
|
||||||
const baseF = withoutTrailingComma.slice(0, -1);
|
const baseF = withoutTrailingComma.slice(0, -1);
|
||||||
const baseP = p.slice(-1) === "ع" ? p : p.slice(0, -1);
|
const baseP = p.slice(-1) === "ع" ? p : p.slice(0, -1);
|
||||||
|
@ -362,9 +422,8 @@ function inflectRegularAWithHimPEnding(p: string, f: string): T.Inflections {
|
||||||
}
|
}
|
||||||
|
|
||||||
function inflectRegularInanMissingAFem(p: string, f: string): T.Inflections {
|
function inflectRegularInanMissingAFem(p: string, f: string): T.Inflections {
|
||||||
const fBase = splitUpSyllables(f).length === 1
|
const fBase =
|
||||||
? accentFSylsOnNFromEnd(f, 0)
|
splitUpSyllables(f).length === 1 ? accentFSylsOnNFromEnd(f, 0) : f;
|
||||||
: f;
|
|
||||||
return {
|
return {
|
||||||
fem: [
|
fem: [
|
||||||
[{ p, f }],
|
[{ p, f }],
|
||||||
|
@ -401,16 +460,13 @@ function inflectRegularUyFem(p: string, f: string): T.Inflections {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePashtoPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
|
function makePashtoPlural(
|
||||||
|
word: T.DictionaryEntryNoFVars
|
||||||
|
): T.PluralInflections | undefined {
|
||||||
if (!(word.ppp && word.ppf)) return undefined;
|
if (!(word.ppp && word.ppf)) return undefined;
|
||||||
const base = splitPsByVarients(
|
const base = splitPsByVarients(makePsString(word.ppp, word.ppf));
|
||||||
makePsString(word.ppp, word.ppf)
|
|
||||||
);
|
|
||||||
function getBaseAndO(): T.PluralInflectionSet {
|
function getBaseAndO(): T.PluralInflectionSet {
|
||||||
return [
|
return [base, base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
|
||||||
base,
|
|
||||||
base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
if (word.c?.includes("n. m.")) {
|
if (word.c?.includes("n. m.")) {
|
||||||
return { masc: getBaseAndO() };
|
return { masc: getBaseAndO() };
|
||||||
|
@ -422,14 +478,14 @@ function makePashtoPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections |
|
||||||
return undefined;
|
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.")) {
|
if (!endsInConsonant(word) || !word.c?.includes("n.")) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const w = makePsString(word.p, word.f);
|
const w = makePsString(word.p, word.f);
|
||||||
const base = countSyllables(w) === 1
|
const base = countSyllables(w) === 1 ? accentOnNFromEnd(w, 0) : w;
|
||||||
? accentOnNFromEnd(w, 0)
|
|
||||||
: w;
|
|
||||||
return {
|
return {
|
||||||
masc: [
|
masc: [
|
||||||
[concatPsString(base, { p: "ه", f: "a" })],
|
[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;
|
if (!(word.apf && word.app)) return undefined;
|
||||||
const w = makePsString(word.app, word.apf);
|
const w = makePsString(word.app, word.apf);
|
||||||
const plural = splitPsByVarients(w);
|
const plural = splitPsByVarients(w);
|
||||||
|
@ -456,15 +514,19 @@ function makeArabicPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections |
|
||||||
return { masc: value };
|
return { masc: value };
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections, bundledPlural?: T.PluralInflections } | { arabicPlural: T.PluralInflections, bundledPlural?: T.PluralInflections } | undefined {
|
function makePlural(
|
||||||
function addSecondInf(plur: T.ArrayOneOrMore<T.PsString> | T.PsString): T.PluralInflectionSet {
|
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)) {
|
if (!Array.isArray(plur)) {
|
||||||
return addSecondInf([plur]);
|
return addSecondInf([plur]);
|
||||||
}
|
}
|
||||||
return [
|
return [plur, plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
|
||||||
plur,
|
|
||||||
plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
if (w.c && w.c.includes("pl.")) {
|
if (w.c && w.c.includes("pl.")) {
|
||||||
const plural = addSecondInf(makePsString(w.p, w.f));
|
const plural = addSecondInf(makePsString(w.p, w.f));
|
||||||
|
@ -476,19 +538,31 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
const arabicPlural = makeArabicPlural(w);
|
const arabicPlural = makeArabicPlural(w);
|
||||||
const pashtoPlural = makePashtoPlural(w);
|
const pashtoPlural = makePashtoPlural(w);
|
||||||
const bundledPlural = makeBundledPlural(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)) {
|
if (shortSquish && (w.infap === undefined || w.infaf === undefined)) {
|
||||||
throw new Error(`no irregular inflection info for ${w.p} - ${w.ts}`);
|
throw new Error(`no irregular inflection info for ${w.p} - ${w.ts}`);
|
||||||
}
|
}
|
||||||
const b = removeAccents(shortSquish
|
const b = removeAccents(
|
||||||
? makePsString((w.infap as string).slice(0, -1), (w.infaf as string).slice(0, -1))
|
shortSquish
|
||||||
|
? makePsString(
|
||||||
|
(w.infap as string).slice(0, -1),
|
||||||
|
(w.infaf as string).slice(0, -1)
|
||||||
|
)
|
||||||
: w
|
: w
|
||||||
);
|
);
|
||||||
const base = endsInShwa(b)
|
const base = endsInShwa(b)
|
||||||
? makePsString(b.p.slice(0, -1), b.f.slice(0, -1))
|
? makePsString(b.p.slice(0, -1), b.f.slice(0, -1))
|
||||||
: b;
|
: b;
|
||||||
return addSecondInf(
|
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> {
|
function addAnimUnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
|
||||||
|
@ -505,10 +579,14 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
f: b.f.slice(0, -2),
|
f: b.f.slice(0, -2),
|
||||||
};
|
};
|
||||||
const firstInf: T.ArrayOneOrMore<T.PsString> = [
|
const firstInf: T.ArrayOneOrMore<T.PsString> = [
|
||||||
concatPsString(base, { p: "یان", f: "iyáan" }, gender === "fem" ? { p: "ې", f: "e" } : ""),
|
concatPsString(
|
||||||
...gender === "fem"
|
base,
|
||||||
|
{ p: "یان", f: "iyáan" },
|
||||||
|
gender === "fem" ? { p: "ې", f: "e" } : ""
|
||||||
|
),
|
||||||
|
...(gender === "fem"
|
||||||
? [concatPsString(base, { p: "یګانې", f: "eegáane" })]
|
? [concatPsString(base, { p: "یګانې", f: "eegáane" })]
|
||||||
: [],
|
: []),
|
||||||
];
|
];
|
||||||
return [
|
return [
|
||||||
firstInf,
|
firstInf,
|
||||||
|
@ -537,11 +615,12 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
function addLongVowelSuffix(gender: "masc" | "fem"): T.PluralInflectionSet {
|
function addLongVowelSuffix(gender: "masc" | "fem"): T.PluralInflectionSet {
|
||||||
const base = removeEndTick(makePsString(w.p, w.f));
|
const base = removeEndTick(makePsString(w.p, w.f));
|
||||||
const baseWOutAccents = removeAccents(base);
|
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") {
|
if (gender === "fem") {
|
||||||
return addSecondInf([
|
return addSecondInf([
|
||||||
concatPsString(base, space, { p: "وې", f: "we" }),
|
concatPsString(base, space, { p: "وې", f: "we" }),
|
||||||
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" })
|
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" }),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
return addSecondInf([
|
return addSecondInf([
|
||||||
|
@ -571,24 +650,32 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
|
|
||||||
const shortSquish = !!w.infap && !w.infap.includes("ا");
|
const shortSquish = !!w.infap && !w.infap.includes("ا");
|
||||||
const anim = w.c?.includes("anim.");
|
const anim = w.c?.includes("anim.");
|
||||||
const type = (w.c?.includes("unisex"))
|
const type = w.c?.includes("unisex")
|
||||||
? "unisex noun"
|
? "unisex noun"
|
||||||
: (w.c?.includes("n. m."))
|
: w.c?.includes("n. m.")
|
||||||
? "masc noun"
|
? "masc noun"
|
||||||
: (w.c?.includes("n. f."))
|
: w.c?.includes("n. f.")
|
||||||
? "fem noun"
|
? "fem noun"
|
||||||
: "other";
|
: "other";
|
||||||
if (pashtoPlural) return {
|
if (pashtoPlural)
|
||||||
|
return {
|
||||||
plural: pashtoPlural,
|
plural: pashtoPlural,
|
||||||
arabicPlural,
|
arabicPlural,
|
||||||
};
|
};
|
||||||
if (type === "unisex noun") {
|
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
|
// 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)) {
|
if (endsInConsonant(w) && !w.infap) {
|
||||||
return { arabicPlural, bundledPlural, plural: addAnimUnisexPluralSuffix() };
|
return {
|
||||||
|
arabicPlural,
|
||||||
|
bundledPlural,
|
||||||
|
plural: addAnimUnisexPluralSuffix(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (shortSquish && !anim) {
|
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)) {
|
if (endsWith([{ p: "ی", f: "éy" }, { p: "ي" }], w, true)) {
|
||||||
return { arabicPlural, plural: addAnimN3UnisexPluralSuffix() };
|
return { arabicPlural, plural: addAnimN3UnisexPluralSuffix() };
|
||||||
|
@ -598,8 +685,8 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
type === "masc noun" &&
|
type === "masc noun" &&
|
||||||
(shortSquish || ((endsInConsonant(w) || endsInShwa(w)) && (!w.infap))) &&
|
(shortSquish || ((endsInConsonant(w) || endsInShwa(w)) && !w.infap)) &&
|
||||||
(w.p.slice(-3) !== "توب")
|
w.p.slice(-3) !== "توب"
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
arabicPlural,
|
arabicPlural,
|
||||||
|
@ -609,11 +696,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (type === "masc noun" && endsWith({ p: "ی", f: "éy" }, w, true) && anim) {
|
||||||
type === "masc noun" &&
|
|
||||||
endsWith({ p: "ی", f: "éy" }, w, true) &&
|
|
||||||
anim
|
|
||||||
) {
|
|
||||||
const { masc } = addAnimN3UnisexPluralSuffix();
|
const { masc } = addAnimN3UnisexPluralSuffix();
|
||||||
return {
|
return {
|
||||||
arabicPlural,
|
arabicPlural,
|
||||||
|
@ -630,7 +713,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// TODO: What about endings in long ee / animate at inanimate
|
// 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 {
|
return {
|
||||||
arabicPlural,
|
arabicPlural,
|
||||||
plural: {
|
plural: {
|
||||||
|
@ -639,7 +722,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// TODO: What about endings in long ee / animate at inanimate
|
// 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 {
|
return {
|
||||||
arabicPlural,
|
arabicPlural,
|
||||||
plural: {
|
plural: {
|
||||||
|
@ -661,6 +744,8 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
||||||
return undefined;
|
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);
|
return fmapSingleOrLengthOpts((x) => inflectRegularYeyUnisex(x.p, x.f), ps);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,31 +15,53 @@ export function makeKid(kid: T.Kid["kid"], key?: number): T.Kid {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSubjectSelection(blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]): T.SubjectSelectionComplete;
|
export function getSubjectSelection(
|
||||||
export function getSubjectSelection(blocks: T.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection;
|
blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]
|
||||||
export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[] | T.VPSBlockComplete[] | T.VPSBlock[]): T.SubjectSelection | T.SubjectSelectionComplete {
|
): T.SubjectSelectionComplete;
|
||||||
const b = blocks.find(f => f.block?.type === "subjectSelection");
|
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") {
|
if (!b || !b.block || b.block.type !== "subjectSelection") {
|
||||||
throw new Error("subjectSelection not found in blocks");
|
throw new Error("subjectSelection not found in blocks");
|
||||||
}
|
}
|
||||||
return b.block;
|
return b.block;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getComplementFromBlocks(blocks: T.Block[][]): T.Rendered<T.ComplementSelection> | T.UnselectedComplementSelection | undefined {
|
export function getComplementFromBlocks(
|
||||||
const b = blocks[0].find(f => f.block.type === "complement");
|
blocks: T.Block[][]
|
||||||
return b?.block as T.Rendered<T.ComplementSelection> | T.UnselectedComplementSelection | undefined;
|
):
|
||||||
|
| 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> {
|
export function getSubjectSelectionFromBlocks(
|
||||||
const b = blocks[0].find(f => f.block.type === "subjectSelection");
|
blocks: T.Block[][]
|
||||||
|
): T.Rendered<T.SubjectSelectionComplete> {
|
||||||
|
const b = blocks[0].find((f) => f.block.type === "subjectSelection");
|
||||||
if (!b || b.block.type !== "subjectSelection") {
|
if (!b || b.block.type !== "subjectSelection") {
|
||||||
throw new Error("subjectSelection not found in blocks");
|
throw new Error("subjectSelection not found in blocks");
|
||||||
}
|
}
|
||||||
return b.block;
|
return b.block;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.ObjectSelectionComplete> {
|
export function getObjectSelectionFromBlocks(
|
||||||
const b = blocks[0].find(f => f.block.type === "objectSelection");
|
blocks: T.Block[][]
|
||||||
|
): T.Rendered<T.ObjectSelectionComplete> {
|
||||||
|
const b = blocks[0].find((f) => f.block.type === "objectSelection");
|
||||||
if (!b || b.block.type !== "objectSelection") {
|
if (!b || b.block.type !== "objectSelection") {
|
||||||
throw new Error("objectSelection not found in blocks");
|
throw new Error("objectSelection not found in blocks");
|
||||||
}
|
}
|
||||||
|
@ -48,27 +70,37 @@ export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.
|
||||||
|
|
||||||
export function includesShrunkenServant(kids?: T.Kid[]): boolean {
|
export function includesShrunkenServant(kids?: T.Kid[]): boolean {
|
||||||
if (!kids) return false;
|
if (!kids) return false;
|
||||||
return kids.some(k => (
|
return kids.some(
|
||||||
k.kid.type === "mini-pronoun" && k.kid.source === "servant"
|
(k) => k.kid.type === "mini-pronoun" && k.kid.source === "servant"
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.PredicateSelectionComplete> {
|
export function getPredicateSelectionFromBlocks(
|
||||||
const b = blocks[0].find(f => f.block.type === "predicateSelection");
|
blocks: T.Block[][]
|
||||||
|
): T.Rendered<T.PredicateSelectionComplete> {
|
||||||
|
const b = blocks[0].find((f) => f.block.type === "predicateSelection");
|
||||||
if (!b || b.block.type !== "predicateSelection") {
|
if (!b || b.block.type !== "predicateSelection") {
|
||||||
throw new Error("predicateSelection not found in blocks");
|
throw new Error("predicateSelection not found in blocks");
|
||||||
}
|
}
|
||||||
return b.block;
|
return b.block;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAPsFromBlocks(blocks: T.Block[][]): T.Rendered<T.APSelection>[] {
|
export function getAPsFromBlocks(
|
||||||
return blocks[0].filter(b => b.block.type === "AP").map(b => b.block) as T.Rendered<T.APSelection>[];
|
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.ObjectSelection;
|
||||||
export function getObjectSelection(blocks: T.VPSBlock[] | T.VPSBlockComplete[]): T.ObjectSelection | T.ObjectSelectionComplete {
|
export function getObjectSelection(
|
||||||
const b = blocks.find(f => f.block?.type === "objectSelection");
|
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") {
|
if (!b || !b.block || b.block.type !== "objectSelection") {
|
||||||
throw new Error("objectSelection not found in blocks");
|
throw new Error("objectSelection not found in blocks");
|
||||||
}
|
}
|
||||||
|
@ -83,18 +115,24 @@ export function makeEPSBlocks(): T.EPSBlock[] {
|
||||||
type: "subjectSelection",
|
type: "subjectSelection",
|
||||||
selection: undefined,
|
selection: undefined,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeAPBlock(): { key: number, block: undefined } {
|
export function makeAPBlock(): { key: number; block: undefined } {
|
||||||
return {
|
return {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
block: undefined,
|
block: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelection | T.NPSelection["selection"] | undefined): T.SubjectSelection {
|
export function makeSubjectSelection(
|
||||||
|
selection:
|
||||||
|
| T.SubjectSelection
|
||||||
|
| T.NPSelection
|
||||||
|
| T.NPSelection["selection"]
|
||||||
|
| undefined
|
||||||
|
): T.SubjectSelection {
|
||||||
if (!selection) {
|
if (!selection) {
|
||||||
return {
|
return {
|
||||||
type: "subjectSelection",
|
type: "subjectSelection",
|
||||||
|
@ -115,16 +153,23 @@ export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelecti
|
||||||
selection: {
|
selection: {
|
||||||
type: "NP",
|
type: "NP",
|
||||||
selection,
|
selection,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP | T.NPSelection | T.NPSelection["selection"] | undefined): T.ObjectSelection {
|
export function makeObjectSelection(
|
||||||
|
selection:
|
||||||
|
| T.ObjectSelection
|
||||||
|
| T.ObjectNP
|
||||||
|
| T.NPSelection
|
||||||
|
| T.NPSelection["selection"]
|
||||||
|
| undefined
|
||||||
|
): T.ObjectSelection {
|
||||||
if (!selection) {
|
if (!selection) {
|
||||||
return {
|
return {
|
||||||
type: "objectSelection",
|
type: "objectSelection",
|
||||||
selection: undefined,
|
selection: undefined,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if (typeof selection !== "object") {
|
if (typeof selection !== "object") {
|
||||||
return {
|
return {
|
||||||
|
@ -150,16 +195,20 @@ export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP |
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EPSBlocksAreComplete(blocks: T.EPSBlock[]): blocks is T.EPSBlockComplete[] {
|
export function EPSBlocksAreComplete(
|
||||||
if (blocks.some(block => block.block === undefined)) {
|
blocks: T.EPSBlock[]
|
||||||
|
): blocks is T.EPSBlockComplete[] {
|
||||||
|
if (blocks.some((block) => block.block === undefined)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const subject = getSubjectSelection(blocks);
|
const subject = getSubjectSelection(blocks);
|
||||||
return !!subject.selection;
|
return !!subject.selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function VPSBlocksAreComplete(blocks: T.VPSBlock[]): blocks is T.VPSBlockComplete[] {
|
export function VPSBlocksAreComplete(
|
||||||
if (blocks.some(block => block.block === undefined)) {
|
blocks: T.VPSBlock[]
|
||||||
|
): blocks is T.VPSBlockComplete[] {
|
||||||
|
if (blocks.some((block) => block.block === undefined)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const subject = getSubjectSelection(blocks);
|
const subject = getSubjectSelection(blocks);
|
||||||
|
@ -169,70 +218,137 @@ export function VPSBlocksAreComplete(blocks: T.VPSBlock[]): blocks is T.VPSBlock
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function adjustSubjectSelection(blocks: T.EPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.EPSBlock[];
|
export function adjustSubjectSelection(
|
||||||
export function adjustSubjectSelection(blocks: T.VPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.VPSBlock[];
|
blocks: T.EPSBlock[],
|
||||||
export function adjustSubjectSelection(blocks: T.VPSBlock[] | T.EPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.VPSBlock[] | 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 nb = [...blocks];
|
||||||
const i = nb.findIndex(b => b.block && b.block.type === "subjectSelection");
|
const i = nb.findIndex((b) => b.block && b.block.type === "subjectSelection");
|
||||||
if (i === -1) {
|
if (i === -1) {
|
||||||
throw new Error("couldn't find subjectSelection to modify");
|
throw new Error("couldn't find subjectSelection to modify");
|
||||||
}
|
}
|
||||||
nb[i].block = subject?.type === "subjectSelection" ? subject : makeSubjectSelection(subject);
|
nb[i].block =
|
||||||
|
subject?.type === "subjectSelection"
|
||||||
|
? subject
|
||||||
|
: makeSubjectSelection(subject);
|
||||||
return nb;
|
return nb;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelectionComplete | T.NPSelection | T.VerbObject | T.ObjectSelectionComplete): T.VPSBlockComplete[];
|
export function adjustObjectSelection(
|
||||||
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelection | T.NPSelection | T.VerbObject | T.ObjectSelection | undefined): T.EPSBlock[];
|
blocks: Readonly<T.VPSBlock[]>,
|
||||||
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelection | T.ObjectSelectionComplete | T.VerbObject | T.NPSelection | undefined): T.VPSBlock[] | T.VPSBlockComplete[] {
|
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 nb = [...blocks];
|
||||||
const i = nb.findIndex(b => b.block && b.block.type === "objectSelection");
|
const i = nb.findIndex((b) => b.block && b.block.type === "objectSelection");
|
||||||
if (i === -1) {
|
if (i === -1) {
|
||||||
throw new Error("couldn't find objectSelection to modify");
|
throw new Error("couldn't find objectSelection to modify");
|
||||||
}
|
}
|
||||||
nb[i].block = typeof object === "object" && object?.type === "objectSelection"
|
nb[i].block =
|
||||||
|
typeof object === "object" && object?.type === "objectSelection"
|
||||||
? object
|
? object
|
||||||
: makeObjectSelection(object);
|
: makeObjectSelection(object);
|
||||||
return nb;
|
return nb;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shiftBlock<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number, direction: "back" | "forward"): B {
|
export function moveObjectToEnd(
|
||||||
const newIndex = index + (direction === "forward"
|
blocks: T.VPSBlockComplete[]
|
||||||
? 1 // (isNoObject(blocks[index + 1].block) ? 2 : 1)
|
): T.VPSBlockComplete[] {
|
||||||
: -1 // (isNoObject(blocks[index - 1].block) ? -2 : -2)
|
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 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;
|
return arrayMove(blocks, index, newIndex) as B;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insertNewAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B): B {
|
export function insertNewAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||||
|
blocks: B
|
||||||
|
): B {
|
||||||
return [makeAPBlock(), ...blocks] as B;
|
return [makeAPBlock(), ...blocks] as B;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number, AP: T.APSelection | undefined): B {
|
export function setAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||||
|
blocks: B,
|
||||||
|
index: number,
|
||||||
|
AP: T.APSelection | undefined
|
||||||
|
): B {
|
||||||
const nBlocks = [...blocks] as B;
|
const nBlocks = [...blocks] as B;
|
||||||
nBlocks[index].block = AP;
|
nBlocks[index].block = AP;
|
||||||
return nBlocks;
|
return nBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number): B {
|
export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||||
|
blocks: B,
|
||||||
|
index: number
|
||||||
|
): B {
|
||||||
const nBlocks = [...blocks] as B;
|
const nBlocks = [...blocks] as B;
|
||||||
nBlocks.splice(index, 1);
|
nBlocks.splice(index, 1);
|
||||||
return nBlocks;
|
return nBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNoObject(b: T.VPSBlock["block"] | T.EPSBlock["block"]): b is { type: "objectSelection", selection: "none" } {
|
export function isNoObject(
|
||||||
return !!(
|
b: T.VPSBlock["block"] | T.EPSBlock["block"]
|
||||||
b
|
): b is { type: "objectSelection"; selection: "none" } {
|
||||||
&&
|
return !!(b && b.type === "objectSelection" && b.selection === "none");
|
||||||
(b.type === "objectSelection" && b.selection === "none")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function specifyEquativeLength(blocksWVars: T.Block[][], length: "long" | "short"): T.Block[][] {
|
export function specifyEquativeLength(
|
||||||
|
blocksWVars: T.Block[][],
|
||||||
|
length: "long" | "short"
|
||||||
|
): T.Block[][] {
|
||||||
function specify(blocks: T.Block[]): T.Block[] {
|
function specify(blocks: T.Block[]): T.Block[] {
|
||||||
const i = blocks.findIndex(b => b.block.type === "equative");
|
const i = blocks.findIndex((b) => b.block.type === "equative");
|
||||||
if (i === -1) throw new Error("equative block not found in EPRendered");
|
if (i === -1) throw new Error("equative block not found in EPRendered");
|
||||||
const eq = blocks[i];
|
const eq = blocks[i];
|
||||||
if (eq.block.type !== "equative") throw new Error("error searching for equative block");
|
if (eq.block.type !== "equative")
|
||||||
|
throw new Error("error searching for equative block");
|
||||||
const adjusted = [...blocks];
|
const adjusted = [...blocks];
|
||||||
adjusted[i] = {
|
adjusted[i] = {
|
||||||
...eq,
|
...eq,
|
||||||
|
@ -268,23 +384,21 @@ export function isRenderedVerbB({ block }: T.Block): boolean {
|
||||||
if (block.type === "complement") {
|
if (block.type === "complement") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasEquativeWithLengths(blocks: T.Block[][]): boolean {
|
export function hasEquativeWithLengths(blocks: T.Block[][]): boolean {
|
||||||
const equative = blocks[0].find(x => x.block.type === "equative");
|
const equative = blocks[0].find((x) => x.block.type === "equative");
|
||||||
if (!equative) throw new Error("equative not found in blocks");
|
if (!equative) throw new Error("equative not found in blocks");
|
||||||
if (equative.block.type !== "equative") throw new Error("error finding equative in blocks");
|
if (equative.block.type !== "equative")
|
||||||
|
throw new Error("error finding equative in blocks");
|
||||||
return "long" in equative.block.equative.ps;
|
return "long" in equative.block.equative.ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrayMove<X>(ar: X[], old_index: number, new_index: number): X[] {
|
function arrayMove<X>(ar: X[], old_index: number, new_index: number): X[] {
|
||||||
const arr = [...ar];
|
const arr = [...ar];
|
||||||
const new_i = (new_index >= arr.length)
|
const new_i =
|
||||||
? (arr.length - 1)
|
new_index >= arr.length ? arr.length - 1 : new_index < 0 ? 0 : new_index;
|
||||||
: (new_index < 0)
|
|
||||||
? 0
|
|
||||||
: new_index;
|
|
||||||
arr.splice(new_i, 0, arr.splice(old_index, 1)[0]);
|
arr.splice(new_i, 0, arr.splice(old_index, 1)[0]);
|
||||||
return arr;
|
return arr;
|
||||||
};
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import {
|
||||||
specifyEquativeLength,
|
specifyEquativeLength,
|
||||||
} from "./blocks-utils";
|
} from "./blocks-utils";
|
||||||
import { blank, kidsBlank } from "../misc-helpers";
|
import { blank, kidsBlank } from "../misc-helpers";
|
||||||
|
import { monoidPsStringWVars } from "../fp-ps";
|
||||||
|
import { concatAll } from "fp-ts/lib/Monoid";
|
||||||
|
|
||||||
type BlankoutOptions = {
|
type BlankoutOptions = {
|
||||||
equative?: boolean;
|
equative?: boolean;
|
||||||
|
@ -215,64 +217,66 @@ export function combineIntoText(
|
||||||
subjectPerson: T.Person,
|
subjectPerson: T.Person,
|
||||||
blankOut?: BlankoutOptions
|
blankOut?: BlankoutOptions
|
||||||
): T.PsString[] {
|
): T.PsString[] {
|
||||||
function removeDoubleBlanks(x: T.PsString): T.PsString {
|
return piecesWVars
|
||||||
return {
|
.map((pieces) => {
|
||||||
p: x.p.replace(blank.p + blank.p, blank.p),
|
const psVarsBlocks = getPsVarsBlocks(
|
||||||
f: x.f.replace(blank.f + blank.f, blank.f),
|
applyBlankOut(pieces, blankOut),
|
||||||
};
|
subjectPerson
|
||||||
|
);
|
||||||
|
return concatAll(monoidPsStringWVars)(psVarsBlocks);
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
}
|
}
|
||||||
function combine(pieces: (T.Block | T.Kid | T.PsString)[]): T.PsString[] {
|
|
||||||
const first = pieces[0];
|
function getPsVarsBlocks(
|
||||||
const next = pieces[1];
|
pieces: (T.Block | T.Kid | T.PsString)[],
|
||||||
const rest = pieces.slice(1);
|
subjectPerson: T.Person
|
||||||
// better to do map-reduce
|
): T.PsString[][] {
|
||||||
// map the blocks into monoids [T.PsString] (with appropriate space blocks) and then concat them all together
|
const space = [{ p: " ", f: " " }];
|
||||||
const firstPs =
|
const phToCliticNegSpace = [{ p: "", f: "-" }];
|
||||||
"p" in first
|
const endIndex = pieces.length - 1;
|
||||||
? [first]
|
return pieces.reduce<T.PsString[][]>((acc, x, i) => {
|
||||||
: (blankOut?.equative &&
|
const next = pieces[i + 1];
|
||||||
"block" in first &&
|
if ("p" in x) {
|
||||||
first.block.type === "equative") ||
|
return [...acc, [x]];
|
||||||
(blankOut?.verb && "block" in first && isRenderedVerbB(first)) ||
|
}
|
||||||
|
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 &&
|
(blankOut?.predicate &&
|
||||||
"block" in first &&
|
"block" in x &&
|
||||||
first.block.type === "predicateSelection")
|
x.block.type === "predicateSelection")
|
||||||
? [blank]
|
) {
|
||||||
: blankOut?.ba && "kid" in first && first.kid.type === "ba"
|
return blank;
|
||||||
? [kidsBlank]
|
|
||||||
: blankOut?.negative &&
|
|
||||||
"block" in first &&
|
|
||||||
first.block.type === "negative"
|
|
||||||
? [{ p: "", f: "" }]
|
|
||||||
: getPsFromPiece(first, subjectPerson);
|
|
||||||
if (!rest.length) {
|
|
||||||
return firstPs;
|
|
||||||
}
|
}
|
||||||
return combine(rest)
|
if (blankOut?.ba && "kid" in x && x.kid.type === "ba") {
|
||||||
.flatMap((r) =>
|
return kidsBlank;
|
||||||
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);
|
if (blankOut?.negative && "block" in x && x.block.type === "negative") {
|
||||||
|
return { p: "", f: "" };
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPsFromPiece(
|
function getPsFromPiece(
|
||||||
|
|
|
@ -12,14 +12,18 @@ export function makeAdverbSelection(entry: T.AdverbEntry): T.AdverbSelection {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeLocativeAdverbSelection(entry: T.LocativeAdverbEntry): T.LocativeAdverbSelection {
|
export function makeLocativeAdverbSelection(
|
||||||
|
entry: T.LocativeAdverbEntry
|
||||||
|
): T.LocativeAdverbSelection {
|
||||||
return {
|
return {
|
||||||
type: "loc. adv.",
|
type: "loc. adv.",
|
||||||
entry: entry,
|
entry: entry,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeAdjectiveSelection(entry: T.AdjectiveEntry): T.AdjectiveSelection {
|
export function makeAdjectiveSelection(
|
||||||
|
entry: T.AdjectiveEntry
|
||||||
|
): T.AdjectiveSelection {
|
||||||
return {
|
return {
|
||||||
type: "adjective",
|
type: "adjective",
|
||||||
entry: entry,
|
entry: entry,
|
||||||
|
@ -27,7 +31,9 @@ export function makeAdjectiveSelection(entry: T.AdjectiveEntry): T.AdjectiveSele
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelection {
|
export function makeParticipleSelection(
|
||||||
|
verb: T.VerbEntry
|
||||||
|
): T.ParticipleSelection {
|
||||||
return {
|
return {
|
||||||
type: "participle",
|
type: "participle",
|
||||||
verb,
|
verb,
|
||||||
|
@ -35,7 +41,11 @@ export function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelectio
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeNounSelection(entry: T.NounEntry, old: T.NounSelection | undefined, dynamicComplement?: true): T.NounSelection {
|
export function makeNounSelection(
|
||||||
|
entry: T.NounEntry,
|
||||||
|
old: T.NounSelection | undefined,
|
||||||
|
complementType?: "dynamic" | "generative stative"
|
||||||
|
): T.NounSelection {
|
||||||
const number = isPluralNounEntry(entry) ? "plural" : "singular";
|
const number = isPluralNounEntry(entry) ? "plural" : "singular";
|
||||||
return {
|
return {
|
||||||
type: "noun",
|
type: "noun",
|
||||||
|
@ -44,9 +54,10 @@ export function makeNounSelection(entry: T.NounEntry, old: T.NounSelection | und
|
||||||
genderCanChange: isUnisexNounEntry(entry),
|
genderCanChange: isUnisexNounEntry(entry),
|
||||||
number,
|
number,
|
||||||
numberCanChange: number === "singular",
|
numberCanChange: number === "singular",
|
||||||
adjectives: (!dynamicComplement && old) ? old.adjectives : [],
|
adjectives: !complementType && old ? old.adjectives : [],
|
||||||
possesor: !dynamicComplement ? old?.possesor : undefined,
|
possesor: !complementType ? old?.possesor : undefined,
|
||||||
dynamicComplement,
|
dynamicComplement: complementType === "dynamic",
|
||||||
|
genStativeComplement: complementType === "generative stative",
|
||||||
demonstrative: undefined,
|
demonstrative: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import { mapVerbRenderedOutput } from "../fmaps";
|
import { mapVerbRenderedOutput } from "../fp-ps";
|
||||||
import { removeAccents } from "../accent-helpers";
|
import { removeAccents } from "../accent-helpers";
|
||||||
import { getPersonFromNP, isPastTense } from "./vp-tools";
|
import { getPersonFromNP, isPastTense } from "./vp-tools";
|
||||||
import { isImperativeTense, isPattern4Entry } from "../type-predicates";
|
import { isImperativeTense, isPattern4Entry } from "../type-predicates";
|
||||||
|
@ -19,6 +19,7 @@ import {
|
||||||
getMiniPronounPs,
|
getMiniPronounPs,
|
||||||
} from "./render-common";
|
} from "./render-common";
|
||||||
import { renderComplementSelection } from "./render-complement";
|
import { renderComplementSelection } from "./render-complement";
|
||||||
|
import { statVerb } from "../new-verb-engine/roots-and-stems";
|
||||||
|
|
||||||
export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
||||||
const subject = getSubjectSelection(VP.blocks).selection;
|
const subject = getSubjectSelection(VP.blocks).selection;
|
||||||
|
@ -45,8 +46,18 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
||||||
king,
|
king,
|
||||||
complementPerson,
|
complementPerson,
|
||||||
});
|
});
|
||||||
|
// TODO: for dynamic -
|
||||||
const { vbs, hasBa } = renderVerb({
|
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,
|
tense: VP.verb.tense,
|
||||||
subject: subjectPerson,
|
subject: subjectPerson,
|
||||||
object: objectPerson,
|
object: objectPerson,
|
||||||
|
@ -128,7 +139,6 @@ export function insertNegative(
|
||||||
if (!negative) {
|
if (!negative) {
|
||||||
return [blocks.flat().map(makeBlock)];
|
return [blocks.flat().map(makeBlock)];
|
||||||
}
|
}
|
||||||
const blocksA = blocks.flat().map(makeBlock);
|
|
||||||
const blocksNoAccentA = mapVerbRenderedOutput(removeAccents, blocks)
|
const blocksNoAccentA = mapVerbRenderedOutput(removeAccents, blocks)
|
||||||
.flat()
|
.flat()
|
||||||
.map(makeBlock);
|
.map(makeBlock);
|
||||||
|
@ -138,13 +148,13 @@ export function insertNegative(
|
||||||
// swapped ending with negative for ability and perfect verb forms
|
// swapped ending with negative for ability and perfect verb forms
|
||||||
if (nonStandPerfectiveSplit) {
|
if (nonStandPerfectiveSplit) {
|
||||||
return [
|
return [
|
||||||
insertFromEnd(swapEndingBlocks(blocksA), neg, 2),
|
insertFromEnd(swapEndingBlocks(blocksNoAccentA), neg, 2),
|
||||||
insertFromEnd(swapEndingBlocks(blocksA, 2), neg, 3),
|
insertFromEnd(swapEndingBlocks(blocksNoAccentA, 2), neg, 3),
|
||||||
insertFromEnd(blocksNoAccentA, neg, 1),
|
insertFromEnd(blocksNoAccentA, neg, 1),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
insertFromEnd(swapEndingBlocks(blocksA), neg, 2),
|
insertFromEnd(swapEndingBlocks(blocksNoAccentA), neg, 2),
|
||||||
insertFromEnd(blocksNoAccentA, neg, 1),
|
insertFromEnd(blocksNoAccentA, neg, 1),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -280,8 +290,9 @@ function whatsAdjustable(
|
||||||
VP: T.VPSelectionComplete
|
VP: T.VPSelectionComplete
|
||||||
): "both" | "king" | "servant" {
|
): "both" | "king" | "servant" {
|
||||||
// TODO: intransitive dynamic compounds?
|
// TODO: intransitive dynamic compounds?
|
||||||
return VP.verb.isCompound === "dynamic" &&
|
return VP.verb.isCompound === "dynamic" ||
|
||||||
VP.verb.transitivity === "transitive"
|
(VP.verb.isCompound === "generative stative" &&
|
||||||
|
VP.verb.transitivity === "transitive")
|
||||||
? isPastTense(VP.verb.tense)
|
? isPastTense(VP.verb.tense)
|
||||||
? "servant"
|
? "servant"
|
||||||
: "king"
|
: "king"
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import {
|
import { makeNounSelection } from "./make-selections";
|
||||||
makeNounSelection,
|
|
||||||
} from "./make-selections";
|
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import { getVerbInfo } from "../verb-info";
|
import { getVerbInfo } from "../verb-info";
|
||||||
import {
|
import {
|
||||||
|
@ -9,16 +7,24 @@ import {
|
||||||
getSubjectSelection,
|
getSubjectSelection,
|
||||||
makeObjectSelection,
|
makeObjectSelection,
|
||||||
makeSubjectSelection,
|
makeSubjectSelection,
|
||||||
|
moveObjectToEnd,
|
||||||
} from "./blocks-utils";
|
} from "./blocks-utils";
|
||||||
|
|
||||||
export function makeVPSelectionState(
|
export function makeVPSelectionState(
|
||||||
verb: T.VerbEntry,
|
verb: T.VerbEntry,
|
||||||
os?: T.VPSelectionState,
|
os?: T.VPSelectionState
|
||||||
): T.VPSelectionState {
|
): T.VPSelectionState {
|
||||||
const info = getVerbInfo(verb.entry, verb.complement);
|
const info = getVerbInfo(verb.entry, verb.complement);
|
||||||
const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound")
|
const subject =
|
||||||
? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true)
|
os?.verb.voice === "passive" && info.type === "dynamic compound"
|
||||||
: (os?.blocks ? getSubjectSelection(os.blocks).selection : undefined);
|
? makeNounSelection(
|
||||||
|
info.objComplement.entry as T.NounEntry,
|
||||||
|
undefined,
|
||||||
|
"dynamic"
|
||||||
|
)
|
||||||
|
: os?.blocks
|
||||||
|
? getSubjectSelection(os.blocks).selection
|
||||||
|
: undefined;
|
||||||
function getTransObjFromos() {
|
function getTransObjFromos() {
|
||||||
const osObj = os ? getObjectSelection(os.blocks).selection : undefined;
|
const osObj = os ? getObjectSelection(os.blocks).selection : undefined;
|
||||||
if (
|
if (
|
||||||
|
@ -26,32 +32,52 @@ export function makeVPSelectionState(
|
||||||
osObj === "none" ||
|
osObj === "none" ||
|
||||||
typeof osObj === "number" ||
|
typeof osObj === "number" ||
|
||||||
os.verb.isCompound === "dynamic" ||
|
os.verb.isCompound === "dynamic" ||
|
||||||
(osObj?.selection.type === "noun" && osObj.selection.dynamicComplement)
|
(osObj?.selection.type === "noun" &&
|
||||||
) return undefined;
|
(osObj.selection.dynamicComplement ||
|
||||||
|
osObj.selection.genStativeComplement))
|
||||||
|
)
|
||||||
|
return undefined;
|
||||||
return osObj;
|
return osObj;
|
||||||
}
|
}
|
||||||
const transitivity: T.Transitivity = "grammaticallyTransitive" in info
|
const transitivity: T.Transitivity =
|
||||||
? "transitive"
|
"grammaticallyTransitive" in info ? "transitive" : info.transitivity;
|
||||||
: info.transitivity;
|
const object =
|
||||||
const object = (transitivity === "grammatically transitive")
|
transitivity === "grammatically transitive"
|
||||||
? T.Person.ThirdPlurMale
|
? T.Person.ThirdPlurMale
|
||||||
: (info.type === "dynamic compound" && os?.verb.voice !== "passive")
|
: (info.type === "dynamic compound" ||
|
||||||
? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true)
|
info.type === "generative stative compound") &&
|
||||||
: (transitivity === "transitive" && os?.verb.voice !== "passive")
|
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()
|
? getTransObjFromos()
|
||||||
: "none";
|
: "none";
|
||||||
const isCompound = ("stative" in info || info.type === "stative compound")
|
const isCompound =
|
||||||
|
"stative" in info && info.type === "dynamic or generative stative compound"
|
||||||
|
? "generative stative"
|
||||||
|
: "stative" in info || info.type === "stative compound"
|
||||||
? "stative"
|
? "stative"
|
||||||
: info.type === "dynamic compound"
|
: info.type === "dynamic compound"
|
||||||
? "dynamic"
|
? "dynamic"
|
||||||
: false;
|
: false;
|
||||||
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
|
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
|
||||||
const dynAuxVerb: T.VerbEntry | undefined = isCompound !== "dynamic"
|
const dynAuxVerb: T.VerbEntry | undefined =
|
||||||
|
isCompound !== "dynamic"
|
||||||
? undefined
|
? undefined
|
||||||
: info.type === "dynamic compound"
|
: info.type === "dynamic compound"
|
||||||
? { entry: info.auxVerb } as T.VerbEntry
|
? ({ entry: info.auxVerb } as T.VerbEntry)
|
||||||
: "dynamic" in info
|
: "dynamic" in info
|
||||||
? { entry: info.dynamic.auxVerb } as T.VerbEntry
|
? ({ entry: info.dynamic.auxVerb } as T.VerbEntry)
|
||||||
: undefined;
|
: undefined;
|
||||||
const blocks = [
|
const blocks = [
|
||||||
{ key: Math.random(), block: makeSubjectSelection(subject) },
|
{ key: Math.random(), block: makeSubjectSelection(subject) },
|
||||||
|
@ -69,9 +95,8 @@ export function makeVPSelectionState(
|
||||||
tenseCategory: os ? os.verb.tenseCategory : "basic",
|
tenseCategory: os ? os.verb.tenseCategory : "basic",
|
||||||
transitivity,
|
transitivity,
|
||||||
isCompound,
|
isCompound,
|
||||||
voice: transitivity === "transitive"
|
voice:
|
||||||
? (os?.verb.voice || "active")
|
transitivity === "transitive" ? os?.verb.voice || "active" : "active",
|
||||||
: "active",
|
|
||||||
negative: os ? os.verb.negative : false,
|
negative: os ? os.verb.negative : false,
|
||||||
canChangeTransitivity: "grammaticallyTransitive" in info,
|
canChangeTransitivity: "grammaticallyTransitive" in info,
|
||||||
canChangeVoice: transitivity === "transitive",
|
canChangeVoice: transitivity === "transitive",
|
||||||
|
@ -80,7 +105,8 @@ export function makeVPSelectionState(
|
||||||
externalComplement: takesExternalComplement(verb)
|
externalComplement: takesExternalComplement(verb)
|
||||||
? { type: "complement", selection: { type: "unselected" } }
|
? { type: "complement", selection: { type: "unselected" } }
|
||||||
: undefined,
|
: undefined,
|
||||||
form: (os && info.type !== "dynamic compound")
|
form:
|
||||||
|
os && info.type !== "dynamic compound"
|
||||||
? os.form
|
? os.form
|
||||||
: { removeKing: false, shrinkServant: false },
|
: { removeKing: false, shrinkServant: false },
|
||||||
};
|
};
|
||||||
|
@ -96,33 +122,62 @@ function takesExternalComplement(v: T.VerbEntry): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeStatDyn(v: T.VPSelectionState, s: "dynamic" | "stative"): T.VPSelectionState {
|
export function changeStatDyn(
|
||||||
|
v: T.VPSelectionState,
|
||||||
|
s: "dynamic" | "stative"
|
||||||
|
): T.VPSelectionState {
|
||||||
const info = getVerbInfo(v.verb.verb.entry, v.verb.verb.complement);
|
const info = getVerbInfo(v.verb.verb.entry, v.verb.verb.complement);
|
||||||
if (!("stative" in info)) {
|
if (!("stative" in info)) {
|
||||||
return v;
|
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 {
|
return {
|
||||||
...v,
|
...v,
|
||||||
blocks: adjustObjectSelection(
|
blocks:
|
||||||
v.blocks,
|
s === "stative" && info.type === "dynamic or generative stative compound"
|
||||||
s === "dynamic"
|
? moveObjectToEnd(newBlocks)
|
||||||
? { type: "NP", selection: makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, undefined, true) }
|
: newBlocks,
|
||||||
: undefined,
|
|
||||||
),
|
|
||||||
verb: {
|
verb: {
|
||||||
...v.verb,
|
...v.verb,
|
||||||
isCompound: s,
|
isCompound:
|
||||||
dynAuxVerb: s === "dynamic"
|
info.type === "dynamic or generative stative compound" &&
|
||||||
? { entry: info.dynamic.auxVerb } as T.VerbEntry
|
s === "stative"
|
||||||
|
? "generative stative"
|
||||||
|
: s,
|
||||||
|
dynAuxVerb:
|
||||||
|
s === "dynamic"
|
||||||
|
? ({ entry: info.dynamic.auxVerb } as T.VerbEntry)
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeTransitivity(v: T.VPSelectionState, transitivity: "transitive" | "grammatically transitive"): T.VPSelectionState {
|
export function changeTransitivity(
|
||||||
|
v: T.VPSelectionState,
|
||||||
|
transitivity: "transitive" | "grammatically transitive"
|
||||||
|
): T.VPSelectionState {
|
||||||
return {
|
return {
|
||||||
...v,
|
...v,
|
||||||
blocks: adjustObjectSelection(v.blocks, transitivity === "grammatically transitive" ? T.Person.ThirdPlurMale : undefined),
|
blocks: adjustObjectSelection(
|
||||||
|
v.blocks,
|
||||||
|
transitivity === "grammatically transitive"
|
||||||
|
? T.Person.ThirdPlurMale
|
||||||
|
: undefined
|
||||||
|
),
|
||||||
verb: {
|
verb: {
|
||||||
...v.verb,
|
...v.verb,
|
||||||
transitivity,
|
transitivity,
|
||||||
|
|
|
@ -132,12 +132,14 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||||
// throw new Error("unknown tense");
|
// throw new Error("unknown tense");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export function getPersonFromNP(np: T.NPSelection): T.Person;
|
|
||||||
export function getPersonFromNP(
|
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;
|
): T.Person | undefined;
|
||||||
export function getPersonFromNP(
|
export function getPersonFromNP(
|
||||||
np: T.NPSelection | T.ObjectNP
|
np: T.NPSelection | T.Rendered<T.NPSelection> | T.ObjectNP
|
||||||
): T.Person | undefined {
|
): T.Person | undefined {
|
||||||
if (np === "none") {
|
if (np === "none") {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -28,15 +28,9 @@ import {
|
||||||
psStringEquals,
|
psStringEquals,
|
||||||
} from "./p-text-helpers";
|
} from "./p-text-helpers";
|
||||||
import { makePsString } from "./accent-and-ps-utils";
|
import { makePsString } from "./accent-and-ps-utils";
|
||||||
import {
|
import { inflectYey } from "./pashto-inflector";
|
||||||
inflectYey,
|
import { accentOnNFromEnd, removeAccents } from "./accent-helpers";
|
||||||
} from "./pashto-inflector";
|
import { mapInflections } from "./fp-ps";
|
||||||
import {
|
|
||||||
accentOnNFromEnd, removeAccents,
|
|
||||||
} from "./accent-helpers";
|
|
||||||
import {
|
|
||||||
mapInflections,
|
|
||||||
} from "./fmaps";
|
|
||||||
import { pashtoConsonants } from "./pashto-consonants";
|
import { pashtoConsonants } from "./pashto-consonants";
|
||||||
import {
|
import {
|
||||||
checkForIrregularConjugation,
|
checkForIrregularConjugation,
|
||||||
|
@ -49,14 +43,29 @@ import {
|
||||||
} from "./misc-helpers";
|
} from "./misc-helpers";
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
|
|
||||||
const dummyEntry: T.DictionaryEntry = { i: 0, p: "", f: "", g: "", e: "", c: "", ts: 0 };
|
const dummyEntry: T.DictionaryEntry = {
|
||||||
|
i: 0,
|
||||||
|
p: "",
|
||||||
|
f: "",
|
||||||
|
g: "",
|
||||||
|
e: "",
|
||||||
|
c: "",
|
||||||
|
ts: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const aayTail = [{p: "ای", f: "aay" }, { p: "ی", f: "ey" }];
|
const aayTail = [
|
||||||
|
{ p: "ای", f: "aay" },
|
||||||
|
{ p: "ی", f: "ey" },
|
||||||
|
];
|
||||||
|
|
||||||
export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.DictionaryEntry, verbInfo?: T.NonComboVerbInfo): T.VerbOutput {
|
export function conjugateVerb(
|
||||||
|
entry: T.DictionaryEntry,
|
||||||
|
complement?: T.DictionaryEntry,
|
||||||
|
verbInfo?: T.NonComboVerbInfo
|
||||||
|
): T.VerbOutput {
|
||||||
if (!(entry.c && entry.c.slice(0, 2) === "v.")) {
|
if (!(entry.c && entry.c.slice(0, 2) === "v.")) {
|
||||||
throw new Error("not a verb");
|
throw new Error("not a verb");
|
||||||
};
|
}
|
||||||
const irregularConj = checkForIrregularConjugation(entry);
|
const irregularConj = checkForIrregularConjugation(entry);
|
||||||
if (irregularConj) {
|
if (irregularConj) {
|
||||||
return irregularConj;
|
return irregularConj;
|
||||||
|
@ -65,16 +74,35 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
||||||
if (info.type === "transitive or grammatically transitive simple") {
|
if (info.type === "transitive or grammatically transitive simple") {
|
||||||
return {
|
return {
|
||||||
info,
|
info,
|
||||||
transitive: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("/gramm. trans.", "") : "" }, dummyEntry, info.transitive) as T.VerbConjugation,
|
transitive: conjugateVerb(
|
||||||
grammaticallyTransitive: conjugateVerb({ ...entry, c: entry.c ? entry.c?.replace("trans./", "") : "" }, dummyEntry, info.grammaticallyTransitive) as T.VerbConjugation,
|
{ ...entry, c: entry.c ? entry.c.replace("/gramm. trans.", "") : "" },
|
||||||
|
dummyEntry,
|
||||||
|
info.transitive
|
||||||
|
) as T.VerbConjugation,
|
||||||
|
grammaticallyTransitive: conjugateVerb(
|
||||||
|
{ ...entry, c: entry.c ? entry.c?.replace("trans./", "") : "" },
|
||||||
|
dummyEntry,
|
||||||
|
info.grammaticallyTransitive
|
||||||
|
) as T.VerbConjugation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.type === "dynamic or stative compound" || info.type === "dynamic or generative stative compound") {
|
if (
|
||||||
|
info.type === "dynamic or stative compound" ||
|
||||||
|
info.type === "dynamic or generative stative compound"
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
info,
|
info,
|
||||||
stative: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("dyn./", "") : "" }, dummyEntry, info.stative) as T.VerbConjugation,
|
stative: conjugateVerb(
|
||||||
dynamic: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("/stat.", "") : "" }, dummyEntry, info.dynamic) as T.VerbConjugation,
|
{ ...entry, c: entry.c ? entry.c.replace("dyn./", "") : "" },
|
||||||
|
dummyEntry,
|
||||||
|
info.stative
|
||||||
|
) as T.VerbConjugation,
|
||||||
|
dynamic: conjugateVerb(
|
||||||
|
{ ...entry, c: entry.c ? entry.c.replace("/stat.", "") : "" },
|
||||||
|
dummyEntry,
|
||||||
|
info.dynamic
|
||||||
|
) as T.VerbConjugation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +119,22 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
||||||
hypothetical: makeHypotheticalContent(nonComboInfo),
|
hypothetical: makeHypotheticalContent(nonComboInfo),
|
||||||
participle: makeParticipleContent(nonComboInfo),
|
participle: makeParticipleContent(nonComboInfo),
|
||||||
perfect: makePerfectContent(nonComboInfo),
|
perfect: makePerfectContent(nonComboInfo),
|
||||||
..."singularForm" in info ? {
|
...("singularForm" in info
|
||||||
singularForm: conjugateVerb(entry, complement, info.singularForm) as T.VerbConjugation,
|
? {
|
||||||
} : {},
|
singularForm: conjugateVerb(
|
||||||
|
entry,
|
||||||
|
complement,
|
||||||
|
info.singularForm
|
||||||
|
) as T.VerbConjugation,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
// if transitive include passive voice
|
// if transitive include passive voice
|
||||||
...info.transitivity !== "intransitive" ? {
|
...(info.transitivity !== "intransitive"
|
||||||
|
? {
|
||||||
// TODO: STATIVE COMPOUND VERSION OF THIS
|
// TODO: STATIVE COMPOUND VERSION OF THIS
|
||||||
passive: makePassiveContent(nonComboInfo),
|
passive: makePassiveContent(nonComboInfo),
|
||||||
} : {},
|
}
|
||||||
|
: {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
return nonComboInfo.transitivity === "grammatically transitive"
|
return nonComboInfo.transitivity === "grammatically transitive"
|
||||||
|
@ -108,7 +144,9 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
||||||
: conjugation;
|
: conjugation;
|
||||||
}
|
}
|
||||||
|
|
||||||
function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation {
|
function conjugateDynamicCompound(
|
||||||
|
info: T.DynamicCompoundVerbInfo
|
||||||
|
): T.VerbConjugation {
|
||||||
// const willUseImperative = !(
|
// const willUseImperative = !(
|
||||||
// info.type === "dynamic compound"
|
// info.type === "dynamic compound"
|
||||||
// && info.transitivity === "intransitive"
|
// && info.transitivity === "intransitive"
|
||||||
|
@ -116,18 +154,24 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
// );
|
// );
|
||||||
const auxConj = enforceObject(
|
const auxConj = enforceObject(
|
||||||
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
|
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
|
||||||
info.objComplement.person,
|
info.objComplement.person
|
||||||
);
|
);
|
||||||
const complement = info.objComplement.plural
|
const complement = info.objComplement.plural
|
||||||
? info.objComplement.plural
|
? info.objComplement.plural
|
||||||
: makePsString(info.objComplement.entry.p, info.objComplement.entry.f);
|
: makePsString(info.objComplement.entry.p, info.objComplement.entry.f);
|
||||||
const makeAspectContent = (aspect: T.Aspect): T.AspectContent => {
|
const makeAspectContent = (aspect: T.Aspect): T.AspectContent => {
|
||||||
const makeDynamicModalContent = (): T.ModalContent => {
|
const makeDynamicModalContent = (): T.ModalContent => {
|
||||||
const nonImperative = addToForm([complement, " "], auxConj[aspect].modal.nonImperative);
|
const nonImperative = addToForm(
|
||||||
|
[complement, " "],
|
||||||
|
auxConj[aspect].modal.nonImperative
|
||||||
|
);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const past = addToForm([complement, " "], auxConj[aspect].modal.past);
|
const past = addToForm([complement, " "], auxConj[aspect].modal.past);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
const hypotheticalPast = addToForm([complement, " "], auxConj[aspect].modal.hypotheticalPast);
|
const hypotheticalPast = addToForm(
|
||||||
|
[complement, " "],
|
||||||
|
auxConj[aspect].modal.hypotheticalPast
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
nonImperative,
|
nonImperative,
|
||||||
future,
|
future,
|
||||||
|
@ -151,20 +195,18 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
habitualPast,
|
habitualPast,
|
||||||
modal,
|
modal,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
const hypothetical = addToForm([complement, " "], auxConj.hypothetical);
|
const hypothetical = addToForm([complement, " "], auxConj.hypothetical);
|
||||||
const auxPPart = auxConj.participle.past;
|
const auxPPart = auxConj.participle.past;
|
||||||
const participle = {
|
const participle = {
|
||||||
present: concatInflections(complement, auxConj.participle.present),
|
present: concatInflections(complement, auxConj.participle.present),
|
||||||
past: (
|
past:
|
||||||
(("long" in auxPPart) && ("masc" in auxPPart.long)) ||
|
("long" in auxPPart && "masc" in auxPPart.long) || "masc" in auxPPart
|
||||||
("masc" in auxPPart)
|
? // @ts-ignore
|
||||||
)
|
concatInflections(complement, auxPPart)
|
||||||
// @ts-ignore
|
: // @ts-ignore
|
||||||
? concatInflections(complement, auxPPart)
|
concatPsString(complement, " ", auxPPart),
|
||||||
// @ts-ignore
|
};
|
||||||
: concatPsString(complement, " ", auxPPart)
|
|
||||||
}
|
|
||||||
const makePerfect = (pset: T.PerfectContent): T.PerfectContent => ({
|
const makePerfect = (pset: T.PerfectContent): T.PerfectContent => ({
|
||||||
halfPerfect: addToForm([complement, " "], pset.halfPerfect),
|
halfPerfect: addToForm([complement, " "], pset.halfPerfect),
|
||||||
past: addToForm([complement, " "], pset.past),
|
past: addToForm([complement, " "], pset.past),
|
||||||
|
@ -176,12 +218,21 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
pastSubjunctive: addToForm([complement, " "], pset.pastSubjunctive),
|
pastSubjunctive: addToForm([complement, " "], pset.pastSubjunctive),
|
||||||
wouldHaveBeen: addToForm([complement, " "], pset.wouldHaveBeen),
|
wouldHaveBeen: addToForm([complement, " "], pset.wouldHaveBeen),
|
||||||
});
|
});
|
||||||
const makePassiveAspectContent = (aspect: T.Aspect, passive: T.PassiveContent): T.AspectContentPassive => {
|
const makePassiveAspectContent = (
|
||||||
const nonImperative = addToForm([complement, " "], passive[aspect].nonImperative);
|
aspect: T.Aspect,
|
||||||
|
passive: T.PassiveContent
|
||||||
|
): T.AspectContentPassive => {
|
||||||
|
const nonImperative = addToForm(
|
||||||
|
[complement, " "],
|
||||||
|
passive[aspect].nonImperative
|
||||||
|
);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const past = addToForm([complement, " "], passive[aspect].past);
|
const past = addToForm([complement, " "], passive[aspect].past);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal);
|
const modal = makePassiveModalSection(
|
||||||
|
[complement, " "],
|
||||||
|
stativeAux.intransitive.imperfective.modal
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
imperative: undefined,
|
imperative: undefined,
|
||||||
nonImperative,
|
nonImperative,
|
||||||
|
@ -189,8 +240,8 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
past,
|
past,
|
||||||
habitualPast,
|
habitualPast,
|
||||||
modal,
|
modal,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
return {
|
return {
|
||||||
info,
|
info,
|
||||||
imperfective: makeAspectContent("imperfective"),
|
imperfective: makeAspectContent("imperfective"),
|
||||||
|
@ -198,24 +249,36 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
||||||
hypothetical,
|
hypothetical,
|
||||||
participle,
|
participle,
|
||||||
perfect: makePerfect(auxConj.perfect),
|
perfect: makePerfect(auxConj.perfect),
|
||||||
...auxConj.passive ? {
|
...(auxConj.passive
|
||||||
|
? {
|
||||||
passive: {
|
passive: {
|
||||||
imperfective: makePassiveAspectContent("imperfective", auxConj.passive),
|
imperfective: makePassiveAspectContent(
|
||||||
|
"imperfective",
|
||||||
|
auxConj.passive
|
||||||
|
),
|
||||||
perfective: makePassiveAspectContent("perfective", auxConj.passive),
|
perfective: makePassiveAspectContent("perfective", auxConj.passive),
|
||||||
perfect: makePerfect(auxConj.passive.perfect),
|
perfect: makePerfect(auxConj.passive.perfect),
|
||||||
},
|
},
|
||||||
} : {},
|
}
|
||||||
...info.singularForm ? {
|
: {}),
|
||||||
singularForm: conjugateDynamicCompound(info.singularForm)
|
...(info.singularForm
|
||||||
} : {},
|
? {
|
||||||
...info.intransitiveForm ? {
|
singularForm: conjugateDynamicCompound(info.singularForm),
|
||||||
intransitiveForm: conjugateDynamicCompound(info.intransitiveForm)
|
}
|
||||||
} : {},
|
: {}),
|
||||||
|
...(info.intransitiveForm
|
||||||
|
? {
|
||||||
|
intransitiveForm: conjugateDynamicCompound(info.intransitiveForm),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.AspectContent {
|
function makeAspectContent(
|
||||||
if ((info.type === "stative compound") && spaceInForm(info.root[aspect])) {
|
info: T.NonComboVerbInfo,
|
||||||
|
aspect: T.Aspect
|
||||||
|
): T.AspectContent {
|
||||||
|
if (info.type === "stative compound" && spaceInForm(info.root[aspect])) {
|
||||||
return makeStativeCompoundSeperatedAspectContent(info, aspect);
|
return makeStativeCompoundSeperatedAspectContent(info, aspect);
|
||||||
}
|
}
|
||||||
const stem = noPersInfs(info.stem[aspect]);
|
const stem = noPersInfs(info.stem[aspect]);
|
||||||
|
@ -223,7 +286,10 @@ function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.Aspect
|
||||||
const nonImperative = addToForm([stem], presentEndings);
|
const nonImperative = addToForm([stem], presentEndings);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const imperative = addToForm([stem], imperativeEndings);
|
const imperative = addToForm([stem], imperativeEndings);
|
||||||
const roughPast = addToForm([root], pastEndings) as T.LengthOptions<T.VerbBlock>;
|
const roughPast = addToForm(
|
||||||
|
[root],
|
||||||
|
pastEndings
|
||||||
|
) as T.LengthOptions<T.VerbBlock>;
|
||||||
// add accents and idiosyncratic third person sing masc forms
|
// add accents and idiosyncratic third person sing masc forms
|
||||||
const past = finishSimpleVerbPast(info, aspect, roughPast);
|
const past = finishSimpleVerbPast(info, aspect, roughPast);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
|
@ -237,14 +303,26 @@ function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.Aspect
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T.ModalContent {
|
function makeJoinedModalContent(
|
||||||
|
info: T.NonComboVerbInfo,
|
||||||
|
aspectIn: T.Aspect
|
||||||
|
): T.ModalContent {
|
||||||
const aspect: T.Aspect = noPerfectiveModal(info) ? "imperfective" : aspectIn;
|
const aspect: T.Aspect = noPerfectiveModal(info) ? "imperfective" : aspectIn;
|
||||||
const aux = stativeAux.intransitive.perfective;
|
const aux = stativeAux.intransitive.perfective;
|
||||||
const rAndT = info.yulEnding
|
const rAndT = info.yulEnding
|
||||||
? [concatPsString(noPersInfs(info.root[aspect]).long, aayTail[1]), concatPsString(noPersInfs(info.root[aspect]).long, aayTail[0])]
|
? [
|
||||||
: [concatPsString(noPersInfs(info.root[aspect]), aayTail[1]), concatPsString(noPersInfs(info.root[aspect]), aayTail[0])]
|
concatPsString(noPersInfs(info.root[aspect]).long, aayTail[1]),
|
||||||
const rootAndTail = aspect === "imperfective"
|
concatPsString(noPersInfs(info.root[aspect]).long, aayTail[0]),
|
||||||
? rAndT.map((x: T.PsString | T.LengthOptions<T.PsString>) => accentImperfectiveModalRootAndTail(info, x))
|
]
|
||||||
|
: [
|
||||||
|
concatPsString(noPersInfs(info.root[aspect]), aayTail[1]),
|
||||||
|
concatPsString(noPersInfs(info.root[aspect]), aayTail[0]),
|
||||||
|
];
|
||||||
|
const rootAndTail =
|
||||||
|
aspect === "imperfective"
|
||||||
|
? rAndT.map((x: T.PsString | T.LengthOptions<T.PsString>) =>
|
||||||
|
accentImperfectiveModalRootAndTail(info, x)
|
||||||
|
)
|
||||||
: rAndT;
|
: rAndT;
|
||||||
|
|
||||||
const nonImperative = addToForm([rootAndTail, " "], aux.nonImperative);
|
const nonImperative = addToForm([rootAndTail, " "], aux.nonImperative);
|
||||||
|
@ -252,7 +330,7 @@ function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T
|
||||||
const past = addToForm(
|
const past = addToForm(
|
||||||
[rootAndTail, " "],
|
[rootAndTail, " "],
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
aux.past.short,
|
aux.past.short
|
||||||
);
|
);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
function mhp(rt: T.PsString[]): T.VerbBlock {
|
function mhp(rt: T.PsString[]): T.VerbBlock {
|
||||||
|
@ -270,11 +348,13 @@ function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T
|
||||||
[form, form],
|
[form, form],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
const hypotheticalPast = "short" in rootAndTail[0]
|
const hypotheticalPast =
|
||||||
|
"short" in rootAndTail[0]
|
||||||
? {
|
? {
|
||||||
short: mhp(rootAndTail.map((rt) => "short" in rt ? rt.short : rt)),
|
short: mhp(rootAndTail.map((rt) => ("short" in rt ? rt.short : rt))),
|
||||||
long: mhp(rootAndTail.map((rt) => "short" in rt ? rt.long : rt)),
|
long: mhp(rootAndTail.map((rt) => ("short" in rt ? rt.long : rt))),
|
||||||
} : mhp(rootAndTail.map((rt) => "short" in rt ? rt.long : rt));
|
}
|
||||||
|
: mhp(rootAndTail.map((rt) => ("short" in rt ? rt.long : rt)));
|
||||||
|
|
||||||
// const hypotheticalPast = [
|
// const hypotheticalPast = [
|
||||||
// [concatPsString(rootAndTail[0], " ", { p: "سو", f: "shw" }, aayTail[0])]
|
// [concatPsString(rootAndTail[0], " ", { p: "سو", f: "shw" }, aayTail[0])]
|
||||||
|
@ -289,18 +369,26 @@ function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbInfo, aspect: T.Aspect): T.AspectContent {
|
function makeStativeCompoundSeperatedAspectContent(
|
||||||
|
info: T.StativeCompoundVerbInfo,
|
||||||
|
aspect: T.Aspect
|
||||||
|
): T.AspectContent {
|
||||||
const transitivity = getTransitivity(info);
|
const transitivity = getTransitivity(info);
|
||||||
const complement: T.UnisexInflections = aspect === "imperfective"
|
const complement: T.UnisexInflections =
|
||||||
|
aspect === "imperfective"
|
||||||
? mapInflections(removeAccents, info.complement)
|
? mapInflections(removeAccents, info.complement)
|
||||||
: info.complement;
|
: info.complement;
|
||||||
const presentComplement = (transitivity === "transitive" && complementInflects(complement))
|
const presentComplement =
|
||||||
|
transitivity === "transitive" && complementInflects(complement)
|
||||||
? unisexInfToObjectMatrix(complement) // transitive verb requires an object matrix for the complex
|
? unisexInfToObjectMatrix(complement) // transitive verb requires an object matrix for the complex
|
||||||
: complement; // intransitive verb doesn't require that because the complement matches the subject
|
: complement; // intransitive verb doesn't require that because the complement matches the subject
|
||||||
|
|
||||||
function makeTransitiveStativeModalContent() {
|
function makeTransitiveStativeModalContent() {
|
||||||
const aux = stativeAux[transitivity][aspect].modal;
|
const aux = stativeAux[transitivity][aspect].modal;
|
||||||
const nonImperative = addToForm([presentComplement, " "], aux.nonImperative);
|
const nonImperative = addToForm(
|
||||||
|
[presentComplement, " "],
|
||||||
|
aux.nonImperative
|
||||||
|
);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const past = addToForm([complement, " "], aux.past);
|
const past = addToForm([complement, " "], aux.past);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
|
@ -318,7 +406,7 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
|
||||||
// CHECK, does this work with transitive and intransitive??
|
// CHECK, does this work with transitive and intransitive??
|
||||||
const nonImperative = addToForm(
|
const nonImperative = addToForm(
|
||||||
[presentComplement, " "],
|
[presentComplement, " "],
|
||||||
stativeAux[transitivity][aspect].nonImperative,
|
stativeAux[transitivity][aspect].nonImperative
|
||||||
);
|
);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const imperative = addToForm([presentComplement, " "], aux.imperative);
|
const imperative = addToForm([presentComplement, " "], aux.imperative);
|
||||||
|
@ -330,27 +418,38 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
|
||||||
past,
|
past,
|
||||||
habitualPast,
|
habitualPast,
|
||||||
imperative,
|
imperative,
|
||||||
modal: info.transitivity === "transitive"
|
modal:
|
||||||
|
info.transitivity === "transitive"
|
||||||
? makeTransitiveStativeModalContent()
|
? makeTransitiveStativeModalContent()
|
||||||
: makeJoinedModalContent(info, "imperfective"),
|
: makeJoinedModalContent(info, "imperfective"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
||||||
function makeStativeCompoundSepHypotheticalContent(info: T.StativeCompoundVerbInfo): T.VerbForm {
|
function makeStativeCompoundSepHypotheticalContent(
|
||||||
|
info: T.StativeCompoundVerbInfo
|
||||||
|
): T.VerbForm {
|
||||||
const transitivity = getTransitivity(info);
|
const transitivity = getTransitivity(info);
|
||||||
const aux = stativeAux[transitivity].hypothetical;
|
const aux = stativeAux[transitivity].hypothetical;
|
||||||
return addToForm([
|
return addToForm(
|
||||||
(transitivity === "transitive" && complementInflects(info.complement))
|
[
|
||||||
|
transitivity === "transitive" && complementInflects(info.complement)
|
||||||
? unisexInfToObjectMatrix(info.complement)
|
? unisexInfToObjectMatrix(info.complement)
|
||||||
: info.complement,
|
: info.complement,
|
||||||
" ",
|
" ",
|
||||||
], aux);
|
],
|
||||||
|
aux
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (("complement" in info) && spaceInForm(info.root.imperfective)) {
|
if ("complement" in info && spaceInForm(info.root.imperfective)) {
|
||||||
return makeStativeCompoundSepHypotheticalContent(info as T.StativeCompoundVerbInfo);
|
return makeStativeCompoundSepHypotheticalContent(
|
||||||
|
info as T.StativeCompoundVerbInfo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const makeHypothetical = (root: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>, length: "short" | "long"): T.PsString[] => {
|
const makeHypothetical = (
|
||||||
|
root: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>,
|
||||||
|
length: "short" | "long"
|
||||||
|
): T.PsString[] => {
|
||||||
if ("mascSing" in root) {
|
if ("mascSing" in root) {
|
||||||
// BIG TODO: SHOULD THERE BE PERS INFS HERE?? IGNORING THEM NOW IF THEY EXIST
|
// BIG TODO: SHOULD THERE BE PERS INFS HERE?? IGNORING THEM NOW IF THEY EXIST
|
||||||
return makeHypothetical(root.mascSing, length) as T.PsString[];
|
return makeHypothetical(root.mascSing, length) as T.PsString[];
|
||||||
|
@ -358,16 +457,22 @@ function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
||||||
return [
|
return [
|
||||||
accentOnNFromEnd(
|
accentOnNFromEnd(
|
||||||
concatPsString(root[length], aayTail[0]),
|
concatPsString(root[length], aayTail[0]),
|
||||||
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0),
|
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0)
|
||||||
),
|
),
|
||||||
accentOnNFromEnd(
|
accentOnNFromEnd(
|
||||||
concatPsString(root[length], aayTail[1]),
|
concatPsString(root[length], aayTail[1]),
|
||||||
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0),
|
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0)
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
const short = makeHypothetical(info.root.imperfective, "short") as T.ArrayOneOrMore<T.PsString>;
|
const short = makeHypothetical(
|
||||||
const long = makeHypothetical(info.root.imperfective, "long") as T.ArrayOneOrMore<T.PsString>;
|
info.root.imperfective,
|
||||||
|
"short"
|
||||||
|
) as T.ArrayOneOrMore<T.PsString>;
|
||||||
|
const long = makeHypothetical(
|
||||||
|
info.root.imperfective,
|
||||||
|
"long"
|
||||||
|
) as T.ArrayOneOrMore<T.PsString>;
|
||||||
return {
|
return {
|
||||||
short: [
|
short: [
|
||||||
[short, short],
|
[short, short],
|
||||||
|
@ -390,13 +495,26 @@ function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
||||||
|
|
||||||
function makeParticipleContent(info: T.NonComboVerbInfo): T.ParticipleContent {
|
function makeParticipleContent(info: T.NonComboVerbInfo): T.ParticipleContent {
|
||||||
const transitivity = getTransitivity(info);
|
const transitivity = getTransitivity(info);
|
||||||
const past = ("complement" in info)
|
const past =
|
||||||
? concatInflections(info.complement, stativeAux[transitivity].participle.past as T.UnisexInflections)
|
"complement" in info
|
||||||
: ("objComplement" in info)
|
? concatInflections(
|
||||||
? concatInflections(info.objComplement.plural ? info.objComplement.plural : info.objComplement.entry, stativeAux[transitivity].participle.past as T.UnisexInflections)
|
info.complement,
|
||||||
|
stativeAux[transitivity].participle.past as T.UnisexInflections
|
||||||
|
)
|
||||||
|
: "objComplement" in info
|
||||||
|
? concatInflections(
|
||||||
|
info.objComplement.plural
|
||||||
|
? info.objComplement.plural
|
||||||
|
: info.objComplement.entry,
|
||||||
|
stativeAux[transitivity].participle.past as T.UnisexInflections
|
||||||
|
)
|
||||||
: inflectYey(noPersInfs(info.participle.past));
|
: inflectYey(noPersInfs(info.participle.past));
|
||||||
const present = ("complement" in info && spaceInForm(info.root.imperfective))
|
const present =
|
||||||
? concatInflections(info.complement, stativeAux[transitivity].participle.present as T.UnisexInflections)
|
"complement" in info && spaceInForm(info.root.imperfective)
|
||||||
|
? concatInflections(
|
||||||
|
info.complement,
|
||||||
|
stativeAux[transitivity].participle.present as T.UnisexInflections
|
||||||
|
)
|
||||||
: inflectYey(noPersInfs(info.participle.present));
|
: inflectYey(noPersInfs(info.participle.present));
|
||||||
return {
|
return {
|
||||||
present, // PRESENT PARTICIPLE inflected
|
present, // PRESENT PARTICIPLE inflected
|
||||||
|
@ -406,22 +524,45 @@ function makeParticipleContent(info: T.NonComboVerbInfo): T.ParticipleContent {
|
||||||
|
|
||||||
function makePerfectContent(info: T.NonComboVerbInfo): T.PerfectContent {
|
function makePerfectContent(info: T.NonComboVerbInfo): T.PerfectContent {
|
||||||
const transitivity = getTransitivity(info);
|
const transitivity = getTransitivity(info);
|
||||||
const pastPart: (" " | T.SingleOrLengthOpts<T.UnisexInflections> | T.SingleOrLengthOpts<T.PsString>)[] =
|
const pastPart: (
|
||||||
(info.type === "stative compound")
|
| " "
|
||||||
// for stative compounds
|
| T.SingleOrLengthOpts<T.UnisexInflections>
|
||||||
? [mapInflections(removeAccents, info.complement), " ", stativeAux[transitivity].participle.past]
|
| T.SingleOrLengthOpts<T.PsString>
|
||||||
// for regular compounds
|
)[] =
|
||||||
: [inflectYey(noPersInfs(info.participle.past))]
|
info.type === "stative compound"
|
||||||
|
? // for stative compounds
|
||||||
|
[
|
||||||
|
mapInflections(removeAccents, info.complement),
|
||||||
|
" ",
|
||||||
|
stativeAux[transitivity].participle.past,
|
||||||
|
]
|
||||||
|
: // for regular compounds
|
||||||
|
[inflectYey(noPersInfs(info.participle.past))];
|
||||||
|
|
||||||
const halfPerfect = addToForm([...pastPart], emptyVerbBlock);
|
const halfPerfect = addToForm([...pastPart], emptyVerbBlock);
|
||||||
const past = addToForm([...pastPart, " "], equativeEndings.past.short);
|
const past = addToForm([...pastPart, " "], equativeEndings.past.short);
|
||||||
const present = addToForm([...pastPart, " "], equativeEndings.present);
|
const present = addToForm([...pastPart, " "], equativeEndings.present);
|
||||||
const habitual = addToForm([...pastPart, " "], equativeEndings.habitual);
|
const habitual = addToForm([...pastPart, " "], equativeEndings.habitual);
|
||||||
const subjunctive = addToForm([...pastPart, " "], equativeEndings.subjunctive);
|
const subjunctive = addToForm(
|
||||||
const future = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.habitual);
|
[...pastPart, " "],
|
||||||
const wouldBe = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.past.short);
|
equativeEndings.subjunctive
|
||||||
const pastSubjunctive = addToForm([...pastPart, " "], equativeEndings.pastSubjunctive);
|
);
|
||||||
const wouldHaveBeen = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.pastSubjunctive);
|
const future = addToForm(
|
||||||
|
[baParticle, " ", ...pastPart, " "],
|
||||||
|
equativeEndings.habitual
|
||||||
|
);
|
||||||
|
const wouldBe = addToForm(
|
||||||
|
[baParticle, " ", ...pastPart, " "],
|
||||||
|
equativeEndings.past.short
|
||||||
|
);
|
||||||
|
const pastSubjunctive = addToForm(
|
||||||
|
[...pastPart, " "],
|
||||||
|
equativeEndings.pastSubjunctive
|
||||||
|
);
|
||||||
|
const wouldHaveBeen = addToForm(
|
||||||
|
[baParticle, " ", ...pastPart, " "],
|
||||||
|
equativeEndings.pastSubjunctive
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
halfPerfect, // Past Participle
|
halfPerfect, // Past Participle
|
||||||
past, // Past Participle + Past Equative
|
past, // Past Participle + Past Equative
|
||||||
|
@ -436,29 +577,31 @@ function makePerfectContent(info: T.NonComboVerbInfo): T.PerfectContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePassiveContent(info: T.NonComboVerbInfo): {
|
function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
imperfective: T.AspectContentPassive // --╖ ASPECT = "imperfective"
|
imperfective: T.AspectContentPassive; // --╖ ASPECT = "imperfective"
|
||||||
perfective: T.AspectContentPassive // --╜ ASPECT = "perfective"
|
perfective: T.AspectContentPassive; // --╜ ASPECT = "perfective"
|
||||||
perfect: T.PerfectContent;
|
perfect: T.PerfectContent;
|
||||||
} {
|
} {
|
||||||
function makePassiveAspectContent(aspect: T.Aspect): T.AspectContentPassive {
|
function makePassiveAspectContent(aspect: T.Aspect): T.AspectContentPassive {
|
||||||
if ("complement" in info && spaceInForm(info.root[aspect])) {
|
if ("complement" in info && spaceInForm(info.root[aspect])) {
|
||||||
// seperated stative compound verb
|
// seperated stative compound verb
|
||||||
const bridge = aspect === "imperfective"
|
const bridge =
|
||||||
|
aspect === "imperfective"
|
||||||
? noPersInfs(stativeAux.transitive.info.root.imperfective).long
|
? noPersInfs(stativeAux.transitive.info.root.imperfective).long
|
||||||
: passiveStativeBridge;
|
: passiveStativeBridge;
|
||||||
const nonImperative = addToForm(
|
const nonImperative = addToForm(
|
||||||
[info.complement, " ", bridge, " "],
|
[info.complement, " ", bridge, " "],
|
||||||
stativeAux.intransitive[aspect].nonImperative,
|
stativeAux.intransitive[aspect].nonImperative
|
||||||
);
|
);
|
||||||
const future = addToForm([baParticle, " "], nonImperative);
|
const future = addToForm([baParticle, " "], nonImperative);
|
||||||
const past = addToForm(
|
const past = addToForm(
|
||||||
[info.complement, " ", bridge, " "],
|
[info.complement, " ", bridge, " "],
|
||||||
stativeAux.intransitive[aspect].past,
|
stativeAux.intransitive[aspect].past
|
||||||
);
|
);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
const modal = makePassiveModalSection([
|
const modal = makePassiveModalSection(
|
||||||
noPersInfs(info.root.imperfective).long, " ",
|
[noPersInfs(info.root.imperfective).long, " "],
|
||||||
], stativeAux.intransitive.imperfective.modal);
|
stativeAux.intransitive.imperfective.modal
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
imperative: undefined,
|
imperative: undefined,
|
||||||
nonImperative,
|
nonImperative,
|
||||||
|
@ -468,7 +611,8 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
modal,
|
modal,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const root = (aspect === "imperfective")
|
const root =
|
||||||
|
aspect === "imperfective"
|
||||||
? removeAccents(noPersInfs(info.root[aspect]).long)
|
? removeAccents(noPersInfs(info.root[aspect]).long)
|
||||||
: noPersInfs(info.root[aspect]).long;
|
: noPersInfs(info.root[aspect]).long;
|
||||||
const aux = stativeAux.intransitive[aspect];
|
const aux = stativeAux.intransitive[aspect];
|
||||||
|
@ -477,7 +621,10 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
const past = addToForm([root, " "], aux.past);
|
const past = addToForm([root, " "], aux.past);
|
||||||
const habitualPast = addToForm([baParticle, " "], past);
|
const habitualPast = addToForm([baParticle, " "], past);
|
||||||
const auxModal = aux.modal;
|
const auxModal = aux.modal;
|
||||||
const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal);
|
const modal = makePassiveModalSection(
|
||||||
|
[noPersInfs(info.root.imperfective).long, " "],
|
||||||
|
auxModal
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
imperative: undefined,
|
imperative: undefined,
|
||||||
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
|
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
|
||||||
|
@ -491,11 +638,12 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
past: concatPsString(
|
past: concatPsString(
|
||||||
removeAccents(noPersInfs(info.root.imperfective).long),
|
removeAccents(noPersInfs(info.root.imperfective).long),
|
||||||
" ",
|
" ",
|
||||||
stativeAux.intransitive.info.participle.past as T.PsString,
|
stativeAux.intransitive.info.participle.past as T.PsString
|
||||||
),
|
),
|
||||||
present: { p: "ن ا", f: "n / a" },
|
present: { p: "ن ا", f: "n / a" },
|
||||||
};
|
};
|
||||||
const perfect = (info.type === "stative compound")
|
const perfect =
|
||||||
|
info.type === "stative compound"
|
||||||
? makePassivePerfectContent(info)
|
? makePassivePerfectContent(info)
|
||||||
: makePerfectContent({ ...info, participle: simpleVerbParticiple });
|
: makePerfectContent({ ...info, participle: simpleVerbParticiple });
|
||||||
return {
|
return {
|
||||||
|
@ -505,7 +653,18 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePassiveModalSection(base: Array<" " | T.SingleOrLengthOpts<T.PsString> | T.SingleOrLengthOpts<T.UnisexInflections> | T.SingleOrLengthOpts<T.PsString>[] | T.SingleOrLengthOpts<T.PsString[]> | T.OptionalPersonInflections<T.PsString> | T.VerbBlock>, auxModal: T.ModalContent): T.ModalContent {
|
function makePassiveModalSection(
|
||||||
|
base: Array<
|
||||||
|
| " "
|
||||||
|
| T.SingleOrLengthOpts<T.PsString>
|
||||||
|
| T.SingleOrLengthOpts<T.UnisexInflections>
|
||||||
|
| T.SingleOrLengthOpts<T.PsString>[]
|
||||||
|
| T.SingleOrLengthOpts<T.PsString[]>
|
||||||
|
| T.OptionalPersonInflections<T.PsString>
|
||||||
|
| T.VerbBlock
|
||||||
|
>,
|
||||||
|
auxModal: T.ModalContent
|
||||||
|
): T.ModalContent {
|
||||||
return {
|
return {
|
||||||
nonImperative: addToForm(base, auxModal.nonImperative),
|
nonImperative: addToForm(base, auxModal.nonImperative),
|
||||||
future: addToForm(base, auxModal.future),
|
future: addToForm(base, auxModal.future),
|
||||||
|
@ -515,44 +674,73 @@ function makePassiveModalSection(base: Array<" " | T.SingleOrLengthOpts<T.PsStri
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePassivePerfectContent(info: T.StativeCompoundVerbInfo): T.PerfectContent {
|
function makePassivePerfectContent(
|
||||||
|
info: T.StativeCompoundVerbInfo
|
||||||
|
): T.PerfectContent {
|
||||||
const pPart = stativeAux.intransitive.participle.past;
|
const pPart = stativeAux.intransitive.participle.past;
|
||||||
// will always be transitive
|
// will always be transitive
|
||||||
const halfPerfect = addToForm(
|
const halfPerfect = addToForm(
|
||||||
[info.complement, " ", passiveStativeBridge, " ", pPart],
|
[info.complement, " ", passiveStativeBridge, " ", pPart],
|
||||||
emptyVerbBlock,
|
emptyVerbBlock
|
||||||
);
|
);
|
||||||
const past = addToForm(
|
const past = addToForm(
|
||||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||||
equativeEndings.past.short,
|
equativeEndings.past.short
|
||||||
);
|
);
|
||||||
const present = addToForm(
|
const present = addToForm(
|
||||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||||
equativeEndings.present,
|
equativeEndings.present
|
||||||
);
|
);
|
||||||
const habitual = addToForm(
|
const habitual = addToForm(
|
||||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||||
equativeEndings.habitual,
|
equativeEndings.habitual
|
||||||
);
|
);
|
||||||
const subjunctive = addToForm(
|
const subjunctive = addToForm(
|
||||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||||
equativeEndings.subjunctive,
|
equativeEndings.subjunctive
|
||||||
);
|
);
|
||||||
const future = addToForm(
|
const future = addToForm(
|
||||||
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[
|
||||||
equativeEndings.habitual,
|
baParticle,
|
||||||
|
" ",
|
||||||
|
info.complement,
|
||||||
|
" ",
|
||||||
|
passiveStativeBridge,
|
||||||
|
" ",
|
||||||
|
pPart,
|
||||||
|
" ",
|
||||||
|
],
|
||||||
|
equativeEndings.habitual
|
||||||
);
|
);
|
||||||
const wouldBe = addToForm(
|
const wouldBe = addToForm(
|
||||||
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[
|
||||||
equativeEndings.past.short,
|
baParticle,
|
||||||
|
" ",
|
||||||
|
info.complement,
|
||||||
|
" ",
|
||||||
|
passiveStativeBridge,
|
||||||
|
" ",
|
||||||
|
pPart,
|
||||||
|
" ",
|
||||||
|
],
|
||||||
|
equativeEndings.past.short
|
||||||
);
|
);
|
||||||
const pastSubjunctive = addToForm(
|
const pastSubjunctive = addToForm(
|
||||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||||
equativeEndings.pastSubjunctive,
|
equativeEndings.pastSubjunctive
|
||||||
);
|
);
|
||||||
const wouldHaveBeen = addToForm(
|
const wouldHaveBeen = addToForm(
|
||||||
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
[
|
||||||
equativeEndings.pastSubjunctive,
|
baParticle,
|
||||||
|
" ",
|
||||||
|
info.complement,
|
||||||
|
" ",
|
||||||
|
passiveStativeBridge,
|
||||||
|
" ",
|
||||||
|
pPart,
|
||||||
|
" ",
|
||||||
|
],
|
||||||
|
equativeEndings.pastSubjunctive
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
halfPerfect,
|
halfPerfect,
|
||||||
|
@ -567,7 +755,10 @@ function makePassivePerfectContent(info: T.StativeCompoundVerbInfo): T.PerfectCo
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjugation {
|
function enforceObject(
|
||||||
|
conj: T.VerbConjugation,
|
||||||
|
person: T.Person
|
||||||
|
): T.VerbConjugation {
|
||||||
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
|
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
|
||||||
// WATCH OUT FOR DIFFERENCES WITH allOnePersonInflection (for the object w/ present tense)
|
// WATCH OUT FOR DIFFERENCES WITH allOnePersonInflection (for the object w/ present tense)
|
||||||
// AND allOnePersonVerbForm (for the object w/ past tense object)
|
// AND allOnePersonVerbForm (for the object w/ past tense object)
|
||||||
|
@ -584,7 +775,9 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
||||||
hypotheticalPast: allOnePersonVerbForm(as.modal.hypotheticalPast, person),
|
hypotheticalPast: allOnePersonVerbForm(as.modal.hypotheticalPast, person),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const modifyParticiple = (part: T.ParticipleContent): T.ParticipleContent => ({
|
const modifyParticiple = (
|
||||||
|
part: T.ParticipleContent
|
||||||
|
): T.ParticipleContent => ({
|
||||||
// TODO: What to do with this!
|
// TODO: What to do with this!
|
||||||
present: allOnePersonInflection(part.present, person),
|
present: allOnePersonInflection(part.present, person),
|
||||||
past: chooseParticipleInflection(part.past, person),
|
past: chooseParticipleInflection(part.past, person),
|
||||||
|
@ -600,7 +793,9 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
||||||
pastSubjunctive: allOnePersonVerbForm(perf.pastSubjunctive, person),
|
pastSubjunctive: allOnePersonVerbForm(perf.pastSubjunctive, person),
|
||||||
wouldHaveBeen: allOnePersonVerbForm(perf.wouldHaveBeen, person),
|
wouldHaveBeen: allOnePersonVerbForm(perf.wouldHaveBeen, person),
|
||||||
});
|
});
|
||||||
const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({
|
const modifyPassiveAspect = (
|
||||||
|
as: T.AspectContentPassive
|
||||||
|
): T.AspectContentPassive => ({
|
||||||
imperative: undefined,
|
imperative: undefined,
|
||||||
nonImperative: allOnePersonVerbForm(as.nonImperative, person),
|
nonImperative: allOnePersonVerbForm(as.nonImperative, person),
|
||||||
future: allOnePersonVerbForm(as.future, person),
|
future: allOnePersonVerbForm(as.future, person),
|
||||||
|
@ -620,13 +815,15 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
||||||
perfective: modifyPastInAspect(conj.perfective),
|
perfective: modifyPastInAspect(conj.perfective),
|
||||||
participle: modifyParticiple(conj.participle),
|
participle: modifyParticiple(conj.participle),
|
||||||
perfect: modifyPerfect(conj.perfect),
|
perfect: modifyPerfect(conj.perfect),
|
||||||
...conj.passive ? {
|
...(conj.passive
|
||||||
|
? {
|
||||||
passive: {
|
passive: {
|
||||||
imperfective: modifyPassiveAspect(conj.passive.imperfective),
|
imperfective: modifyPassiveAspect(conj.passive.imperfective),
|
||||||
perfective: modifyPassiveAspect(conj.passive.perfective),
|
perfective: modifyPassiveAspect(conj.passive.perfective),
|
||||||
perfect: modifyPerfect(conj.passive.perfect),
|
perfect: modifyPerfect(conj.passive.perfect),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
} : {},
|
: {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,18 +832,29 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
||||||
function finishSimpleVerbPast(
|
function finishSimpleVerbPast(
|
||||||
info: T.NonComboVerbInfo,
|
info: T.NonComboVerbInfo,
|
||||||
aspect: T.Aspect,
|
aspect: T.Aspect,
|
||||||
roughPast: T.LengthOptions<T.VerbBlock>,
|
roughPast: T.LengthOptions<T.VerbBlock>
|
||||||
): T.VerbForm {
|
): T.VerbForm {
|
||||||
const applyAccent = (block: T.VerbBlock, form: "short" | "long"): T.VerbBlock => (
|
const applyAccent = (
|
||||||
mapVerbBlock((item: T.PsString, rowNum: number | undefined, colNum: number | undefined) => {
|
block: T.VerbBlock,
|
||||||
const nonRedundantLEnding = (
|
form: "short" | "long"
|
||||||
(rowNum === 4 && colNum === 1) &&
|
): T.VerbBlock =>
|
||||||
|
mapVerbBlock(
|
||||||
|
(
|
||||||
|
item: T.PsString,
|
||||||
|
rowNum: number | undefined,
|
||||||
|
colNum: number | undefined
|
||||||
|
) => {
|
||||||
|
const nonRedundantLEnding =
|
||||||
|
rowNum === 4 &&
|
||||||
|
colNum === 1 &&
|
||||||
item.p.slice(-1) === "ل" &&
|
item.p.slice(-1) === "ل" &&
|
||||||
["ul", "úl"].includes(item.f.slice(-2))
|
["ul", "úl"].includes(item.f.slice(-2));
|
||||||
)
|
const n =
|
||||||
const n = (((form === "short") || nonRedundantLEnding) ? 0 : 1) + (info.yulEnding ? 1 : 0);
|
(form === "short" || nonRedundantLEnding ? 0 : 1) +
|
||||||
|
(info.yulEnding ? 1 : 0);
|
||||||
return accentOnNFromEnd(item, n);
|
return accentOnNFromEnd(item, n);
|
||||||
}, block)
|
},
|
||||||
|
block
|
||||||
);
|
);
|
||||||
const short = ensureShort3rdPersMascSing(info, aspect, roughPast.short);
|
const short = ensureShort3rdPersMascSing(info, aspect, roughPast.short);
|
||||||
if (aspect === "imperfective") {
|
if (aspect === "imperfective") {
|
||||||
|
@ -663,29 +871,24 @@ function finishSimpleVerbPast(
|
||||||
function ensureShort3rdPersMascSing(
|
function ensureShort3rdPersMascSing(
|
||||||
info: T.NonComboVerbInfo,
|
info: T.NonComboVerbInfo,
|
||||||
aspect: T.Aspect,
|
aspect: T.Aspect,
|
||||||
block: T.VerbBlock,
|
block: T.VerbBlock
|
||||||
): T.VerbBlock {
|
): T.VerbBlock {
|
||||||
const replace3rdPersMascSing = (
|
const replace3rdPersMascSing = (
|
||||||
replacement: T.ArrayOneOrMore<T.PsString>,
|
replacement: T.ArrayOneOrMore<T.PsString>,
|
||||||
block: T.VerbBlock,
|
block: T.VerbBlock
|
||||||
): T.VerbBlock => ([
|
): T.VerbBlock =>
|
||||||
...block.slice(0, 4),
|
[...block.slice(0, 4), [replacement, block[4][1]], block[5]] as T.VerbBlock;
|
||||||
[replacement, block[4][1]],
|
|
||||||
block[5],
|
|
||||||
] as T.VerbBlock);
|
|
||||||
const makeAawuForm = (root: T.PsString): T.PsString => {
|
const makeAawuForm = (root: T.PsString): T.PsString => {
|
||||||
const base = {
|
const base = {
|
||||||
p: root.p.slice(0, -1),
|
p: root.p.slice(0, -1),
|
||||||
f: root.f.slice(0, -2),
|
f: root.f.slice(0, -2),
|
||||||
};
|
};
|
||||||
return concatPsString(base, { p: "اوه", f: "aawu" });
|
return concatPsString(base, { p: "اوه", f: "aawu" });
|
||||||
}
|
};
|
||||||
const infinitive = noPersInfs(info.root.imperfective).long;
|
const infinitive = noPersInfs(info.root.imperfective).long;
|
||||||
const endsInAwul = (
|
const endsInAwul =
|
||||||
(["awul", "awúl"].includes(infinitive.f.slice(-4)))
|
["awul", "awúl"].includes(infinitive.f.slice(-4)) &&
|
||||||
&&
|
infinitive.p.slice(-2) === "ول";
|
||||||
(infinitive.p.slice(-2) === "ول")
|
|
||||||
);
|
|
||||||
if (endsInAwul) {
|
if (endsInAwul) {
|
||||||
const root = noPersInfs(info.root[aspect]).short;
|
const root = noPersInfs(info.root[aspect]).short;
|
||||||
return replace3rdPersMascSing([makeAawuForm(root)], block);
|
return replace3rdPersMascSing([makeAawuForm(root)], block);
|
||||||
|
@ -694,7 +897,8 @@ function ensureShort3rdPersMascSing(
|
||||||
const form = info.idiosyncraticThirdMascSing[aspect];
|
const form = info.idiosyncraticThirdMascSing[aspect];
|
||||||
// if it ends in a consonant, the special form will also have another
|
// if it ends in a consonant, the special form will also have another
|
||||||
// variation ending with a ه - u
|
// variation ending with a ه - u
|
||||||
const endsInAConsonant = (pashtoConsonants.includes(form.p.slice(-1)) || form.f.slice(-1) === "w");
|
const endsInAConsonant =
|
||||||
|
pashtoConsonants.includes(form.p.slice(-1)) || form.f.slice(-1) === "w";
|
||||||
const replacement: T.ArrayOneOrMore<T.PsString> = endsInAConsonant
|
const replacement: T.ArrayOneOrMore<T.PsString> = endsInAConsonant
|
||||||
? [
|
? [
|
||||||
form,
|
form,
|
||||||
|
@ -711,24 +915,28 @@ function ensureShort3rdPersMascSing(
|
||||||
function accentImperfectiveModalRootAndTail(
|
function accentImperfectiveModalRootAndTail(
|
||||||
info: T.NonComboVerbInfo,
|
info: T.NonComboVerbInfo,
|
||||||
rt: T.SingleOrLengthOpts<T.PsString>,
|
rt: T.SingleOrLengthOpts<T.PsString>,
|
||||||
length?: "long" | "short",
|
length?: "long" | "short"
|
||||||
): T.SingleOrLengthOpts<T.PsString> {
|
): T.SingleOrLengthOpts<T.PsString> {
|
||||||
if ("long" in rt) {
|
if ("long" in rt) {
|
||||||
return {
|
return {
|
||||||
short: accentImperfectiveModalRootAndTail(info, rt.short, "short") as T.PsString,
|
short: accentImperfectiveModalRootAndTail(
|
||||||
long: accentImperfectiveModalRootAndTail(info, rt.long, "long") as T.PsString,
|
info,
|
||||||
|
rt.short,
|
||||||
|
"short"
|
||||||
|
) as T.PsString,
|
||||||
|
long: accentImperfectiveModalRootAndTail(
|
||||||
|
info,
|
||||||
|
rt.long,
|
||||||
|
"long"
|
||||||
|
) as T.PsString,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
const n = info.yulEnding ? 2 : length === "short" ? 0 : 1;
|
||||||
const n = info.yulEnding
|
|
||||||
? 2
|
|
||||||
: length === "short"
|
|
||||||
? 0
|
|
||||||
: 1;
|
|
||||||
return accentOnNFromEnd(rt, n);
|
return accentOnNFromEnd(rt, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransitivity(info: T.VerbInfo): "transitive" | "intransitive" {
|
function getTransitivity(info: T.VerbInfo): "transitive" | "intransitive" {
|
||||||
return ("transitivity" in info && info.transitivity === "intransitive")
|
return "transitivity" in info && info.transitivity === "intransitive"
|
||||||
? "intransitive"
|
? "intransitive"
|
||||||
: "transitive";
|
: "transitive";
|
||||||
}
|
}
|
||||||
|
|
|
@ -693,7 +693,7 @@ export type VPRendered = {
|
||||||
servant: "subject" | "object" | undefined;
|
servant: "subject" | "object" | undefined;
|
||||||
isPast: boolean;
|
isPast: boolean;
|
||||||
isTransitive: boolean;
|
isTransitive: boolean;
|
||||||
isCompound: "stative" | "dynamic" | false;
|
isCompound: "stative" | "dynamic" | "generative stative" | false;
|
||||||
blocks: Block[][];
|
blocks: Block[][];
|
||||||
kids: Kid[];
|
kids: Kid[];
|
||||||
englishBase?: string[];
|
englishBase?: string[];
|
||||||
|
@ -811,7 +811,7 @@ export type VerbSelection = {
|
||||||
transitivity: Transitivity;
|
transitivity: Transitivity;
|
||||||
canChangeTransitivity: boolean;
|
canChangeTransitivity: boolean;
|
||||||
canChangeStatDyn: boolean;
|
canChangeStatDyn: boolean;
|
||||||
isCompound: "stative" | "dynamic" | false;
|
isCompound: "stative" | "dynamic" | "generative stative" | false;
|
||||||
voice: Voice;
|
voice: Voice;
|
||||||
canChangeVoice: boolean;
|
canChangeVoice: boolean;
|
||||||
negative: boolean;
|
negative: boolean;
|
||||||
|
@ -867,6 +867,7 @@ export type NounSelection = {
|
||||||
number: NounNumber;
|
number: NounNumber;
|
||||||
numberCanChange: boolean;
|
numberCanChange: boolean;
|
||||||
dynamicComplement?: boolean;
|
dynamicComplement?: boolean;
|
||||||
|
genStativeComplement?: boolean;
|
||||||
adjectives: AdjectiveSelection[];
|
adjectives: AdjectiveSelection[];
|
||||||
possesor: undefined | PossesorSelection;
|
possesor: undefined | PossesorSelection;
|
||||||
demonstrative: undefined | DemonstrativeSelection;
|
demonstrative: undefined | DemonstrativeSelection;
|
||||||
|
@ -1199,7 +1200,6 @@ export type MiniPronoun = {
|
||||||
export type RenderVerbOutput = {
|
export type RenderVerbOutput = {
|
||||||
hasBa: boolean;
|
hasBa: boolean;
|
||||||
vbs: VerbRenderedOutput;
|
vbs: VerbRenderedOutput;
|
||||||
objComp: Rendered<NPSelection> | undefined;
|
|
||||||
};
|
};
|
||||||
export type VerbRenderedOutput = [[VHead] | [], [VB, VBE] | [VBE]];
|
export type VerbRenderedOutput = [[VHead] | [], [VB, VBE] | [VBE]];
|
||||||
export type RootsStemsOutput = [[VHead] | [], [VB, VBA] | [VBA]]; // or perfect / equative
|
export type RootsStemsOutput = [[VHead] | [], [VB, VBA] | [VBA]]; // or perfect / equative
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
|
1527818320, // جارو کول - to sweep
|
||||||
|
1658796089458, // استري کول - to iron
|
||||||
1527816643, // استعفا کول - to resign, to quit (a job or position)
|
1527816643, // استعفا کول - to resign, to quit (a job or position)
|
||||||
1527817823, // اصرار کول - to insist, persist, demand
|
1527817823, // اصرار کول - to insist, persist, demand
|
||||||
1591002320547, // امر کول - to order, command
|
1591002320547, // امر کول - to order, command
|
||||||
|
@ -139,4 +141,4 @@ module.exports = [
|
||||||
1609599425410, // دعا کول - to pray
|
1609599425410, // دعا کول - to pray
|
||||||
1527812939, // منډې وهل - to run
|
1527812939, // منډې وهل - to run
|
||||||
1614602054303, // بدله اخیستل - to take revenge
|
1614602054303, // بدله اخیستل - to take revenge
|
||||||
]
|
];
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
|
1608137130992, // چیغه کول
|
||||||
1658537998960, // لېونی کول
|
1658537998960, // لېونی کول
|
||||||
1527812403, // بچ کول - to save, protect, guard, spare, rescue, economize
|
1527812403, // بچ کول - to save, protect, guard, spare, rescue, economize
|
||||||
1577299232429, // بدلول - to change, to adapt, exchange, replace
|
1577299232429, // بدلول - to change, to adapt, exchange, replace
|
||||||
|
@ -83,4 +84,4 @@ module.exports = [
|
||||||
1527816559, // یادول - to remember, to recall, to think on, to call
|
1527816559, // یادول - to remember, to recall, to think on, to call
|
||||||
1527813556, // یو ځای کول - to gather, bring together
|
1527813556, // یو ځای کول - to gather, bring together
|
||||||
1527815444, // زده کول - to learn, to teach
|
1527815444, // زده کول - to learn, to teach
|
||||||
]
|
];
|
||||||
|
|
|
@ -5427,7 +5427,7 @@ forwarded@0.2.0:
|
||||||
|
|
||||||
fp-ts@^2.16.0:
|
fp-ts@^2.16.0:
|
||||||
version "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==
|
integrity sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==
|
||||||
|
|
||||||
fragment-cache@^0.2.1:
|
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"
|
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
|
||||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
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:
|
react-overlays@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.npmjs.org/react-overlays/-/react-overlays-5.1.1.tgz"
|
resolved "https://registry.npmjs.org/react-overlays/-/react-overlays-5.1.1.tgz"
|
||||||
|
|
Loading…
Reference in New Issue