diff --git a/package.json b/package.json index 0c2af8b..56ff084 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "@fortawesome/fontawesome-free": "^5.15.4", "@lingdocs/lingdocs-main": "^0.2.0", - "@lingdocs/pashto-inflector": "^1.5.4", + "@lingdocs/pashto-inflector": "^1.5.5", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", diff --git a/src/lib/phrase-building/compile-vp.ts b/src/lib/phrase-building/compile-vp.ts index c40cd95..b7e1569 100644 --- a/src/lib/phrase-building/compile-vp.ts +++ b/src/lib/phrase-building/compile-vp.ts @@ -5,64 +5,90 @@ import { grammarUnits, getVerbBlockPosFromPerson, } from "@lingdocs/pashto-inflector"; -import { isMiniPronoun, removeBa } from "./vp-tools"; +import { removeBa } from "./vp-tools"; -type ListOfSegments = (T.PsString & { isVerbPrefix?: boolean, prefixFollowedByMiniPronoun?: boolean })[][]; +type Segment = { + isVerbHead?: boolean, + isOoHead?: boolean, + isVerbRest?: boolean, + isMiniPronoun?: boolean, + isNu?: boolean, + isBa?: boolean, + ps: T.PsString[], +}; export function compileVP(VP: VPRendered, form: FormVersion): { ps: T.SingleOrLengthOpts, e?: string [] } { const { head, rest } = VP.verb.ps; const { kids, NPs } = shrinkSegmentsAndGatherKids(VP, form); return { - ps: compilePs(NPs, head, rest, VP.verb.negative, kids), + ps: compilePs({ + NPs, + kids, + head, + rest, + negative: VP.verb.negative, + }), e: compileEnglish(VP), }; } -// TODO: ISSUE off prefix-nu in the phonetics - -function compilePs( - nps: ListOfSegments, - head: T.PsString | undefined, - rest: T.PsString[], - negative: boolean, - kids: ListOfSegments, -): T.PsString[]; -function compilePs( - nps: ListOfSegments, +type CompilePsInput = { + NPs: Segment[], + kids: Segment[], head: T.PsString | undefined, rest: T.SingleOrLengthOpts, negative: boolean, - kids: ListOfSegments, -): T.SingleOrLengthOpts; -function compilePs( - nps: ListOfSegments, - head: T.PsString | undefined, - rest: T.SingleOrLengthOpts, - negative: boolean, - kids: ListOfSegments, -): T.SingleOrLengthOpts { +} +function compilePs({ NPs, kids, head, rest, negative }: CompilePsInput): T.SingleOrLengthOpts { if ("long" in rest) { return { - long: compilePs(nps, head, rest.long, negative, kids), - short: compilePs(nps, head, rest.short, negative, kids), + long: compilePs({ NPs, head, rest: rest.long, negative, kids }) as T.PsString[], + short: compilePs({ NPs, head, rest: rest.short, negative, kids }) as T.PsString[], ...rest.mini ? { - mini: compilePs(nps, head, rest.mini, negative, kids), + mini: compilePs({ NPs, head, rest: rest.mini, negative, kids }) as T.PsString[], } : {}, }; } const verbSegments = compileVerbWNegative(head, rest, negative) - const segments: ListOfSegments = [ - ...nps, + const segments: Segment[] = [ + ...NPs, ...verbSegments, ]; const segmentsWKids = putKidsInKidsSection( segments, kids, ); - return combineSegments(segmentsWKids); + // have all these pieces labelled + // add spaces + const segmentsWithSpaces = addSpacesBetweenSegments(segmentsWKids); + return combineSegments(segmentsWithSpaces); } -function shrinkSegmentsAndGatherKids(VP: VPRendered, form: FormVersion): { kids: ListOfSegments, NPs: ListOfSegments } { +function addSpacesBetweenSegments(segments: Segment[]): (Segment | " " | "" | "-")[] { + const o: (Segment | " " | "" | "-")[] = []; + for (let i = 0; i < segments.length; i++) { + const current = segments[i]; + const next = segments[i+1]; + o.push(current); + if (!next) break; + if (current.isVerbHead && + ( + (next.isMiniPronoun || next.isNu) + || + (current.isOoHead && next.isBa) + ) + ) { + o.push("-"); + } else if (current.isVerbHead && next.isVerbRest) { + o.push(""); + } else { + o.push(" "); + } + } + return o; +} + +function shrinkSegmentsAndGatherKids(VP: VPRendered, form: FormVersion): { kids: Segment[], NPs: Segment[] } { const main = { subject: VP.subject.ps, object: typeof VP.object === "object" ? VP.object.ps : undefined, @@ -83,13 +109,13 @@ function shrinkSegmentsAndGatherKids(VP: VPRendered, form: FormVersion): { kids: return { kids: [ ...VP.verb.hasBa - ? [[grammarUnits.baParticle]] : [], + ? [{ isBa: true, ps: [grammarUnits.baParticle] }] : [], ...toShrink - ? [shrink(toShrink)] : [], + ? [{ isMiniPronoun: true, ps: shrink(toShrink) }] : [], ], NPs: [ - ...showSubject ? [main.subject] : [], - ...(showObject && main.object) ? [main.object] : [], + ...showSubject ? [{ ps: main.subject }] : [], + ...(showObject && main.object) ? [{ ps: main.object }] : [], ], } } @@ -99,66 +125,74 @@ function shrink(np: Rendered): T.PsString[] { return grammarUnits.pronouns.mini[row][col]; } -function putKidsInKidsSection(segments: ListOfSegments, kids: ListOfSegments): ListOfSegments { +function putKidsInKidsSection(segments: Segment[], kids: Segment[]): Segment[] { const first = segments[0]; const rest = segments.slice(1); - console.log({ kids }, kids.length); return [ - first.map(x => ( - (x.isVerbPrefix && isMiniPronoun(kids[0][0])) - ? { ...x, prefixFollowedByMiniPronoun: true } - : x - )), + first, ...kids, ...rest, ]; } -function combineSegments(loe: ListOfSegments): T.PsString[] { - function isLast(index: number, arr: any[]): boolean { - return index === (arr.length - 1); - } - const first = loe[0]; - const rest = loe.slice(1); - if (!rest.length) return first; - return combineSegments(rest).flatMap((r, restIndex, arr) => ( - first.map(ps => concatPsString( - ps, - (ps.isVerbPrefix && isLast(restIndex, arr) - ? "" - : ps.prefixFollowedByMiniPronoun - ? { p: "", f: "-" } - : ps.isVerbPrefix ? " " : " "), - r, - )) - )); -} - - -function compileVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[], negative: boolean): ListOfSegments { - const rest = restRaw.map(removeBa); +function compileVerbWNegative(headRaw: T.PsString | undefined, restRaw: T.PsString[], negative: boolean): Segment[] { + const rest: Segment = { + isVerbRest: true, + ps: restRaw.map(removeBa), + }; + const head: Segment | undefined = !headRaw + ? headRaw + : { + ps: [headRaw], + isVerbHead: true, + isOoHead: headRaw.p === "و" + }; if (!negative) { return [ - ...head ? [[{...head, isVerbPrefix: true}]] : [], + ...head ? [head] : [], rest, ]; } const nu: T.PsString = { p: "نه", f: "nú" }; if (!head) { return [ - [nu], - rest.map(r => removeAccents(r)), + { ps: [nu], isNu: true }, + { + ...rest, + ps: rest.ps.map(p => removeAccents(p)), + }, ]; } - // const regularPrefix = head.p === "و" || head.p === "وا"; - // if (regularPrefix) { - // dashes for oo-nu etc return [ - [{ ...removeAccents(head), isVerbPrefix: true }], - rest.map(r => concatPsString(nu, " ", removeAccents(r))), + ...head ? [{ ...head, ps: head.ps.map(h =>removeAccents(h)) }] : [], + { + ...rest, + isNu: true, + ps: rest.ps.map(r => concatPsString(nu, " ", removeAccents(r))), + }, ]; } +function combineSegments(loe: (Segment | " " | "" | "-")[]): T.PsString[] { + const first = loe[0]; + const rest = loe.slice(1); + if (!rest.length) { + if (typeof first === "string") { + throw new Error("can't end with a spacer"); + } + return first.ps; + } + function spaceOrDash(s: "" | " " | "-"): "" | " " | T.PsString { + return s === "-" ? { p: "", f: "-" } : s; + } + return combineSegments(rest).flatMap((r) => ( + typeof first === "string" + ? [concatPsString(spaceOrDash(first), r)] + : first.ps.map(f => concatPsString(f, r) + ) + )); +} + function compileEnglish(VP: VPRendered): string[] | undefined { function insertEWords(e: string, { subject, object }: { subject: string, object?: string }): string { return e.replace("$SUBJ", subject).replace("$OBJ", object || ""); diff --git a/src/lib/phrase-building/vp-tools.ts b/src/lib/phrase-building/vp-tools.ts index 8ccea48..7bb34e8 100644 --- a/src/lib/phrase-building/vp-tools.ts +++ b/src/lib/phrase-building/vp-tools.ts @@ -26,19 +26,3 @@ export function getPersonFromNP(np: NPSelection | ObjectNP): T.Person | undefine export function removeBa(ps: T.PsString): T.PsString { return psRemove(ps, concatPsString(grammarUnits.baParticle, " ")); } - -export function isMiniPronoun(ps: T.PsString | undefined): boolean { - if (!ps) return false; - return isInVerbBlock(ps.p, grammarUnits.pronouns.mini); -} - -/** - * returns true if the pashto text matches any item in a verb block - * - * @param vb - */ -function isInVerbBlock(p: string, vb: T.VerbBlock): boolean { - return vb.some((r) => ( - r.some(x => x.some(y => y.p === p) - ))); -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 286a4ec..a914d30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1684,10 +1684,10 @@ pbf "^3.2.1" rambda "^6.7.0" -"@lingdocs/pashto-inflector@^1.5.4": - version "1.5.4" - resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.5.4.tgz#2ef3ebce061e62493f79b0b0862d1d9fb7954b40" - integrity sha512-rvQuhld+Ioz5P1SsMKDoeT27RLSZN/r2qy4qm8JCpfPs3y/pFXmoTWhgnfXtbcZ8n2dy7UNiO3jTd4eCQXPsFA== +"@lingdocs/pashto-inflector@^1.5.5": + version "1.5.5" + resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.5.5.tgz#166e0181711cf019aef2e637bc798c3f41e8df8d" + integrity sha512-NK5slwLJrMTdS/whYoSjvtRQgN9vdy+PFJxecih7HgcaSEwfFVy+wxWXLwufznpGI4VCoDgIo4+gWNkNxvAt3Q== dependencies: classnames "^2.2.6" pbf "^3.2.1"