added adjectives to Nouns and also fixed the the issue with the nouns not saving the gender/number flexibility. Still need to refactor to keep the flexibility for the VerbSelections - (functions arent saved in useStickyState 🤦♂️)
This commit is contained in:
parent
3f9b1161d5
commit
06cd3d2f18
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@lingdocs/pashto-inflector",
|
||||
"version": "2.3.2",
|
||||
"version": "2.3.3",
|
||||
"author": "lingdocs.com",
|
||||
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
||||
"homepage": "https://verbs.lingdocs.com",
|
||||
|
|
|
@ -173,18 +173,21 @@ function massageSubjectChange(subject: T.NPSelection | undefined, old: T.EPSelec
|
|||
}
|
||||
if (subject.type === "pronoun" && old.predicate.type === "NP" && old.predicate.NP?.type === "noun" && isUnisexNounEntry(old.predicate.NP.entry)) {
|
||||
const predicate = old.predicate.NP;
|
||||
const numberAdjusted = predicate.changeNumber
|
||||
? predicate.changeNumber(personNumber(subject.person))
|
||||
: predicate;
|
||||
const fullyAdjusted = numberAdjusted.changeGender
|
||||
? numberAdjusted.changeGender(personGender(subject.person))
|
||||
: numberAdjusted;
|
||||
const adjusted = {
|
||||
...predicate,
|
||||
...predicate.numberCanChange ? {
|
||||
number: personNumber(subject.person),
|
||||
} : {},
|
||||
...predicate.genderCanChange ? {
|
||||
gender: personGender(subject.person),
|
||||
} : {},
|
||||
}
|
||||
return {
|
||||
...old,
|
||||
subject,
|
||||
predicate: {
|
||||
...old.predicate,
|
||||
NP: fullyAdjusted,
|
||||
NP: adjusted,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import * as T from "../../types";
|
||||
import { useState } from "react";
|
||||
import AdjectivePicker from "./AdjectivePicker";
|
||||
|
||||
function AdjectiveManager(props: {
|
||||
adjectives: T.AdjectiveSelection[],
|
||||
entryFeeder: T.EntryFeederSingleType<T.AdjectiveEntry>,
|
||||
opts: T.TextOptions,
|
||||
onChange: (adjs: T.AdjectiveSelection[]) => void,
|
||||
}) {
|
||||
const [adding, setAdding] = useState<boolean>(false);
|
||||
function handleChange(i: number) {
|
||||
return (a: T.AdjectiveSelection | undefined) => {
|
||||
if (a === undefined) return;
|
||||
const updated = [...props.adjectives];
|
||||
updated[i] = a;
|
||||
props.onChange(
|
||||
updated.filter((x): x is T.AdjectiveSelection => !!x)
|
||||
);
|
||||
};
|
||||
}
|
||||
function deleteAdj(i: number) {
|
||||
return () => {
|
||||
props.onChange(remove(props.adjectives, i));
|
||||
};
|
||||
}
|
||||
function handleAddNew(a: T.AdjectiveSelection | undefined) {
|
||||
if (a === undefined) return;
|
||||
setAdding(false);
|
||||
props.onChange([
|
||||
a,
|
||||
...props.adjectives,
|
||||
]);
|
||||
}
|
||||
// const flippedList = [...props.adjectives];
|
||||
// flippedList.reverse();
|
||||
// console.log(props.adjectives);
|
||||
return <div className="mb-1">
|
||||
{!!props.adjectives.length && <div className="d-flex flex-row justify-content-between">
|
||||
<h6>Adjectives</h6>
|
||||
{!adding ? <h6 onClick={() => setAdding(true)}>+ Adj.</h6> : <div></div>}
|
||||
</div>}
|
||||
{adding && <div>
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<div>Add Adjective</div>
|
||||
<div onClick={() => setAdding(false)}>Cancel</div>
|
||||
</div>
|
||||
<AdjectivePicker
|
||||
noTitle
|
||||
adjective={undefined}
|
||||
entryFeeder={props.entryFeeder}
|
||||
opts={props.opts}
|
||||
onChange={handleAddNew}
|
||||
/>
|
||||
</div>}
|
||||
{props.adjectives.map((adj, i) => (
|
||||
<div className="d-flex flex-row align-items-baseline">
|
||||
<AdjectivePicker
|
||||
noTitle
|
||||
key={`adj${i}`}
|
||||
adjective={adj}
|
||||
entryFeeder={props.entryFeeder}
|
||||
opts={props.opts}
|
||||
onChange={handleChange(i)}
|
||||
/>
|
||||
<div onClick={deleteAdj(i)} className="ml-4">
|
||||
<div className="fas fa-trash" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{!adding && !props.adjectives.length && <h6 className="clickable" style={{ float: "right" }}>
|
||||
<div onClick={() => setAdding(true)}>+ Adj.</div>
|
||||
</h6>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function remove<X>(arr: X[], i: number): X[] {
|
||||
return [
|
||||
...arr.slice(0, i),
|
||||
...arr.slice(i + 1),
|
||||
];
|
||||
}
|
||||
|
||||
export default AdjectiveManager;
|
|
@ -6,6 +6,7 @@ function AdjectivePicker(props: {
|
|||
adjective: T.AdjectiveSelection | undefined,
|
||||
onChange: (p: T.AdjectiveSelection | undefined) => void,
|
||||
opts: T.TextOptions,
|
||||
noTitle?: boolean,
|
||||
}) {
|
||||
function onEntrySelect(entry: T.AdjectiveEntry | undefined) {
|
||||
if (!entry) {
|
||||
|
@ -14,7 +15,7 @@ function AdjectivePicker(props: {
|
|||
props.onChange(makeAdjectiveSelection(entry));
|
||||
}
|
||||
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||
<h6>Adjective</h6>
|
||||
{!props.noTitle && <h6>Adjective</h6>}
|
||||
<div>
|
||||
<EntrySelect
|
||||
value={props.adjective?.entry}
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
import * as T from "../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import InlinePs from "../InlinePs";
|
||||
// import { useState } from "react";
|
||||
// import { isFemNounEntry, isPattern1Entry, isPattern2Entry, isPattern3Entry, isPattern4Entry, isPattern5Entry, isPattern6FemEntry } from "../../lib/type-predicates";
|
||||
import EntrySelect from "../EntrySelect";
|
||||
import AdjectiveManager from "./AdjectiveManager";
|
||||
|
||||
// const filterOptions = [
|
||||
// {
|
||||
|
@ -56,7 +56,7 @@ import EntrySelect from "../EntrySelect";
|
|||
// }
|
||||
|
||||
function NPNounPicker(props: {
|
||||
entryFeeder: T.EntryFeederSingleType<T.NounEntry>,
|
||||
entryFeeder: T.EntryFeeder,
|
||||
noun: T.NounSelection | undefined,
|
||||
onChange: (p: T.NounSelection | undefined) => void,
|
||||
opts: T.TextOptions,
|
||||
|
@ -76,6 +76,14 @@ function NPNounPicker(props: {
|
|||
// setPatternFilter(undefined);
|
||||
// setShowFilter(false);
|
||||
// }
|
||||
function handelAdjectivesUpdate(adjectives: T.AdjectiveSelection[]) {
|
||||
if (props.noun) {
|
||||
props.onChange({
|
||||
...props.noun,
|
||||
adjectives,
|
||||
});
|
||||
}
|
||||
}
|
||||
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||
{/* {showFilter && <div className="mb-2 text-center">
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
|
@ -90,11 +98,17 @@ function NPNounPicker(props: {
|
|||
handleChange={setPatternFilter}
|
||||
/>
|
||||
</div>} */}
|
||||
{props.noun && <AdjectiveManager
|
||||
adjectives={props.noun?.adjectives}
|
||||
entryFeeder={props.entryFeeder.adjectives}
|
||||
opts={props.opts}
|
||||
onChange={handelAdjectivesUpdate}
|
||||
/>}
|
||||
<h6>Noun</h6>
|
||||
{!(props.noun && props.noun.dynamicComplement) ? <div>
|
||||
<EntrySelect
|
||||
value={props.noun?.entry}
|
||||
entryFeeder={props.entryFeeder}
|
||||
entryFeeder={props.entryFeeder.nouns}
|
||||
onChange={onEntrySelect}
|
||||
name="Noun"
|
||||
opts={props.opts}
|
||||
|
@ -112,30 +126,36 @@ function NPNounPicker(props: {
|
|||
</div>}
|
||||
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>
|
||||
{props.noun.changeGender ? <ButtonSelect
|
||||
{props.noun.genderCanChange ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Masc", value: "masc" },
|
||||
{ label: "Fem", value: "fem" },
|
||||
]}
|
||||
value={props.noun.gender}
|
||||
handleChange={(g) => {
|
||||
if (!props.noun || !props.noun.changeGender) return;
|
||||
props.onChange(props.noun.changeGender(g));
|
||||
handleChange={(gender) => {
|
||||
if (!props.noun || !props.noun.genderCanChange) return;
|
||||
props.onChange({
|
||||
...props.noun,
|
||||
gender,
|
||||
});
|
||||
}}
|
||||
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
|
||||
</div>
|
||||
<div>
|
||||
{props.noun.changeNumber ? <ButtonSelect
|
||||
{props.noun.numberCanChange ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Sing.", value: "singular" },
|
||||
{ label: "Plur.", value: "plural" },
|
||||
]}
|
||||
value={props.noun.number}
|
||||
handleChange={(n) => {
|
||||
if (!props.noun || !props.noun.changeNumber) return;
|
||||
props.onChange(props.noun.changeNumber(n));
|
||||
handleChange={(number) => {
|
||||
if (!props.noun || !props.noun.numberCanChange) return;
|
||||
props.onChange({
|
||||
...props.noun,
|
||||
number,
|
||||
});
|
||||
}}
|
||||
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
|
||||
</div>
|
||||
|
|
|
@ -93,7 +93,7 @@ function NPPicker(props: {
|
|||
/>
|
||||
: npType === "noun"
|
||||
? <NounPicker
|
||||
entryFeeder={props.entryFeeder.nouns}
|
||||
entryFeeder={props.entryFeeder}
|
||||
noun={(props.np && props.np.type === "noun") ? props.np : undefined}
|
||||
onChange={props.onChange}
|
||||
opts={props.opts}
|
||||
|
|
|
@ -102,23 +102,10 @@ export function makeNounSelection(entry: T.NounEntry, dynamicComplement?: true):
|
|||
type: "noun",
|
||||
entry,
|
||||
gender: isMascNounEntry(entry) ? "masc" : "fem",
|
||||
genderCanChange: isUnisexNounEntry(entry),
|
||||
number,
|
||||
numberCanChange: number === "singular",
|
||||
adjectives: [],
|
||||
dynamicComplement,
|
||||
...isUnisexNounEntry(entry) ? {
|
||||
changeGender: function(gender: T.Gender): T.NounSelection {
|
||||
return {
|
||||
...this,
|
||||
gender,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
...number === "singular" ? {
|
||||
changeNumber: function(number: T.NounNumber): T.NounSelection {
|
||||
return {
|
||||
...this,
|
||||
number,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
};
|
||||
}
|
|
@ -68,7 +68,7 @@ function CompoundDisplay({ info, opts, handleLinkClick }: {
|
|||
<div className="text-center">{info.type}</div>
|
||||
<CompoundFormula
|
||||
a={<div
|
||||
className={classNames([{ clickable: handleLinkClick }])}
|
||||
className={classNames([{ clickable: typeof handleLinkClick === "function" }])}
|
||||
onClick={(handleLinkClick)
|
||||
// @ts-ignore - thinks there might not be a complement, but there will be
|
||||
? () => handleLinkClick(info.entry.complement?.ts)
|
||||
|
|
|
@ -11,10 +11,11 @@ import {
|
|||
flattenLengths,
|
||||
} from "./segment";
|
||||
import { removeAccents } from "../accent-helpers";
|
||||
import { getEnglishFromRendered, getPashtoFromRendered } from "./np-tools";
|
||||
|
||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion, combineLengths: true): { ps: T.PsString[], e?: string [] };
|
||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion, combineLengths?: true): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
|
||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] };
|
||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion, combineLengths: true): { ps: T.PsString[], e?: string[] };
|
||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion, combineLengths?: true): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] } {
|
||||
const { kids, NPs } = getSegmentsAndKids(EP, form);
|
||||
const equative = EP.equative.ps;
|
||||
const psResult = compilePs({
|
||||
|
@ -36,12 +37,12 @@ function getSegmentsAndKids(EP: T.EPRendered, form: T.FormVersion): { kids: Segm
|
|||
}
|
||||
return [s];
|
||||
}
|
||||
const subject = makeSegment(EP.subject.ps);
|
||||
const predicate = makeSegment(EP.predicate.ps);
|
||||
const subject = makeSegment(getPashtoFromRendered(EP.subject));
|
||||
const predicate = makeSegment(getPashtoFromRendered(EP.predicate));
|
||||
return {
|
||||
kids: EP.equative.hasBa
|
||||
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])]
|
||||
: [],
|
||||
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])]
|
||||
: [],
|
||||
NPs: [
|
||||
...ifNotRemoved(subject, "subject"),
|
||||
...ifNotRemoved(predicate, "predicate"),
|
||||
|
@ -77,8 +78,8 @@ function compileEnglish(EP: T.EPRendered): string[] | undefined {
|
|||
function insertEWords(e: string, { subject, predicate }: { subject: string, predicate: string }): string {
|
||||
return e.replace("$SUBJ", subject).replace("$PRED", predicate || "");
|
||||
}
|
||||
const engSubj = EP.subject.e || undefined;
|
||||
const engPred = EP.predicate.e || undefined;
|
||||
const engSubj = getEnglishFromRendered(EP.subject);
|
||||
const engPred = getEnglishFromRendered(EP.predicate);
|
||||
// require all English parts for making the English phrase
|
||||
return (EP.englishBase && engSubj && engPred)
|
||||
? EP.englishBase.map(e => insertEWords(e, {
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
removeDuplicates,
|
||||
} from "./vp-tools";
|
||||
import { isImperativeTense, isModalTense, isPerfectTense } from "../type-predicates";
|
||||
import { getEnglishFromRendered, getPashtoFromRendered } from "./np-tools";
|
||||
|
||||
type Form = T.FormVersion & { OSV?: boolean };
|
||||
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
||||
|
@ -79,8 +80,8 @@ function compilePs({ NPs, kids, verb: { head, rest }, VP }: CompilePsInput): T.S
|
|||
|
||||
function getSegmentsAndKids(VP: T.VPRendered, form: Form): { kids: Segment[], NPs: Segment[][] } {
|
||||
const SO = {
|
||||
subject: VP.subject.ps,
|
||||
object: typeof VP.object === "object" ? VP.object.ps : undefined,
|
||||
subject: getPashtoFromRendered(VP.subject),
|
||||
object: typeof VP.object === "object" ? getPashtoFromRendered(VP.object) : undefined,
|
||||
}
|
||||
const removeKing = form.removeKing && !(VP.isCompound === "dynamic" && VP.isPast);
|
||||
const shrinkServant = form.shrinkServant && !(VP.isCompound === "dynamic" && !VP.isPast);
|
||||
|
@ -282,8 +283,10 @@ function compileEnglish(VP: T.VPRendered): string[] | undefined {
|
|||
function insertEWords(e: string, { subject, object }: { subject: string, object?: string }): string {
|
||||
return e.replace("$SUBJ", subject).replace("$OBJ", object || "");
|
||||
}
|
||||
const engSubj = VP.subject.e || undefined;
|
||||
const engObj = (typeof VP.object === "object" && VP.object.e) ? VP.object.e : undefined;
|
||||
const engSubj = getEnglishFromRendered(VP.subject);
|
||||
const engObj = typeof VP.object === "object"
|
||||
? getEnglishFromRendered(VP.object)
|
||||
: undefined;
|
||||
// require all English parts for making the English phrase
|
||||
return (VP.englishBase && engSubj && (engObj || typeof VP.object !== "object"))
|
||||
? VP.englishBase.map(e => insertEWords(e, {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import * as T from "../../types";
|
||||
import { concatPsString } from "../p-text-helpers";
|
||||
|
||||
export function getPashtoFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSelection>): T.PsString[] {
|
||||
const adjs = np.adjectives;
|
||||
if (!adjs) {
|
||||
return np.ps;
|
||||
}
|
||||
return np.ps.map(p => (
|
||||
concatPsString(
|
||||
adjs.reduce((accum, curr) => (
|
||||
// TODO: with variations of adjs?
|
||||
concatPsString(accum, " ", curr.ps[0])
|
||||
), { p: "", f: "" }),
|
||||
" ",
|
||||
p,
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
export function getEnglishFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSelection>): string | undefined {
|
||||
if (!np.e) return undefined;
|
||||
if (np.type === "noun") {
|
||||
try {
|
||||
// split out the atricles so adjectives can be stuck inbetween them and the word
|
||||
const chunks = np.e.split("the)");
|
||||
const [articles, word] = chunks.length === 1
|
||||
? ["", np.e]
|
||||
: [chunks[0] + "the) ", chunks[1]];
|
||||
const adjs = !np.adjectives
|
||||
? ""
|
||||
: np.adjectives.reduce((accum, curr): string => {
|
||||
if (!curr.e) throw new Error("no english for adjective");
|
||||
return accum + curr.e + " ";
|
||||
}, "");
|
||||
return `${articles}${adjs}${word}`;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return np.e;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import * as T from "../../types";
|
||||
import { inflectWord } from "../../lib/pashto-inflector";
|
||||
import {
|
||||
psStringFromEntry,
|
||||
isUnisexSet,
|
||||
} from "../../lib/p-text-helpers";
|
||||
import { getEnglishWord } from "../get-english-word";
|
||||
import {
|
||||
personGender,
|
||||
personIsPlural,
|
||||
} from "../../lib/misc-helpers";
|
||||
|
||||
function chooseInflection(inflections: T.UnisexSet<T.InflectionSet>, pers: T.Person, inflected?: boolean): T.ArrayOneOrMore<T.PsString> {
|
||||
const gender = personGender(pers);
|
||||
const plural = personIsPlural(pers);
|
||||
const infNumber = (plural ? 1 : 0) + (inflected ? 1 : 0);
|
||||
return inflections[gender][infNumber];
|
||||
}
|
||||
|
||||
export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Person, inflected: boolean): T.Rendered<T.AdjectiveSelection> {
|
||||
const infs = inflectWord(a.entry);
|
||||
const eWord = getEnglishWord(a.entry);
|
||||
const e = !eWord
|
||||
? undefined
|
||||
: typeof eWord === "string"
|
||||
? eWord
|
||||
: (eWord.singular || undefined);
|
||||
if (!infs) return {
|
||||
type: "adjective",
|
||||
entry: a.entry,
|
||||
ps: [psStringFromEntry(a.entry)],
|
||||
e,
|
||||
inflected: false,
|
||||
person,
|
||||
}
|
||||
if (!infs.inflections || !isUnisexSet(infs.inflections)) {
|
||||
throw new Error("error getting inflections for adjective, looks like a noun's inflections");
|
||||
}
|
||||
return {
|
||||
type: "adjective",
|
||||
entry: a.entry,
|
||||
ps: chooseInflection(infs.inflections, person, inflected),
|
||||
e,
|
||||
inflected: false,
|
||||
person,
|
||||
};
|
||||
}
|
|
@ -7,10 +7,10 @@ import { renderNPSelection } from "./render-np";
|
|||
import { getPersonFromVerbForm } from "../../lib/misc-helpers";
|
||||
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
||||
import { getEnglishWord } from "../get-english-word";
|
||||
import { isUnisexSet, psStringFromEntry } from "../p-text-helpers";
|
||||
import { inflectWord } from "../pashto-inflector";
|
||||
import { psStringFromEntry } from "../p-text-helpers";
|
||||
import { personGender, personIsPlural } from "../../library";
|
||||
import { isLocativeAdverbEntry } from "../type-predicates";
|
||||
import { renderAdjectiveSelection } from "./render-adj";
|
||||
|
||||
export function renderEP(EP: T.EPSelectionComplete): T.EPRendered {
|
||||
const kingPerson = (EP.subject.type === "pronoun")
|
||||
|
@ -71,26 +71,7 @@ function renderEqCompSelection(s: T.EqCompSelection, person: T.Person): T.Render
|
|||
};
|
||||
}
|
||||
if (s.type === "adjective") {
|
||||
const infs = inflectWord(s.entry);
|
||||
if (!infs) return {
|
||||
type: "adjective",
|
||||
entry: s.entry,
|
||||
ps: [psStringFromEntry(s.entry)],
|
||||
e,
|
||||
inflected: false,
|
||||
person,
|
||||
}
|
||||
if (!infs.inflections || !isUnisexSet(infs.inflections)) {
|
||||
throw new Error("error getting inflections for adjective, looks like a noun's inflections");
|
||||
}
|
||||
return {
|
||||
type: "adjective",
|
||||
entry: s.entry,
|
||||
ps: chooseInflection(infs.inflections, person),
|
||||
e,
|
||||
inflected: false,
|
||||
person,
|
||||
};
|
||||
return renderAdjectiveSelection(s, person, false)
|
||||
}
|
||||
throw new Error("invalid EqCompSelection");
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from "../p-text-helpers";
|
||||
import { parseEc } from "../misc-helpers";
|
||||
import { getEnglishWord } from "../get-english-word";
|
||||
import { renderAdjectiveSelection } from "./render-adj";
|
||||
|
||||
export function renderNPSelection(NP: T.NPSelection, inflected: boolean, inflectEnglish: boolean, role: "subject"): T.Rendered<T.NPSelection>
|
||||
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "object"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none";
|
||||
|
@ -48,9 +49,11 @@ function renderNounSelection(n: T.NounSelection, inflected: boolean): T.Rendered
|
|||
? ps
|
||||
: [psStringFromEntry(n.entry)];
|
||||
})();
|
||||
const person = getPersonNumber(n.gender, n.number);
|
||||
return {
|
||||
...n,
|
||||
person: getPersonNumber(n.gender, n.number),
|
||||
adjectives: n.adjectives.map(a => renderAdjectiveSelection(a, person, inflected)),
|
||||
person,
|
||||
inflected,
|
||||
ps: pashto,
|
||||
e: english,
|
||||
|
|
|
@ -43,7 +43,7 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
|||
const inflectSubject = isPast && isTransitive && !isMascSingAnimatePattern4(VP.subject);
|
||||
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.verb.object);
|
||||
// Render Elements
|
||||
return {
|
||||
const b: T.VPRendered = {
|
||||
type: "VPRendered",
|
||||
king,
|
||||
servant,
|
||||
|
@ -59,6 +59,7 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
|||
vs: VP.verb,
|
||||
}),
|
||||
};
|
||||
return b;
|
||||
}
|
||||
|
||||
function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, objectPerson: T.Person | undefined): T.VerbRendered {
|
||||
|
|
|
@ -25,10 +25,23 @@ export type Segment = { ps: T.PsString[] } & SegmentDescriptions & {
|
|||
adjust: (o: { ps?: T.PsString | T.PsString[] | ((ps: T.PsString) => T.PsString), desc?: SDT[] }) => Segment,
|
||||
};
|
||||
|
||||
function addAdjectives(ps: T.PsString[], adjectives?: T.Rendered<T.AdjectiveSelection>[]): T.PsString[] {
|
||||
if (!adjectives) return ps;
|
||||
return ps.map(p => {
|
||||
// TODO: more thorough use of all possible variends?
|
||||
return concatPsString(...adjectives.map(a => a.ps[0]), p);
|
||||
});
|
||||
}
|
||||
|
||||
export function makeSegment(
|
||||
ps: T.PsString | T.PsString[],
|
||||
input: T.Rendered<T.NounSelection> | T.PsString | T.PsString[],
|
||||
options?: (keyof SegmentDescriptions)[],
|
||||
): Segment {
|
||||
const ps: T.PsString[] = Array.isArray(input)
|
||||
? input
|
||||
: "type" in input
|
||||
? addAdjectives(input.ps, input.adjectives)
|
||||
: [input];
|
||||
return {
|
||||
ps: Array.isArray(ps) ? ps : [ps],
|
||||
...options && options.reduce((all, curr) => ({
|
||||
|
@ -39,6 +52,7 @@ export function makeSegment(
|
|||
return {
|
||||
...this,
|
||||
...o.ps ? {
|
||||
// TODO: is this ok with the adjectives?
|
||||
ps: Array.isArray(o.ps)
|
||||
? o.ps
|
||||
: "p" in o.ps
|
||||
|
|
|
@ -41,4 +41,4 @@ export default function useStickyState<T extends string | number | object | bool
|
|||
}, [key, value]);
|
||||
|
||||
return [value, setValue];
|
||||
}
|
||||
}
|
||||
|
|
17
src/types.ts
17
src/types.ts
|
@ -592,16 +592,11 @@ export type NounSelection = {
|
|||
type: "noun",
|
||||
entry: NounEntry,
|
||||
gender: Gender,
|
||||
genderCanChange: boolean,
|
||||
number: NounNumber,
|
||||
numberCanChange: boolean,
|
||||
dynamicComplement?: boolean,
|
||||
// TODO: Implement
|
||||
// adjectives: [],
|
||||
// TODO: Implement
|
||||
// possesor: NPSelection | undefined,
|
||||
/* method only present if it's possible to change gender */
|
||||
changeGender?: (gender: Gender) => NounSelection,
|
||||
/* method only present if it's possible to change number */
|
||||
changeNumber?: (number: NounNumber) => NounSelection,
|
||||
adjectives: AdjectiveSelection[],
|
||||
};
|
||||
|
||||
export type AdjectiveSelection = {
|
||||
|
@ -633,8 +628,8 @@ export type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ?
|
|||
|
||||
export type FormVersion = { removeKing: boolean, shrinkServant: boolean };
|
||||
|
||||
export type Rendered<T extends NPSelection | EqCompSelection> = ReplaceKey<
|
||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,
|
||||
export type Rendered<T extends NPSelection | EqCompSelection | AdjectiveSelection> = ReplaceKey<
|
||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance" | "adjectives">,
|
||||
"e",
|
||||
string
|
||||
> & {
|
||||
|
@ -642,6 +637,8 @@ export type Rendered<T extends NPSelection | EqCompSelection> = ReplaceKey<
|
|||
e?: string,
|
||||
inflected: boolean,
|
||||
person: Person,
|
||||
// TODO: better recursive thing
|
||||
adjectives?: Rendered<AdjectiveSelection>[],
|
||||
};
|
||||
// TODO: recursive changing this down into the possesor etc.
|
||||
|
||||
|
|
Loading…
Reference in New Issue