Refactor for use of keys in the blocks so that we can autoAnimate the blocks diagrams, but it still doesn't work because we need a way to persist the keys in the blocks on re-renders - could be tricky

This commit is contained in:
lingdocs 2022-06-24 14:29:33 -05:00
parent 7275fbd73c
commit 4062cedd48
9 changed files with 280 additions and 228 deletions

View File

@ -1,4 +1,5 @@
import { useState } from "react"; import { useState } from "react";
// import autoAnimate from "@formkit/auto-animate";
import { filterForVisibleBlocksEP, filterForVisibleBlocksVP } from "../lib/phrase-building/compile"; import { filterForVisibleBlocksEP, filterForVisibleBlocksVP } from "../lib/phrase-building/compile";
import * as T from "../types"; import * as T from "../types";
import Block from "./blocks/Block"; import Block from "./blocks/Block";
@ -11,6 +12,11 @@ function RenderedBlocksDisplay({ opts, rendered, justify, script }: {
justify?: "left" | "right" | "center", justify?: "left" | "right" | "center",
}) { }) {
const [variation, setVariation] = useState<number>(0); const [variation, setVariation] = useState<number>(0);
// not using autoAnimate here because we need a way to persist the keys in the blocks first
// const parent = useRef(null);
// useEffect(() => {
// parent.current && autoAnimate(parent.current)
// }, [parent]);
const blocksWVars = ("omitSubject" in rendered) const blocksWVars = ("omitSubject" in rendered)
? filterForVisibleBlocksEP(rendered.blocks, rendered.omitSubject) ? filterForVisibleBlocksEP(rendered.blocks, rendered.omitSubject)
: filterForVisibleBlocksVP(rendered.blocks, rendered.form, rendered.king); : filterForVisibleBlocksVP(rendered.blocks, rendered.form, rendered.king);
@ -19,14 +25,14 @@ function RenderedBlocksDisplay({ opts, rendered, justify, script }: {
function handleVariationChange() { function handleVariationChange() {
setVariation(ov => ((ov + 1) % blocksWVars.length)); setVariation(ov => ((ov + 1) % blocksWVars.length));
} }
return <div className={`d-flex flex-row justify-content-${justify ? justify : "center"}`} style={{}}> return <div className={`d-flex flex-row justify-content-${justify ? justify : "center"}`}>
<div className={`d-flex flex-row${script === "p" ? "-reverse" : ""} justify-content-left align-items-end mt-3 pb-2`} style={{ overflowX: "auto" }}> <div className={`d-flex flex-row${script === "p" ? "-reverse" : ""} justify-content-left align-items-end mt-3 pb-2`} style={{ overflowX: "auto" }}>
<div key={Math.random()} className="mr-2"> <div key={blocks[0].key} className="mr-2">
<Block opts={opts} block={blocks[0]} king={king} script={script} /> <Block opts={opts} block={blocks[0]} king={king} script={script} />
</div> </div>
<KidsSection opts={opts} kids={rendered.kids} script={script} /> <KidsSection key="kidsSection" opts={opts} kids={rendered.kids} script={script} />
{blocks.slice(1).map((block) => ( {blocks.slice(1).map((block) => (
<div key={Math.random()} className="mr-2"> <div key={block.key} className="mr-2">
<Block opts={opts} block={block} king={king} script={script} /> <Block opts={opts} block={block} king={king} script={script} />
</div> </div>
))} ))}
@ -42,10 +48,15 @@ function KidsSection({ opts, kids, script }: {
kids: T.Kid[], kids: T.Kid[],
script: "p" | "f", script: "p" | "f",
}) { }) {
// not using autoAnimate here because we need a way to persist the keys in the blocks first
// const parent = useRef(null);
// useEffect(() => {
// parent.current && autoAnimate(parent.current)
// }, [parent]);
return kids.length > 0 ? <div className="text-center mx-1 mr-3" style={{ paddingBottom: "1rem"}}> return kids.length > 0 ? <div className="text-center mx-1 mr-3" style={{ paddingBottom: "1rem"}}>
<div className={`d-flex flex-row${script === "p" ? "-reverse" : ""} mb-3 justify-content-center`}> <div className={`d-flex flex-row${script === "p" ? "-reverse" : ""} mb-3 justify-content-center`}>
{kids.map(kid => ( {kids.map(kid => (
<KidDisplay key={Math.random()} opts={opts} kid={kid} script={script} /> <KidDisplay key={kid.key} opts={opts} kid={kid} script={script} />
))} ))}
</div> </div>
<div><strong>kids</strong></div> <div><strong>kids</strong></div>

View File

@ -15,53 +15,53 @@ function Block({ opts, block, king, script }: {
king?: "subject" | "object" | undefined, king?: "subject" | "object" | undefined,
script: "p" | "f"; script: "p" | "f";
}) { }) {
if ("equative" in block) { if ("equative" in block.block) {
return <EquativeBlock opts={opts} eq={block.equative} script={script} />; return <EquativeBlock opts={opts} eq={block.block.equative} script={script} />;
} }
if (block.type === "AP") { if (block.block.type === "AP") {
const english = getEnglishFromRendered(block); const english = getEnglishFromRendered(block.block);
return <APBlock opts={opts} english={english} script={script}>{block}</APBlock> return <APBlock opts={opts} english={english} script={script}>{block.block}</APBlock>
} }
if (block.type === "subjectSelection") { if (block.block.type === "subjectSelection") {
const role = king === "subject" ? "king" : king === "object" ? "servant" : undefined; const role = king === "subject" ? "king" : king === "object" ? "servant" : undefined;
return <SubjectBlock opts={opts} np={block.selection} role={role} script={script} /> return <SubjectBlock opts={opts} np={block.block.selection} role={role} script={script} />
} }
if (block.type === "predicateSelection") { if (block.block.type === "predicateSelection") {
const english = getEnglishFromRendered(block.selection); const english = getEnglishFromRendered(block.block.selection);
return <div className="text-center"> return <div className="text-center">
<div><strong>Predicate</strong></div> <div><strong>Predicate</strong></div>
{block.selection.type === "EQComp" {block.block.selection.type === "EQComp"
? <EqCompBlock opts={opts} comp={block.selection.selection} script={script} /> ? <EqCompBlock opts={opts} comp={block.block.selection.selection} script={script} />
: <NPBlock opts={opts} english={english} script={script}>{block.selection}</NPBlock>} : <NPBlock opts={opts} english={english} script={script}>{block.block.selection}</NPBlock>}
</div> </div>
} }
if (block.type === "negative") { if (block.block.type === "negative") {
return <NegBlock opts={opts} imperative={block.imperative} script={script} /> return <NegBlock opts={opts} imperative={block.block.imperative} script={script} />
} }
if (block.type === "perfectiveHead") { if (block.block.type === "perfectiveHead") {
return <PerfHeadBlock opts={opts} ps={block.ps} script={script} /> return <PerfHeadBlock opts={opts} ps={block.block.ps} script={script} />
} }
if (block.type === "verbComplement") { if (block.block.type === "verbComplement") {
return <VCompBlock opts={opts} comp={block.complement} script={script} />; return <VCompBlock opts={opts} comp={block.block.complement} script={script} />;
} }
if (block.type === "verb") { if (block.block.type === "verb") {
return <VerbSBlock opts={opts} v={block.block.block} script={script} />;
}
if (block.block.type === "objectSelection") {
const role = king === "object" ? "king" : king === "subject" ? "servant" : undefined;
return <ObjectBlock opts={opts} obj={block.block.selection} role={role} script={script} />;
}
if (block.block.type === "perfectParticipleBlock") {
return <VerbSBlock opts={opts} v={block.block} script={script} />; return <VerbSBlock opts={opts} v={block.block} script={script} />;
} }
if (block.type === "objectSelection") { if (block.block.type === "perfectEquativeBlock") {
const role = king === "object" ? "king" : king === "subject" ? "servant" : undefined; return <EquativeBlock opts={opts} eq={block.block} script={script} />;
return <ObjectBlock opts={opts} obj={block.selection} role={role} script={script} />;
} }
if (block.type === "perfectParticipleBlock") { if (block.block.type === "modalVerbBlock") {
return <VerbSBlock opts={opts} v={block} script={script} />; return <ModalVerbBlock opts={opts} v={block.block} script={script} />;
} }
if (block.type === "perfectEquativeBlock") { if (block.block.type === "modalVerbKedulPart") {
return <EquativeBlock opts={opts} eq={block} script={script} />; return <ModalAuxBlock opts={opts} aux={block.block} script={script} />
}
if (block.type === "modalVerbBlock") {
return <ModalVerbBlock opts={opts} v={block} script={script} />;
}
if (block.type === "modalVerbKedulPart") {
return <ModalAuxBlock opts={opts} aux={block} script={script} />
} }
return null; return null;
} }

View File

@ -8,10 +8,10 @@ function KidDisplay({ opts, kid, script }: {
kid: T.Kid, kid: T.Kid,
script: "p" | "f", script: "p" | "f",
}) { }) {
const ps = kid.type === "ba" const ps = kid.kid.type === "ba"
? baParticle ? baParticle
: kid.ps; : kid.kid.ps;
return <div className="mx-1"> return <div className="mx-1" key={kid.key}>
{script === "p" {script === "p"
? <Pashto opts={opts}>{ps}</Pashto> ? <Pashto opts={opts}>{ps}</Pashto>
: <Phonetics opts={opts}>{ps}</Phonetics>} : <Phonetics opts={opts}>{ps}</Phonetics>}

View File

@ -1,6 +1,20 @@
import * as T from "../../types"; import * as T from "../../types";
import { getLength } from "../p-text-helpers"; import { getLength } from "../p-text-helpers";
export function makeBlock(block: T.Block["block"], key?: number): T.Block {
return {
key: key === undefined ? Math.random() : key,
block,
};
}
export function makeKid(kid: T.Kid["kid"], key?: number): T.Kid {
return {
key: key === undefined ? Math.random() : key,
kid,
};
}
export function getSubjectSelection(blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]): T.SubjectSelectionComplete; export function getSubjectSelection(blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]): T.SubjectSelectionComplete;
export function getSubjectSelection(blocks: T.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection; export function getSubjectSelection(blocks: T.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection;
export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[] | T.VPSBlockComplete[] | T.VPSBlock[]): T.SubjectSelection | T.SubjectSelectionComplete { export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[] | T.VPSBlockComplete[] | T.VPSBlock[]): T.SubjectSelection | T.SubjectSelectionComplete {
@ -12,31 +26,31 @@ export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[]
} }
export function getSubjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.SubjectSelectionComplete> { export function getSubjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.SubjectSelectionComplete> {
const b = blocks[0].find(f => f.type === "subjectSelection"); const b = blocks[0].find(f => f.block.type === "subjectSelection");
if (!b || b.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; return b.block;
} }
export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.ObjectSelectionComplete> { export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.ObjectSelectionComplete> {
const b = blocks[0].find(f => f.type === "objectSelection"); const b = blocks[0].find(f => f.block.type === "objectSelection");
if (!b || b.type !== "objectSelection") { if (!b || b.block.type !== "objectSelection") {
throw new Error("objectSelection not found in blocks"); throw new Error("objectSelection not found in blocks");
} }
return b; return b.block;
} }
export function getVerbFromBlocks(blocks: T.Block[][]): T.VerbRenderedBlock { export function getVerbFromBlocks(blocks: T.Block[][]): T.VerbRenderedBlock {
const b = blocks[0].find(f => f.type === "verb"); const b = blocks[0].find(f => f.block.type === "verb");
const p = blocks[0].find(f => f.type === "perfectParticipleBlock"); const p = blocks[0].find(f => f.block.type === "perfectParticipleBlock");
const m = blocks[0].find(f => f.type === "modalVerbBlock"); const m = blocks[0].find(f => f.block.type === "modalVerbBlock");
const v = (b && b.type === "verb") const v = (b && b.block.type === "verb")
? b ? b.block
: (p && p.type === "perfectParticipleBlock") : (p && p.block.type === "perfectParticipleBlock")
? p.verb ? p.block.verb
: (m && m.type === "modalVerbBlock") : (m && m.block.type === "modalVerbBlock")
? m.verb ? m.block.verb
: undefined; : undefined;
if (!v) { if (!v) {
throw new Error("verbSelection not found in blocks"); throw new Error("verbSelection not found in blocks");
@ -46,8 +60,8 @@ export function getVerbFromBlocks(blocks: T.Block[][]): T.VerbRenderedBlock {
export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRenderedBlock, perfectiveHead: T.PerfectiveHeadBlock | undefined } { export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRenderedBlock, perfectiveHead: T.PerfectiveHeadBlock | undefined } {
const verb = getVerbFromBlocks(blocks); const verb = getVerbFromBlocks(blocks);
const perfectiveHead = blocks[0].find(f => f.type === "perfectiveHead"); const perfectiveHead = blocks[0].find(f => f.block.type === "perfectiveHead");
if (!perfectiveHead || perfectiveHead.type !== "perfectiveHead") { if (!perfectiveHead || perfectiveHead.block.type !== "perfectiveHead") {
return { return {
verb, verb,
perfectiveHead: undefined, perfectiveHead: undefined,
@ -55,27 +69,27 @@ export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRen
} }
return { return {
verb, verb,
perfectiveHead, perfectiveHead: perfectiveHead.block,
}; };
} }
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 => (
k.type === "mini-pronoun" && k.source === "servant" k.kid.type === "mini-pronoun" && k.kid.source === "servant"
)); ));
} }
export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.PredicateSelectionComplete> { export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.PredicateSelectionComplete> {
const b = blocks[0].find(f => f.type === "predicateSelection"); const b = blocks[0].find(f => f.block.type === "predicateSelection");
if (!b || b.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; return b.block;
} }
export function getAPsFromBlocks(blocks: T.Block[][]): T.Rendered<T.APSelection>[] { export function getAPsFromBlocks(blocks: T.Block[][]): T.Rendered<T.APSelection>[] {
return blocks[0].filter(b => b.type === "AP") as 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;
@ -238,16 +252,19 @@ export function isNoObject(b: T.VPSBlock["block"] | T.EPSBlock["block"]): b is {
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.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.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,
equative: { block: {
...eq.equative, ...eq.block,
ps: getLength(eq.equative.ps, length), equative: {
...eq.block.equative,
ps: getLength(eq.block.equative.ps, length),
},
}, },
}; };
return adjusted; return adjusted;
@ -257,28 +274,37 @@ export function specifyEquativeLength(blocksWVars: T.Block[][], length: "long" |
export function specifyVerbLength(blocksWVars: T.Block[][], length: "long" | "short" | "mini"): T.Block[][] { export function specifyVerbLength(blocksWVars: T.Block[][], length: "long" | "short" | "mini"): T.Block[][] {
function specify(blocks: T.Block[]): T.Block[] { function specify(blocks: T.Block[]): T.Block[] {
return blocks.map((block) => { return blocks.map((block): T.Block => {
if (block.type === "verb") { if (block.block.type === "verb") {
const v: T.VerbRenderedBlock = { const v: T.Block = {
...block,
block: {
...block.block,
block: {
...block.block.block,
ps: getLength(block.block.block.ps, length),
},
},
};
return v;
}
if (block.block.type === "perfectParticipleBlock") {
const p: T.Block = {
...block, ...block,
block: { block: {
...block.block, ...block.block,
ps: getLength(block.block.ps, length), ps: getLength(block.block.ps, length),
}, },
}; };
return v;
}
if (block.type === "perfectParticipleBlock") {
const p: T.PerfectParticipleBlock = {
...block,
ps: getLength(block.ps, length),
};
return p; return p;
} }
if (block.type === "modalVerbBlock") { if (block.block.type === "modalVerbBlock") {
const m: T.ModalVerbBlock = { const m: T.Block = {
...block, ...block,
ps: getLength(block.ps, length), block: {
...block.block,
ps: getLength(block.block.ps, length),
},
}; };
return m; return m;
} }
@ -289,21 +315,21 @@ export function specifyVerbLength(blocksWVars: T.Block[][], length: "long" | "sh
} }
export function hasEquativeWithLengths(blocks: T.Block[][]): boolean { export function hasEquativeWithLengths(blocks: T.Block[][]): boolean {
const equative = blocks[0].find(x => x.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.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.equative.ps; return "long" in equative.block.equative.ps;
} }
export function hasVerbWithLengths(blocks: T.Block[][]): boolean { export function hasVerbWithLengths(blocks: T.Block[][]): boolean {
// TODO: handle length options with perfect verb equative as well? // TODO: handle length options with perfect verb equative as well?
const verb = blocks[0].find(x => (x.type === "verb" || x.type === "perfectParticipleBlock" || x.type === "modalVerbBlock")); const verb = blocks[0].find(x => (x.block.type === "verb" || x.block.type === "perfectParticipleBlock" || x.block.type === "modalVerbBlock"));
if (!verb) throw new Error("verb not found in blocks"); if (!verb) throw new Error("verb not found in blocks");
if (verb.type !== "verb" && verb.type !== "perfectParticipleBlock" && verb.type !== "modalVerbBlock") throw new Error("error finding verb in blocks"); if (verb.block.type !== "verb" && verb.block.type !== "perfectParticipleBlock" && verb.block.type !== "modalVerbBlock") throw new Error("error finding verb in blocks");
return ( return (
(verb.type === "verb" && "long" in verb.block.ps) (verb.block.type === "verb" && "long" in verb.block.block.ps)
|| (verb.type === "perfectParticipleBlock" && "long" in verb.ps) || (verb.block.type === "perfectParticipleBlock" && "long" in verb.block.ps)
|| (verb.type === "modalVerbBlock" && "long" in verb.ps) || (verb.block.type === "modalVerbBlock" && "long" in verb.block.ps)
); );
} }

View File

@ -107,7 +107,7 @@ function compileEPPs(blocks: T.Block[][], kids: T.Kid[], omitSubject: boolean, b
const subjectPerson = getSubjectSelectionFromBlocks(blocks) const subjectPerson = getSubjectSelectionFromBlocks(blocks)
.selection.selection.person; .selection.selection.person;
const blocksWKids = putKidsInKidsSection( const blocksWKids = putKidsInKidsSection(
omitSubject ? blocks.map(blks => blks.filter(b => b.type !== "subjectSelection")) : blocks, omitSubject ? blocks.map(blks => blks.filter(b => b.block.type !== "subjectSelection")) : blocks,
kids, kids,
!!blankOut?.kidsSection !!blankOut?.kidsSection
); );
@ -119,19 +119,19 @@ export function filterForVisibleBlocksVP(blocks: T.Block[][], form: T.FormVersio
return blocks.map(blks => blks.filter((block) => { return blocks.map(blks => blks.filter((block) => {
if (form.removeKing) { if (form.removeKing) {
if ( if (
(king === "subject" && block.type === "subjectSelection") (king === "subject" && block.block.type === "subjectSelection")
|| ||
(king === "object" && block.type === "objectSelection") (king === "object" && block.block.type === "objectSelection")
) return false; ) return false;
} }
if (form.shrinkServant) { if (form.shrinkServant) {
if ( if (
(servant === "subject" && block.type === "subjectSelection") (servant === "subject" && block.block.type === "subjectSelection")
|| ||
(servant === "object" && block.type === "objectSelection") (servant === "object" && block.block.type === "objectSelection")
) return false; ) return false;
} }
if (block.type === "objectSelection" && typeof block.selection !== "object") { if (block.block.type === "objectSelection" && typeof block.block.selection !== "object") {
return false; return false;
} }
return true; return true;
@ -140,7 +140,7 @@ export function filterForVisibleBlocksVP(blocks: T.Block[][], form: T.FormVersio
export function filterForVisibleBlocksEP(blocks: T.Block[][], omitSubject: boolean): T.Block[][] { export function filterForVisibleBlocksEP(blocks: T.Block[][], omitSubject: boolean): T.Block[][] {
if (!omitSubject) return blocks; if (!omitSubject) return blocks;
return blocks.map(blks => blks.filter((block) => { return blocks.map(blks => blks.filter(({ block }) => {
if (block.type === "subjectSelection") { if (block.type === "subjectSelection") {
return false; return false;
} }
@ -155,9 +155,9 @@ function combineIntoText(piecesWVars: (T.Block | T.Kid | T.PsString)[][], subjec
const rest = pieces.slice(1); const rest = pieces.slice(1);
const firstPs = ("p" in first) const firstPs = ("p" in first)
? [first] ? [first]
: (blankOut?.equative && first.type === "equative") : (blankOut?.equative && "block" in first && first.block.type === "equative")
? [blank] ? [blank]
: ((blankOut?.ba) && first.type === "ba") : ((blankOut?.ba) && "kid" in first && first.kid.type === "ba")
? [kidsBlank] ? [kidsBlank]
: getPsFromPiece(first, subjectPerson); : getPsFromPiece(first, subjectPerson);
if (!rest.length) { if (!rest.length) {
@ -166,8 +166,8 @@ function combineIntoText(piecesWVars: (T.Block | T.Kid | T.PsString)[][], subjec
return combine(rest).flatMap(r => ( return combine(rest).flatMap(r => (
firstPs.map(fPs => concatPsString( firstPs.map(fPs => concatPsString(
fPs, fPs,
(!("p" in first) && first.type === "perfectiveHead" && !("p" in next) && (next.type === "verb" || next.type === "negative" || next.type === "mini-pronoun")) (!("p" in first) && "block" in first && first.block.type === "perfectiveHead" && !("p" in next) && (("block" in next && (next.block.type === "verb" || next.block.type === "negative")) || ("kid" in next && next.kid.type === "mini-pronoun")))
? ((next.type === "negative" || next.type === "mini-pronoun") ? { p: "", f: "-" } : "") ? ((("block" in next && next.block.type === "negative") || ("kid" in next && next.kid.type === "mini-pronoun")) ? { p: "", f: "-" } : "")
: " ", : " ",
r, r,
)) ))
@ -178,59 +178,64 @@ function combineIntoText(piecesWVars: (T.Block | T.Kid | T.PsString)[][], subjec
} }
function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsString[] { function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsString[] {
if (piece.type === "ba") { if ("block" in piece) {
return [grammarUnits.baParticle]; if (piece.block.type === "negative") {
} return [
if (piece.type === "mini-pronoun") { negativeParticle[piece.block.imperative ? "imperative" : "nonImperative"],
return [piece.ps]; ];
} }
if (piece.type === "negative") { if (piece.block.type === "equative") {
return [ // length will already be specified in compileEPPs - this is just for type safety
negativeParticle[piece.imperative ? "imperative" : "nonImperative"], return getLong(piece.block.equative.ps);
]; }
} if (piece.block.type === "subjectSelection" || piece.block.type === "predicateSelection") {
if (piece.type === "equative") { return getPashtoFromRendered(piece.block.selection, subjectPerson);
// length will already be specified in compileEPPs - this is just for type safety }
return getLong(piece.equative.ps); if (piece.block.type === "AP") {
} return getPashtoFromRendered(piece.block, subjectPerson);
if (piece.type === "subjectSelection" || piece.type === "predicateSelection") { }
return getPashtoFromRendered(piece.selection, subjectPerson); if (piece.block.type === "perfectiveHead") {
} return [piece.block.ps];
if (piece.type === "AP") { }
return getPashtoFromRendered(piece, subjectPerson); if (piece.block.type === "verbComplement") {
} return [{ p: "---", f: "---"}]; //getPashtoFromRendered(piece.block.complement);
if (piece.type === "perfectiveHead") { }
return [piece.ps]; if (piece.block.type === "objectSelection") {
} if (typeof piece.block.selection !== "object") {
if (piece.type === "verbComplement") { return [{ p: "", f: "" }];
return [{ p: "---", f: "---"}]; //getPashtoFromRendered(piece.complement); }
} return getPashtoFromRendered(piece.block.selection, subjectPerson);
if (piece.type === "objectSelection") { }
if (typeof piece.selection !== "object") { if (piece.block.type === "verb") {
return [{ p: "", f: "" }]; // getLong is just for type safety - we will have split up the length options earlier in compileVPPs
return getLong(piece.block.block.ps);
}
if (piece.block.type === "perfectParticipleBlock") {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs
return getLong(piece.block.ps);
}
if (piece.block.type === "perfectEquativeBlock") {
// just using the short one for now - it will only be short anyways
return getShort(piece.block.ps);
}
if (piece.block.type === "modalVerbBlock") {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs
return getLong(piece.block.ps);
}
if (piece.block.type === "modalVerbKedulPart") {
// just using the short one for now - it will only be short anyways
return getShort(piece.block.ps);
} }
return getPashtoFromRendered(piece.selection, subjectPerson);
} }
if (piece.type === "verb") { if ("kid" in piece) {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs if (piece.kid.type === "ba") {
return getLong(piece.block.ps); return [grammarUnits.baParticle];
} }
if (piece.type === "perfectParticipleBlock") { if (piece.kid.type === "mini-pronoun") {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs return [piece.kid.ps];
return getLong(piece.ps); }
}
if (piece.type === "perfectEquativeBlock") {
// just using the short one for now - it will only be short anyways
return getShort(piece.ps);
}
if (piece.type === "modalVerbBlock") {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs
return getLong(piece.ps);
}
if (piece.type === "modalVerbKedulPart") {
// just using the short one for now - it will only be short anyways
return getShort(piece.ps);
} }
throw new Error("unrecognized piece type"); throw new Error("unrecognized piece type");
} }
@ -317,7 +322,7 @@ export function checkForMiniPronounsError(s: T.EPSelectionState | T.VPSelectionS
return renderVP(VPS).kids; return renderVP(VPS).kids;
})(); })();
if (!kids) return undefined; if (!kids) return undefined;
const miniPronouns = kids.filter(x => x.type === "mini-pronoun") as T.MiniPronoun[]; const miniPronouns = kids.filter(x => x.kid.type === "mini-pronoun").map(m => m.kid) as T.MiniPronoun[];
if (miniPronouns.length > 2) { if (miniPronouns.length > 2) {
return "can't add another mini-pronoun, there are alread two"; return "can't add another mini-pronoun, there are alread two";
} }

View File

@ -88,11 +88,11 @@ export function getMiniPronounPs(person: T.Person): T.PsString {
export function orderKids(kids: T.Kid[]): T.Kid[] { export function orderKids(kids: T.Kid[]): T.Kid[] {
const sorted = [...kids].sort((a, b) => { const sorted = [...kids].sort((a, b) => {
// ba first // ba first
if (a.type === "ba") return -1; if (a.kid.type === "ba") return -1;
// kinds lined up 1st 2nd 3rd person // kinds lined up 1st 2nd 3rd person
if (a.type === "mini-pronoun" && b.type === "mini-pronoun") { if (a.kid.type === "mini-pronoun" && b.kid.type === "mini-pronoun") {
const aPers = getFirstSecThird(a.person); const aPers = getFirstSecThird(a.kid.person);
const bPers = getFirstSecThird(b.person); const bPers = getFirstSecThird(b.kid.person);
if (aPers < bPers) { if (aPers < bPers) {
return -1; return -1;
} }

View File

@ -11,7 +11,7 @@ import { psStringFromEntry } from "../p-text-helpers";
import { isLocativeAdverbEntry } from "../type-predicates"; import { isLocativeAdverbEntry } from "../type-predicates";
import { renderAdjectiveSelection } from "./render-adj"; import { renderAdjectiveSelection } from "./render-adj";
import { renderSandwich } from "./render-sandwich"; import { renderSandwich } from "./render-sandwich";
import { EPSBlocksAreComplete, getSubjectSelection } from "./blocks-utils"; import { EPSBlocksAreComplete, getSubjectSelection, makeBlock, makeKid } from "./blocks-utils";
import { removeAccentsWLength } from "../accent-helpers"; import { removeAccentsWLength } from "../accent-helpers";
import { findPossesivesToShrink, orderKids } from "./render-common"; import { findPossesivesToShrink, orderKids } from "./render-common";
@ -41,18 +41,18 @@ function getEPSBlocksAndKids(EP: T.EPSelectionComplete): { kids: T.Kid[], blocks
const equative: T.EquativeBlock = { type: "equative", equative: renderEquative(EP.equative, commandingPerson) }; const equative: T.EquativeBlock = { type: "equative", equative: renderEquative(EP.equative, commandingPerson) };
const blocks: T.Block[][] = insertNegative([ const blocks: T.Block[][] = insertNegative([
...renderEPSBlocks(EP.blocks), ...renderEPSBlocks(EP.blocks),
{ makeBlock({
type: "predicateSelection", type: "predicateSelection",
selection: EP.predicate.selection.type === "NP" selection: EP.predicate.selection.type === "NP"
? renderNPSelection(EP.predicate.selection, false, false, "subject", "king") ? renderNPSelection(EP.predicate.selection, false, false, "subject", "king")
: renderEqCompSelection(EP.predicate.selection, commandingPerson), : renderEqCompSelection(EP.predicate.selection, commandingPerson),
}, }),
equative, makeBlock(equative),
], EP.equative.negative); ], EP.equative.negative);
const miniPronouns = findPossesivesToShrink(removeOrKeepSubject([...EP.blocks, EP.predicate], EP.omitSubject)); const miniPronouns = findPossesivesToShrink(removeOrKeepSubject([...EP.blocks, EP.predicate], EP.omitSubject));
const kids: T.Kid[] = orderKids([ const kids: T.Kid[] = orderKids([
...equative.equative.hasBa ? [{ type: "ba" } as T.Kid] : [], ...equative.equative.hasBa ? [makeKid({ type: "ba" })] : [],
...miniPronouns, ...miniPronouns.map(makeKid),
]); ]);
return { return {
blocks, blocks,
@ -69,12 +69,12 @@ function insertNegative(blocks: T.Block[], negative: boolean): T.Block[][] {
return [ return [
[ [
...blocksA.slice(0, blocks.length - 1), ...blocksA.slice(0, blocks.length - 1),
{ type: "negative", imperative: false }, makeBlock({ type: "negative", imperative: false }),
...blocksA.slice(-1), // last (equative) ...blocksA.slice(-1), // last (equative)
], ],
[ [
...blocksA.slice(0, blocks.length - 2), ...blocksA.slice(0, blocks.length - 2),
{ type: "negative", imperative: false }, makeBlock({ type: "negative", imperative: false }),
...blocksA.slice(-1), // last (equative) ...blocksA.slice(-1), // last (equative)
...blocksA.slice(-2, -1), // second last (predicate) ...blocksA.slice(-2, -1), // second last (predicate)
], ],
@ -100,25 +100,25 @@ export function getEquativeForm(tense: T.EquativeTense): { hasBa: boolean, form:
} }
function renderEPSBlocks(blocks: T.EPSBlockComplete[]): T.Block[] { function renderEPSBlocks(blocks: T.EPSBlockComplete[]): T.Block[] {
return blocks.map(({ block }): (T.Rendered<T.SubjectSelectionComplete> | T.Rendered<T.APSelection>) => { return blocks.map(({ block }): T.Block => {
if (block.type === "AP") { if (block.type === "AP") {
if (block.selection.type === "adverb") { if (block.selection.type === "adverb") {
return { return makeBlock({
type: "AP", type: "AP",
selection: renderAdverbSelection(block.selection), selection: renderAdverbSelection(block.selection),
}; });
} }
// if (block.selection.type === "sandwich") { // if (block.selection.type === "sandwich") {
return { return makeBlock({
type: "AP", type: "AP",
selection: renderSandwich(block.selection), selection: renderSandwich(block.selection),
}; });
// } // }
} }
return { return makeBlock({
type: "subjectSelection", type: "subjectSelection",
selection: renderNPSelection(block.selection, false, false, "subject", "none") selection: renderNPSelection(block.selection, false, false, "subject", "none"),
}; });
}); });
} }
@ -279,15 +279,17 @@ export function completeEPSelection(eps: T.EPSelectionState): T.EPSelectionCompl
function removeAccentsFromEq(blocks: T.Block[]): T.Block[] { function removeAccentsFromEq(blocks: T.Block[]): T.Block[] {
return blocks.map((block) => { return blocks.map((block) => {
if (block.type === "equative") { if (block.block.type === "equative") {
const e: T.EquativeBlock = { return {
...block, ...block,
equative: { block: {
...block.equative, ...block.block,
ps: removeAccentsWLength(block.equative.ps), equative: {
}, ...block.block.equative,
}; ps: removeAccentsWLength(block.block.equative.ps),
return e; }
}
}
} }
return block; return block;
}); });

View File

@ -26,7 +26,7 @@ import {
import { renderEnglishVPBase } from "./english-vp-rendering"; import { renderEnglishVPBase } from "./english-vp-rendering";
import { personGender } from "../../lib/misc-helpers"; import { personGender } from "../../lib/misc-helpers";
import { renderNPSelection } from "./render-np"; import { renderNPSelection } from "./render-np";
import { getObjectSelection, getSubjectSelection } from "./blocks-utils"; import { getObjectSelection, getSubjectSelection, makeBlock, makeKid } from "./blocks-utils";
import { renderAPSelection } from "./render-ap"; import { renderAPSelection } from "./render-ap";
import { findPossesivesToShrink, orderKids, getMiniPronounPs } from "./render-common"; import { findPossesivesToShrink, orderKids, getMiniPronounPs } from "./render-common";
@ -67,7 +67,7 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
isCompound: VP.verb.isCompound, isCompound: VP.verb.isCompound,
blocks: insertNegative([ blocks: insertNegative([
...firstBlocks, ...firstBlocks,
...verbBlocks, ...verbBlocks.map(makeBlock),
], VP.verb.negative, isImperativeTense(VP.verb.tense)), ], VP.verb.negative, isImperativeTense(VP.verb.tense)),
kids: getVPKids(hasBa, VP.blocks, VP.form, king), kids: getVPKids(hasBa, VP.blocks, VP.form, king),
englishBase: renderEnglishVPBase({ englishBase: renderEnglishVPBase({
@ -200,11 +200,11 @@ function getVPKids(hasBa: boolean, blocks: T.VPSBlockComplete[], form: T.FormVer
const object = typeof objectS === "object" ? objectS : undefined; const object = typeof objectS === "object" ? objectS : undefined;
const servantNP = king === "subject" ? object : subject; const servantNP = king === "subject" ? object : subject;
const shrunkenServant = (form.shrinkServant && servantNP) const shrunkenServant = (form.shrinkServant && servantNP)
? shrinkServant(servantNP) ? makeKid(shrinkServant(servantNP))
: undefined; : undefined;
const shrunkenPossesives = findPossesivesToShrink(removeAbbreviated(blocks, form, king)); const shrunkenPossesives = findPossesivesToShrink(removeAbbreviated(blocks, form, king)).map(makeKid);
return orderKids([ return orderKids([
...hasBa ? [{ type: "ba" } as T.Kid] : [], ...hasBa ? [makeKid({ type: "ba" })] : [],
...shrunkenServant ? [shrunkenServant] : [], ...shrunkenServant ? [shrunkenServant] : [],
...shrunkenPossesives ? shrunkenPossesives : [], ...shrunkenPossesives ? shrunkenPossesives : [],
]); ]);
@ -231,10 +231,10 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea
const blocksA = removeVerbAccent(blocks); const blocksA = removeVerbAccent(blocks);
const basic: T.Block[] = [ const basic: T.Block[] = [
...blocksA.slice(0, blocks.length - 1), ...blocksA.slice(0, blocks.length - 1),
{ makeBlock({
type: "negative", type: "negative",
imperative, imperative,
}, }),
...blocksA.slice(-1), ...blocksA.slice(-1),
]; ];
if (hasNonStandardPerfectiveSplit(blocks)) { if (hasNonStandardPerfectiveSplit(blocks)) {
@ -242,7 +242,7 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea
basic, basic,
[ [
...blocksA.slice(0, blocks.length - 2), ...blocksA.slice(0, blocks.length - 2),
{ type: "negative", imperative }, makeBlock({ type: "negative", imperative }),
...blocksA.slice(-2, -1), // second last (perfective split) ...blocksA.slice(-2, -1), // second last (perfective split)
...blocksA.slice(-1), // last (verb) ...blocksA.slice(-1), // last (verb)
], ],
@ -252,7 +252,7 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea
return [ return [
[ [
...blocksA.slice(0, blocks.length - 2), ...blocksA.slice(0, blocks.length - 2),
{ type: "negative", imperative }, makeBlock({ type: "negative", imperative }),
...blocksA.slice(-1), // last ...blocksA.slice(-1), // last
...blocksA.slice(-2, -1), // second last ...blocksA.slice(-2, -1), // second last
], ],
@ -263,31 +263,34 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea
} }
function hasLeapFroggable(blocks: T.Block[]): boolean { function hasLeapFroggable(blocks: T.Block[]): boolean {
return blocks.some(b => b.type === "perfectEquativeBlock" || b.type === "modalVerbBlock"); return blocks.some(b => b.block.type === "perfectEquativeBlock" || b.block.type === "modalVerbBlock");
} }
function hasNonStandardPerfectiveSplit(blocks: T.Block[]): boolean { function hasNonStandardPerfectiveSplit(blocks: T.Block[]): boolean {
const perfS = blocks.find(b => b.type === "perfectiveHead"); const perfS = blocks.find(b => b.block.type === "perfectiveHead");
if (!perfS || perfS.type !== "perfectiveHead") { if (!perfS || perfS.block.type !== "perfectiveHead") {
return false; return false;
} }
return !["و", "وا"].includes(perfS.ps.p); return !["و", "وا"].includes(perfS.block.ps.p);
} }
function removeVerbAccent(blocks: T.Block[]): T.Block[] { function removeVerbAccent(blocks: T.Block[]): T.Block[] {
return blocks.map((block) => { return blocks.map((block) => {
if (block.type === "perfectiveHead") { if (block.block.type === "perfectiveHead") {
return {
...block,
ps: removeAccents(block.ps),
};
}
if (block.type === "verb") {
return { return {
...block, ...block,
block: { block: {
...block.block, ...block.block,
ps: removeAccentsWLength(block.block.ps), ps: removeAccents(block.block.ps),
},
};
}
if (block.block.type === "verb") {
return {
...block,
block: {
...block.block,
ps: removeAccentsWLength(block.block.block.ps),
}, },
}; };
} }
@ -315,10 +318,10 @@ function renderVPBlocks(blocks: T.VPSBlockComplete[], config: {
if (block.type === "subjectSelection") { if (block.type === "subjectSelection") {
return [ return [
...blocks, ...blocks,
{ makeBlock({
type: "subjectSelection", type: "subjectSelection",
selection: renderNPSelection(block.selection, config.inflectSubject, false, "subject", config.king === "subject" ? "king" : "servant"), selection: renderNPSelection(block.selection, config.inflectSubject, false, "subject", config.king === "subject" ? "king" : "servant"),
}, }),
]; ];
} }
if (block.type === "objectSelection") { if (block.type === "objectSelection") {
@ -326,24 +329,24 @@ function renderVPBlocks(blocks: T.VPSBlockComplete[], config: {
if (typeof object !== "object") { if (typeof object !== "object") {
return [ return [
...blocks, ...blocks,
{ makeBlock({
type: "objectSelection", type: "objectSelection",
selection: object, selection: object,
}, }),
]; ];
} }
const selection = renderNPSelection(object, config.inflectObject, true, "object", config.king === "object" ? "king" : "servant"); const selection = renderNPSelection(object, config.inflectObject, true, "object", config.king === "object" ? "king" : "servant");
return [ return [
...blocks, ...blocks,
{ makeBlock({
type: "objectSelection", type: "objectSelection",
selection, selection,
}, }),
]; ];
} }
return [ return [
...blocks, ...blocks,
renderAPSelection(block), makeBlock(renderAPSelection(block)),
]; ];
}, [] as T.Block[]); }, [] as T.Block[]);
} }
@ -362,7 +365,8 @@ function whatsAdjustable(VP: T.VPSelectionComplete): "both" | "king" | "servant"
: "king"; : "king";
} }
type VerbBlocks = | [T.PerfectiveHeadBlock, T.VerbRenderedBlock] // verb w perfective split type VerbBlocks =
| [T.PerfectiveHeadBlock, T.VerbRenderedBlock] // verb w perfective split
| [T.VerbRenderedBlock] // verb w/out perfective split | [T.VerbRenderedBlock] // verb w/out perfective split
| [T.PerfectParticipleBlock, T.PerfectEquativeBlock] // perfect verb | [T.PerfectParticipleBlock, T.PerfectEquativeBlock] // perfect verb
| [T.ModalVerbBlock, T.ModalVerbKedulPart] // modal verb | [T.ModalVerbBlock, T.ModalVerbKedulPart] // modal verb

View File

@ -900,24 +900,28 @@ export type VerbRenderedBlock = {
}, },
}; };
export type Block = export type Block = {
| Rendered<SubjectSelectionComplete> key: number,
| Rendered<ObjectSelectionComplete> block: | Rendered<SubjectSelectionComplete>
| Rendered<APSelection> | Rendered<ObjectSelectionComplete>
| Rendered<PredicateSelectionComplete> | Rendered<APSelection>
| PerfectParticipleBlock | Rendered<PredicateSelectionComplete>
| PerfectEquativeBlock | PerfectParticipleBlock
| ModalVerbBlock | PerfectEquativeBlock
| ModalVerbKedulPart | ModalVerbBlock
| { type: "negative", imperative: boolean } | ModalVerbKedulPart
| PerfectiveHeadBlock | { type: "negative", imperative: boolean }
| VerbRenderedBlock | PerfectiveHeadBlock
| VerbComplementBlock | VerbRenderedBlock
| EquativeBlock; | VerbComplementBlock
| EquativeBlock;
}
export type Kid = export type Kid = {
| { type: "ba" } key: number,
| MiniPronoun; kid: | { type: "ba" }
| MiniPronoun,
}
export type MiniPronoun = { export type MiniPronoun = {
type: "mini-pronoun", type: "mini-pronoun",