From 4062cedd484376dd89c9a0df188732a938b8e0df Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Fri, 24 Jun 2022 14:29:33 -0500 Subject: [PATCH] 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 --- src/components/RenderedBlocksDisplay.tsx | 21 +++- src/components/blocks/Block.tsx | 64 +++++------ src/components/blocks/KidDisplay.tsx | 6 +- src/lib/phrase-building/blocks-utils.ts | 124 +++++++++++++--------- src/lib/phrase-building/compile.ts | 129 ++++++++++++----------- src/lib/phrase-building/render-common.ts | 8 +- src/lib/phrase-building/render-ep.ts | 56 +++++----- src/lib/phrase-building/render-vp.ts | 62 ++++++----- src/types.ts | 38 ++++--- 9 files changed, 280 insertions(+), 228 deletions(-) diff --git a/src/components/RenderedBlocksDisplay.tsx b/src/components/RenderedBlocksDisplay.tsx index afdb076..34c4052 100644 --- a/src/components/RenderedBlocksDisplay.tsx +++ b/src/components/RenderedBlocksDisplay.tsx @@ -1,4 +1,5 @@ import { useState } from "react"; +// import autoAnimate from "@formkit/auto-animate"; import { filterForVisibleBlocksEP, filterForVisibleBlocksVP } from "../lib/phrase-building/compile"; import * as T from "../types"; import Block from "./blocks/Block"; @@ -11,6 +12,11 @@ function RenderedBlocksDisplay({ opts, rendered, justify, script }: { justify?: "left" | "right" | "center", }) { const [variation, setVariation] = useState(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) ? filterForVisibleBlocksEP(rendered.blocks, rendered.omitSubject) : filterForVisibleBlocksVP(rendered.blocks, rendered.form, rendered.king); @@ -19,14 +25,14 @@ function RenderedBlocksDisplay({ opts, rendered, justify, script }: { function handleVariationChange() { setVariation(ov => ((ov + 1) % blocksWVars.length)); } - return
+ return
-
+
- + {blocks.slice(1).map((block) => ( -
+
))} @@ -42,10 +48,15 @@ function KidsSection({ opts, kids, script }: { kids: T.Kid[], 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 ?
{kids.map(kid => ( - + ))}
kids
diff --git a/src/components/blocks/Block.tsx b/src/components/blocks/Block.tsx index 4ae4782..68cb46a 100644 --- a/src/components/blocks/Block.tsx +++ b/src/components/blocks/Block.tsx @@ -15,53 +15,53 @@ function Block({ opts, block, king, script }: { king?: "subject" | "object" | undefined, script: "p" | "f"; }) { - if ("equative" in block) { - return ; + if ("equative" in block.block) { + return ; } - if (block.type === "AP") { - const english = getEnglishFromRendered(block); - return {block} + if (block.block.type === "AP") { + const english = getEnglishFromRendered(block.block); + return {block.block} } - if (block.type === "subjectSelection") { + if (block.block.type === "subjectSelection") { const role = king === "subject" ? "king" : king === "object" ? "servant" : undefined; - return + return } - if (block.type === "predicateSelection") { - const english = getEnglishFromRendered(block.selection); + if (block.block.type === "predicateSelection") { + const english = getEnglishFromRendered(block.block.selection); return
Predicate
- {block.selection.type === "EQComp" - ? - : {block.selection}} + {block.block.selection.type === "EQComp" + ? + : {block.block.selection}}
} - if (block.type === "negative") { - return + if (block.block.type === "negative") { + return } - if (block.type === "perfectiveHead") { - return + if (block.block.type === "perfectiveHead") { + return } - if (block.type === "verbComplement") { - return ; + if (block.block.type === "verbComplement") { + return ; } - if (block.type === "verb") { + if (block.block.type === "verb") { + return ; + } + if (block.block.type === "objectSelection") { + const role = king === "object" ? "king" : king === "subject" ? "servant" : undefined; + return ; + } + if (block.block.type === "perfectParticipleBlock") { return ; } - if (block.type === "objectSelection") { - const role = king === "object" ? "king" : king === "subject" ? "servant" : undefined; - return ; + if (block.block.type === "perfectEquativeBlock") { + return ; } - if (block.type === "perfectParticipleBlock") { - return ; + if (block.block.type === "modalVerbBlock") { + return ; } - if (block.type === "perfectEquativeBlock") { - return ; - } - if (block.type === "modalVerbBlock") { - return ; - } - if (block.type === "modalVerbKedulPart") { - return + if (block.block.type === "modalVerbKedulPart") { + return } return null; } diff --git a/src/components/blocks/KidDisplay.tsx b/src/components/blocks/KidDisplay.tsx index 714b977..593e285 100644 --- a/src/components/blocks/KidDisplay.tsx +++ b/src/components/blocks/KidDisplay.tsx @@ -8,10 +8,10 @@ function KidDisplay({ opts, kid, script }: { kid: T.Kid, script: "p" | "f", }) { - const ps = kid.type === "ba" + const ps = kid.kid.type === "ba" ? baParticle - : kid.ps; - return
+ : kid.kid.ps; + return
{script === "p" ? {ps} : {ps}} diff --git a/src/lib/phrase-building/blocks-utils.ts b/src/lib/phrase-building/blocks-utils.ts index ae8d60a..8c77e28 100644 --- a/src/lib/phrase-building/blocks-utils.ts +++ b/src/lib/phrase-building/blocks-utils.ts @@ -1,6 +1,20 @@ import * as T from "../../types"; import { getLength } from "../p-text-helpers"; +export function makeBlock(block: T.Block["block"], key?: number): T.Block { + return { + key: key === undefined ? Math.random() : key, + block, + }; +} + +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.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection; 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 { - const b = blocks[0].find(f => f.type === "subjectSelection"); - if (!b || b.type !== "subjectSelection") { + const b = blocks[0].find(f => f.block.type === "subjectSelection"); + if (!b || b.block.type !== "subjectSelection") { throw new Error("subjectSelection not found in blocks"); } - return b; + return b.block; } export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered { - const b = blocks[0].find(f => f.type === "objectSelection"); - if (!b || b.type !== "objectSelection") { + const b = blocks[0].find(f => f.block.type === "objectSelection"); + if (!b || b.block.type !== "objectSelection") { throw new Error("objectSelection not found in blocks"); } - return b; + return b.block; } export function getVerbFromBlocks(blocks: T.Block[][]): T.VerbRenderedBlock { - const b = blocks[0].find(f => f.type === "verb"); - const p = blocks[0].find(f => f.type === "perfectParticipleBlock"); - const m = blocks[0].find(f => f.type === "modalVerbBlock"); - const v = (b && b.type === "verb") - ? b - : (p && p.type === "perfectParticipleBlock") - ? p.verb - : (m && m.type === "modalVerbBlock") - ? m.verb + const b = blocks[0].find(f => f.block.type === "verb"); + const p = blocks[0].find(f => f.block.type === "perfectParticipleBlock"); + const m = blocks[0].find(f => f.block.type === "modalVerbBlock"); + const v = (b && b.block.type === "verb") + ? b.block + : (p && p.block.type === "perfectParticipleBlock") + ? p.block.verb + : (m && m.block.type === "modalVerbBlock") + ? m.block.verb : undefined; if (!v) { 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 } { const verb = getVerbFromBlocks(blocks); - const perfectiveHead = blocks[0].find(f => f.type === "perfectiveHead"); - if (!perfectiveHead || perfectiveHead.type !== "perfectiveHead") { + const perfectiveHead = blocks[0].find(f => f.block.type === "perfectiveHead"); + if (!perfectiveHead || perfectiveHead.block.type !== "perfectiveHead") { return { verb, perfectiveHead: undefined, @@ -55,27 +69,27 @@ export function getVerbAndHeadFromBlocks(blocks: T.Block[][]): { verb: T.VerbRen } return { verb, - perfectiveHead, + perfectiveHead: perfectiveHead.block, }; } export function includesShrunkenServant(kids?: T.Kid[]): boolean { if (!kids) return false; 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 { - const b = blocks[0].find(f => f.type === "predicateSelection"); - if (!b || b.type !== "predicateSelection") { + const b = blocks[0].find(f => f.block.type === "predicateSelection"); + if (!b || b.block.type !== "predicateSelection") { throw new Error("predicateSelection not found in blocks"); } - return b; + return b.block; } export function getAPsFromBlocks(blocks: T.Block[][]): T.Rendered[] { - return blocks[0].filter(b => b.type === "AP") as T.Rendered[]; + return blocks[0].filter(b => b.block.type === "AP").map(b => b.block) as T.Rendered[]; } 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[][] { 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"); 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]; adjusted[i] = { ...eq, - equative: { - ...eq.equative, - ps: getLength(eq.equative.ps, length), + block: { + ...eq.block, + equative: { + ...eq.block.equative, + ps: getLength(eq.block.equative.ps, length), + }, }, }; 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[][] { function specify(blocks: T.Block[]): T.Block[] { - return blocks.map((block) => { - if (block.type === "verb") { - const v: T.VerbRenderedBlock = { + return blocks.map((block): T.Block => { + if (block.block.type === "verb") { + 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, ps: getLength(block.block.ps, length), }, }; - return v; - } - if (block.type === "perfectParticipleBlock") { - const p: T.PerfectParticipleBlock = { - ...block, - ps: getLength(block.ps, length), - }; return p; } - if (block.type === "modalVerbBlock") { - const m: T.ModalVerbBlock = { + if (block.block.type === "modalVerbBlock") { + const m: T.Block = { ...block, - ps: getLength(block.ps, length), + block: { + ...block.block, + ps: getLength(block.block.ps, length), + }, }; return m; } @@ -289,21 +315,21 @@ export function specifyVerbLength(blocksWVars: T.Block[][], length: "long" | "sh } 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.type !== "equative") throw new Error("error finding equative in blocks"); - return "long" in equative.equative.ps; + if (equative.block.type !== "equative") throw new Error("error finding equative in blocks"); + return "long" in equative.block.equative.ps; } export function hasVerbWithLengths(blocks: T.Block[][]): boolean { // 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.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 ( - (verb.type === "verb" && "long" in verb.block.ps) - || (verb.type === "perfectParticipleBlock" && "long" in verb.ps) - || (verb.type === "modalVerbBlock" && "long" in verb.ps) + (verb.block.type === "verb" && "long" in verb.block.block.ps) + || (verb.block.type === "perfectParticipleBlock" && "long" in verb.block.ps) + || (verb.block.type === "modalVerbBlock" && "long" in verb.block.ps) ); } diff --git a/src/lib/phrase-building/compile.ts b/src/lib/phrase-building/compile.ts index 9f38c88..84cb3ff 100644 --- a/src/lib/phrase-building/compile.ts +++ b/src/lib/phrase-building/compile.ts @@ -107,7 +107,7 @@ function compileEPPs(blocks: T.Block[][], kids: T.Kid[], omitSubject: boolean, b const subjectPerson = getSubjectSelectionFromBlocks(blocks) .selection.selection.person; 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, !!blankOut?.kidsSection ); @@ -119,19 +119,19 @@ export function filterForVisibleBlocksVP(blocks: T.Block[][], form: T.FormVersio return blocks.map(blks => blks.filter((block) => { if (form.removeKing) { 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; } if (form.shrinkServant) { 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; } - if (block.type === "objectSelection" && typeof block.selection !== "object") { + if (block.block.type === "objectSelection" && typeof block.block.selection !== "object") { return false; } 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[][] { if (!omitSubject) return blocks; - return blocks.map(blks => blks.filter((block) => { + return blocks.map(blks => blks.filter(({ block }) => { if (block.type === "subjectSelection") { return false; } @@ -155,9 +155,9 @@ function combineIntoText(piecesWVars: (T.Block | T.Kid | T.PsString)[][], subjec const rest = pieces.slice(1); const firstPs = ("p" in first) ? [first] - : (blankOut?.equative && first.type === "equative") + : (blankOut?.equative && "block" in first && first.block.type === "equative") ? [blank] - : ((blankOut?.ba) && first.type === "ba") + : ((blankOut?.ba) && "kid" in first && first.kid.type === "ba") ? [kidsBlank] : getPsFromPiece(first, subjectPerson); if (!rest.length) { @@ -166,8 +166,8 @@ function combineIntoText(piecesWVars: (T.Block | T.Kid | T.PsString)[][], subjec return combine(rest).flatMap(r => ( firstPs.map(fPs => concatPsString( fPs, - (!("p" in first) && first.type === "perfectiveHead" && !("p" in next) && (next.type === "verb" || next.type === "negative" || next.type === "mini-pronoun")) - ? ((next.type === "negative" || next.type === "mini-pronoun") ? { p: "", f: "-" } : "") + (!("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"))) + ? ((("block" in next && next.block.type === "negative") || ("kid" in next && next.kid.type === "mini-pronoun")) ? { p: "", f: "-" } : "") : " ", 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[] { - if (piece.type === "ba") { - return [grammarUnits.baParticle]; - } - if (piece.type === "mini-pronoun") { - return [piece.ps]; - } - if (piece.type === "negative") { - return [ - negativeParticle[piece.imperative ? "imperative" : "nonImperative"], - ]; - } - if (piece.type === "equative") { - // length will already be specified in compileEPPs - this is just for type safety - return getLong(piece.equative.ps); - } - if (piece.type === "subjectSelection" || piece.type === "predicateSelection") { - return getPashtoFromRendered(piece.selection, subjectPerson); - } - if (piece.type === "AP") { - return getPashtoFromRendered(piece, subjectPerson); - } - if (piece.type === "perfectiveHead") { - return [piece.ps]; - } - if (piece.type === "verbComplement") { - return [{ p: "---", f: "---"}]; //getPashtoFromRendered(piece.complement); - } - if (piece.type === "objectSelection") { - if (typeof piece.selection !== "object") { - return [{ p: "", f: "" }]; + if ("block" in piece) { + if (piece.block.type === "negative") { + return [ + negativeParticle[piece.block.imperative ? "imperative" : "nonImperative"], + ]; + } + if (piece.block.type === "equative") { + // length will already be specified in compileEPPs - this is just for type safety + return getLong(piece.block.equative.ps); + } + if (piece.block.type === "subjectSelection" || piece.block.type === "predicateSelection") { + return getPashtoFromRendered(piece.block.selection, subjectPerson); + } + if (piece.block.type === "AP") { + return getPashtoFromRendered(piece.block, subjectPerson); + } + if (piece.block.type === "perfectiveHead") { + return [piece.block.ps]; + } + if (piece.block.type === "verbComplement") { + return [{ p: "---", f: "---"}]; //getPashtoFromRendered(piece.block.complement); + } + if (piece.block.type === "objectSelection") { + if (typeof piece.block.selection !== "object") { + return [{ p: "", f: "" }]; + } + return getPashtoFromRendered(piece.block.selection, subjectPerson); + } + if (piece.block.type === "verb") { + // 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") { - // getLong is just for type safety - we will have split up the length options earlier in compileVPPs - return getLong(piece.block.ps); - } - if (piece.type === "perfectParticipleBlock") { - // getLong is just for type safety - we will have split up the length options earlier in compileVPPs - 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); + if ("kid" in piece) { + if (piece.kid.type === "ba") { + return [grammarUnits.baParticle]; + } + if (piece.kid.type === "mini-pronoun") { + return [piece.kid.ps]; + } } + throw new Error("unrecognized piece type"); } @@ -317,7 +322,7 @@ export function checkForMiniPronounsError(s: T.EPSelectionState | T.VPSelectionS return renderVP(VPS).kids; })(); 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) { return "can't add another mini-pronoun, there are alread two"; } diff --git a/src/lib/phrase-building/render-common.ts b/src/lib/phrase-building/render-common.ts index 237bd41..abdb3f5 100644 --- a/src/lib/phrase-building/render-common.ts +++ b/src/lib/phrase-building/render-common.ts @@ -88,11 +88,11 @@ export function getMiniPronounPs(person: T.Person): T.PsString { export function orderKids(kids: T.Kid[]): T.Kid[] { const sorted = [...kids].sort((a, b) => { // ba first - if (a.type === "ba") return -1; + if (a.kid.type === "ba") return -1; // kinds lined up 1st 2nd 3rd person - if (a.type === "mini-pronoun" && b.type === "mini-pronoun") { - const aPers = getFirstSecThird(a.person); - const bPers = getFirstSecThird(b.person); + if (a.kid.type === "mini-pronoun" && b.kid.type === "mini-pronoun") { + const aPers = getFirstSecThird(a.kid.person); + const bPers = getFirstSecThird(b.kid.person); if (aPers < bPers) { return -1; } diff --git a/src/lib/phrase-building/render-ep.ts b/src/lib/phrase-building/render-ep.ts index f9cff82..dc44250 100644 --- a/src/lib/phrase-building/render-ep.ts +++ b/src/lib/phrase-building/render-ep.ts @@ -11,7 +11,7 @@ import { psStringFromEntry } from "../p-text-helpers"; import { isLocativeAdverbEntry } from "../type-predicates"; import { renderAdjectiveSelection } from "./render-adj"; 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 { 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 blocks: T.Block[][] = insertNegative([ ...renderEPSBlocks(EP.blocks), - { + makeBlock({ type: "predicateSelection", - selection: EP.predicate.selection.type === "NP" - ? renderNPSelection(EP.predicate.selection, false, false, "subject", "king") - : renderEqCompSelection(EP.predicate.selection, commandingPerson), - }, - equative, + selection: EP.predicate.selection.type === "NP" + ? renderNPSelection(EP.predicate.selection, false, false, "subject", "king") + : renderEqCompSelection(EP.predicate.selection, commandingPerson), + }), + makeBlock(equative), ], EP.equative.negative); const miniPronouns = findPossesivesToShrink(removeOrKeepSubject([...EP.blocks, EP.predicate], EP.omitSubject)); const kids: T.Kid[] = orderKids([ - ...equative.equative.hasBa ? [{ type: "ba" } as T.Kid] : [], - ...miniPronouns, + ...equative.equative.hasBa ? [makeKid({ type: "ba" })] : [], + ...miniPronouns.map(makeKid), ]); return { blocks, @@ -69,12 +69,12 @@ function insertNegative(blocks: T.Block[], negative: boolean): T.Block[][] { return [ [ ...blocksA.slice(0, blocks.length - 1), - { type: "negative", imperative: false }, + makeBlock({ type: "negative", imperative: false }), ...blocksA.slice(-1), // last (equative) ], [ ...blocksA.slice(0, blocks.length - 2), - { type: "negative", imperative: false }, + makeBlock({ type: "negative", imperative: false }), ...blocksA.slice(-1), // last (equative) ...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[] { - return blocks.map(({ block }): (T.Rendered | T.Rendered) => { + return blocks.map(({ block }): T.Block => { if (block.type === "AP") { if (block.selection.type === "adverb") { - return { + return makeBlock({ type: "AP", selection: renderAdverbSelection(block.selection), - }; + }); } // if (block.selection.type === "sandwich") { - return { + return makeBlock({ type: "AP", selection: renderSandwich(block.selection), - }; + }); // } } - return { + return makeBlock({ 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[] { return blocks.map((block) => { - if (block.type === "equative") { - const e: T.EquativeBlock = { + if (block.block.type === "equative") { + return { ...block, - equative: { - ...block.equative, - ps: removeAccentsWLength(block.equative.ps), - }, - }; - return e; + block: { + ...block.block, + equative: { + ...block.block.equative, + ps: removeAccentsWLength(block.block.equative.ps), + } + } + } } return block; }); diff --git a/src/lib/phrase-building/render-vp.ts b/src/lib/phrase-building/render-vp.ts index 5e9c3f5..8bdd485 100644 --- a/src/lib/phrase-building/render-vp.ts +++ b/src/lib/phrase-building/render-vp.ts @@ -26,7 +26,7 @@ import { import { renderEnglishVPBase } from "./english-vp-rendering"; import { personGender } from "../../lib/misc-helpers"; 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 { findPossesivesToShrink, orderKids, getMiniPronounPs } from "./render-common"; @@ -67,7 +67,7 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered { isCompound: VP.verb.isCompound, blocks: insertNegative([ ...firstBlocks, - ...verbBlocks, + ...verbBlocks.map(makeBlock), ], VP.verb.negative, isImperativeTense(VP.verb.tense)), kids: getVPKids(hasBa, VP.blocks, VP.form, king), englishBase: renderEnglishVPBase({ @@ -200,11 +200,11 @@ function getVPKids(hasBa: boolean, blocks: T.VPSBlockComplete[], form: T.FormVer const object = typeof objectS === "object" ? objectS : undefined; const servantNP = king === "subject" ? object : subject; const shrunkenServant = (form.shrinkServant && servantNP) - ? shrinkServant(servantNP) + ? makeKid(shrinkServant(servantNP)) : undefined; - const shrunkenPossesives = findPossesivesToShrink(removeAbbreviated(blocks, form, king)); + const shrunkenPossesives = findPossesivesToShrink(removeAbbreviated(blocks, form, king)).map(makeKid); return orderKids([ - ...hasBa ? [{ type: "ba" } as T.Kid] : [], + ...hasBa ? [makeKid({ type: "ba" })] : [], ...shrunkenServant ? [shrunkenServant] : [], ...shrunkenPossesives ? shrunkenPossesives : [], ]); @@ -231,10 +231,10 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea const blocksA = removeVerbAccent(blocks); const basic: T.Block[] = [ ...blocksA.slice(0, blocks.length - 1), - { + makeBlock({ type: "negative", imperative, - }, + }), ...blocksA.slice(-1), ]; if (hasNonStandardPerfectiveSplit(blocks)) { @@ -242,7 +242,7 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea basic, [ ...blocksA.slice(0, blocks.length - 2), - { type: "negative", imperative }, + makeBlock({ type: "negative", imperative }), ...blocksA.slice(-2, -1), // second last (perfective split) ...blocksA.slice(-1), // last (verb) ], @@ -252,7 +252,7 @@ function insertNegative(blocks: T.Block[], negative: boolean, imperative: boolea return [ [ ...blocksA.slice(0, blocks.length - 2), - { type: "negative", imperative }, + makeBlock({ type: "negative", imperative }), ...blocksA.slice(-1), // 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 { - 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 { - const perfS = blocks.find(b => b.type === "perfectiveHead"); - if (!perfS || perfS.type !== "perfectiveHead") { + const perfS = blocks.find(b => b.block.type === "perfectiveHead"); + if (!perfS || perfS.block.type !== "perfectiveHead") { return false; } - return !["و", "وا"].includes(perfS.ps.p); + return !["و", "وا"].includes(perfS.block.ps.p); } function removeVerbAccent(blocks: T.Block[]): T.Block[] { return blocks.map((block) => { - if (block.type === "perfectiveHead") { - return { - ...block, - ps: removeAccents(block.ps), - }; - } - if (block.type === "verb") { + if (block.block.type === "perfectiveHead") { return { ...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") { return [ ...blocks, - { + makeBlock({ type: "subjectSelection", selection: renderNPSelection(block.selection, config.inflectSubject, false, "subject", config.king === "subject" ? "king" : "servant"), - }, + }), ]; } if (block.type === "objectSelection") { @@ -326,24 +329,24 @@ function renderVPBlocks(blocks: T.VPSBlockComplete[], config: { if (typeof object !== "object") { return [ ...blocks, - { + makeBlock({ type: "objectSelection", selection: object, - }, + }), ]; } const selection = renderNPSelection(object, config.inflectObject, true, "object", config.king === "object" ? "king" : "servant"); return [ ...blocks, - { + makeBlock({ type: "objectSelection", selection, - }, + }), ]; } return [ ...blocks, - renderAPSelection(block), + makeBlock(renderAPSelection(block)), ]; }, [] as T.Block[]); } @@ -362,7 +365,8 @@ function whatsAdjustable(VP: T.VPSelectionComplete): "both" | "king" | "servant" : "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.PerfectParticipleBlock, T.PerfectEquativeBlock] // perfect verb | [T.ModalVerbBlock, T.ModalVerbKedulPart] // modal verb diff --git a/src/types.ts b/src/types.ts index 4977785..a1d4a40 100644 --- a/src/types.ts +++ b/src/types.ts @@ -900,24 +900,28 @@ export type VerbRenderedBlock = { }, }; -export type Block = - | Rendered - | Rendered - | Rendered - | Rendered - | PerfectParticipleBlock - | PerfectEquativeBlock - | ModalVerbBlock - | ModalVerbKedulPart - | { type: "negative", imperative: boolean } - | PerfectiveHeadBlock - | VerbRenderedBlock - | VerbComplementBlock - | EquativeBlock; +export type Block = { + key: number, + block: | Rendered + | Rendered + | Rendered + | Rendered + | PerfectParticipleBlock + | PerfectEquativeBlock + | ModalVerbBlock + | ModalVerbKedulPart + | { type: "negative", imperative: boolean } + | PerfectiveHeadBlock + | VerbRenderedBlock + | VerbComplementBlock + | EquativeBlock; +} -export type Kid = - | { type: "ba" } - | MiniPronoun; +export type Kid = { + key: number, + kid: | { type: "ba" } + | MiniPronoun, +} export type MiniPronoun = { type: "mini-pronoun",