wohoo new VPExplorer moved into the grammar engine!

This commit is contained in:
lingdocs 2022-04-08 15:04:16 +05:00
parent 53bb07fcdc
commit 8d841a6c24
65 changed files with 4525 additions and 152 deletions

1
.gitignore vendored
View File

@ -28,3 +28,4 @@ yarn-debug.log*
yarn-error.log*
/src/verbs.ts
/src/noun-adjs.ts

View File

@ -1,71 +0,0 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const fs = require("fs");
const fetch = require("node-fetch");
const path = require("path");
const collectionPath = path.join(".", "verbs");
const verbTsFiles = fs.readdirSync(collectionPath);
const protoModels = require("./src/lib/dictionary-models.js");
const Pbf = require("pbf");
const allTsS = [...new Set(verbTsFiles.reduce((arr, fileName) => {
const TsS = require("./verbs/"+fileName);
return [...arr, ...TsS];
}, []))];
fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(buffer => {
const pbf = new Pbf(buffer);
const dictionary = protoModels.Dictionary.read(pbf);
const entries = dictionary.entries;
const allVerbs = getFromTsS(entries);
const content = `
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { DictionaryEntry } from "./types";
const verbs: {
entry: DictionaryEntry,
complement?: DictionaryEntry,
}[] = ${JSON.stringify(allVerbs)};
export default verbs;`;
fs.writeFileSync("./src/verbs.ts", content);
console.log("fetched verbs from dictionary");
});
function getFromTsS(entries) {
const missingEc = [];
const toReturn = allTsS.map(ts => {
const entry = entries.find(x => ts === x.ts);
if (!entry.ec) {
missingEc.push(entry.ts);
}
if (!entry) {
console.log("couldn't find ts", ts);
return undefined;
}
if (entry.c && entry.c.includes("comp.")) {
const complement = entries.find(x => entry.l === x.ts);
return {
entry,
complement,
};
}
return { entry };
}).filter(x => x);
if (missingEc.length !== 0) {
console.log("missingEc", missingEc);
}
return toReturn;
}

113
get-words.js Normal file
View File

@ -0,0 +1,113 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const fs = require("fs");
const fetch = require("node-fetch");
const path = require("path");
const verbCollectionPath = path.join(".", "verbs");
const nounAdjCollectionPath = path.join(".", "nouns-adjs");
const verbTsFiles = fs.readdirSync(verbCollectionPath);
const nounAdjTsFiles = fs.readdirSync(nounAdjCollectionPath);
const protoModels = require("./src/lib/dictionary-models.js");
const Pbf = require("pbf");
const allVerbTsS = [...new Set(verbTsFiles.reduce((arr, fileName) => {
const TsS = require("./verbs/"+fileName);
return [...arr, ...TsS];
}, []))];
const allNounAdjTsS = [...new Set(nounAdjTsFiles.reduce((arr, fileName) => {
const TsS = require("./nouns-adjs/"+fileName).map(x => x.ts);
return [...arr, ...TsS];
}, []))];
fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(buffer => {
const pbf = new Pbf(buffer);
const dictionary = protoModels.Dictionary.read(pbf);
const entries = dictionary.entries;
const allVerbs = getVerbsFromTsS(entries, allVerbTsS);
const verbsContent = `
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { DictionaryEntry, VerbEntry } from "./types";
const verbs: {
entry: DictionaryEntry,
complement?: DictionaryEntry,
}[] = ${JSON.stringify(allVerbs)};
export default verbs as VerbEntry[];`;
fs.writeFileSync("./src/verbs.ts", verbsContent);
const allNounsAdjs = getNounsAdjsFromTsS(entries, allNounAdjTsS);
const nounsAdjsContent = `
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { DictionaryEntry } from "./types";
const nounsAdjs: DictionaryEntry[] = ${JSON.stringify(allNounsAdjs)};
export default nounsAdjs;`;
fs.writeFileSync("./src/nouns-adjs.ts", nounsAdjsContent);
console.log("fetched words from dictionary");
});
function getNounsAdjsFromTsS(entries, tss) {
const missingEc = [];
const toReturn = tss.map(ts => {
const entry = entries.find(x => ts === x.ts);
if (!entry) {
console.log("couldn't find ts", ts);
return undefined;
}
if (ts.ec) {
missingEc.push(ts);
}
return entry;
}).filter(x => x);
if (missingEc.length !== 0) {
console.log("missingEc", missingEc);
}
return toReturn;
}
function getVerbsFromTsS(entries, tss) {
const missingEc = [];
const toReturn = tss.map(ts => {
const entry = entries.find(x => ts === x.ts);
if (!entry.ec) {
missingEc.push(entry.ts);
}
if (!entry) {
console.log("couldn't find ts", ts);
return undefined;
}
if (entry.c && entry.c.includes("comp.")) {
const complement = entries.find(x => entry.l === x.ts);
return {
entry,
complement,
};
}
return { entry };
}).filter(x => x);
if (missingEc.length !== 0) {
console.log("missingEc", missingEc);
}
return toReturn;
}

102
nouns-adjs/a-fem.js Normal file
View File

@ -0,0 +1,102 @@
module.exports = [
{ ts: 1527812797, e: "woman" }, // xudza
{ ts: 1527816466, e: `peace` }, // صلح - sUlha
{ ts: 1527816589, e: `plan` }, // طرح - tarha
{ ts: 1589023873660, e: `victory, conquest` }, // فتح - fathá
{ ts: 1527813791, e: `permission` }, // اجازه - ijaaza
{ ts: 1614083533098, e: `agenda` }, // اجنډه - ajanDa
{ ts: 1527811425, e: "door" }, // darwaaza
{ ts: 1527816215, e: `administration, management, directorate` }, // اداره - idaara
{ ts: 1527812687, e: `continuation` }, // ادامه - idaama
{ ts: 1527811661, e: `base, army post, (air) port` }, // اډه - aDa
{ ts: 1527814310, e: `evaluation, appraisal, assessment` }, // ارزونه - arzawuna
{ ts: 1527821380, e: `saw (the tool)` }, // اره - ara
{ ts: 1527822277, e: `mare, female horse; fever` }, // اسپه - aspa
{ ts: 1527814922, e: `addition, add-on, augmentation` }, // اضافه - izaafa
{ ts: 1527822458, e: `expression` }, // افاده - ifaada
{ ts: 1527813303, e: `myth, legend, fairy tale` }, // افسانه - afsaana
{ ts: 1527822494, e: `cheek` }, // انانګه - anaangá
{ ts: 1527817225, e: `measure, dimension, extent, scale` }, // اندازه - andaaza
{ ts: 1527813759, e: `worry, concern, fear` }, // اندېښنه - andexna
{ ts: 1527815787, e: `shoulder` }, // اوږه - ooGá
{ ts: 1527813787, e: `tear (from eye)` }, // اوښکه - ooxka
{ ts: 1527819927, e: `liver` }, // اینه - éena
{ ts: 1527816261, e: `wallet` }, // بټوه - baTwa
{ ts: 1527812001, e: `poriton, part, share` }, // برخه - barkha
{ ts: 1578009902092, e: `veil, burka` }, // برقه - bUrqá
{ ts: 1527816994, e: `program` }, // برنامه - barnaama
{ ts: 1579294091093, e: `balcony, veranda, porch` }, // برنډه - baranDá
{ ts: 1527823617, e: `crime, offense, sin, guilt, fault` }, // بزه - bazá
{ ts: 1527823619, e: `moth` }, // بزه - bUzá
{ ts: 1527823620, e: `patch (in a garment)` }, // بزه - bza
{ ts: 1591026261598, e: `she-goat` }, // بزه - buza
{ ts: 1574188090133, e: `contribution, donation, gift, charity` }, // بسپنه - baspuna
{ ts: 1527816590, e: `sufficiency, to have enough or get by` }, // بسنه - basuna
{ ts: 1593852212828, e: `fear, fright` }, // بېره - béra
{ ts: 1527815862, e: `speed, rush, hurry, urgency` }, // بېړه - beRa
{ ts: 1527815156, e: `leaf` }, // پاڼه - paaNa
{ ts: 1527813481, e: `project` }, // پروژه - projza
{ ts: 1527818409, e: `process` }, // پروسه - purosa
{ ts: 1527815192, e: `decision` }, // پرېکړه - prékRa
{ ts: 1527822412, e: `nose` }, // پزه - páza
{ ts: 1527816124, e: `foot` }, // پښه - pxa
{ ts: 1527815155, e: `pretext, excuse` }, // پلمه - palma
{ ts: 1566469328688, e: `fan` }, // پنکه - panka
{ ts: 1527815184, e: `question` }, // پوښتنه - poxtuna
{ ts: 1527822437, e: `shelf, niche` }, // تاخچه - taakhchá
{ ts: 1527814974, e: `fever` }, // تبه - tuba
{ ts: 1527815332, e: `expectation` }, // تمه - tama
{ ts: 1527815716, e: `stone, rock` }, // تیږه - teeGa
{ ts: 1582390417084, e: `escape, flight, running away` }, // تېښته - téxta
{ ts: 1527822268, e: `carriage, buggy` }, // ټانګه - Taangá
{ ts: 1527812014, e: `society, association, gathering, assembly, congregation` }, // ټولنه - Toluna
{ ts: 1527816696, e: `sentence; whole, total, sum` }, // جمله - jUmla
{ ts: 1527820504, e: `land, earth, ground` }, // ځمکه - dzmuka
{ ts: 1527815497, e: `face, picture` }, // څېره - tsera
{ ts: 1527811993, e: `attack, assault` }, // حمله - hamla
{ ts: 1527812720, e: `language` }, // ژبه - jzúba, jzíba
{ ts: 1527812052, e: `brick, cinder-block` }, // خښته - khuxta
{ ts: 1527813475, e: `minute` }, // دقیقه - daqeeqa
{ ts: 1527812542, e: `break, rest` }, // دمه - dama
{ ts: 1527812085, e: `obligation, duty, responsibility; job, work, position` }, // دنده - danda
{ ts: 1527822847, e: `jaw` }, // ژامه - jzaamá
{ ts: 1527815278, e: `night` }, // شپه - shpa
{ ts: 1527813145, e: `tribe` }, // قبیله - qabeela
{ ts: 1566653299904, e: `camara` }, // کمره - kamara
{ ts: 1527812825, e: `street` }, // کوڅه - kootsa
{ ts: 1527812756, e: `banana` }, // کېله - kela
{ ts: 1527812859, e: `game, match` }, // لوبه - lóba
{ ts: 1527819087, e: `defeat` }, // ماته - maata
{ ts: 1588076706989, e: `distance, span` }, // مسافه - masaafá
{ ts: 1527818358, e: `apple` }, // مڼه - maNá
{ ts: 1527812901, e: `stomach` }, // مېده - meda
{ ts: 1527813387, e: `gluing, joining, wrangle, quarrel, fighting, skirmish, battle` }, // نښته - nuxúta
{ ts: 1527815110, e: `sign, mark, indication` }, // نښه - náxa, núxa
{ ts: 1527813391, e: `date (as in time)` }, // نېټه - neTa
{ ts: 1527811429, e: `graveyard, cemetery` }, // هدیره - hadeera
{ ts: 1527814323, e: `gift, present, donation, contribution` }, // هدیه - hadiya
{ ts: 1527812655, e: `week` }, // هفته - hafta
{ ts: 1527812681, e: `agreement` }, // هوکړه - hókRa
{ ts: 1578343468611, e: `tendon, sinew; hamstring` }, // واڼه - wáaNa
{ ts: 1527822717, e: `snow` }, // واوره - wáawra
{ ts: 1527811207, e: `eyebrow` }, // وروځه - wróodza
{ ts: 1527816375, e: `niece; brother's daughter` }, // ورېره - wrera
{ ts: 1527822259, e: `breeze, light wind` }, // وږمه - waGmá
{ ts: 1527814719, e: `weapons, firearms, artillery` }, // وسله - wasla
{ ts: 1527823717, e: `cloth, fabric, material, clothing, garment` }, // کپړه - kapRá
{ ts: 1527816257, e: `notebook, little book` }, // کتابچه - kitaabcha
{ ts: 1527820050, e: `bag, purse` }, // کڅوړه - katsóRa
{ ts: 1527813252, e: `line, trace` }, // کرښه - kurxa
{ ts: 1527823590, e: `sphere, globe` }, // کره - kará
{ ts: 1527823591, e: `shovel, scraper, scoop` }, // کره - kára
{ ts: 1527815884, e: `criticism` }, // کره کتنه - karakatuna
{ ts: 1527823035, e: `whip` }, // کروړه - karoRá
{ ts: 1527816870, e: `farmland` }, // کرونده - karwanda
{ ts: 1527817371, e: `lament, mourning aloud, wail, cry (also out of hapiness)` }, // کریږه - kreeGa
{ ts: 1598119732734, e: `bitter melon` }, // کرېله - karelá
{ ts: 1527820606, e: `cave, cavern` }, // سمڅه - smútsa
{ ts: 1527815249, e: `song, poem, verse` }, // سندره - sandura
{ ts: 1591034128816, e: `mistake, error, blunder, fault` }, // سهوه - sáhwa
{ ts: 1527814370, e: `nostril` }, // سوږمه - soGma
{ ts: 1527817498, e: `famine, starvation, serious hunger/lack of food, drought, crop failure` }, // سوکړه - sookRá
];

36
nouns-adjs/aa-fem.js Normal file
View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527813115, e: "claim" }, // ادعا - idaa
{ ts: 1527818119, e: "stick, walking staff, walking stick, crutch" }, // امسا - amsaa
{ ts: 1527815043, e: "punishment, retribution" }, // جزا - jazaa
{ ts: 1527819022, e: "well, water-hole" }, // څا - tsaa
{ ts: 1527814225, e: "mistake, error, blunder" }, // خطا - khataa
{ ts: 1610797589510, e: "cavity, emptiness, vacuum, empty space, space (as in planets etc.)" }, // خلا - khaláa
{ ts: 1527812582, e: "prayer" }, // دعا - dUaa
{ ts: 1527813415, e: "medicine, medication" }, // دوا - dawaa
{ ts: 1527812272, e: "light, glory" }, // رڼا - raNaa
{ ts: 1527823245, e: "dream, vision" }, // رویا - rooyáa
{ ts: 1586596579414, e: "council (an institution)" }, // شورا - shooraa
{ ts: 1527815984, e: "beauty" }, // ښکلا - xkulaa
{ ts: 1527817670, e: "theft, robbery, stealing" }, // غلا - ghlaa
{ ts: 1527814362, e: "cow" }, // غوا - ghwaa
{ ts: 1585487002625, e: "castle, fort, fortress" }, // قلا - qaláa
{ ts: 1527812048, e: "meaning, sense, spirit" }, // مانا - maanaa
{ ts: 1527815483, e: "back (body part)" }, // ملا - mlaa
{ ts: 1527812230, e: "friendship" }, // ملګرتیا - malgurtiyaa
{ ts: 1527812910, e: "hospitality; invitation, event, party, banquet, reception" }, // مېلمستیا - melmastiyaa
{ ts: 1617781446945, e: "sickness, illness" }, // ناجوړتیا - naajoRtiyaa, naajoRtyaa
{ ts: 1527815120, e: "grandmother" }, // نیا - niyaa
{ ts: 1527811740, e: "incompleteness, default, shortcoming" }, // نیمګړتیا - neemguRtiyaa
{ ts: 1527821040, e: "plague, cholera" }, // وبا - wabáa
{ ts: 1527823534, e: "ability, capacity, capability, power, volumeá" }, // وړتیا - waRtiyáa
{ ts: 1610443988250, e: "division, distribution" }, // وېشلتیا - weshiltyaa, weshiltiyaa
{ ts: 1527816806, e: "speech, statement" }, // وینا - waynaa
];

46
nouns-adjs/aanu-unisex.js Normal file
View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527815197, e: "Pashtun" }, // پښتون
{ ts: 1527813148, e: "lying" }, // پروت
{ ts: 1574867531681, e: "mature, ripe, cooked" }, // پوخ
{ ts: 1576952412644, e: "soft" }, // پوست
{ ts: 1527815366, e: "bitter" }, // تریخ
{ ts: 1527818789, e: "sour" }, // تریو
// { ts: 1527815333, e: "'tandoor'" }, // تنور
{ ts: 1527817664, e: "hot" }, // تود
// { ts: 1577408901204, e: "knee" }, // ځنګون
{ ts: 1527816071, e: "spread" }, // خپور
{ ts: 1574865652928, e: "sweet" }, // خوږ
{ ts: 1527813499, e: "heavy" }, // دروند
{ ts: 1527813943, e: "returned, come back" }, // راستون
{ ts: 1576596860977, e: "clear, bright" }, // روڼ
{ ts: 1527811971, e: "blind" }, // ړوند
{ ts: 1527815451, e: "old" }, // زوړ
// { ts: 1527815845, e: "life" }, // ژوندون
{ ts: 1527815300, e: "rider, mounted" }, // سپور
{ ts: 1527819505, e: "being (in a place after returning, coming back etc.)" }, // ستون
{ ts: 1600080053835, e: "riding, mounted" }, // سور
{ ts: 1527813068, e: "cold" }, // سوړ
{ ts: 1575924767041, e: "shepherd" }, // شپون
// { ts: 1610448014063, e: "large flat basket" }, // شکور
{ ts: 1527813172, e: "bent" }, // کوږ
{ ts: 1527811973, e: "deaf" }, // کوڼ
// { ts: 1527823497, e: "intestines" }, // لړمون
// { ts: 1527813809, e: "namaz" }, // لمونځ
{ ts: 1527817123, e: "wet" }, // لومد
{ ts: 1527817117, e: "wet" }, // لوند
{ ts: 1576889120767, e: "wet" }, // لوند
{ ts: 1527812927, e: "full, satisfied" }, // موړ
{ ts: 1527812908, e: "guest" }, // مېلمه
{ ts: 1579463171333, e: "cleansed" }, // نوږ
{ ts: 1576113803291, e: "small" }, // ووړ
{ ts: 1527819244, e: "host" }, // کوربه
{ ts: 1527812908, e: "guest" }, // مېلمه
];

18
nouns-adjs/basic-fem.js Normal file
View File

@ -0,0 +1,18 @@
module.exports = [
{ ts: 1527814150, e: `road, way, path` }, // لار - laar
{ ts: 1527815417, e: `day` }, // ورځ - wradz
{ ts: 1527812922, e: `month` }, // میاشت - miyaasht
{ ts: 1527823306, e: `elbow` }, // څنګل - tsangúl
{ ts: 1527813824, e: `bosom, breast; wrestling` }, // غېږ - gheG
{ ts: 1527820524, e: `pelt, skin, hide, leather` }, // څرمن - tsarmún
{ ts: 1527814147, e: `blanket, coving, quilt` }, // بړستن - bRastun
{ ts: 1527818707, e: `wedge; gusset (in a shirt)` }, // ترخځ - turkhúdz
{ ts: 1527822792, e: `narrow mattress used as a bed or a couch, reversible rug` }, // توشک - toshák
{ ts: 1527813294, e: `comb` }, // ږمنځ - Gmundz
{ ts: 1527811580, e: `needle, injection; pillar, mast` }, // ستن - stun
{ ts: 1527815779, e: `swearing, name-calling, verbal abuse, bad language` }, // کنځل - kundzul
{ ts: 1527817456, e: `skirt, portion of clothing hanging down from the waist; foot, base (eg. of a mountain)` }, // لمن - lamun
{ ts: 1527822725, e: `span` }, // لوېشت - lwesht
{ ts: 1527811609, e: `claw, paw` }, // منګل - mangul
{ ts: 1527821684, e: `cloud` }, // ورېځ - wurédz
]

102
nouns-adjs/basic-masc.js Normal file
View File

@ -0,0 +1,102 @@
module.exports = [
{ ts: 1527812432, e: `sky, heaven` }, // آسمان - aasmaan
{ ts: 1527812431, e: `mango` }, // آم - aam
{ ts: 1527812434, e: `sound, voice` }, // آواز - aawaaz
{ ts: 1527816724, e: `room, chamber` }, // اتاق - Utaaq
{ ts: 1527811859, e: `union, alliance` }, // اتحاد - itihaad
{ ts: 1527822033, e: `joining, connection, contiguity, junction` }, // اتصال - ittisáal
{ ts: 1527811858, e: `unity, alliance, agreement, understanding, consent; coincidence` }, // اتفاق - itifaaq
{ ts: 1527813560, e: `accusation, charge, indictment` }, // اتهام - itihaam
{ ts: 1527812105, e: `respect, honor, esteem, deference` }, // احترام - ihtiraam
{ ts: 1527819653, e: `possibility, probability, likelihood` }, // احتمال - ihtimaal
{ ts: 1527812689, e: `need, requirement` }, // احتیاج - ihtiyaaj
{ ts: 1527812690, e: `caution` }, // احتیاط - ihtiyaat
{ ts: 1527813782, e: `feeling, sensation, emotion` }, // احساس - ahsaas
{ ts: 1527817303, e: `objection, protest` }, // اعتراض - itiraaz
{ ts: 1527813418, e: `influence, effect, affect, action` }, // اغېز - aghez
{ ts: 1527816625, e: `disaster` }, // افت - afat
{ ts: 1527813558, e: `accusation, charge, blame` }, // الزام - ilzaam
{ ts: 1527815388, e: `hope, expectation` }, // امید - Umeed
{ ts: 1527812453, e: `picture, painting, image` }, // انځور - andzoor
{ ts: 1527813827, e: `fire, flame` }, // اور - or
{ ts: 1527814787, e: `rain` }, // باران - baaraan
{ ts: 1527817293, e: `roof` }, // بام - baam
{ ts: 1527814849, e: `eggplant` }, // بانجن - baanjan
{ ts: 1527814106, e: `crisis` }, // بحران - bUhraan
{ ts: 1527814885, e: `fortune, luck, fate` }, // بخت - bakht
{ ts: 1527811281, e: `garden` }, // بڼ - baN
{ ts: 1624039195280, e: `scholarship` }, // بورس - boors
{ ts: 1527816877, e: `flag` }, // بیرغ - beyragh
{ ts: 1527820423, e: `passport` }, // پاسپورټ - paasporT
{ ts: 1527813224, e: `bridge` }, // پل - pUl
{ ts: 1527813480, e: `plan` }, // پلان - plaan
{ ts: 1527815199, e: `central-asian/middle-eastern rice dish, pilaf` }, // پلاو - pulaaw
{ ts: 1527815185, e: `loan, debt` }, // پور - por
{ ts: 1527815176, e: `onion` }, // پیاز - piyaaz
{ ts: 1527815171, e: `start` }, // پیل - peyl
{ ts: 1527816610, e: `crown, crest` }, // تاج - taaj
{ ts: 1527822373, e: `vine; mouthful` }, // تاک - taak
{ ts: 1527815326, e: `confirmation` }, // تایید - taayeed
{ ts: 1527815357, e: `seed` }, // تخم - tUkhum
{ ts: 1527821586, e: `pity, sympathy` }, // ترحم - tarahhÚm
{ ts: 1527811389, e: `picture` }, // تصویر - tasweer
{ ts: 1527814679, e: `guarantee, insurance, security` }, // تضمین - tazmeen
{ ts: 1527814258, e: `speech, lecture` }, // تقریر - taqreer
{ ts: 1527821670, e: `cheating, deception, fraud, forgery` }, // تقلب - taqalÚb
{ ts: 1527811602, e: `attempt, aspiration, intention, effort` }, // تکل - takál
{ ts: 1527813398, e: `movement, motion, going` }, // تګ - tug, tag
{ ts: 1527822126, e: `anniversary` }, // تلین - tleen
{ ts: 1527811308, e: `contact, touch` }, // تماس - tamaas
{ ts: 1527817900, e: `body, flesh` }, // تن - tan
{ ts: 1527821061, e: `contrast, opposition, contradiction` }, // تناقض - tanaaqÚz
{ ts: 1527822387, e: `rope, cord; a measurement of ground or distances` }, // تناو - tanáaw
{ ts: 1527818995, e: `lightning` }, // تندر - tandúr
{ ts: 1527815362, e: `ball; (cannon) ball` }, // توپ - top
{ ts: 1527816820, e: `spit` }, // توک - took
{ ts: 1527816520, e: `family, clan, tribe, people` }, // ټبر - Tabar
{ ts: 1527811348, e: `wound` }, // ټپ - Tap
{ ts: 1527819566, e: `piece, part; cloth, fabric` }, // ټکر - TUkúr
{ ts: 1527812213, e: `mosque` }, // جمات - jUmaat
{ ts: 1527811705, e: `structure` }, // جوړښت - joRuxt
{ ts: 1527814058, e: `answer, reply` }, // ځواب - dzawaab
{ ts: 1527816887, e: `life, existence, energy, force` }, // ځواک - dzwaak
{ ts: 1527814649, e: `market square, crossroads, paved area in front of entrance` }, // چوک - chok
{ ts: 1527815065, e: `hammer` }, // څټک - tsaTak, tsTuk
{ ts: 1527814589, e: `side` }, // څنګ - tsang
{ ts: 1527816228, e: `boundary, limit, extent` }, // حد - had
{ ts: 1527813749, e: `government, reign, rule` }, // حکومت - hUkoomat
{ ts: 1527814125, e: `solution` }, // حل - hal
{ ts: 1527818703, e: `shirt` }, // خت - khut
{ ts: 1527813804, e: `sleep, dream` }, // خوب - khob
{ ts: 1527812815, e: `safety, security` }, // خوندیتوب - khwundeetob
{ ts: 1527813763, e: `religion, faith` }, // دین - deen
{ ts: 1527811517, e: `journey, travel` }, // سفر - safar
{ ts: 1527815389, e: `age, life` }, // عمر - Úmur
{ ts: 1527816746, e: `tooth` }, // غاښ - ghaax
{ ts: 1527812631, e: `ear` }, // غوږ - ghwuG, ghwaG
{ ts: 1527812265, e: `decree, order` }, // فرمان - farmaan
{ ts: 1527817205, e: `film, movie` }, // فلم - film
{ ts: 1527812727, e: `year` }, // کال - kaal
{ ts: 1527812817, e: `book` }, // کتاب - kitaab
{ ts: 1527812611, e: `step, move` }, // ګام - gaam
{ ts: 1527812641, e: `rose, flower` }, // ګل - gUl
{ ts: 1527812650, e: `threat, danger, challeng` }, // ګواښ - gwaax
{ ts: 1527813521, e: `mourning, grief, grieving, deep sorrow` }, // ماتم - maatam
{ ts: 1527812176, e: `evening` }, // ماښام - maaxaam
{ ts: 1527813601, e: `death` }, // مرګ - marg
{ ts: 1527817691, e: `future` }, // مستقبل - mUstaqbil
{ ts: 1527811866, e: `damage, defect, loss` }, // نقصان - nUqsaan
{ ts: 1527815122, e: `name` }, // نوم - noom
{ ts: 1527812661, e: `boy, young lad` }, // هلک - halík, halúk
{ ts: 1566476070874, e: `street, road` }, // واټ - waaT
{ ts: 1527816036, e: `authority, power` }, // واک - waak
{ ts: 1527815400, e: `time` }, // وخت - wakht
{ ts: 1527818582, e: `building, prosperity, habitable state` }, // ودانښت - wadaanuxt
{ ts: 1527811441, e: `door, gate, entrance` }, // ور - war
{ ts: 1527815406, e: `homeland, home country` }, // وطن - watán
{ ts: 1573149648251, e: `fellow country-man` }, // وطن وال - watanwaal
{ ts: 1586428847646, e: `national (person), a citizen or person of that land` }, // وطنوال - watanwáal
{ ts: 1527822208, e: `bat, coward, pipsqueak, hesitant person` }, // وطواط - watwáat
{ ts: 1527819571, e: `apprehension, anxiety, suspicion; imagination, whims, some problem made up in someones head` }, // وهم - wáhum, wahm
{ ts: 1527816332, e: `pride, glory` }, // ویاړ - wyaaR
];

128
nouns-adjs/basic-unisex.js Normal file
View File

@ -0,0 +1,128 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527815408, e: "asleep" }, // ویده - weedú
{ ts: 1527812796, e: "good" }, // ښه - xu
{ ts: 1527821744, e: "cook, chef" }, // آشپز - aashpáz
{ ts: 1527812461, e: "hero, brave" }, // اتل - atul
{ ts: 1527821649, e: "impressive, effective, influencing" }, // اثرناک - asarnáak
{ ts: 1527818704, e: "wide, spacious, extensive" }, // ارت - arát
{ ts: 1578340121962, e: "free, independant" }, // ازاد - azáad
{ ts: 1527819418, e: "independant, autonomous" }, // خپلواک - khpulwaak
{ ts: 1527817146, e: "resident; settled" }, // استوګن - astogan
{ ts: 1527813713, e: "hopeful, pregnant" }, // امیدوار - Umeedwaar
{ ts: 1527819451, e: "Englishman, English (adjective)" }, // انګرېز - angréz
{ ts: 1527820346, e: "on-line" }, // انلاین - anlaayn
{ ts: 1527813667, e: "important" }, // اهم - aham
{ ts: 1598724912198, e: "dry" }, // اوچ - ooch
{ ts: 1527815138, e: "insurgent" }, // اورپک - orpak
{ ts: 1586452587974, e: "free, available" }, // اوزګار - oozgáar
{ ts: 1527816489, e: "faithful, believer" }, // ایماندار - eemaandaar
{ ts: 1527820433, e: "valiant" }, // باتور - baatóor
{ ts: 1527813425, e: "stingy" }, // بخیل - bakheel
{ ts: 1527812511, e: "bad" }, // بد - bud, bad
{ ts: 1527812518, e: "equal, even, set up" }, // برابر - buraabur
{ ts: 1527811861, e: "naked" }, // بربنډ - barbunD
{ ts: 1527811511, e: "full, complete" }, // بشپړ - bushpuR
{ ts: 1527812515, e: "other, next" }, // بل - bul
{ ts: 1527815725, e: "knowledgeable, accustomed" }, // بلد - balad
{ ts: 1577301753727, e: "closed" }, // بند - band
{ ts: 1527812490, e: "useless" }, // بې کار - be kaar
{ ts: 1527812031, e: "separate, different" }, // بېل - bel
{ ts: 1527815144, e: "clean, pure" }, // پاک - paak
{ ts: 1527815201, e: "hidden" }, // پټ - puT
{ ts: 1527815179, e: "wide" }, // پلن - plun
{ ts: 1527819059, e: "thick, fat" }, // پنډ - punD
{ ts: 1611767359178, e: "compassionate" }, // ترسناک - tarsnáak
{ ts: 1527813270, e: "sour" }, // تروش - troosh
{ ts: 1527813817, e: "narrow, cramped" }, // تنګ - tang
{ ts: 1527816354, e: "ready" }, // تیار - tayaar
{ ts: 1527817056, e: "sharp, fast" }, // تېز - tez
{ ts: 1527814076, e: "societal, social" }, // ټولنیز - Toluneez
{ ts: 1527819864, e: "low" }, // ټیټ - TeeT
{ ts: 1527811894, e: "firm, tough, rigid" }, // ټینګ - Teeng
{ ts: 1527812943, e: "constant, stable, proven" }, // ثابت - saabit
{ ts: 1527813085, e: "heavy, difficult" }, // ثقیل - saqeel
{ ts: 1527820479, e: "ignorant" }, // جاهل - jaahíl
{ ts: 1588160800930, e: "surgeon" }, // جراح - jarráah
{ ts: 1527812707, e: "high, tall" }, // جګ - jig, jug
{ ts: 1527816944, e: "clear, evident" }, // جوت - jawat
{ ts: 1527822996, e: "alongside, adjoining" }, // جوخت - jokht
{ ts: 1527812711, e: "well, healthy" }, // جوړ - joR
{ ts: 1527816323, e: "shining, sparkling" }, // ځلاند - dzalaand
{ ts: 1527812291, e: "young, youthful" }, // ځوان - dzwaan
{ ts: 1527820112, e: "hanging" }, // ځوړند - dzwáRund
{ ts: 1527819672, e: "crafty" }, // چالاک - chaaláak
{ ts: 1527811230, e: "quick, fast" }, // چټک - chaTak
{ ts: 1527812524, e: "started, in motion" }, // چلان - chalaan
{ ts: 1527815370, e: "clear, apparent" }, // څرګند - tsărgund
{ ts: 1576366107077, e: "straight, upright" }, // څک - tsak
{ ts: 1527812113, e: "present, on hand, ready" }, // حاضر - haazir, haazur
{ ts: 1527820699, e: "pregnant, carrying" }, // حامل - haamíl
{ ts: 1527819824, e: "greedy" }, // حریص - harées
{ ts: 1527812669, e: "sensitive" }, // حساس - hasaas
{ ts: 1527812057, e: "raw, unripe" }, // خام - khaam
{ ts: 1527811523, e: "traitor, treacherous" }, // خاین - khaayin
{ ts: 1527814219, e: "relative, one's own" }, // خپل - khpul
{ ts: 1527812795, e: "relative" }, // خپلوان - khpulwaan
{ ts: 1527812808, e: "poor, miserable" }, // خوار - khwaar
{ ts: 1527814880, e: "tall" }, // دنګ - dung
{ ts: 1527812537, e: "assured" }, // ډاډمن - DaaDmun
{ ts: 1527812583, e: "full" }, // ډک - Duk
{ ts: 1527822674, e: "gaunt" }, // ډنګر - Dungár, Dangár
{ ts: 1527817256, e: "sunk" }, // ډوب - Doob
{ ts: 1527814277, e: "healthy" }, // روغ - rogh
{ ts: 1609780006604, e: "fruitful" }, // زرخېز - zarkhéz
{ ts: 1527817116, e: "green, flourishing" }, // زرغون - zarghoon
{ ts: 1527814026, e: "golden" }, // زرین - zareen
{ ts: 1567594312839, e: "brave" }, // زړه ور - zuRawár
{ ts: 1527815848, e: "committed" }, // ژمن - jzman
{ ts: 1527813498, e: "light" }, // سپک - spuk
{ ts: 1578329248464, e: "white" }, // سپین - speen
{ ts: 1527811860, e: "great" }, // ستر - stur
{ ts: 1527820178, e: "problematic" }, // ستونزمن - stoonzmán
{ ts: 1527815246, e: "difficult" }, // سخت - sakht
{ ts: 1527817262, e: "barren" }, // شنډ - shanD
{ ts: 1527813426, e: "stingy" }, // شوم - shoom
{ ts: 1527812625, e: "big" }, // غټ - ghuT, ghaT
{ ts: 1527811846, e: "successful" }, // کامیاب - kaamyaab
{ ts: 1527823678, e: "lazy" }, // کاهل - kaahíl
{ ts: 1527814896, e: "proud, arrogant" }, // کبرجن - kaburjun
{ ts: 1527813117, e: "firm, solid" }, // کلک - klak, kluk
{ ts: 1578769492475, e: "few, little" }, // کم - kam
// { ts: 1527814253, e: "mixed up" }, // ګډ وډ // TODO: FIX INFLECTION MACHINE FOR DOUBLES!
{ ts: 1578769409512, e: "weak" }, // کمزور - kamzór
{ ts: 1527812639, e: "dear, difficult" }, // ګران - graan
{ ts: 1527816786, e: "all" }, // ګرد - gurd
{ ts: 1527814811, e: "warm, hot" }, // ګرم - garm, garum
{ ts: 1527817662, e: "guilty" }, // ګرم - gram
{ ts: 1527812308, e: "thick, lots" }, // ګڼ - gaN
{ ts: 1527813848, e: "desiring, eager" }, // لېوال - lewaal
{ ts: 1527816011, e: "broken" }, // مات - maat
{ ts: 1527812881, e: "child" }, // ماشوم - maashoom
{ ts: 1527817007, e: "known" }, // مالوم - maaloom
{ ts: 1527814321, e: "positive" }, // مثبت - mUsbat
{ ts: 1527811264, e: "condemned" }, // محکوم - mahkoom
{ ts: 1527814802, e: "foul" }, // مردار - mUrdáar
{ ts: 1527821812, e: "arrogant" }, // مغرور - maghróor
{ ts: 1527820222, e: "lying down" }, // ملاست - mlaast
{ ts: 1527814344, e: "important" }, // مهم - mUhím
{ ts: 1527816033, e: "uncommon" }, // نادر - naadir
{ ts: 1527815106, e: "sitting, seated" }, // ناست - naast
{ ts: 1527815127, e: "nurse" }, // نرس - nurs
{ ts: 1527821673, e: "moist, damp, wet" }, // نمجن - namjún
{ ts: 1527815130, e: "dry, land, ground" }, // وچ - wuch, wUch
{ ts: 1527817486, e: "ruined, destroyed; destructive, bad, naughty" }, // وران - wraan
{ ts: 1527814373, e: "lost" }, // ورک - wruk
{ ts: 1527822838, e: "decayed, spoiled, rotten" }, // وروست - wrost
{ ts: 1609949334478, e: "roasted" }, // وریت - wreet
{ ts: 1527811544, e: "standing" }, // ولاړ - waláaR, wuláaR
{ ts: 1527815498, e: "aforementioned" }, // یاد - yaad
{ ts: 1527815434, e: "cold" }, // یخ - yakh, yukh
];

25
nouns-adjs/e-fem.js Normal file
View File

@ -0,0 +1,25 @@
module.exports = [
{ ts: 1568926976497, e: `x-ray` }, // اکسرې - iksre
{ ts: 1602179757779, e: `alphabet` }, // الف بې - alif be
{ ts: 1527813840, e: `ashes` }, // ایرې - eere
{ ts: 1527816692, e: `glasses, spectacles` }, // اینکې - aynake
{ ts: 1527819286, e: `stairs, steps, staircase` }, // پاشتقې - paashtáqe
{ ts: 1527816299, e: `money (plural of پېسې)` }, // پیسې - peyse
{ ts: 1527814529, e: `buttermilk` }, // تروې - turwe
{ ts: 1527816369, e: `widow, woman` }, // تورسرې - torsăre
{ ts: 1577408787088, e: `sprey (as in a medicinal spray)` }, // سپرې - spre
{ ts: 1527822255, e: `break of dawn, first light of day, sunrise` }, // سپېدې - spedé
{ ts: 1626765107329, e: `chickenpox, chicken pox` }, // شرې - sharé
{ ts: 1527815008, e: `milk` }, // شودې - shoode
{ ts: 1527822131, e: `raw rice, unprocessed rice` }, // شولې - shole
{ ts: 1527815009, e: `milk (plural of شيده)` }, // شیدې - sheede
{ ts: 1527823571, e: `spit, saliva` }, // ښیالمې - xyaalmé
{ ts: 1527816530, e: `sister in law` }, // ښینې - xeene
{ ts: 1527823567, e: `spit, saliva, slobber, slime` }, // لاړې - laaRe
{ ts: 1527822275, e: `dishes, pots, pans` }, // لوښې - looxe
{ ts: 1617443138210, e: `urine, pee, piss` }, // مچیازې - michyaaze, muchyaaze
{ ts: 1527814420, e: `yogurt` }, // مستې - maste
{ ts: 1577999538077, e: `a sound/cry used to drive sheep on` }, // هرې - hire
{ ts: 1586551382412, e: `rice` }, // وریژې - wreejze
{ ts: 1527820261, e: `plow, plowing, plough, ploughing` }, // یوې - yuwe
];

34
nouns-adjs/ee-fem.js Normal file
View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527820771, e: "population, number of settlers; prosperity, well-being; organization of public services and amenities; construction" }, // آباداني - aabaadaanee
{ ts: 1527813939, e: "freedom, independence" }, // آزادي - aazaadee
{ ts: 1527818402, e: "championship; courage" }, // اتلولي - atalwalée
{ ts: 1527814060, e: "ease" }, // اساني - asaanee
{ ts: 1527821293, e: "preparation, readiness, planning" }, // امادګي - amaadagee
{ ts: 1527819502, e: "kingship, kingdom, rule, throne, authority" }, // باچهي - baachahee
{ ts: 1527820035, e: "dominion, holding sway over someone" }, // باداري - baadaaree
{ ts: 1527817732, e: "misfortune, difficulty" }, // بدبختي - badbakhtee
{ ts: 1588786872582, e: "shame, disrepute, dishonour" }, // بدنامي - badnaamee
{ ts: 1573682378816, e: "sickness, illness" }, // بیماري - beemaaree
{ ts: 1527816817, e: "cleanliness, hygiene" }, // پاکوالي - paakwaalee
{ ts: 1586204619186, e: "righteousness, abstinence, self-control" }, // پرهېزګاري - parhezgaaree
{ ts: 1584444376984, e: "patriarchy" }, // پلارواکي - plaarwaakee
{ ts: 1527818744, e: "carpentry" }, // ترکاڼي - tarkaaNee
{ ts: 1527815337, e: "consolation, comfort, satisfaction" }, // تسلي - tasallee
{ ts: 1527819521, e: "happiness (خوشحالي)" }, // خوشالي - khoshaalee
{ ts: 1527818037, e: "good fortune, good luck, hapiness" }, // خوشبختي - khooshbakhtee
{ ts: 1527815914, e: "optimism" }, // خوشبیني - khooshbeenee
{ ts: 1527811877, e: "friendship" }, // دوستي - dostee
{ ts: 1527818019, e: "shopkeeping, retail store selling" }, // دوکانداري - dookaandaaree
{ ts: 1527822080, e: "democracy" }, // دېموکراسي - demokraasee
{ ts: 1527813462, e: "key" }, // کیلي - keelee
{ ts: 1527814492, e: "cattle farming" }, // ګاوداري - gaawdaaree
{ ts: 1610013679820, e: "brotherhood" }, // ورورولي - wrorwalée
];

View File

@ -0,0 +1,13 @@
module.exports = [
{ ts: 1527821971, e: `second wife of own husband` }, // بن - bun
{ ts: 1527816397, e: `aunt` }, // ترور - tror
{ ts: 1578704593901, e: `aunt (paternal uncle's wife)` }, // تندار - tandaar
{ ts: 1527812785, e: `sister` }, // خور - khor
{ ts: 1527812861, e: `daughter` }, // لور - loor
{ ts: 1527812928, e: `mother, mom` }, // مور - mor
{ ts: 1527812912, e: `lady, woman, wife` }, // مېرمن - mermán
{ ts: 1527816476, e: `stepsister, half sister` }, // مېرېنۍ خور - merenuy khor
{ ts: 1527823521, e: `daughter-in-law` }, // نږور - nGor
{ ts: 1527816350, e: `brothers wife, sister-in-law` }, // ورندار - wrundaar
{ ts: 1527816485, e: `wife of husbands brother, wife of brother-in-law` }, // یور - yor
];

View File

@ -0,0 +1,37 @@
module.exports = [
{ ts: 1527821817, e: `uncle (paternal)` }, // اکا - akáa
{ ts: 1527816411, e: `father, grandfather (vocative or in child's speech)` }, // بابا - baabaa
{ ts: 1527819439, e: `king, ruler, president, padishah` }, // باچا - baacháa
{ ts: 1527823298, e: `sparrow-hawk, eagle` }, // باښه - baaxá
{ ts: 1527817718, e: `slave, servant, a human, person (as in a slave of God)` }, // بنده - bandá
{ ts: 1527815031, e: `prisoner, captive` }, // بندي - bandee
{ ts: 1527815142, e: `king` }, // پاچا - paachaa
{ ts: 1527817280, e: `leper` }, // جذامي - jUzaamee
{ ts: 1527814236, e: `pot smoker, pothead, someone addicted to marijuana, pot, hash` }, // چرسي - charsee
{ ts: 1578618561154, e: `Haji, someone who has gone on the Hajj` }, // حاجي - haajee
{ ts: 1527821193, e: `supporter, protector, defender, patron, saviour` }, // حامي - haamee
{ ts: 1591711877815, e: `washerman, someone who does the laundry` }, // دوبي - dobée
{ ts: 1527820139, e: `rabab player, rubab player` }, // ربابي - rabaabee
{ ts: 1619278755267, e: `troubling, pestering` }, // ربړنه - rabaRúna
{ ts: 1577066022588, e: `cupbearer, butler, bartender, alchohol maker` }, // ساقي - saaqée
{ ts: 1527822817, e: `soldier, warrior, guard` }, // سپاهي - sipaahee
{ ts: 1527812975, e: `barber, hairdresser` }, // سلماني - salmaanee
{ ts: 1527819414, e: `prince` }, // شاهزاده - shaahzaadá
{ ts: 1527818084, e: `drinker, drunkard, alcoholic, wine-bibber` }, // شرابي - sharaabee
{ ts: 1527821950, e: `prince` }, // شهزاده - shahzaadá
{ ts: 1588158828142, e: `hunter` }, // ښکاري - xkaaree
{ ts: 1527815206, e: `judge, religious authority/judge` }, // قاضي - qaazee
{ ts: 1527818500, e: `contractor, supplier` }, // قراردادي - qaraardaadee
{ ts: 1527816446, e: `paternal uncle, term of address for elderly man` }, // کاکا - kaakaa
{ ts: 1595232159907, e: `begger, panhandler` }, // ګدا - gadáa
{ ts: 1527816512, e: `elder brother, general form of familiar and respectful address` }, // لالا - laalaa
{ ts: 1527812878, e: `uncle (maternal), respectful form of address` }, // ماما - maamaa
{ ts: 1610556640847, e: `census` }, // مردمشماري - mărdamshUmaaree
{ ts: 1527815484, e: `mullah, priest` }, // ملا - mUllaa
{ ts: 1527821714, e: `parallel, matching, appropriate, identical` }, // موازي - mUwaazée
{ ts: 1527816514, e: `shoemaker, shoe repairman, cobbler` }, // موچي - mochee
{ ts: 1527823093, e: `prophet` }, // نبي - nabee
{ ts: 1579041957559, e: `call, appeal, shout, summoning` }, // ندا - nadáa
{ ts: 1527816253, e: `grandson` }, // نواسه - nawaasa
{ ts: 1527819971, e: `governor` }, // والي - waalée
];

133
nouns-adjs/ey-masc.js Normal file
View File

@ -0,0 +1,133 @@
module.exports = [
{ ts: 1527818948, e: `sneezing, sneeze` }, // اټسکی - aTúskey
{ ts: 1573681135691, e: `tribal constable, tribal offical with police powers` }, // اربکی - arbakéy
{ ts: 1573659054031, e: `width, spaciousness` }, // ارتوالی - artwaaley, aratwaaley
{ ts: 1527811890, e: `thorn, prickle` }, // ازغی - azghey
{ ts: 1527817036, e: `representative, envoy, ambassador, commissioner` }, // استازی - astaazey
{ ts: 1527816982, e: `residence, dwelling; hostel, dormitory` }, // استوګنځی - astogundzey
{ ts: 1527818489, e: `yawn, sigh, deep breath, shivering` }, // اسوېلی - asweley
{ ts: 1527822497, e: `cheek` }, // اننګی - anangey
{ ts: 1527821967, e: `beaver, seal` }, // اوبسپی - obspéy
{ ts: 1527822190, e: `stove, oven, furnace, hearth, floor of a fireplace` }, // اور غالی - orgháaley
{ ts: 1527821545, e: `volcano` }, // اورشیندی - orsheendéy
{ ts: 1527819192, e: `train` }, // اورګاډی - orgáaDey
{ ts: 1527815585, e: `summer` }, // اوړی - oRey
{ ts: 1623044357441, e: `tuft, clump, shock of hair` }, // ببوتنکی - bubootúnkey
{ ts: 1527821668, e: `spark, speck, flicker` }, // بڅری - batsúrey
{ ts: 1527821239, e: `kidney` }, // بډوری - baDóorey
{ ts: 1527821099, e: `earring` }, // برغوږی - barghwáGey
{ ts: 1527822629, e: `lid, cover` }, // برغولی - barghóley
{ ts: 1527811903, e: `success, victory` }, // بری - barey
{ ts: 1594904072731, e: `bracelet` }, // بنګړی - bangRéy
{ ts: 1527817159, e: `plant` }, // بوټی - booTey
{ ts: 1527815055, e: `terrible` }, // بوږنوړی - boGnwaRey
{ ts: 1610618917483, e: `orphanage, nursery` }, // پالنځی - paalundzéy
{ ts: 1527814666, e: `final point, end point` }, // پای ټکی - paayTakey
{ ts: 1527816195, e: `small turban` }, // پټکی - paTkey
{ ts: 1527811611, e: `field, place where crops are sown` }, // پټی - paTey
{ ts: 1588762458105, e: `kitchen` }, // پخلنځی - pukhlandzéy
{ ts: 1527816059, e: `cooking, preparation of food; wisdom, maturity` }, // پخلی - pakhley
{ ts: 1527821241, e: `acorn` }, // پرګی - purgéy
{ ts: 1527813812, e: `veil, covering for women, cover` }, // پړونی - paRóoney
{ ts: 1527822385, e: `rope, cable, cord` }, // پړی - púRey
{ ts: 1527812980, e: `whispering, murmuring, rumor, gossip` }, // پس پسی - puspusey
{ ts: 1527814005, e: `spring, springtime (season)` }, // پسرلی - psarléy, pusărléy
{ ts: 1527821229, e: `kidney` }, // پښتورګی - paxtawurgey
{ ts: 1527817035, e: `mission, delegation` }, // پلاوی - plaawey
{ ts: 1527815187, e: `mat` }, // پوزی - pozey
{ ts: 1527816627, e: `fleece, pelt, skin, shell, rind, bark; ear lobe` }, // پوستکی - postukey
{ ts: 1527819332, e: `kidney` }, // پوښتورګی - pooxtawúrgey
{ ts: 1527819496, e: `understanding, comprehension` }, // پوهاوی - pohaawéy
{ ts: 1527815168, e: `load, weight, burden` }, // پېټی - peTéy
{ ts: 1527815927, e: `customer` }, // پېرونکی - peroonkey
{ ts: 1527815017, e: `cream` }, // پېروی - perúwey, peráwey
{ ts: 1527815325, e: `violence` }, // تاوتریخوالی - taawtreekhwaaley
{ ts: 1611397750325, e: `screwdriver, screw` }, // تاوی - taawéy
{ ts: 1622374978659, e: `hatchet` }, // تبرګی - tubúrgey
{ ts: 1527818705, e: `gusset (in a shirt)` }, // تخرګی - tkhurgéy
{ ts: 1527814392, e: `band, bandage` }, // تړونی - taRooney
{ ts: 1527822723, e: `side, groin, empty place, void` }, // تشی - túshey
{ ts: 1577585114379, e: `sole (of a shoe); yard, compound; palm` }, // تلی - táley
{ ts: 1527816630, e: `forehead, brow, slope` }, // تندی - tandey
{ ts: 1527821980, e: `bellyband (of a harness)` }, // تڼی - taNéy
{ ts: 1527819719, e: `spleen` }, // توری - tórey
{ ts: 1527819721, e: `letter, letter of the alphabet` }, // توری - tórey
{ ts: 1527819622, e: `rocket, missile` }, // توغندی - toghandéy
{ ts: 1527814705, e: `element, item, material; thing, material, kind, type` }, // توکی - tokey
{ ts: 1527819563, e: `piece, small piece; a length (of cloth); blanket` }, // ټکری - TUkréy
{ ts: 1577408381145, e: `shawl, head-covering` }, // ټکری - Tikréy
{ ts: 1527814667, e: `word; point; dot` }, // ټکی - Tákey
{ ts: 1527813617, e: `shawl, head covering` }, // ټیکری - Teekréy
{ ts: 1527819733, e: `young, youth, young lad` }, // ځلمی - dzalméy
{ ts: 1527815465, e: `official authority, official, authority` }, // چارواکی - chaarwaakey
{ ts: 1527822356, e: `worm, small insect` }, // چنجی - chinjéy
{ ts: 1527822808, e: `basin, bowl` }, // چنی - chanéy
{ ts: 1527822357, e: `worm, small insect` }, // چینجی - cheenjéy
{ ts: 1527819046, e: `drop` }, // څاڅکی - tsáatskey
{ ts: 1527817874, e: `quality, nature` }, // څرنګوالی - tsurangwaaley
{ ts: 1527814041, e: `spring (season)` }, // څړمنی - tsaRmuney
{ ts: 1573055311846, e: `warning, notice, alarm` }, // خبرداری - khabardaarey
{ ts: 1527820324, e: `melon` }, // خټکی - khaTakéy
{ ts: 1527819828, e: `weight; respect, honour` }, // درناوی - dranaawey
{ ts: 1588161660483, e: `crutch, walking-stick, cane` }, // ډانګوری - Daangooréy
{ ts: 1527819732, e: `young, youth, young lad` }, // زلمی - zalméy
{ ts: 1527813708, e: `good news, gospel` }, // زېری - zerey
{ ts: 1588758498458, e: `jaundice` }, // زېړی - zeRéy
{ ts: 1571626392709, e: `birthplace` }, // زېږنځی - zeGundzey
{ ts: 1527815698, e: `winter` }, // ژمی - jzúmey
{ ts: 1573686563723, e: `wineskin, bagpipe, skin for carrying liquid` }, // ژی - jzey
{ ts: 1527815239, e: `entertainment, fun, recreation` }, // ساتېری - saaterey
{ ts: 1527813725, e: `equal, equivalent, match, precedent` }, // ساری - sáarey
{ ts: 1527814021, e: `spring (season)` }, // سپرلی - sparléy
{ ts: 1527813509, e: `insult, disgrace, defamation, disrespect` }, // سپکاوی - spukaawéy
{ ts: 1527815298, e: `clarification, attestation` }, // سپیناوی - speenaawey
{ ts: 1578002674551, e: `eye-socket, eyelid; orbit` }, // سترغلی - sturghúley
{ ts: 1527811999, e: `star` }, // ستوری - storey
{ ts: 1527817001, e: `throat, larynx` }, // ستونی - stóoney
{ ts: 1527813511, e: `headache, trouble` }, // سرخوږی - sărkhwuGey
{ ts: 1527815251, e: `man` }, // سړی - saRéy
{ ts: 1527819850, e: `lung` }, // سږی - súGey
{ ts: 1527812302, e: `hole, slit, opening` }, // سوری - soorey
{ ts: 1527818221, e: `burning, zeal, fervour` }, // سوی - swey
{ ts: 1527812304, e: `shade, shadow` }, // سیوری - syórey, syóorey
{ ts: 1527815268, e: `thing` }, // شی - shey
{ ts: 1527822527, e: `ankle, ankle-bone` }, // ښتګری - xatgaréy
{ ts: 1527812793, e: `school` }, // ښوونځی - xowundzey
{ ts: 1527821064, e: `a quick, clever, agile, bright man; a swindler, a fraud` }, // ښویکی - xwayakéy
{ ts: 1527822650, e: `largeness, bigness` }, // غټوالی - ghaTwaaley
{ ts: 1527814569, e: `member` }, // غړی - ghuRey
{ ts: 1527817627, e: `arrow` }, // غشی - ghúshey
{ ts: 1527822913, e: `precious stone, precious stone in a signet ring` }, // غمی - ghaméy
{ ts: 1527816181, e: `vomit, nausea (Arabic)` }, // قی - qey
{ ts: 1527814715, e: `user` }, // کاروونکی - kaarawoonkey
{ ts: 1527823295, e: `stone, rock` }, // کاڼی - káaNey
{ ts: 1527818563, e: `muscle` }, // کبوړی - kabóoRey
{ ts: 1527822824, e: `booklet, notebook` }, // کتاب ګوټی - kitaabgóTey
{ ts: 1582388629980, e: `pupil (of an eye)` }, // کسی - kúsey
{ ts: 1594906790729, e: `boy` }, // ککی - kakéy
{ ts: 1527812836, e: `village` }, // کلی - kuley, kiley
{ ts: 1610616852625, e: `echo` }, // کنګرېزی - kangrezéy
{ ts: 1527819196, e: `car, train` }, // ګاډی - gaaDey
{ ts: 1579016593220, e: `beehive; wasps' nest` }, // ګنی - ganéy
{ ts: 1527819076, e: `doll, puppet` }, // ګوډاګی - gooDaagéy
{ ts: 1527822505, e: `cheek` }, // ګومبوری - goomboorey
{ ts: 1527819079, e: `puppet` }, // لاسپوڅی - laaspotséy
{ ts: 1573149568665, e: `access, availability` }, // لاسرسی - laasraséy
{ ts: 1527817464, e: `wood, timber` }, // لرګی - largey
{ ts: 1527822801, e: `sleeve` }, // لستوڼی - lastóNey
{ ts: 1527814401, e: `toy` }, // لوبونی - lobawuney
{ ts: 1527814519, e: `side, direction` }, // لوری - lorey
{ ts: 1527823103, e: `perspective, viewpoint` }, // لیدلوری - leedlorey
{ ts: 1527819920, e: `mosquito, midge` }, // ماشی - maashey
{ ts: 1527820224, e: `fly swatter` }, // مچوژی - muchwajzéy
{ ts: 1527817770, e: `dead body, corpse` }, // مړی - múRey
{ ts: 1527813189, e: `fall, autumn` }, // منی - máney
{ ts: 1527812421, e: `ant` }, // مېږی - meGey
{ ts: 1527819227, e: `lack` }, // نشتوالی - nashtwaaley
{ ts: 1527823577, e: `sapling, seedling, sprout, young tree` }, // نیالګی - niyaalgey
{ ts: 1527812073, e: `bone` }, // هډوکی - haDookey
{ ts: 1527812668, e: `welcome` }, // هرکلی - hărkáley
{ ts: 1588153218244, e: `height, elevation, tallness` }, // هسکوالی - haskwáaley
{ ts: 1585309922022, e: `flu, respiratory illness, influenza, cold` }, // والګی - waalgéy
{ ts: 1527821465, e: `shoulder` }, // ولی - wuléy
]

View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527822004, e: "last, final" }, // آخرینی - aakhireenéy
{ ts: 1591872915426, e: "Afghan (person)" }, // افغانی - afghaanéy
{ ts: 1612616237182, e: "Pakistani (person)"}, // پاکستانی - paakistaanéy
{ ts: 1527813400, e: "current" }, // اوسنی - oosanéy
{ ts: 1527815661, e: "first" }, // اولنی - awwalunéy
{ ts: 1527812476, e: "child" }, // بچی - bachéy
{ ts: 1527816646, e: "foreigner, outer" }, // بهرنی - baharanéy, bahranéy
{ ts: 1527818769, e: "emergency" }, // بېړنی - beRanéy
{ ts: 1592382613021, e: "old, ancient, former" }, // پخوانی - pakhwaanéy
{ ts: 1527819532, e: "foreign, unrelated" }, // پردی - pradéy, prudéy
{ ts: 1577381894391, e: "Englishman, Westerner" }, // پرنګی - parangéy
{ ts: 1527820194, e: "so-and-so" }, // پلانکی - pulaankéy
{ ts: 1527820130, e: "adherent" }, // پلوی - palawéy
{ ts: 1582390092514, e: "upper, above" }, // پورتنی - portinéy
{ ts: 1610617741649, e: "old, ancient" }, // ځنډنی - dzanDanéy, dzanDunéy
{ ts: 1610793723568, e: "goat" }, // چېلی - cheléy
{ ts: 1527819362, e: "calf (animal)" }, // خوسی - khooséy
{ ts: 1590052667427, e: "witness" }, // درستی - drustéy, drastéy
{ ts: 1527822854, e: "first, before" }, // ړومبی - Roombéy
{ ts: 1527820213, e: "lion" }, // زمری - zmaréy
{ ts: 1527813923, e: "living" }, // ژوندی - jzwundéy
{ ts: 1527815299, e: "dog" }, // سپی - spéy
{ ts: 1527820788, e: "city, urban" }, // ښارنی - xaaranéy
{ ts: 1527812822, e: "little, small" }, // کوچنی - koochnéy
{ ts: 1527823742, e: "nomadic" }, // کوچی - kochéy
{ ts: 1527818765, e: "speedy, quick" }, // ګړندی - guRandéy
{ ts: 1527819130, e: "cute" }, // ګلالی - gUlaaléy
{ ts: 1576101261017, e: "mute (person)" }, // ګنګی - gangéy
{ ts: 1582316583262, e: "lower, bottom" }, // لاندینی - laandeenéy
{ ts: 1527816249, e: "grandchild" }, // لمسی - lmaséy
{ ts: 1527813472, e: "first" }, // لومړنی - loomRanéy
{ ts: 1527813132, e: "first" }, // لومړی - loomRéy
{ ts: 1527819910, e: "slippery, smooth" }, // متلی - mutléy
{ ts: 1527820414, e: "middle, central" }, // منځنی - mandzunéy
{ ts: 1527811202, e: "monthly" }, // میاشتنی - miyaashtanéy
{ ts: 1527819320, e: "thin" }, // نری - naréy
{ ts: 1527816251, e: "grandchild" }, // نمسی - nmaséy
{ ts: 1527821373, e: "deer" }, // هوسی - hoséy
{ ts: 1527813636, e: "last" }, // وروستی - wroostéy
{ ts: 1527815430, e: "only" }, // یوازنی - yawaazunéy
];

View File

@ -0,0 +1,64 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1582853867682, e: "resident" }, // اوسېدونکی
{ ts: 1527813469, e: "forgiving" }, // بخښونکی
{ ts: 1527817829, e: "debtor" }, // پوروړی
{ ts: 1527815205, e: "powerful" }, // پیاوړی
{ ts: 1527815924, e: "customer" }, // پېرودونکی
{ ts: 1527819604, e: "tense, stern" }, // ترینګلی
{ ts: 1527813406, e: "bound, tied" }, // تړلی
{ ts: 1527815381, e: "thirsty" }, // تږی
{ ts: 1527817607, e: "disgraceful, shameful, dishonered" }, // تور مخی
{ ts: 1527822859, e: "dishevelled, messy, curly (with hair etc.)" }, // څپولی
{ ts: 1527811466, e: "researcher" }, // څېړونکی
{ ts: 1527812377, e: "obedient, submissive" }, // حکم منونکی
{ ts: 1527817299, e: "amazing, surprising" }, // حیرانوونکی
{ ts: 1527813282, e: "seller" }, // خرڅوونکی
{ ts: 1527812809, e: "malnourished" }, // خوار ځواکی
{ ts: 1591871233587, e: "well-spoken" }, // خوږژبی
{ ts: 1527814118, e: "painful, agonizing" }, // دردوونکی
{ ts: 1527820657, e: "mediator, arbitrator" }, // درېیمګړی
{ ts: 1527815713, e: "coming, future" }, // راتلونکی
{ ts: 1527812142, e: "true, truthful" }, // رښتنی
{ ts: 1527812161, e: "true, truthful" }, // رښتونی
{ ts: 1527811507, e: "true, truthful" }, // رښتینی
{ ts: 1527813758, e: "student" }, // زدکوونکی
{ ts: 1577058349091, e: "interesting, pleasant" }, // زړه پوری
{ ts: 1527817400, e: "merciful, compassionate" }, // زړه سواندی
{ ts: 1527819587, e: "translator" }, // ژباړونکی
{ ts: 1527814888, e: "savior, saviour, rescuer" }, // ژغورونکی
{ ts: 1527818109, e: "pure, holy, magnificent" }, // سپېڅلی
{ ts: 1527811338, e: "sincere hearted, trusting" }, // سپین زړی
{ ts: 1527815306, e: "tired" }, // ستړی
{ ts: 1527822745, e: "burned" }, // سټکوری
{ ts: 1527817442, e: "heard-hearted" }, // سخت زړی
{ ts: 1527816932, e: "soldier" }, // سرتېری
{ ts: 1527820170, e: "singer" }, // سندرغاړی
{ ts: 1527819964, e: "burning" }, // سوځېدونکی
{ ts: 1527821951, e: "burned" }, // سوی
{ ts: 1527812779, e: "beautiful" }, // ښکلی
{ ts: 1527812806, e: "teacher" }, // ښوونکی
{ ts: 1527811350, e: "quiet, silent" }, // غلی
{ ts: 1527819637, e: "worker" }, // کارکوونکی
{ ts: 1527818613, e: "weak" }, // کمزوری
{ ts: 1595516629483, e: "deafening" }, // کڼوونکی
{ ts: 1527820661, e: "mediator" }, // مېنځګړی
{ ts: 1527814047, e: "aforesaid, above-mentioned" }, // نوموړی
{ ts: 1527813822, e: "new" }, // نوی
{ ts: 1586453720908, e: "encouraging" }, // هڅوونکی
{ ts: 1588163180700, e: "stunning, amazing" }, // هېښوونکی
{ ts: 1527823715, e: "small, little" }, // وړکوټی
{ ts: 1527823714, e: "small, little" }, // وړکی
{ ts: 1527815403, e: "little, small" }, // وړوکی
{ ts: 1527813916, e: "lethal, deadly" }, // وژونکی
{ ts: 1527815424, e: "hungry" }, // وږی
{ ts: 1527823713, e: "small, little" }, // ووړکی
{ ts: 1527816455, e: "separated, divided" }, // وېشلی
];

View File

@ -0,0 +1,5 @@
module.exports = [
{"ts":1527812798,"i":5593,"p":"خفه","f":"khúfa","g":"khufa","e":"sad, upset, angry; choked, suffocated","c":"adj."},
{"ts":1527812792,"i":5773,"p":"خوشاله","f":"khoshaala","g":"khoshaala","e":"happy, glad","c":"adj."},
{"ts":1527812761,"i":8534,"p":"ښایسته","f":"xáaysta","g":"xaayusta","e":"beautiful","c":"adj."},
];

View File

@ -0,0 +1,79 @@
module.exports = [
{ ts: 1527821744, e: `cook, chef` }, // آشپز - aashpáz
{ ts: 1527812156, e: `officer` }, // افسر - afsar
{ ts: 1591872915426, e: `Afghan (person)` }, // افغانی - afghaanéy
{ ts: 1527815137, e: `instigator, insurgent, terrorist` }, // اورپکی - orpakey
{ ts: 1582853867682, e: `resident` }, // اوسېدونکی - osedóonkey
{ ts: 1527812476, e: `child, offspring` }, // بچی - bachéy
{ ts: 1623044005072, e: `insurrectionist, rebel` }, // بلواګر - balwaagar
{ ts: 1612616237182, e: `Pakistani (person)` }, // پاکستانی - paakistaanéy
{ ts: 1527817965, e: `keeper, one who brings up, raises (cattle etc.)` }, // پالونکی - paaloonkey
{ ts: 1527815197, e: `Pashtun` }, // پښتون - puxtoon
{ ts: 1527819228, e: `inspector, detective, person checking people at the doors etc.` }, // پلټونکی - pulaToonkey
{ ts: 1527820130, e: `adherent, supporter; the outside or further ox in a team of oxes grinding or threshing` }, // پلوی - palawéy
{ ts: 1527815924, e: `customer` }, // پېرودونکی - perodoonkey
{ ts: 1527816431, e: `cousin (of paternal aunt)` }, // ترورزی - trorzéy
{ ts: 1527820820, e: `follower` }, // تعقیبوونکی - ta'qeebawóonkey
{ ts: 1586270915475, e: `mammal` }, // تي لرونکی - tee laroonkey
{ ts: 1613563994424, e: `joker, jester, mocker` }, // ټوقمار - Toqmaar
{ ts: 1610793723568, e: `ram, goat` }, // چېلی - cheléy
{ ts: 1527811466, e: `researcher` }, // څېړونکی - tseRoonkey
{ ts: 1527812795, e: `relative` }, // خپلوان - khpulwaan
{ ts: 1527812802, e: `donkey` }, // خر - khur
{ ts: 1527813282, e: `seller` }, // خرڅوونکی - khartsawóonkey
{ ts: 1527819362, e: `calf (animal)` }, // خوسی - khooséy
{ ts: 1527822535, e: `tailor` }, // خیاط - khayáat
{ ts: 1590052667427, e: `witness` }, // درستی - drustéy, drastéy
{ ts: 1622873938137, e: `crook, swindler, criminal` }, // درغلګر - darghalgar
{ ts: 1527820656, e: `mediator, arbitrator` }, // دریمګړی - driyamgúRey
{ ts: 1614081825855, e: `priest, monk/nun` }, // راهب - raahib
{ ts: 1527813758, e: `student, learner, pupil` }, // زدکوونکی - zdakawóonkey
{ ts: 1527819587, e: `translator` }, // ژباړونکی - jzbaaRoonkey
{ ts: 1527815299, e: `dog` }, // سپی - spéy
{ ts: 1610447830096, e: `calf; bull-calf` }, // سخی - skhey
{ ts: 1527816932, e: `soldier` }, // سرتېری - sărtérey
{ ts: 1527811519, e: `embassador, ambassador` }, // سفیر - safeer
{ ts: 1622366208373, e: `secretary` }, // سکرتر - sakratár
{ ts: 1527820170, e: `singer` }, // سندرغاړی - sandurgháaRey
{ ts: 1566468540788, e: `rabbit` }, // سوی - sooy
{ ts: 1527819801, e: `tourist, sightseer, visitor` }, // سیلانی - seylaanéy
{ ts: 1575924767041, e: `shepherd` }, // شپون - shpoon
{ ts: 1527815279, e: `shepherd` }, // شپونکی - shpoonkey
{ ts: 1527819173, e: `analyst, examiner` }, // شنونکی - shanóonkey
{ ts: 1527812806, e: `teacher` }, // ښووونکی - xowóonkey
{ ts: 1527815436, e: `tyrant, oppressor, cruel person` }, // ظالم - zaalim
{ ts: 1527818632, e: `twin` }, // غبرګونی - ghbargoney
{ ts: 1527812624, e: `thief` }, // غل - ghul
{ ts: 1613561408232, e: `guilty, at fault` }, // قصوروار - qUsoorwáar
{ ts: 1527814715, e: `user` }, // کاروونکی - kaarawoonkey
{ ts: 1527816256, e: `great-grandson` }, // کړوسی - kaRwaséy
{ ts: 1594906790729, e: `child` }, // ککی - kakéy
{ ts: 1527819244, e: `host, hostess; master of house` }, // کوربه - korba
{ ts: 1527812174, e: `neighbour` }, // ګاونډی - gaawanDéy
{ ts: 1579030083953, e: `sinner, sinful` }, // ګناه ګار - gUnaahgáar
{ ts: 1527816249, e: `grandchild` }, // لمسی - lmaséy
{ ts: 1527822661, e: `athlete, player; actor; mischevious, playful (of a child)` }, // لوبغاړی - lobgháaRey
{ ts: 1589885143650, e: `fox` }, // لومبړ - loombáR
{ ts: 1527812043, e: `writer, author` }, // لیکوال - leekwaal
{ ts: 1527820680, e: `crazy, insane, mad person` }, // لېونی - lewanéy
{ ts: 1527812881, e: `child, kid` }, // ماشوم - maashoom
{ ts: 1527814445, e: `assigned, appointed, given orders or istructions (Arabic), authorized, sent on business; officer (as in government worker)` }, // مامور - maamóor
{ ts: 1527818760, e: `civil activist` }, // مدني فاعل - madanee faa'al
{ ts: 1527821523, e: `slave, servant` }, // مریی - mrayéy
{ ts: 1527814159, e: `friend, companion` }, // ملګری - malgúrey
{ ts: 1527820661, e: `mediator, go-between, arbitrator` }, // مېنځګړی - mendzgúRey
{ ts: 1527823403, e: `fan, someone who loves or appreciates someone or something` }, // مینه وال - meenawáal
{ ts: 1527815127, e: `nurse` }, // نرس - nurs
{ ts: 1527816254, e: `grandson` }, // نوسی - nwaséy
{ ts: 1527814806, e: `peer, someone of the same age` }, // همځولی - hamdzoléy ??
{ ts: 1527812684, e: `co-worker, fellow worker, collaborator, aid` }, // همکار - hamkaar
{ ts: 1527811732, e: `artist, performer` }, // هنر مند - hUnarmand
{ ts: 1527821373, e: `deer` }, // هوسی - hoséy
{ ts: 1591027046896, e: `goat` }, // وز - wuz
{ ts: 1611395180139, e: `fellow countryman, person from the same country` }, // وطندار - watandáar
{ ts: 1527811296, e: `lawyer, proxy holder` }, // وکیل - wakeel
{ ts: 1527813585, e: `person, human being, creature` }, // وګړی - wagúRey
{ ts: 1527814672, e: `spokesperson, spokesman, newcaster` }, // ویاند - wayaand
{ ts: 1586454081484, e: `orphan` }, // یتیم - yateem
{ ts: 1527812461, e: "hero" }, // اتل - atal
];

3
nouns-adjs/o-fem.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = [
{ ts: 1527816016, e: "Pashto" }, // پښټو
]

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527816778, e: "long" }, // اوږد - ooGd, ooGud
{ ts: 1527822706, e: "raw, unripe, immature" }, // اوم - oom
{ ts: 1527812802, e: "donkey" }, // خر - khur
{ ts: 1527813293, e: "red, hot" }, // سور - soor
{ ts: 1527815265, e: "green, blue" }, // شین - sheen
{ ts: 1527812624, e: "thief" }, // غل - ghul
{ ts: 1527815087, e: "dead" }, // مړ - muR
{ ts: 1527814151, e: "companion, friend" }, // مل - mal
{ ts: 1527813580, e: "one" }, // یو - yo
];

23
nouns-adjs/u-masc.js Normal file
View File

@ -0,0 +1,23 @@
module.exports = [
{ ts: 1527819345, e: `sheep, ram` }, // پسه - psu
{ ts: 1527822173, e: `bush, shrub` }, // جاړه - jaaRú
{ ts: 1527813508, e: `heart` }, // زړه - zRu
{ ts: 1588857967561, e: `bull` }, // غوایه - ghwaayú
{ ts: 1527817108, e: `look, gaze, examination, inspection, spying` }, // کاته - kaatu
{ ts: 1527817768, e: `raven, crow` }, // کارګه - kaargu
{ ts: 1527819245, e: `master of house, head of family, married man` }, // کوربانه - korbaanú
{ ts: 1527818516, e: `swimming, bathing` }, // لمبېده - lambedú
{ ts: 1527813986, e: `sunset, west` }, // لمر پرېواته - lmarprewaatu
{ ts: 1527813992, e: `sunset` }, // لمر لوېده - lmarlwedu
{ ts: 1527813987, e: `sunrise, east` }, // لمرخاته - lmarkhaatu
{ ts: 1527818255, e: `wolf, wild dog` }, // لېوه - lewú
{ ts: 1527821522, e: `slave, servant` }, // مریه - mrayú
{ ts: 1527812911, e: `husband, brave` }, // مېړه - meRu
{ ts: 1527811626, e: `impracticability, impossibility, improbability` }, // نکېده - nukedu
{ ts: 1527816410, e: `grandfather, grandpa` }, // نیکه - neekú
{ ts: 1527822420, e: `rein, bridle (for horses); string for trousers, string used inside to hold up the partoog/shalwar` }, // واګه - waagu
{ ts: 1527816357, e: `nephew, brother's son` }, // وراره - wraaru
{ ts: 1527823225, e: `flock, herd, drove` }, // وله - wUlú
{ ts: 1527814789, e: `hair` }, // وېښته - wextu
{ ts: 1527815394, e: 'wedding' }, // واده - waadú
];

33
nouns-adjs/uy-fem.js Normal file
View File

@ -0,0 +1,33 @@
/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
module.exports = [
{ ts: 1527818017, e: "store, shop" }, // اټۍ - aTuy
{ ts: 1527812694, e: "girl" }, // انجنۍ - injUnuy
{ ts: 1527815140, e: "week" }, // اونۍ - onuy, ownuy, owunuy
{ ts: 1566476931206, e: "lamp, light" }, // بتۍ - batúy
{ ts: 1527822192, e: "stove, oven, furnace" }, // بټۍ - baTúy
{ ts: 1527820828, e: "daughter, girl" }, // بچۍ - bachúy
{ ts: 1527822974, e: "cart, buggy, stroller" }, // بګۍ - bagúy
{ ts: 1591805634565, e: "rib" }, // پوښتۍ - pooxtúy
{ ts: 1586276322639, e: "hat, cap" }, // ټوپۍ - Topuy
{ ts: 1527820058, e: "kneecap, patella" }, // ټوټکۍ - ToTakúy
{ ts: 1527812564, e: "bread, food, meal" }, // ډوډۍ - DoDuy
{ ts: 1527821555, e: "edge, verge, side" }, // ژۍ - jzuy
{ ts: 1527814788, e: "moon" }, // سپوږمۍ - spoGmuy
{ ts: 1527820120, e: "hill, hillrock, mound" }, // غونډۍ - ghwunDúy
{ ts: 1527814203, e: "chair, seat, stool" }, // کرسۍ - kUrsuy
{ ts: 1527812045, e: "window" }, // کړکۍ - kuRkúy
{ ts: 1527816026, e: "ring, curl; handcuffs, link, chain; loom; department, section" }, // کړۍ - kaRuy
{ ts: 1527813870, e: "boat, ship" }, // کشتۍ - kishtúy
{ ts: 1527821895, e: "doll" }, // ګوډۍ - gooDúy
{ ts: 1527814564, e: "pill tablet; bullet" }, // ګولۍ - golúy
{ ts: 1527811763, e: "tail" }, // لکۍ - lakuy
{ ts: 1527812659, e: "egg" }, // هګۍ - haguy
{ ts: 1527821372, e: "gazelle, antelope" }, // هوسۍ - hosúy
];

14
nouns-adjs/y-masc.js Normal file
View File

@ -0,0 +1,14 @@
module.exports = [
{ ts: 1527815154, e: `end, finish, close, conclusion` }, // پای - paay
{ ts: 1527812594, e: `place, space` }, // ځای - dzaay
{ ts: 1527812525, e: `tea` }, // چای - chaay
{ ts: 1527812783, e: `God, Lord` }, // خدای - khUdaay
{ ts: 1527819514, e: `tier, row, foundation (masonry etc.)` }, // دای - daay
{ ts: 1610797797756, e: `hollow, depression` }, // سای - saay
{ ts: 1527822345, e: `caravansary, inn, large house` }, // سرای - saráay
{ ts: 1586598425514, e: `smell` }, // بوی - booy
{ ts: 1527814511, e: `character, nature, disposition, habit` }, // خوی - khooy
{ ts: 1566468540788, e: `rabbit` }, // سوی - sooy
]

View File

@ -1,6 +1,6 @@
{
"name": "@lingdocs/pashto-inflector",
"version": "1.7.0",
"version": "1.8.0",
"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",
@ -25,7 +25,8 @@
"dependencies": {
"classnames": "^2.2.6",
"pbf": "^3.2.1",
"rambda": "^6.7.0"
"rambda": "^6.7.0",
"react-select": "^5.2.2"
},
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.15.2",
@ -64,10 +65,10 @@
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build-website": "node get-verbs.js && npm run build",
"build-library": "node get-verbs.js && rimraf dist && rimraf dist-cjs && tsc --project library-tsconfig.json && node library-post-build.js && rollup -c",
"build-website": "node get-words.js && npm run build",
"build-library": "node get-words.js && rimraf dist && rimraf dist-cjs && tsc --project library-tsconfig.json && node library-post-build.js && rollup -c",
"test-ci": "npm run test -- --watchAll=false",
"get-verbs": "node get-verbs.js"
"get-words": "node get-words.js"
},
"eslintConfig": {
"extends": [

View File

@ -5,6 +5,11 @@
* LICENSE file in the root directory of this source tree.
*
*/
* {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
:root {
--secondary: #00c1fc;

View File

@ -7,8 +7,8 @@
*/
import { useEffect, useState } from "react";
import ConjugationViewer from "./components/ConjugationViewer";
import verbs from "./verbs";
import nounsAdjs from "./nouns-adjs";
import Pashto from "./components/Pashto";
import Phonetics from "./components/Phonetics";
import { getVerbInfo } from "./lib/verb-info";
@ -23,7 +23,9 @@ import {
Modal
} from "react-bootstrap";
import * as T from "./types";
import { isNounEntry } from "./lib/type-predicates";
import defualtTextOptions from "./lib/default-text-options";
import PhraseBuilder from "./components/vp-explorer/VPExplorer";
const textOptionsLocalStorageName = "textOptions2";
type VerbType = "simple" | "stative compound" | "dynamic compound";
const verbTypes: VerbType[] = [
@ -31,6 +33,7 @@ const verbTypes: VerbType[] = [
"stative compound",
"dynamic compound",
];
const nouns = nounsAdjs.filter(isNounEntry);
const transitivities: T.Transitivity[] = [
"transitive",
@ -192,7 +195,7 @@ function App() {
<p className="lead my-4">
Each form is made from one simple <samp>formula</samp> which <a href="https://www.lingdocs.com/blog/pashto-verbs-master-chart">works for all verbs</a>. 👨🔬
</p>
<p>Choose a verb 👇, look at its roots and stems 🌳, see how all the forms are made and what they mean. 🤓</p>
<p>Choose a verb 👇, look at its roots and stems 🌳, see how all the forms are made. 🤓</p>
</div>
<div className="d-block mx-auto card" style={{ maxWidth: "700px", background: "var(--closer)"}}>
<div className="card-body">
@ -288,11 +291,14 @@ function App() {
</div>
</div>
</div>
{v?.verb.entry && <ConjugationViewer
entry={v?.verb.entry}
complement={v?.verb.complement}
textOptions={textOptions}
/>}
{v?.verb.entry && <div style={{ paddingBottom: "100px" }}>
<PhraseBuilder
verb={v.verb as T.VerbEntry}
nouns={nouns}
verbs={verbs}
opts={textOptions}
/>
</div>}
</div>
</main>
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>

View File

@ -0,0 +1,90 @@
import * as T from "../types";
import Select from "react-select";
import AsyncSelect from "react-select/async";
import {
makeSelectOption,
makeVerbSelectOption,
zIndexProps,
} from "./np-picker/picker-tools";
function EntrySelect<E extends T.DictionaryEntry | T.VerbEntry>(props: ({
entries: E[]
} | {
searchF: (search: string) => E[],
getByTs: (ts: number) => E | undefined,
}) & {
value: E | undefined,
onChange: (value: E | undefined) => void,
name: string | undefined,
isVerbSelect?: boolean,
opts: T.TextOptions,
}) {
function makeOption(e: E | T.DictionaryEntry) {
if ("entry" in e) {
return (props.isVerbSelect ? makeVerbSelectOption : makeSelectOption)(e, props.opts);
}
return makeSelectOption(e, props.opts);
}
const value = props.value ? makeOption(props.value) : undefined;
if ("searchF" in props) {
const options = (searchString: string) =>
new Promise<{ value: string, label: string | JSX.Element }[]>(resolve => {
resolve(props.searchF(searchString).map(makeOption));
});
const onChange = (v: { label: string | JSX.Element, value: string } | null) => {
if (!v) {
props.onChange(undefined);
return;
}
const s = props.getByTs(parseInt(v.value));
if (!s) return;
props.onChange(s);
}
return <div>
<AsyncSelect
isSearchable={true}
className="mb-2"
value={value}
onChange={onChange}
defaultOptions={[]}
loadOptions={options}
placeholder={props.name ? `Select ${props.name}...` : undefined}
{...zIndexProps}
/>
</div>;
}
const options = props.entries
.sort((a, b) => {
if ("entry" in a) {
return a.entry.p.localeCompare("p" in b ? b.p : b.entry.p, "af-PS")
}
return a.p.localeCompare("p" in b ? b.p : b.entry.p, "af-PS");
})
.map(makeOption);
const onChange = (v: { label: string | JSX.Element, value: string } | null) => {
if (!v) {
props.onChange(undefined);
return;
}
const s = props.entries.find(e => (
("entry" in e)
? e.entry.ts.toString() === v.value
: e.ts.toString() === v.value
));
if (!s) return;
props.onChange(s);
}
return <div>
<Select
isSearchable={true}
value={value}
onChange={onChange}
className="mb-2"
options={options}
placeholder={props.name ? `Select ${props.name}...` : undefined}
{...zIndexProps}
/>
</div>
}
export default EntrySelect;

View File

@ -0,0 +1,163 @@
import {
makeNounSelection,
} from "./picker-tools";
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";
// const filterOptions = [
// {
// label: "1",
// value: "1",
// },
// {
// label: "2",
// value: "2",
// },
// {
// label: "3",
// value: "3",
// },
// {
// label: "4",
// value: "4",
// },
// {
// label: "5",
// value: "5",
// },
// {
// label: "6",
// value: "6",
// },
// ];
// type FilterPattern = "1" | "2" | "3" | "4" | "5" | "6";
// function nounFilter(p: FilterPattern | undefined) {
// return p === undefined
// ? () => true
// : (p === "1")
// ? isPattern1Entry
// : (p === "2")
// ? isPattern2Entry
// : (p === "3")
// ? isPattern3Entry
// : (p === "4")
// ? isPattern4Entry
// : (p === "5")
// ? isPattern5Entry
// : (p === "6")
// ? (n: NounEntry) => (isFemNounEntry(n) && isPattern6FemEntry(n))
// : () => true;
// }
function NPNounPicker(props: ({
nouns: T.NounEntry[],
} | {
nouns: (s: string) => T.NounEntry[],
getNounByTs: (ts: number) => T.NounEntry | undefined;
}) & {
noun: T.NounSelection | undefined,
onChange: (p: T.NounSelection | undefined) => void,
clearButton?: JSX.Element,
opts: T.TextOptions,
}) {
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
// const [showFilter, setShowFilter] = useState<boolean>(false)
// const nounsFiltered = props.nouns
// .filter(nounFilter(patternFilter))
// .sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
function onEntrySelect(entry: T.NounEntry | undefined) {
if (!entry) {
return props.onChange(undefined);
}
props.onChange(makeNounSelection(entry));
}
// function handleFilterClose() {
// setPatternFilter(undefined);
// setShowFilter(false);
// }
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
<div className="d-flex flex-row justify-content-left">
{props.clearButton}
{/* {(!showFilter && !(noun?.dynamicComplement)) && <div className="text-right">
<button className="btn btn-sm btn-light mb-2 text-small" onClick={() => setShowFilter(true)}>
<i className="fas fa-filter fa-xs" />
</button>
</div>} */}
</div>
{/* {showFilter && <div className="mb-2 text-center">
<div className="d-flex flex-row justify-content-between">
<div className="text-small mb-1">Filter by inflection pattern</div>
<div className="clickable" onClick={handleFilterClose}>X</div>
</div>
<ButtonSelect
options={filterOptions}
// @ts-ignore
value={patternFilter}
// @ts-ignore
handleChange={setPatternFilter}
/>
</div>} */}
{!(props.noun && props.noun.dynamicComplement) ? <div>
<EntrySelect
value={props.noun?.entry}
{..."getNounByTs" in props ? {
getByTs: props.getNounByTs,
searchF: props.nouns
} : {
entries: props.nouns,
}}
onChange={onEntrySelect}
name="Noun"
opts={props.opts}
/>
</div> : <div>
{props.noun && <div>
<div className="mb-2">Included in Dyn. Compound:</div>
<div className="mb-3 text-center">
<InlinePs opts={props.opts}>
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
</InlinePs>
<div className="text-muted">{props.noun.entry.e}</div>
</div>
</div>}
</div>}
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
<div>
{props.noun.changeGender ? <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));
}}
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
</div>
<div>
{props.noun.changeNumber ? <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));
}}
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
</div>
</div>}
</div>;
}
export default NPNounPicker;

View File

@ -0,0 +1,50 @@
import EntrySelect from "../EntrySelect";
import * as T from "../../types";
function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelection {
return {
type: "participle",
verb,
};
}
function NPParticiplePicker(props: ({
verbs: T.VerbEntry[],
} | {
verbs: (s: string) => T.VerbEntry[],
getVerbByTs: (ts: number) => T.VerbEntry | undefined;
}) & {
participle: T.ParticipleSelection | undefined,
onChange: (p: T.ParticipleSelection | undefined) => void,
clearButton: JSX.Element,
opts: T.TextOptions,
}) {
function onEntrySelect(entry: T.VerbEntry | undefined) {
if (!entry) {
props.onChange(undefined);
return;
}
props.onChange(makeParticipleSelection(entry));
}
return <div style={{ maxWidth: "225px" }}>
{props.clearButton}
<EntrySelect
value={props.participle?.verb}
{..."getVerbByTs" in props ? {
getByTs: props.getVerbByTs,
searchF: props.verbs,
} : {
entries: props.verbs,
}}
onChange={onEntrySelect}
name="Pariticple"
opts={props.opts}
/>
{props.participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
<div>Masc.</div>
<div>Plur.</div>
</div>}
</div>;
}
export default NPParticiplePicker;

View File

@ -0,0 +1,113 @@
import PronounPicker from "./NPPronounPicker";
import NounPicker from "./NPNounPicker";
import ParticiplePicker from "./NPParticiplePicker";
// import { getEnglishPronoun } from "../../lib/english-pronoun-tools";
// import { ButtonSelect } from "@lingdocs/pashto-inflector";
import {
randomPerson,
} from "../../lib/np-tools";
import { useState, useEffect } from "react";
import * as T from "../../types";
// import { capitalizeFirstLetter } from "../../lib/text-tools";
const npTypes: T.NPType[] = ["pronoun", "noun", "participle"];
function NPPicker(props: {
onChange: (nps: T.NPSelection | undefined) => void,
np: T.NPSelection | undefined,
counterPart: T.NPSelection | T.VerbObject | undefined,
asObject?: boolean,
opts: T.TextOptions,
} & ({
nouns: (s: string) => T.NounEntry[],
verbs: (s: string) => T.VerbEntry[],
getNounByTs: (ts: number) => T.NounEntry | undefined,
getVerbByTs: (ts: number) => T.VerbEntry | undefined,
} | {
nouns: T.NounEntry[],
verbs: T.VerbEntry[],
})) {
const [npType, setNpType] = useState<T.NPType | undefined>(props.np ? props.np.type : undefined);
useEffect(() => {
setNpType(props.np ? props.np.type : undefined);
}, [props.np]);
function handleClear() {
if (props.np && props.np.type === "noun" && props.np.dynamicComplement) return;
setNpType(undefined);
props.onChange(undefined);
}
function handleNPTypeChange(ntp: T.NPType) {
if (ntp === "pronoun") {
const person = randomPerson({ counterPart: props.counterPart });
const pronoun: T.PronounSelection = {
type: "pronoun",
person,
distance: "far",
};
setNpType(ntp);
props.onChange(pronoun);
} else {
props.onChange(undefined);
setNpType(ntp);
}
}
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
const clearButton = <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>;
return <div>
{!npType && <div className="text-center mt-3">
{/* <div className="h6 mr-3">
Choose NP
</div> */}
{npTypes.map((npt) => <div className="mb-2">
<button
key={npt}
type="button"
className="mr-2 btn btn-sm btn-outline-secondary"
onClick={() => handleNPTypeChange(npt)}
>
{npt}
</button>
</div>)}
</div>}
{(npType === "pronoun" && props.np?.type === "pronoun")
? <PronounPicker
asObject={props.asObject}
pronoun={props.np}
onChange={props.onChange}
clearButton={clearButton}
opts={props.opts}
/>
: npType === "noun"
? <NounPicker
{..."getNounByTs" in props ? {
nouns: props.nouns,
getNounByTs: props.getNounByTs,
} : {
nouns: props.nouns,
}}
noun={(props.np && props.np.type === "noun") ? props.np : undefined}
onChange={props.onChange}
clearButton={!isDynamicComplement ? clearButton : undefined}
opts={props.opts}
/>
: npType === "participle"
? <ParticiplePicker
{..."getVerbByTs" in props ? {
verbs: props.verbs,
getVerbByTs: props.getVerbByTs,
} : {
verbs: props.verbs,
}}
participle={(props.np && props.np.type === "participle") ? props.np : undefined}
onChange={props.onChange}
clearButton={clearButton}
opts={props.opts}
/>
: null
}
</div>;
}
// {(npType && !isDynamicComplement) && }
export default NPPicker;

View File

@ -0,0 +1,147 @@
import * as T from "../../types";
import ButtonSelect from "../ButtonSelect";
import useStickyState from "../../lib/useStickyState";
import classNames from "classnames";
const gColors = {
masc: "LightSkyBlue",
fem: "pink",
};
const labels = (asObject: boolean) => ({
persons: [
["1st", "1st pl."],
["2nd", "2nd pl."],
["3rd", "3rd pl."],
],
e: asObject ? [
["me", "us"],
["you", "you pl."],
[{ masc: "him/it", fem: "her/it"}, "them"],
] : [
["I", "We"],
["You", "You pl."],
[{ masc: "He/It", fem: "She/It"}, "They"],
],
p: {
far: [
["زه", "مونږ"],
["ته", "تاسو"],
["هغه", "هغوي"],
],
near: [
["زه", "مونږ"],
["ته", "تاسو"],
[{ masc: "دی", fem: "دا" }, "دوي"],
],
},
});
type PickerState = { row: number, col: number, gender: T.Gender };
function personToPickerState(person: T.Person): PickerState {
const col = person > 5 ? 1 : 0;
const row = Math.floor((person > 5 ? (person - 6) : person) / 2);
const gender: T.Gender = (person % 2) ? "fem" : "masc";
return { col, row, gender };
}
function pickerStateToPerson(s: PickerState): T.Person {
return (s.row * 2)
+ (s.gender === "masc" ? 0 : 1)
+ (6 * s.col);
}
function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
pronoun: T.PronounSelection,
onChange: (p: T.PronounSelection) => void,
asObject?: boolean,
clearButton?: JSX.Element,
opts: T.TextOptions,
}) {
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("persons", "prounoun-picker-display");
const p = personToPickerState(pronoun.person);
function handleClick(row: number, col: number) {
const person = pickerStateToPerson({ ...p, row, col });
onChange({
...pronoun,
person,
});
}
function handleGenderChange(gender: T.Gender) {
const person = pickerStateToPerson({ ...p, gender });
onChange({
...pronoun,
person,
});
}
function handlePronounTypeChange(distance: "far" | "near") {
onChange({
...pronoun,
distance,
});
}
function handleDisplayChange() {
const newPerson = display === "persons"
? "p"
: display === "p"
? "e"
: "persons";
setDisplay(newPerson);
}
const prs = labels(!!asObject)[display];
const pSpec = "near" in prs ? prs[pronoun.distance] : prs;
return <div style={{ maxWidth: "145px", padding: 0 }}>
{clearButton}
<div className="d-flex flex-row justify-content-around mb-3">
<ButtonSelect
xSmall
options={[
{ label: "Far", value: "far" },
{ label: "Near", value: "near" },
]}
value={pronoun.distance}
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
/>
<button className="btn btn-sm btn-outline" onClick={handleDisplayChange}>{display === "persons" ? "#" : display === "p" ? "PS" : "EN"}</button>
</div>
<table className="table table-bordered table-sm" style={{ textAlign: "center", minWidth: "100px", tableLayout: "fixed" }}>
<tbody>
{pSpec.map((rw, i) => (
<tr>
{rw.map((r, j) => {
const active = (p.row === i && p.col === j)
return <td
onClick={() => handleClick(i, j)}
className={classNames({ "table-active": active })}
style={{
backgroundColor: active ? gColors[p.gender] : "inherit",
padding: "0.25rem 0",
}}
>
<div className="my-1">
{typeof r === "string" ? r : r[p.gender]}
</div>
</td>;
})}
</tr>
))}
</tbody>
</table>
<div className="text-center">
<ButtonSelect
small
options={[
{ label: <div style={{ margin: "0.15rem"}}>Masc.</div>, value: "masc", color: gColors.masc },
{ label: <div style={{ margin: "0.15rem"}}>Fem.</div>, value: "fem", color: gColors.fem },
]}
value={p.gender}
handleChange={(g) => handleGenderChange(g as T.Gender)}
/>
</div>
</div>;
};
export default NPPronounPicker;

View File

@ -0,0 +1,115 @@
import {
isPluralNounEntry,
isMascNounEntry,
isUnisexNounEntry,
isVerbEntry,
} from "../../lib/type-predicates";
import {
getEnglishParticiple,
getEnglishVerb,
} from "../../lib/np-tools";
import * as T from "../../types";
import {
removeFVarients,
} from "../../lib/accent-and-ps-utils";
import {
getEnglishWord,
} from "../../lib/get-english-word";
import { phoneticsToDiacritics } from "../../lib/phonetics-to-diacritics";
import {
convertSpelling,
} from "../../lib/convert-spelling";
import {
translatePhonetics,
} from "../../lib/translate-phonetics";
export const zIndexProps = {
menuPortalTarget: document.body,
styles: { menuPortal: (base: any) => ({ ...base, zIndex: 9999 }) },
};
export function makeVerbSelectOption(e: T.VerbEntry, opts: T.TextOptions): { value: string, label: string | JSX.Element } {
const eng = getEnglishVerb(e.entry);
const ps = plainTextPsAdjustment(
{ p: e.entry.p, f: removeFVarients(e.entry.f) },
opts,
);
return {
label: `${ps.p} - ${ps.f} (${eng})`,
value: e.entry.ts.toString(),
};
}
function plainTextPsAdjustment(ps: T.PsString, opts: T.TextOptions): T.PsString {
function getP(ps: T.PsString): string {
const p = opts.diacritics
? (phoneticsToDiacritics(ps.p, ps.f) || ps.p)
: ps.p;
return convertSpelling(p, opts.spelling);
}
function getF(f: string): string {
if (opts.phonetics === "none") {
return "";
}
return opts.phonetics === "lingdocs"
? f
: translatePhonetics(f, {
dialect: opts.dialect,
// @ts-ignore - weird TS not picking up the elimination of "none herre"
system: opts.phonetics,
});
}
return { p: getP(ps), f: getF(ps.f) };
}
export function makeSelectOption(
e: T.DictionaryEntry | T.VerbEntry | T.NounEntry | T.AdjectiveEntry | T.LocativeAdverbEntry,
opts: T.TextOptions,
): { value: string, label: string } {
const entry = "entry" in e ? e.entry : e;
const eng = (isVerbEntry(e))
? (getEnglishParticiple(e.entry))
: getEnglishWord(e);
const english = typeof eng === "string"
? eng
: !eng
? ""
: ("singular" in eng && eng.singular !== undefined)
? eng.singular
: eng.plural;
const ps = plainTextPsAdjustment(
{ p: entry.p, f: removeFVarients(entry.f) },
opts,
);
return {
label: `${ps.p} - ${ps.f} (${english})`,
value: entry.ts.toString(),
};
}
export function makeNounSelection(entry: T.NounEntry, dynamicComplement?: true): T.NounSelection {
const number = isPluralNounEntry(entry) ? "plural" : "singular";
return {
type: "noun",
entry,
gender: isMascNounEntry(entry) ? "masc" : "fem",
number,
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,
};
},
} : {},
};
}

View File

@ -11,8 +11,8 @@ import InlinePs from "../InlinePs";
import Pashto from "../Pashto";
import Phonetics from "../Phonetics";
import {
makePsString
} from "../../lib/p-text-helpers";
makePsString,
} from "../../lib/accent-and-ps-utils";
import { Modal } from "react-bootstrap";
import stativeCompTrans from "./stative-compound-transitive.svg";
import stativeCompIntrans from "./stative-compound-intransitive.svg";

View File

@ -0,0 +1,101 @@
import ButtonSelect from "../ButtonSelect";
import * as T from "../../types";
const options = [
{
label: "Full",
value: "full",
},
{
label: "🚫 King",
value: "noKing",
},
{
label: "👶 Servant",
value: "shrinkServant",
},
{
label: "👶 🚫 Both",
value: "shortest",
},
];
function formToValue(f: T.FormVersion) {
if (f.removeKing === false && f.shrinkServant === false) {
return "full";
}
if (f.removeKing === true && f.shrinkServant === false) {
return "noKing";
}
if (f.removeKing === false && f.shrinkServant === true) {
return "shrinkServant";
}
if (f.removeKing === true && f.shrinkServant === true) {
return "shortest";
}
throw new Error("unrecognized abbreviation form");
}
function limitOptions(adjustable: "both" | "king" | "servant") {
if (adjustable === "both") {
return options;
}
if (adjustable === "king") {
return options.filter(o => !["shrinkServant", "shortest"].includes(o.value));
}
if (adjustable === "servant") {
return options.filter(o => !["noKing", "shortest"].includes(o.value));
}
}
function limitValue(value: string, adjustable: "both" | "king" | "servant") {
if (adjustable === "both") return value;
if (adjustable === "king") {
return (value === "shortest")
? "noKing"
: (value === "shrinkServant")
? "full"
: value;
}
if (adjustable === "servant") {
return (value === "shortest")
? "shrinkServant"
: (value === "noKing")
? "full"
: value;
}
throw new Error("unrecognized adjustable value");
}
function AbbreviationFormSelector({ form, onChange, adjustable }: {
form: T.FormVersion,
onChange: (f: T.FormVersion) => void,
adjustable: "both" | "king" | "servant",
}) {
function handleChange(f: "full" | "noKing" | "shrinkServant" | "shortest") {
if (f === "full") {
onChange({ removeKing: false, shrinkServant: false });
} else if (f === "noKing") {
onChange({ removeKing: true, shrinkServant: false });
} else if (f === "shrinkServant") {
onChange({ removeKing: false, shrinkServant: true });
} else if (f === "shortest") {
onChange({ removeKing: true, shrinkServant: true });
}
}
// TODO: limit display of shrinking options based on the verb type
return <div className="mb-3">
{/* <div className="text-center text-small mb-2">Abbreviation Options</div> */}
<ButtonSelect
small
// @ts-ignore
value={limitValue(formToValue(form), adjustable)}
// @ts-ignore
options={limitOptions(adjustable)}
// @ts-ignore
handleChange={handleChange}
/>
</div>
}
export default AbbreviationFormSelector;

View File

@ -0,0 +1,27 @@
import { getTenseVerbForm } from "../../lib/phrase-building/vp-tools";
import VerbFormDisplay from "../VerbFormDisplay";
import { conjugateVerb } from "../../lib/verb-conjugation";
import * as T from "../../types";
function ChartDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptions }) {
const rawConjugations = conjugateVerb(VS.verb.entry, VS.verb.complement);
if (!rawConjugations) {
return <div>Error conjugating verb</div>;
}
const conjugations = ("stative" in rawConjugations)
? rawConjugations[VS.isCompound === "stative" ? "stative" : "dynamic"]
: ("transitive" in rawConjugations)
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
: rawConjugations;
const form = getTenseVerbForm(conjugations, VS.tense, VS.tenseCategory, VS.voice);
return <div className="mb-4">
<VerbFormDisplay
displayForm={form}
showingFormInfo={false}
textOptions={opts}
info={conjugations.info}
/>
</div>;
}
export default ChartDisplay;

View File

@ -0,0 +1,178 @@
import Select from "react-select";
import {
zIndexProps,
} from "../np-picker/picker-tools";
import * as T from "../../types";
import ButtonSelect from "../ButtonSelect";
import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
const tenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] = [{
label: <div><i className="fas fa-video mr-2" />present</div>,
value: "presentVerb",
}, {
label: <div><i className="fas fa-camera mr-2" />subjunctive</div>,
value: "subjunctiveVerb",
}, {
label: <div><i className="fas fa-video mr-2" />imperfective future</div>,
value: "imperfectiveFuture",
}, {
label: <div><i className="fas fa-camera mr-2" />perfective future</div>,
value: "perfectiveFuture",
}, {
label: <div><i className="fas fa-video mr-2" />continuous past</div>,
value: "imperfectivePast",
}, {
label: <div><i className="fas fa-camera mr-2" />simple past</div>,
value: "perfectivePast",
}, {
label: <div><i className="fas fa-video mr-2" />habitual continual past</div>,
value: "habitualImperfectivePast",
}, {
label: <div><i className="fas fa-camera mr-2" />habitual simple past</div>,
value: "habitualPerfectivePast",
}];
const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense }[] = [{
label: "Present Perfect",
value: "present perfect",
}, {
label: "Habitual Perfect",
value: "habitual perfect",
}, {
label: "Subjunctive Perfect",
value: "subjunctive perfect",
}, {
label: "Future Perfect",
value: "future perfect",
}, {
label: "Past Perfect",
value: "past perfect",
}, {
label: `"Would Be" Perfect`,
value: "wouldBe perfect",
}, {
label: "Past Subjunctive Perfect",
value: "pastSubjunctive perfect",
}];
function TensePicker({ onChange, verb, mode }: {
verb: T.VerbSelection | undefined,
onChange: (p: T.VerbSelection | undefined) => void,
mode: "charts" | "phrases",
}) {
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) {
const value = o?.value ? o.value : undefined;
if (verb && value) {
if (isPerfectTense(value)) {
onChange({
...verb,
tense: value,
tenseCategory: "perfect",
});
} else {
onChange({
...verb,
tense: value,
tenseCategory: verb.tenseCategory === "perfect" ? "basic" : verb.tenseCategory,
});
}
}
}
function moveTense(dir: "forward" | "back") {
if (!verb) return;
return () => {
const tenses = verb.tenseCategory === "perfect" ? perfectTenseOptions : tenseOptions;
const currIndex = tenses.findIndex(tn => tn.value === verb.tense)
if (currIndex === -1) {
console.error("error moving tense", dir);
return;
}
const newIndex = dir === "forward"
? ((currIndex + 1) % tenses.length)
: (currIndex === 0 ? (tenses.length - 1) : (currIndex - 1))
const newTense = tenses[newIndex];
onTenseSelect(newTense);
};
}
function onPosNegSelect(value: string) {
if (verb) {
onChange({
...verb,
negative: value === "true",
});
}
}
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") {
if (verb) {
if (value === "perfect") {
onChange({
...verb,
tenseCategory: value,
tense: isPerfectTense(verb.tense) ? verb.tense : "present perfect",
});
} else {
onChange({
...verb,
tenseCategory: value,
tense: isPerfectTense(verb.tense) ? "presentVerb" : verb.tense,
});
}
}
}
const tOptions = (verb?.tenseCategory === "perfect") ? perfectTenseOptions : tenseOptions;
return <div>
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
<div className="d-flex flex-row justify-content-between align-items-center">
<div className="h5">Tense:</div>
{verb && <div className="mb-2">
<ButtonSelect
small
value={verb.tenseCategory}
options={[{
label: "Basic",
value: "basic",
}, {
label: "Perfect",
value: "perfect",
}, {
label: "Modal",
value: "modal",
}]}
handleChange={onTenseCategorySelect}
/>
</div>}
</div>
<Select
isSearchable={false}
// for some reason can't use tOptions with find here;
value={verb && ([...tenseOptions, ...perfectTenseOptions].find(o => o.value === verb.tense))}
onChange={onTenseSelect}
className="mb-2"
options={tOptions}
{...zIndexProps}
/>
{verb && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}>
<div className="btn btn-light clickable" onClick={moveTense("back")}>
<i className="fas fa-chevron-left" />
</div>
{mode !== "charts" && <ButtonSelect
small
value={verb.negative.toString()}
options={[{
label: "Pos.",
value: "false",
}, {
label: "Neg.",
value: "true",
}]}
handleChange={onPosNegSelect}
/>}
<div onClick={moveTense("forward")} className="btn btn-light clickable">
<i className="fas fa-chevron-right" />
</div>
</div>}
</div>
</div>;
}
export default TensePicker;

View File

@ -0,0 +1,71 @@
import { useState } from "react";
import { renderVP, compileVP } from "../../lib/phrase-building/index";
import * as T from "../../types";
import InlinePs from "../InlinePs";
import AbbreviationFormSelector from "./AbbreviationFormSelector";
import { isPastTense } from "../../lib/phrase-building/vp-tools";
function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
const [form, setForm] = useState<T.FormVersion>({ removeKing: false, shrinkServant: false });
const [OSV, setOSV] = useState<boolean>(false);
const result = compileVP(renderVP(VP), { ...form, OSV });
return <div className="text-center mt-2">
{VP.verb.transitivity === "transitive" && <div className="form-check mb-2">
<input
className="form-check-input"
type="checkbox"
checked={OSV}
id="OSVCheckbox"
onChange={e => setOSV(e.target.checked)}
/>
<label className="form-check-label text-muted" htmlFor="OSVCheckbox">
Include O S V
</label>
</div>}
<AbbreviationFormSelector
adjustable={whatsAdjustable(VP)}
form={form}
onChange={setForm}
/>
{"long" in result.ps ?
<div>
{/* <div className="h6">Long Verb:</div> */}
<VariationLayer vs={result.ps.long} opts={opts} />
{/* <div className="h6">Short Verb:</div> */}
<VariationLayer vs={result.ps.short} opts={opts} />
{result.ps.mini && <>
{/* <div className="h6">Mini Verb:</div> */}
<VariationLayer vs={result.ps.mini} opts={opts} />
</>}
</div>
: <VariationLayer vs={result.ps} opts={opts} />
}
{result.e && <div className="text-muted">
{result.e.map((e, i) => <div key={i}>{e}</div>)}
</div>}
</div>
}
function whatsAdjustable(VP: T.VPSelection): "both" | "king" | "servant" {
// TODO: intransitive dynamic compounds?
return (VP.verb.isCompound === "dynamic" && VP.verb.transitivity === "transitive")
? (isPastTense(VP.verb.tense) ? "servant" : "king")
: VP.verb.transitivity === "transitive"
? "both"
: VP.verb.transitivity === "intransitive"
? "king"
// grammTrans
: isPastTense(VP.verb.tense)
? "servant"
: "king";
}
function VariationLayer({ vs, opts }: { vs: T.PsString[], opts: T.TextOptions }) {
return <div className="mb-2">
{vs.map((r, i) => <div key={i}>
<InlinePs opts={opts}>{r}</InlinePs>
</div>)}
</div>;
}
export default VPDisplay;

View File

@ -0,0 +1,214 @@
import NPPicker from "../np-picker/NPPicker";
import VerbPicker from "./VerbPicker";
import TensePicker from "./TensePicker";
import VPDisplay from "./VPDisplay";
import ButtonSelect from "../ButtonSelect";
import { renderVP } from "../../lib/phrase-building/index";
import {
isInvalidSubjObjCombo,
} from "../../lib/phrase-building/vp-tools";
import * as T from "../../types";
import ChartDisplay from "./ChartDisplay";
import useStickyState from "../../lib/useStickyState";
import { makeVerbSelection } from "./verb-selection";
import { useEffect } from "react";
const kingEmoji = "👑";
const servantEmoji = "🙇‍♂️";
// TODO: Drill Down text display options
// TODO: SHOW KING AND SERVANT ONCE TENSE PICKED, EVEN IF NPs not selected
// TODO: Issue with dynamic compounds english making with plurals
// TODO: Issue with "the money were taken"
// TODO: Use the same component for PronounPicker and NPPronounPicker (sizing issue)
// get the practice pronoun picker page into a typesafe file
// A little button you can press on the tense select to show the formula and info about the tense
// in a popup
// TODO: option to show 3 modes Phrases - Charts - Quiz
// TODO: error handling on error with rendering etc
export function VPExplorer(props: {
verb?: T.VerbEntry,
opts: T.TextOptions,
} & ({
nouns: T.NounEntry[],
verbs: T.VerbEntry[],
} | {
nouns: (s: string) => T.NounEntry[],
verbs: (s: string) => T.VerbEntry[],
getNounByTs: (ts: number) => T.NounEntry | undefined,
getVerbByTs: (ts: number) => T.VerbEntry | undefined,
})) {
const [subject, setSubject] = useStickyState<T.NPSelection | undefined>(undefined, "subjectNPSelection");
const [mode, setMode] = useStickyState<"charts" | "phrases">("phrases", "verbExplorerMode");
const passedVerb = props.verb;
const [verb, setVerb] = useStickyState<T.VerbSelection | undefined>(
passedVerb
? (old) => makeVerbSelection(passedVerb, setSubject, old)
: undefined,
"verbExplorerVerb",
);
useEffect(() => {
if (!passedVerb) {
setVerb(undefined);
} else {
setVerb(o => makeVerbSelection(passedVerb, setSubject, o));
}
// eslint-disable-next-line
}, [passedVerb]);
function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) {
if (!skipPronounConflictCheck && hasPronounConflict(subject, verb?.object)) {
alert("That combination of pronouns is not allowed");
return;
}
setSubject(subject);
}
function handleObjectChange(object: T.NPSelection | undefined) {
if (!verb) return;
if ((verb.object === "none") || (typeof verb.object === "number")) return;
// check for pronoun conflict
if (hasPronounConflict(subject, object)) {
alert("That combination of pronouns is not allowed");
return;
}
setVerb({ ...verb, object });
}
function handleSubjObjSwap() {
if (verb?.isCompound === "dynamic") return;
const output = switchSubjObj({ subject, verb });
setSubject(output.subject);
setVerb(output.verb);
}
const verbPhrase: T.VPSelection | undefined = verbPhraseComplete({ subject, verb });
const VPRendered = verbPhrase && renderVP(verbPhrase);
return <div className="mt-3" style={{ maxWidth: "950px"}}>
<VerbPicker
{..."getNounByTs" in props ? {
getVerbByTs: props.getVerbByTs,
verbs: props.verbs,
} : {
verbs: props.verbs,
}}
verbLocked={!!props.verb}
verb={verb}
subject={subject}
changeSubject={(s) => handleSubjectChange(s, true)}
onChange={setVerb}
opts={props.opts}
/>
<div className="mt-2 mb-3">
<ButtonSelect
value={mode}
options={[
{ label: "Charts", value: "charts" },
{ label: "Phrases", value: "phrases" },
]}
handleChange={setMode}
/>
</div>
{(verb && (typeof verb.object === "object") && (verb.isCompound !== "dynamic") && (mode !== "charts")) &&
<div className="text-center mt-4">
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
<i className="fas fa-exchange-alt mr-2" /> subj/obj
</button>
</div>}
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
{mode !== "charts" && <>
<div className="my-2">
<div className="h5 text-center">Subject {showRole(VPRendered, "subject")}</div>
<NPPicker
{..."getNounByTs" in props ? {
getNounByTs: props.getNounByTs,
getVerbByTs: props.getVerbByTs,
nouns: props.nouns,
verbs: props.verbs,
} : {
nouns: props.nouns,
verbs: props.verbs,
}}
np={subject}
counterPart={verb ? verb.object : undefined}
onChange={handleSubjectChange}
opts={props.opts}
/>
</div>
{verb && (verb.object !== "none") && <div className="my-2">
<div className="h5 text-center">Object {showRole(VPRendered, "object")}</div>
{(typeof verb.object === "number")
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
: <NPPicker
{..."getNounByTs" in props ? {
getNounByTs: props.getNounByTs,
getVerbByTs: props.getVerbByTs,
nouns: props.nouns,
verbs: props.verbs,
} : {
nouns: props.nouns,
verbs: props.verbs,
}}
asObject
np={verb.object}
counterPart={subject}
onChange={handleObjectChange}
opts={props.opts}
/>}
</div>}
</>}
<div className="my-2">
<TensePicker
verb={verb}
onChange={setVerb}
mode={mode}
/>
</div>
</div>
{(verbPhrase && (mode === "phrases")) &&
<VPDisplay VP={verbPhrase} opts={props.opts} />
}
{(verb && (mode === "charts")) && <ChartDisplay VS={verb} opts={props.opts} />}
</div>
}
export default VPExplorer;
function hasPronounConflict(subject: T.NPSelection | undefined, object: undefined | T.VerbObject): boolean {
const subjPronoun = (subject && subject.type === "pronoun") ? subject : undefined;
const objPronoun = (object && typeof object === "object" && object.type === "pronoun") ? object : undefined;
if (!subjPronoun || !objPronoun) return false;
return isInvalidSubjObjCombo(subjPronoun.person, objPronoun.person);
}
function verbPhraseComplete({ subject, verb }: { subject: T.NPSelection | undefined, verb: T.VerbSelection | undefined }): T.VPSelection | undefined {
if (!subject) return undefined;
if (!verb) return undefined;
if (verb.object === undefined) return undefined;
return {
type: "VPSelection",
subject,
object: verb.object,
verb,
};
}
function showRole(VP: T.VPRendered | undefined, member: "subject" | "object") {
return VP
? <span className="ml-2">
{(VP.king === member ? kingEmoji : VP.servant === member ? servantEmoji : "")}
</span>
: "";
}
type SOClump = { subject: T.NPSelection | undefined, verb: T.VerbSelection | undefined };
function switchSubjObj({ subject, verb }: SOClump): SOClump {
if (!subject|| !verb || !verb.object || !(typeof verb.object === "object")) {
return { subject, verb };
}
return {
subject: verb.object,
verb: {
...verb,
object: subject,
}
};
}

View File

@ -0,0 +1,154 @@
import * as T from "../../types";
import ButtonSelect from "../ButtonSelect";
import { RootsAndStems } from "../verb-info/VerbInfo";
import { getVerbInfo } from "../../lib/verb-info";
import Hider from "../Hider";
import { makeVerbSelection } from "./verb-selection";
import EntrySelect from "../EntrySelect";
import useStickyState from "../../lib/useStickyState";
// TODO: dark on past tense selecitons
function VerbPicker(props: ({
verbs: T.VerbEntry[],
} | {
verbs: (s: string) => T.VerbEntry[],
getVerbByTs: (ts: number) => T.VerbEntry | undefined;
}) & {
verb: T.VerbSelection | undefined,
subject: T.NPSelection | undefined,
onChange: (p: T.VerbSelection | undefined) => void,
changeSubject: (p: T.NPSelection | undefined) => void,
opts: T.TextOptions,
verbLocked: boolean,
}) {
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
const infoRaw = props.verb ? getVerbInfo(props.verb.verb.entry, props.verb.verb.complement) : undefined;
const info = (!infoRaw || !props.verb)
? undefined
: ("stative" in infoRaw)
? infoRaw[props.verb.isCompound === "stative" ? "stative" : "dynamic"]
: ("transitive" in infoRaw)
? infoRaw[props.verb.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
: infoRaw;
if (info && ("stative" in info || "transitive" in info)) {
return <div>ERROR: Verb version should be select first</div>;
}
// const [filters, useFilters] = useState<Filters>({
// stative: true,
// dynamic: true,
// transitive: true,
// intransitive: true,
// grammaticallyTransitive: true,
// });
function onVerbSelect(v: T.VerbEntry | undefined) {
// TODO: what to do when clearing
if (!v) {
return props.onChange(v);
}
props.onChange(makeVerbSelection(v, props.changeSubject, props.verb));
}
function onVoiceSelect(value: "active" | "passive") {
if (props.verb && props.verb.changeVoice) {
if (value === "passive" && (typeof props.verb.object === "object")) {
props.changeSubject(props.verb.object);
}
if (value === "active") {
props.changeSubject(undefined);
}
props.onChange(props.verb.changeVoice(value, value === "active" ? props.subject : undefined));
}
}
function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" {
return t === "intransitive" ? "transitive" : t;
}
function handleChangeTransitivity(t: "transitive" | "grammatically transitive") {
if (props.verb && props.verb.changeTransitivity) {
props.onChange(props.verb.changeTransitivity(t));
}
}
function handleChangeStatDyn(c: "stative" | "dynamic") {
if (props.verb && props.verb.changeStatDyn) {
props.onChange(props.verb.changeStatDyn(c));
}
}
return <div className="mb-3">
{!props.verbLocked && <div style={{ maxWidth: "300px", margin: "0 auto" }}>
<div className="h5">Verb:</div>
<EntrySelect
{..."getVerbByTs" in props ? {
searchF: props.verbs,
getByTs: props.getVerbByTs,
} : {
entries: props.verbs,
}}
value={props.verb?.verb}
onChange={onVerbSelect}
name="Verb"
isVerbSelect
opts={props.opts}
/>
</div>}
{info && <div className="mt-3 mb-1 text-center">
<Hider
showing={showRootsAndStems}
label="🌳 Roots and Stems"
handleChange={() => setShowRootsAndStems(p => !p)}
hLevel={5}
>
<RootsAndStems
textOptions={props.opts}
info={info}
/>
</Hider>
</div>}
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ maxWidth: "400px", margin: "0 auto" }}>
{props.verb && props.verb.changeTransitivity && <div className="text-center my-2">
<ButtonSelect
small
options={[{
label: "gramm. trans.",
value: "grammatically transitive",
}, {
label: "trans.",
value: "transitive",
}]}
value={notInstransitive(props.verb.transitivity)}
handleChange={handleChangeTransitivity}
/>
</div>}
{props.verb && props.verb.changeVoice && <div className="text-center my-2">
<ButtonSelect
small
value={props.verb.voice}
options={[{
label: "Active",
value: "active",
}, {
label: "Passive",
value: "passive",
}]}
handleChange={onVoiceSelect}
/>
</div>}
{props.verb && props.verb.changeStatDyn && <div className="text-center my-2">
<ButtonSelect
small
options={[{
label: "stative",
value: "stative",
}, {
label: "dynamic",
value: "dynamic",
}]}
value={props.verb.isCompound ? props.verb.isCompound : "stative"}
handleChange={handleChangeStatDyn}
/>
</div>}
</div>
</div>;
}
export default VerbPicker;

View File

@ -0,0 +1,106 @@
import {
makeNounSelection,
} from "../np-picker/picker-tools";
import * as T from "../../types";
import { getVerbInfo } from "../../lib/verb-info";
import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
export function makeVerbSelection(verb: T.VerbEntry, changeSubject: (s: T.NPSelection | undefined) => void, oldVerbSelection?: T.VerbSelection): T.VerbSelection {
const info = getVerbInfo(verb.entry, verb.complement);
function getTransObjFromOldVerbSelection() {
if (
!oldVerbSelection ||
oldVerbSelection.object === "none" ||
typeof oldVerbSelection.object === "number" ||
oldVerbSelection.isCompound === "dynamic" ||
(oldVerbSelection.object?.type === "noun" && oldVerbSelection.object.dynamicComplement)
) return undefined;
return oldVerbSelection.object;
}
const transitivity: T.Transitivity = "grammaticallyTransitive" in info
? "transitive"
: info.transitivity;
const object = (transitivity === "grammatically transitive")
? T.Person.ThirdPlurMale
: (info.type === "dynamic compound" && oldVerbSelection?.voice !== "passive")
? makeNounSelection(info.objComplement.entry as T.NounEntry, true)
: (transitivity === "transitive" && oldVerbSelection?.voice !== "passive")
? getTransObjFromOldVerbSelection()
: "none";
if (oldVerbSelection?.voice === "passive" && info.type === "dynamic compound") {
changeSubject(makeNounSelection(info.objComplement.entry as T.NounEntry, true));
}
const isCompound = ("stative" in info || info.type === "stative compound")
? "stative"
: info.type === "dynamic compound"
? "dynamic"
: false;
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
const dynAuxVerb: T.VerbEntry | undefined = isCompound !== "dynamic"
? undefined
: info.type === "dynamic compound"
? { entry: info.auxVerb } as T.VerbEntry
: "dynamic" in info
? { entry: info.dynamic.auxVerb } as T.VerbEntry
: undefined;
const tenseSelection = ((): { tenseCategory: "perfect", tense: T.PerfectTense } | {
tenseCategory: "basic" | "modal",
tense: T.VerbTense,
} => {
if (!oldVerbSelection) {
return { tense: "presentVerb", tenseCategory: "basic" };
}
if (oldVerbSelection.tenseCategory === "modal") {
return { tenseCategory: "modal", tense: isPerfectTense(oldVerbSelection.tense) ? "presentVerb" : oldVerbSelection.tense };
}
if (oldVerbSelection.tenseCategory === "basic") {
return { tenseCategory: "basic", tense: isPerfectTense(oldVerbSelection.tense) ? "presentVerb" : oldVerbSelection.tense };
}
return { tenseCategory: "perfect", tense: isPerfectTense(oldVerbSelection.tense) ? oldVerbSelection.tense : "present perfect" };
})();
return {
type: "verb",
verb: verb,
dynAuxVerb,
...tenseSelection,
object,
transitivity,
isCompound,
voice: transitivity === "transitive"
? (oldVerbSelection?.voice || "active")
: "active",
negative: oldVerbSelection ? oldVerbSelection.negative : false,
...("grammaticallyTransitive" in info) ? {
changeTransitivity: function(t) {
return {
...this,
transitivity: t,
object: t === "grammatically transitive" ? T.Person.ThirdPlurMale : undefined,
};
},
} : {},
...("stative" in info) ? {
changeStatDyn: function(c) {
return {
...this,
isCompound: c,
object: c === "dynamic"
? makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, true)
: undefined,
dynAuxVerb: c === "dynamic"
? { entry: info.dynamic.auxVerb } as T.VerbEntry
: undefined,
};
}
} : {},
...(transitivity === "transitive") ? {
changeVoice: function(v, s) {
return {
...this,
voice: v,
object: v === "active" ? s : "none",
};
},
} : {},
};
}

View File

@ -0,0 +1,12 @@
import { removeFVarients, makePsString } from "./accent-and-ps-utils";
test(`removeFVarients`, () => {
expect(removeFVarients("ist'imaal, istimaal")).toBe("ist'imaal");
expect(removeFVarients({ p: "معالوم", f: "ma'aalóom, maalóom" }))
.toEqual({ p: "معالوم", f: "ma'aalóom" });
expect(removeFVarients("kor")).toBe("kor");
});
test(`makePsString should work`, () => {
expect(makePsString("کور", "kor")).toEqual({ p: "کور", f: "kor" });
});

View File

@ -0,0 +1,30 @@
import * as T from "../types";
/**
* Creates a Pashto string structure
*
* @param p - the Pashto text
* @param f - the phonetics text
*/
export function makePsString(p: string, f: string): T.PsString {
return { p, f };
}
export function removeFVarients(x: T.DictionaryEntry): T.DictionaryEntryNoFVars;
export function removeFVarients(x: T.PsString): T.PsStringNoFVars;
export function removeFVarients(x: string): T.FStringNoFVars;
export function removeFVarients(x: string | T.PsString | T.DictionaryEntry): T.FStringNoFVars | T.PsStringNoFVars | T.DictionaryEntryNoFVars {
if (typeof x === "string") {
return x.split(",")[0] as T.FStringNoFVars;
}
if ("ts" in x) {
return {
...x,
f: removeFVarients(x.f),
} as unknown as T.DictionaryEntryNoFVars;
}
return {
...x,
f: removeFVarients(x.f),
} as unknown as T.PsStringNoFVars;
}

View File

@ -6,7 +6,7 @@
*
*/
import { makePsString } from "./p-text-helpers";
import { makePsString } from "./accent-and-ps-utils";
import {
accentOnFront,
accentPastParticiple,

View File

@ -6,8 +6,8 @@
*
*/
import { makePsString, removeFVarients } from "./p-text-helpers";
import * as T from "../types";
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
/**
* Returns a Pashto string (or string with Length options) ensuring that

View File

@ -29,7 +29,7 @@ import {
PhonemeStatus,
} from "./diacritics-helpers";
import { removeFVarients } from "./p-text-helpers";
import { removeFVarients } from "./accent-and-ps-utils";
import { pipe } from "rambda";
/**

View File

@ -152,6 +152,7 @@ export function randomNumber(minInclusive: number, maxExclusive: number): number
return Math.floor(Math.random() * (maxExclusive - minInclusive) + minInclusive);
}
// TODO: deprecate this because we have it in np-tools?
/**
* Sees if a possiblePerson (for subject/object) is possible, given the other person
*
@ -173,6 +174,7 @@ export function personIsAllowed(possiblePerson: T.Person, existingPerson?: T.Per
return true;
}
// TODO: deprecate this because we have it in np-tools?
/**
* Picks a random person while assuring that the other person is not in conflict
*

91
src/lib/np-tools.ts Normal file
View File

@ -0,0 +1,91 @@
import * as T from "../types";
import { parseEc } from "../lib/misc-helpers";
function getRandPers(): T.Person {
return Math.floor(Math.random() * 12);
}
export function randomPerson(a?: { prev?: T.Person, counterPart?: T.VerbObject | T.NPSelection }) {
// no restrictions, just get any person
if (!a) {
return getRandPers();
}
if (a.counterPart !== undefined && typeof a.counterPart === "object" && a.counterPart.type === "pronoun") {
// with counterpart pronoun
let newP = 0;
do {
newP = getRandPers();
} while (
isInvalidSubjObjCombo(a.counterPart.person, newP)
||
(newP === a.prev)
);
return newP;
}
// without counterpart pronoun, just previous
let newP = 0;
do {
newP = getRandPers();
} while (newP === a.prev);
return newP;
}
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
const firstPeople = [
T.Person.FirstSingMale,
T.Person.FirstSingFemale,
T.Person.FirstPlurMale,
T.Person.FirstPlurFemale,
];
const secondPeople = [
T.Person.SecondSingMale,
T.Person.SecondSingFemale,
T.Person.SecondPlurMale,
T.Person.SecondPlurFemale,
];
return (
(firstPeople.includes(subj) && firstPeople.includes(obj))
||
(secondPeople.includes(subj) && secondPeople.includes(obj))
);
}
export function randomSubjObj(old?: { subj: T.Person, obj: T.Person }): { subj: T.Person, obj: T.Person } {
let subj = 0;
let obj = 0;
do {
subj = getRandPers();
obj = getRandPers();
} while (
(old && ((old.subj === subj) || (old.obj === obj)))
||
isInvalidSubjObjCombo(subj, obj)
);
return { subj, obj };
}
export function getEnglishVerb(entry: T.DictionaryEntry): string {
if (!entry.ec) {
console.log("errored verb");
console.log(entry);
throw new Error("no english information for verb");
}
if (entry.ep) {
const ec = entry.ec.includes(",") ? parseEc(entry.ec)[0] : entry.ec;
return `to ${ec} ${entry.ep}`;
}
const ec = parseEc(entry.ec);
return `to ${ec[0]}`;
}
export function getEnglishParticiple(entry: T.DictionaryEntry): string {
if (!entry.ec) {
console.log("errored participle");
console.log(entry);
throw new Error("no english information for participle");
}
const ec = parseEc(entry.ec);
const participle = ec[2];
return (entry.ep)
? `${participle} ${entry.ep}`
: participle;
}

View File

@ -5,10 +5,9 @@
* LICENSE file in the root directory of this source tree.
*
*/
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
import {
concatPsString,
makePsString,
removeEndingL,
yulEndingInfinitive,
mapVerbBlock,
@ -22,7 +21,6 @@ import {
splitDoubleWord,
endsInConsonant,
addOEnding,
removeFVarients,
endsInShwa,
splitPsByVarients,
endsWith,
@ -701,8 +699,8 @@ test(`splitDoubleWord should work`, () => {
c: "adj.",
i: 1,
},
]
expect(splitDoubleWord(orig)).toEqual(out);
];
expect(splitDoubleWord(removeFVarients(orig))).toEqual(out);
});
// test(`allThirdPersMascPlur should work`, () => {

View File

@ -6,9 +6,6 @@
*
*/
import {
inflectRegularYeyUnisex,
} from "./pashto-inflector";
import { baParticle } from "./grammar-units";
import {
getVerbBlockPosFromPerson,
@ -21,6 +18,7 @@ import {
} from "./accent-helpers";
import { phoneticsConsonants } from "./pashto-consonants";
import { simplifyPhonetics } from "./simplify-phonetics";
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
// export function concatPsStringWithVars(...items: Array<T.PsString | " " | "">): T.PsString[] {
@ -182,25 +180,6 @@ export function ensureBaAt(ps: T.FullForm<T.PsString>, pos: number): T.FullForm<
return baInserted;
}
export function removeFVarients(x: T.DictionaryEntry): T.DictionaryEntryNoFVars;
export function removeFVarients(x: T.PsString): T.PsStringNoFVars;
export function removeFVarients(x: string): T.FStringNoFVars;
export function removeFVarients(x: string | T.PsString | T.DictionaryEntry): T.FStringNoFVars | T.PsStringNoFVars | T.DictionaryEntryNoFVars {
if (typeof x === "string") {
return x.split(",")[0] as T.FStringNoFVars;
}
if ("ts" in x) {
return {
...x,
f: removeFVarients(x.f),
} as unknown as T.DictionaryEntryNoFVars;
}
return {
...x,
f: removeFVarients(x.f),
} as unknown as T.PsStringNoFVars;
}
/**
* Lets us know if all the forms of a verb block are the same
*
@ -214,16 +193,6 @@ export function isAllOne (block: T.VerbBlock | T.ImperativeBlock): boolean {
), true) as unknown as boolean;
}
/**
* Creates a Pashto string structure
*
* @param p - the Pashto text
* @param f - the phonetics text
*/
export function makePsString(p: string, f: string): T.PsString {
return { p, f };
}
/**
* Retuns a Pashto string with the ل - ul on the end removed
*
@ -635,15 +604,7 @@ export function removeRetroflexR(ps: T.PsString): T.PsString {
};
}
export function inflectYey(ps: T.SingleOrLengthOpts<T.PsString>): T.SingleOrLengthOpts<T.UnisexInflections> {
if ("long" in ps) {
return {
long: inflectYey(ps.long) as T.UnisexInflections,
short: inflectYey(ps.short) as T.UnisexInflections,
}
}
return inflectRegularYeyUnisex(ps.p, ps.f);
}
export function clamp(s: string, chars: number): string {
return `${s.slice(0, 20)}${s.length > 20 ? "..." : ""}`;
@ -1010,4 +971,26 @@ export function endsWith(
((matchAccent ? f.slice(-fEnd.length) : removeAccents(f.slice(-fEnd.length))) === (matchAccent ? fEnd : removeAccents(fEnd)))
: true)
);
}
export function firstVariation(s: string): string {
return s.split(/[,|;]/)[0].trim();
}
export function psStringFromEntry(entry: T.PsString): T.PsString {
return {
p: entry.p,
f: removeFVarients(entry.f),
};
}
export function getLong<U>(x: T.SingleOrLengthOpts<U>): U {
if ("long" in x) {
return x.long;
}
return x;
}
export function capitalizeFirstLetter(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}

View File

@ -11,8 +11,6 @@ import {
concatInflections,
splitDoubleWord,
ensureUnisexInflections,
makePsString,
removeFVarients,
concatPsString,
endsInConsonant,
endsInAaOrOo,
@ -22,6 +20,7 @@ import {
removeEndTick,
endsWith,
} from "./p-text-helpers";
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
import {
accentFSylsOnNFromEnd,
hasAccents,
@ -625,3 +624,13 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections
}
return undefined;
}
export function inflectYey(ps: T.SingleOrLengthOpts<T.PsString>): T.SingleOrLengthOpts<T.UnisexInflections> {
if ("long" in ps) {
return {
long: inflectYey(ps.long) as T.UnisexInflections,
short: inflectYey(ps.short) as T.UnisexInflections,
}
}
return inflectRegularYeyUnisex(ps.p, ps.f);
}

View File

@ -0,0 +1,386 @@
import * as T from "../../types";
import {
concatPsString,
} from "../p-text-helpers";
import { makePsString } from "../accent-and-ps-utils";
import {
removeAccents,
} from "../accent-helpers";
import { getVerbBlockPosFromPerson } from "../misc-helpers";
import * as grammarUnits from "../grammar-units";
import {
removeBa,
removeDuplicates,
} from "./vp-tools";
type Form = T.FormVersion & { OSV?: boolean };
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
export function compileVP(VP: T.VPRendered, form: Form, combineLengths: true): { ps: T.PsString[], e?: string [] };
export function compileVP(VP: T.VPRendered, form: Form, combineLengths?: true): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
const verb = VP.verb.ps;
const { kids, NPs } = getSegmentsAndKids(VP, form);
const psResult = compilePs({
NPs,
kids,
verb,
VP,
});
return {
ps: combineLengths ? flattenLengths(psResult) : psResult,
// TODO: English doesn't quite work for dynamic compounds in passive voice
e: (VP.verb.voice === "passive" && VP.isCompound === "dynamic") ? undefined : compileEnglish(VP),
};
}
type CompilePsInput = {
NPs: Segment[][],
kids: Segment[],
verb: {
head: T.PsString | undefined,
rest: T.SingleOrLengthOpts<T.PsString[]>,
},
VP: T.VPRendered,
}
function compilePs({ NPs, kids, verb: { head, rest }, VP }: CompilePsInput): T.SingleOrLengthOpts<T.PsString[]> {
if ("long" in rest) {
return {
long: compilePs({ NPs, verb: { head, rest: rest.long }, VP, kids }) as T.PsString[],
short: compilePs({ NPs, verb: { head, rest: rest.short }, VP, kids }) as T.PsString[],
...rest.mini ? {
mini: compilePs({ NPs, verb: { head, rest: rest.mini }, VP, kids }) as T.PsString[],
} : {},
};
}
const verbWNegativeVersions = arrangeVerbWNegative(head, rest, VP.verb);
// put together all the different possible permutations based on:
// a. potential different versions of where the nu goes
return removeDuplicates(verbWNegativeVersions.flatMap((verbSegments) => (
// b. potential reordering of NPs
NPs.flatMap(NP => {
// for each permutation of the possible ordering of NPs and Verb + nu
// 1. put in kids in the kids section
const segments = putKidsInKidsSection([...NP, ...verbSegments], kids);
// 2. space out the words properly
const withProperSpaces = addSpacesBetweenSegments(segments);
// 3. throw it all together into a PsString for each permutation
return combineSegments(withProperSpaces);
})
)));
}
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,
}
const removeKing = form.removeKing && !(VP.isCompound === "dynamic" && VP.isPast);
const shrinkServant = form.shrinkServant && !(VP.isCompound === "dynamic" && !VP.isPast);
const toShrink = (() => {
if (!shrinkServant) return undefined;
if (!VP.servant) return undefined;
const servant = VP[VP.servant];
if (typeof servant !== "object") return undefined;
return servant;
})();
function getSegment(t: "subject" | "object"): Segment | undefined {
const word = (VP.servant === t)
? (!shrinkServant ? SO[t] : undefined)
: (VP.king === t)
? (!removeKing ? SO[t] : undefined)
: undefined;
if (!word) return undefined;
return makeSegment(word);
}
const subject = getSegment("subject");
const object = getSegment("object");
return {
kids: [
...VP.verb.hasBa
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])] : [],
...toShrink
? [shrinkNP(toShrink)] : [],
],
NPs: [
[
...subject ? [subject] : [],
...object ? [object] : [],
],
// TODO: make this an option to also include O S V order ??
// also show O S V if both are showing
...(subject && object && form.OSV) ? [[object, subject]] : [],
],
};
}
function putKidsInKidsSection(segments: Segment[], kids: Segment[]): Segment[] {
const first = segments[0];
const rest = segments.slice(1);
return [
first,
// TODO: simplify to just isKidAfterHead ??
...(first.isVerbHead && rest[0] && rest[0].isVerbRest)
? kids.map(k => k.adjust({ desc: ["isKidBetweenHeadAndRest"] }))
: kids,
...rest,
];
}
function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[], V: T.VerbRendered): Segment[][] {
const hasLeapfrog = V.tenseCategory === "modal" || V.tenseCategory === "perfect";
const rest = (() => {
if (hasLeapfrog) {
const [restF, restLast] = splitOffLeapfrogWord(restRaw);
return {
front: makeSegment(restF.map(removeBa), ["isVerbRest"]),
last: makeSegment(restLast.map(removeBa), ["isVerbRest"]),
};
}
return makeSegment(restRaw.map(removeBa), ["isVerbRest"]);
})();
const headSegment: Segment | undefined = !head
? head
: makeSegment(
head,
(head.p === "و" || head.p === "وا")
? ["isVerbHead", "isOoOrWaaHead"]
: ["isVerbHead"]
);
if (!V.negative) {
if ("front" in rest) {
return [
headSegment ? [headSegment, rest.front, rest.last] : [rest.front, rest.last],
]
}
return [
headSegment ? [headSegment, rest] : [rest],
];
}
const nu: T.PsString = { p: "نه", f: "nú" };
if (!headSegment) {
if ("front" in rest) {
return [
// pefect nu dey me leeduley and nu me dey leeduley
[
mergeSegments(
makeSegment(nu, ["isNu"]),
rest.last.adjust({ ps: removeAccents }),
),
rest.front.adjust({ ps: removeAccents }),
],
[
makeSegment(nu, ["isNu"]),
rest.last.adjust({ ps: removeAccents }),
rest.front.adjust({ ps: removeAccents }),
],
[
rest.front.adjust({ ps: removeAccents }),
makeSegment(nu, ["isNu"]),
rest.last.adjust({ ps: removeAccents }),
],
];
}
return [[
makeSegment(nu, ["isNu"]),
rest.adjust({ ps: removeAccents }),
]];
}
if ("front" in rest) {
return [
[
headSegment.adjust({ ps: removeAccents }),
rest.last.adjust({
ps: r => concatPsString(nu, " ", removeAccents(r)),
desc: ["isNu"],
}),
rest.front.adjust({
ps: r => removeAccents(r),
}),
],
[
headSegment.adjust({ ps: removeAccents }),
rest.front.adjust({
ps: r => concatPsString(nu, " ", removeAccents(r)),
desc: ["isNu"],
}),
rest.last.adjust({
ps: r => removeAccents(r),
}),
],
...(!headSegment.isOoOrWaaHead && !V.isCompound) ? [[
mergeSegments(headSegment, rest.front, "no space").adjust({
ps: r => concatPsString(nu, " ", removeAccents(r)),
desc: ["isNu"],
}),
rest.last.adjust({
ps: r => removeAccents(r),
}),
]] : [],
];
}
return [
...(V.voice !== "passive") ? [[
...headSegment ? [headSegment.adjust({ ps: removeAccents })] : [],
rest.adjust({
ps: r => concatPsString(nu, " ", removeAccents(r)),
desc: ["isNu"],
}),
]] : [],
// verbs that have a perfective prefix that is not و or وا can put the
// nu *before* the prefix as well // TODO: also وي prefixes?
...((!headSegment.isOoOrWaaHead && !V.isCompound) || (V.voice === "passive")) ? [[
makeSegment(nu, ["isNu"]),
headSegment.adjust({ ps: removeAccents }),
rest.adjust({ ps: removeAccents }),
]] : [],
];
}
function shrinkNP(np: T.Rendered<T.NPSelection>): Segment {
const [row, col] = getVerbBlockPosFromPerson(np.person);
return makeSegment(grammarUnits.pronouns.mini[row][col], ["isKid", "isMiniPronoun"]);
}
function mergeSegments(s1: Segment, s2: Segment, noSpace?: "no space"): Segment {
if (noSpace) {
return s2.adjust({ ps: (p) => concatPsString(s1.ps[0], p) });
}
return s2.adjust({ ps: (p) => concatPsString(s1.ps[0], " ", p) });
}
function addSpacesBetweenSegments(segments: Segment[]): (Segment | " " | "" | T.PsString)[] {
const o: (Segment | " " | "" | T.PsString)[] = [];
for (let i = 0; i < segments.length; i++) {
const current = segments[i];
const next = segments[i+1];
o.push(current);
if (!next) break;
if (
// stative compound part
!current.ps[0].p.endsWith(" ")
&&
(
(next.isKidBetweenHeadAndRest || next.isNu)
||
(next.isVerbRest && current.isKidBetweenHeadAndRest)
)
) {
o.push({
f: " ", // TODO: make this "-" in the right places
p: ((current.isVerbHead && (next.isMiniPronoun || next.isNu))
|| (current.isOoOrWaaHead && (next.isBa || next.isNu))) ? "" : " ", // or if its waa head
});
} else if (current.isVerbHead && next.isVerbRest) {
o.push("");
} else {
o.push(" ");
}
}
return o;
}
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;
// require all English parts for making the English phrase
return (VP.englishBase && engSubj && (engObj || typeof VP.object !== "object"))
? VP.englishBase.map(e => insertEWords(e, {
subject: engSubj,
object: engObj,
}))
: undefined;
}
// SEGMENT TOOLS
// TODO: PULL OUT FOR SHARING ACROSS COMPILE EP ETC?
type SegmentDescriptions = {
isVerbHead?: boolean,
isOoOrWaaHead?: boolean,
isVerbRest?: boolean,
isMiniPronoun?: boolean,
isKid?: boolean,
// TODO: Simplify to just isKidAfterHead?
isKidBetweenHeadAndRest?: boolean,
isNu?: boolean,
isBa?: boolean,
}
type SDT = keyof SegmentDescriptions;
type Segment = { ps: T.PsString[] } & SegmentDescriptions & {
adjust: (o: { ps?: T.PsString | T.PsString[] | ((ps: T.PsString) => T.PsString), desc?: SDT[] }) => Segment,
};
function makeSegment(
ps: T.PsString | T.PsString[],
options?: (keyof SegmentDescriptions)[],
): Segment {
return {
ps: Array.isArray(ps) ? ps : [ps],
...options && options.reduce((all, curr) => ({
...all,
[curr]: true,
}), {}),
adjust: function(o): Segment {
return {
...this,
...o.ps ? {
ps: Array.isArray(o.ps)
? o.ps
: "p" in o.ps
? [o.ps]
: this.ps.map(o.ps)
} : {},
...o.desc && o.desc.reduce((all, curr) => ({
...all,
[curr]: true,
}), {}),
};
},
};
}
function combineSegments(loe: (Segment | " " | "" | T.PsString)[]): T.PsString[] {
const first = loe[0];
const rest = loe.slice(1);
if (!rest.length) {
if (typeof first === "string" || !("ps" in first)) {
throw new Error("can't end with a spacer");
}
return first.ps;
}
return combineSegments(rest).flatMap(r => (
(typeof first === "object" && "ps" in first)
? first.ps.map(f => concatPsString(f, r))
: [concatPsString(first, r)]
)
);
}
function flattenLengths(r: T.SingleOrLengthOpts<T.PsString[]>): T.PsString[] {
if ("long" in r) {
return Object.values(r).flat();
}
return r;
}
function splitOffLeapfrogWord(psVs: T.PsString[]): [T.PsString[], T.PsString[]] {
return psVs.reduce((tp, ps) => {
const pWords = ps.p.split(" ");
const fWords = ps.f.split(" ");
const beginning = makePsString(
pWords.slice(0, -1).join(" "),
fWords.slice(0, -1).join(" "),
);
const end = makePsString(
pWords.slice(-1).join(" "),
fWords.slice(-1).join(" "),
);
return [[...tp[0], beginning], [...tp[1], end]];
}, [[], []] as [T.PsString[], T.PsString[]]);
}

View File

@ -0,0 +1,237 @@
import * as T from "../../types";
import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers";
import * as grammarUnits from "../grammar-units";
function engHave(s: T.Person): string {
function isThirdPersonSing(p: T.Person): boolean {
return (
p === T.Person.ThirdSingMale ||
p === T.Person.ThirdSingFemale
);
}
return isThirdPersonSing(s) ? "has" : "have";
}
export function renderEnglishVPBase({ subjectPerson, object, vs }: {
subjectPerson: T.Person,
object: T.NPSelection | T.ObjectNP,
vs: T.VerbSelection,
}): string[] {
const ec = parseEc(vs.verb.entry.ec || "");
const ep = vs.verb.entry.ep;
function engEquative(tense: "past" | "present", s: T.Person): string {
const [row, col] = getVerbBlockPosFromPerson(s);
return grammarUnits.englishEquative[tense][row][col];
}
function engPresC(s: T.Person, ec: T.EnglishVerbConjugationEc | [string, string]): string {
function isThirdPersonSing(p: T.Person): boolean {
return (
p === T.Person.ThirdSingMale ||
p === T.Person.ThirdSingFemale
);
}
return isThirdPersonSing(s) ? ec[1] : ec[0];
}
function isToBe(v: T.EnglishVerbConjugationEc): boolean {
return (v[2] === "being");
}
const futureEngBuilder: T.EnglishBuilder = (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]);
// TODO: Pull these out to a seperate entity and import it
const basicBuilders: Record<
T.VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
presentVerb: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${isToBe(ec)
? `${engEquative("present", s)}${n ? " not" : ""}`
: `${n ? engPresC(s, ["don't", "doesn't"]) : ""} ${n ? ec[0] : engPresC(s, ec)}`}`,
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} ${ec[2]}`,
]),
subjunctiveVerb: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ ${n ? " won't" : " will"} ${isToBe(ec) ? "be" : ec[0]}`,
`should $SUBJ ${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]),
imperfectiveFuture: futureEngBuilder,
perfectiveFuture: futureEngBuilder,
imperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
// - subj pastEquative (N && "not") ec.2 obj
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${ec[2]}`,
// - subj "would" (N && "not") ec.0 obj
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
// - subj pastEquative (N && "not") going to" ec.0 obj
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} going to ${isToBe(ec) ? "be" : ec[0]}`,
]),
perfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ${isToBe(ec)
? ` ${engEquative("past", s)}${n ? " not" : ""}`
: (n ? ` did not ${ec[0]}` : ` ${ec[3]}`)
}`
]),
habitualPerfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
`$SUBJ used to${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]),
habitualImperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
`$SUBJ used to${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]),
};
const modalBuilders: Record<
T.VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`,
]),
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`,
]),
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]),
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]),
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ could${n ? " not" : ""} ${v[0]}`,
]),
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ could${n ? " not" : ""} ${isToBe(v) ? "be" : v[0]}`,
]),
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]),
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]),
};
const perfectBuilders: Record<
T.PerfectTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
"present perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`,
]),
"past perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ had${n ? " not" : ""} ${v[4]}`,
]),
"habitual perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`,
]),
"subjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will have${n ? " not" : ""} ${v[4]}`,
]),
"future perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} have ${v[4]}`,
]),
"wouldBe perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} have ${v[4]}`,
]),
"pastSubjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} have ${v[4]}`,
`$SUBJ should${n ? " not" : ""} have ${v[4]}`,
]),
}
const passiveBasicBuilders: Record<
T.VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} being ${v[4]}`,
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} ${v[4]}`,
]),
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will${n ? " not" : ""} be ${v[4]}`,
]),
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be ${v[4]}`,
]),
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be ${v[4]}`,
]),
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} being ${v[4]}`,
`$SUBJ would${n ? " not" : ""} be ${v[4]}`,
]),
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${v[4]}`,
]),
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be ${v[4]}`,
]),
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be ${v[4]}`,
]),
};
const passivePerfectBuilders: Record<
T.PerfectTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
"present perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`,
]),
"past perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ had${n ? " not" : ""} been ${v[4]}`,
]),
"habitual perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`,
]),
"subjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will${n ? " not" : ""} have been ${v[4]}`,
]),
"future perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} have been ${v[4]}`,
]),
"wouldBe perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} have been ${v[4]}`,
]),
"pastSubjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} have been ${v[4]}`,
]),
}
const passiveModalBuilders: Record<
T.VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ can${n ? " not" : ""} be ${v[4]}`,
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} able to be ${v[4]}`,
]),
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
`that $SUBJ ${n ? " not" : ""} be able to be ${v[4]}`,
]),
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
]),
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
]),
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} being able to be ${v[4]}`,
]),
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} able to be ${v[4]}`,
]),
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
]),
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
]),
};
const base = (
(vs.tenseCategory === "perfect")
? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense]
: vs.tenseCategory === "basic"
? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense]
: (vs.voice === "active" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative);
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
}

View File

@ -0,0 +1,7 @@
import { renderVP } from "./render-vp";
import { compileVP } from "./compile-vp";
export {
renderVP,
compileVP,
};

View File

@ -0,0 +1,344 @@
import * as T from "../../types";
import { parseEc } from "../../lib/misc-helpers";
import { inflectWord } from "../pashto-inflector";
import { getEnglishWord } from "../get-english-word";
import * as grammarUnits from "../grammar-units";
import {
getVerbBlockPosFromPerson,
getPersonNumber,
} from "../misc-helpers";
import { conjugateVerb } from "../verb-conjugation";
import {
concatPsString,
hasBaParticle,
psStringFromEntry,
getLong,
} from "../p-text-helpers";
import { removeAccents } from "../accent-helpers";
import {
getPersonFromNP,
removeBa,
isPastTense,
isPerfectTense,
getTenseVerbForm,
} from "./vp-tools";
import { isPattern4Entry } from "../type-predicates";
import { renderEnglishVPBase } from "./english-vp-rendering";
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
export function renderVP(VP: T.VPSelection): T.VPRendered {
// Sentence Rules Logic
const isPast = isPastTense(VP.verb.tense);
const isTransitive = VP.object !== "none";
const { king, servant } = getKingAndServant(isPast, isTransitive);
const kingPerson = getPersonFromNP(VP[king]);
// TODO: more elegant way of handling this type safety
if (kingPerson === undefined) {
throw new Error("king of sentance does not exist");
}
const subjectPerson = getPersonFromNP(VP.subject);
const objectPerson = getPersonFromNP(VP.object);
// TODO: also don't inflect if it's a pattern one animate noun
const inflectSubject = isPast && isTransitive && !isMascSingAnimatePattern4(VP.subject);
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
// Render Elements
return {
type: "VPRendered",
king,
servant,
isPast,
isTransitive,
isCompound: VP.verb.isCompound,
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
object: renderNPSelection(VP.object, inflectObject, true, "object"),
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
englishBase: renderEnglishVPBase({
subjectPerson,
object: VP.verb.isCompound === "dynamic" ? "none" : VP.object,
vs: VP.verb,
}),
};
}
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";
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "subject" | "object"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none" {
if (typeof NP !== "object") {
if (role !== "object") {
throw new Error("ObjectNP only allowed for objects");
}
return NP;
}
if (NP.type === "noun") {
return renderNounSelection(NP, inflected);
}
if (NP.type === "pronoun") {
return renderPronounSelection(NP, inflected, inflectEnglish);
}
if (NP.type === "participle") {
return renderParticipleSelection(NP, inflected)
}
throw new Error("unknown NP type");
};
function renderNounSelection(n: T.NounSelection, inflected: boolean): T.Rendered<T.NounSelection> {
const english = getEnglishFromNoun(n.entry, n.number);
const pashto = ((): T.PsString[] => {
const infs = inflectWord(n.entry);
const ps = n.number === "singular"
? getInf(infs, "inflections", n.gender, false, inflected)
: [
...getInf(infs, "plural", n.gender, true, inflected),
...getInf(infs, "arabicPlural", n.gender, true, inflected),
...getInf(infs, "inflections", n.gender, true, inflected),
];
return ps.length > 0
? ps
: [psStringFromEntry(n.entry)];
})();
return {
...n,
person: getPersonNumber(n.gender, n.number),
inflected,
ps: pashto,
e: english,
};
}
function renderPronounSelection(p: T.PronounSelection, inflected: boolean, englishInflected: boolean): T.Rendered<T.PronounSelection> {
const [row, col] = getVerbBlockPosFromPerson(p.person);
return {
...p,
inflected,
ps: grammarUnits.pronouns[p.distance][inflected ? "inflected" : "plain"][row][col],
e: grammarUnits.persons[p.person].label[englishInflected ? "object" : "subject"],
};
}
function renderParticipleSelection(p: T.ParticipleSelection, inflected: boolean): T.Rendered<T.ParticipleSelection> {
return {
...p,
inflected,
person: T.Person.ThirdPlurMale,
// TODO: More robust inflection of inflecting pariticiples - get from the conjugation engine
ps: [psStringFromEntry(p.verb.entry)].map(ps => inflected ? concatPsString(ps, { p: "و", f: "o" }) : ps),
e: getEnglishParticiple(p.verb.entry),
};
}
function renderVerbSelection(vs: T.VerbSelection, person: T.Person, objectPerson: T.Person | undefined): T.VerbRendered {
const v = vs.dynAuxVerb || vs.verb;
const conjugations = conjugateVerb(v.entry, v.complement);
// TODO: error handle this?
const conj = "grammaticallyTransitive" in conjugations
// if there's an option for grammatically transitive or transitive
// will default to transitive
? conjugations.transitive
: "stative" in conjugations
// TODO: option to manually select stative/dynamic
? conjugations.stative
: conjugations;
return {
...vs,
person,
...getPsVerbConjugation(conj, vs, person, objectPerson),
}
}
function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelection, person: T.Person, objectPerson: T.Person | undefined): {
ps: {
head: T.PsString | undefined,
rest: T.SingleOrLengthOpts<T.PsString[]>,
},
hasBa: boolean,
} {
const f = getTenseVerbForm(conj, vs.tense, vs.tenseCategory, vs.voice);
const block = getMatrixBlock(f, objectPerson, person);
const perfective = isPerfective(vs.tense);
const verbForm = getVerbFromBlock(block, person);
const hasBa = hasBaParticle(getLong(verbForm)[0]);
if (perfective) {
const past = isPastTense(vs.tense);
const splitInfo = conj.info[past ? "root" : "stem"].perfectiveSplit;
if (!splitInfo) return { ps: { head: undefined, rest: verbForm }, hasBa };
// TODO: Either solve this in the inflector or here, it seems silly (or redundant)
// to have a length option in the perfective split stem??
const [splitHead] = getLong(getMatrixBlock(splitInfo, objectPerson, person));
const ps = getHeadAndRest(splitHead, verbForm);
return {
hasBa,
ps,
};
}
return { hasBa, ps: { head: undefined, rest: verbForm }};
}
function getVerbFromBlock(block: T.SingleOrLengthOpts<T.VerbBlock>, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
function grabFromBlock(b: T.VerbBlock, [row, col]: [ row: number, col: number ]): T.PsString[] {
return b[row][col];
}
const pos = getVerbBlockPosFromPerson(person);
if ("long" in block) {
return {
long: grabFromBlock(block.long, pos),
short: grabFromBlock(block.short, pos),
...block.mini ? {
mini: grabFromBlock(block.mini, pos),
} : {},
};
}
return grabFromBlock(block, pos);
}
function getHeadAndRest(head: T.PsString, rest: T.PsString[]): { head: T.PsString | undefined, rest: T.PsString[] };
function getHeadAndRest(head: T.PsString, rest: T.SingleOrLengthOpts<T.PsString[]>): { head: T.PsString | undefined, rest: T.SingleOrLengthOpts<T.PsString[]> };
function getHeadAndRest(head: T.PsString, rest: T.SingleOrLengthOpts<T.PsString[]>): { head: T.PsString | undefined, rest: T.SingleOrLengthOpts<T.PsString[]> } {
if ("long" in rest) {
return {
// whether or not to include the head (for irreg tlul) -- eww // TODO: make nicer?
head: removeBa(rest.long[0]).p.slice(0, head.p.length) === head.p
? head : undefined,
rest: {
long: getHeadAndRest(head, rest.long).rest,
short: getHeadAndRest(head, rest.short).rest,
...rest.mini ? {
mini: getHeadAndRest(head, rest.mini).rest,
} : {},
},
};
}
let headMismatch = false;
const restM = rest.map((psRaw) => {
const ps = removeBa(psRaw);
const pMatches = removeAccents(ps.p.slice(0, head.p.length)) === head.p
const fMatches = removeAccents(ps.f.slice(0, head.f.length)) === removeAccents(head.f);
if (!(pMatches && fMatches)) {
headMismatch = true;
return psRaw;
// throw new Error(`split head does not match - ${JSON.stringify(ps)} ${JSON.stringify(head)}`);
}
return {
p: ps.p.slice(head.p.length),
f: ps.f.slice(head.f.length),
}
});
return {
head: headMismatch ? undefined : head,
rest: restM,
}
}
function getMatrixBlock<U>(f: {
mascSing: T.SingleOrLengthOpts<U>;
mascPlur: T.SingleOrLengthOpts<U>;
femSing: T.SingleOrLengthOpts<U>;
femPlur: T.SingleOrLengthOpts<U>;
} | T.SingleOrLengthOpts<U>, objectPerson: T.Person | undefined, kingPerson: T.Person): T.SingleOrLengthOpts<U> {
if (!("mascSing" in f)) {
return f;
}
function personToLabel(p: T.Person): "mascSing" | "mascPlur" | "femSing" | "femPlur" {
if (p === T.Person.FirstSingMale || p === T.Person.SecondSingMale || p === T.Person.ThirdSingMale) {
return "mascSing";
}
if (p === T.Person.FirstSingFemale || p === T.Person.SecondSingFemale || p === T.Person.ThirdSingFemale) {
return "femSing";
}
if (p === T.Person.FirstPlurMale || p === T.Person.SecondPlurMale || p === T.Person.ThirdPlurMale) {
return "mascPlur";
}
return "femPlur";
}
// if there's an object the matrix will agree with that, otherwise with the kingPerson (subject for intransitive)
const person = (objectPerson === undefined) ? kingPerson : objectPerson;
return f[personToLabel(person)];
}
function getEnglishParticiple(entry: T.DictionaryEntry): string {
if (!entry.ec) {
console.log("errored participle");
console.log(entry);
throw new Error("no english information for participle");
}
const ec = parseEc(entry.ec);
const participle = ec[2];
return (entry.ep)
? `${participle} ${entry.ep}`
: participle;
}
function getEnglishFromNoun(entry: T.DictionaryEntry, number: T.NounNumber): string {
const articles = {
singular: "(a/the)",
plural: "(the)",
};
const article = articles[number];
function addArticle(s: string) {
return `${article} ${s}`;
}
const e = getEnglishWord(entry);
if (!e) throw new Error(`unable to get english from subject ${entry.f} - ${entry.ts}`);
if (typeof e === "string") return ` ${e}`;
if (number === "plural") return addArticle(e.plural);
if (!e.singular || e.singular === undefined) {
throw new Error(`unable to get english from subject ${entry.f} - ${entry.ts}`);
}
return addArticle(e.singular);
}
function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflections", gender: T.Gender, plural: boolean, inflected: boolean): T.PsString[] {
// TODO: make this safe!!
// @ts-ignore
if (infs && t in infs && infs[t] !== undefined && gender in infs[t] && infs[t][gender] !== undefined) {
// @ts-ignore
const iset = infs[t][gender] as T.InflectionSet;
const inflectionNumber = (inflected ? 1 : 0) + ((t === "inflections" && plural) ? 1 : 0);
return iset[inflectionNumber];
}
return [];
}
function getKingAndServant(isPast: boolean, isTransitive: boolean):
{ king: "subject", servant: "object" } |
{ king: "object", servant: "subject" } |
{ king: "subject", servant: undefined } {
if (!isTransitive) {
return { king: "subject", servant: undefined };
}
return isPast ? {
king: "object",
servant: "subject",
} : {
king: "subject",
servant: "object",
};
}
function isFirstOrSecondPersPronoun(o: "none" | T.NPSelection | T.Person.ThirdPlurMale): boolean {
if (typeof o !== "object") return false;
if (o.type !== "pronoun") return false;
return [0,1,2,3,6,7,8,9].includes(o.person);
}
function isPerfective(t: T.VerbTense | T.PerfectTense): boolean {
if (isPerfectTense(t)) return false;
if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") {
return false;
}
if (t === "perfectiveFuture" || t === "subjunctiveVerb" || t === "perfectivePast" || t === "habitualPerfectivePast") {
return true;
}
throw new Error("tense not implemented yet");
}
function isMascSingAnimatePattern4(np: T.NPSelection): boolean {
if (np.type !== "noun") {
return false;
}
return isPattern4Entry(np.entry)
&& np.entry.c.includes("anim.")
&& (np.number === "singular")
&& (np.gender === "masc");
}

View File

@ -0,0 +1,156 @@
import * as T from "../../types";
import {
concatPsString,
psRemove,
psStringEquals,
} from "../../lib/p-text-helpers";
import * as grammarUnits from "../../lib/grammar-units";
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
const firstPeople = [
T.Person.FirstSingMale,
T.Person.FirstSingFemale,
T.Person.FirstPlurMale,
T.Person.FirstPlurFemale,
];
const secondPeople = [
T.Person.SecondSingMale,
T.Person.SecondSingFemale,
T.Person.SecondPlurMale,
T.Person.SecondPlurFemale,
];
return (
(firstPeople.includes(subj) && firstPeople.includes(obj))
||
(secondPeople.includes(subj) && secondPeople.includes(obj))
);
}
export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense | T.PerfectTense, tenseCategory: "basic" | "modal" | "perfect", voice: "active" | "passive"): T.VerbForm {
const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR;
if (tenseCategory === "basic") {
if (tense === "presentVerb") {
return conj.imperfective.nonImperative;
}
if (tense === "subjunctiveVerb") {
return conj.perfective.nonImperative;
}
if (tense === "imperfectiveFuture") {
return conj.imperfective.future;
}
if (tense === "perfectiveFuture") {
return conj.perfective.future;
}
if (tense === "imperfectivePast") {
return conj.imperfective.past;
}
if (tense === "perfectivePast") {
return conj.perfective.past;
}
if (tense === "habitualImperfectivePast") {
return conj.imperfective.habitualPast;
}
if (tense === "habitualPerfectivePast") {
return conj.perfective.habitualPast;
}
}
if (tenseCategory === "modal") {
if (tense === "presentVerb") {
return conj.imperfective.modal.nonImperative;
}
if (tense === "subjunctiveVerb") {
return conj.perfective.modal.nonImperative;
}
if (tense === "imperfectiveFuture") {
return conj.imperfective.modal.future;
}
if (tense === "perfectiveFuture") {
return conj.perfective.modal.future;
}
if (tense === "imperfectivePast") {
return conj.imperfective.modal.past;
}
if (tense === "perfectivePast") {
return conj.perfective.modal.past;
}
if (tense === "habitualImperfectivePast") {
return conj.imperfective.modal.habitualPast;
}
if (tense === "habitualPerfectivePast") {
return conj.perfective.modal.habitualPast;
}
}
if (tense === "present perfect") {
return conj.perfect.present;
}
if (tense === "past perfect") {
return conj.perfect.past;
}
if (tense === "future perfect") {
return conj.perfect.future;
}
if (tense === "habitual perfect") {
return conj.perfect.habitual;
}
if (tense === "subjunctive perfect") {
return conj.perfect.subjunctive;
}
if (tense === "wouldBe perfect") {
return conj.perfect.affirmational;
}
if (tense === "pastSubjunctive perfect") {
return conj.perfect.pastSubjunctiveHypothetical;
}
throw new Error("unknown tense");
}
export function getPersonFromNP(np: T.NPSelection): T.Person;
export function getPersonFromNP(np: T.NPSelection | T.ObjectNP): T.Person | undefined;
export function getPersonFromNP(np: T.NPSelection | T.ObjectNP): T.Person | undefined {
if (np === "none") {
return undefined;
}
if (typeof np === "number") return np;
if (np.type === "participle") {
return T.Person.ThirdPlurMale;
}
if (np.type === "pronoun") {
return np.person;
}
return np.number === "plural"
? (np.gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale)
: (np.gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale);
}
export function removeBa(ps: T.PsString): T.PsString {
return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
}
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.EquativeTense {
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
}
export function isPerfectTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.PerfectTense {
return (
t === "present perfect" ||
t === "habitual perfect" ||
t === "future perfect" ||
t === "past perfect" ||
t === "wouldBe perfect" ||
t === "subjunctive perfect" ||
t === "pastSubjunctive perfect"
);
}
export function isPastTense(tense: T.VerbTense | T.PerfectTense): boolean {
if (isPerfectTense(tense)) return true;
return tense.toLowerCase().includes("past");
}
export function removeDuplicates(psv: T.PsString[]): T.PsString[] {
return psv.filter((ps, i, arr) => (
i === arr.findIndex(t => (
psStringEquals(t, ps)
))
));
}

View File

@ -23,6 +23,6 @@ const sampleDictionary: T.Dictionary = {
}
test("should encode and decode", () => {
expect(readDictionaryInfo(writeDictionaryInfo(sampleDictionaryInfo))).toEqual(sampleDictionaryInfo);
expect(readDictionary(writeDictionary(sampleDictionary))).toEqual(sampleDictionary);
expect(readDictionaryInfo(writeDictionaryInfo(sampleDictionaryInfo) as Uint8Array)).toEqual(sampleDictionaryInfo);
expect(readDictionary(writeDictionary(sampleDictionary) as Uint8Array)).toEqual(sampleDictionary);
});

View File

@ -73,6 +73,7 @@ translations.forEach((t) => {
// check each dialect with given system
dialects.forEach((dialect) => {
test(
// @ts-ignore
`${t.original} should be translated to ${t.ipa[dialect]} using ${system} with ${dialect} dialect`,
() => {
const translated = translatePhonetics(t.original, {
@ -81,6 +82,7 @@ translations.forEach((t) => {
// @ts-ignore
dialect,
});
// @ts-ignore
expect(translated).toBe(t[system][dialect]);
},
);

155
src/lib/type-predicates.ts Normal file
View File

@ -0,0 +1,155 @@
import * as T from "../types";
import { pashtoConsonants } from "./pashto-consonants";
import { endsWith } from "../lib/p-text-helpers";
import { countSyllables } from "../lib/accent-helpers";
export function isNounEntry(e: T.Entry | T.DictionaryEntry): e is T.NounEntry {
if ("entry" in e) return false;
return !!(e.c && (e.c.includes("n. m.") || e.c.includes("n. f.")));
}
export function isAdjectiveEntry(e: T.Entry): e is T.AdjectiveEntry {
if ("entry" in e) return false;
return !!e.c?.includes("adj.") && !isNounEntry(e);
}
export function isAdverbEntry(e: T.Entry): e is T.AdverbEntry {
if ("entry" in e) return false;
return !!e.c?.includes("adv.");
}
export function isLocativeAdverbEntry(e: T.Entry): e is T.LocativeAdverbEntry {
return isAdverbEntry(e) && e.c.includes("loc. adv.");
}
export function isNounOrAdjEntry(e: T.Entry): e is (T.NounEntry | T.AdjectiveEntry) {
return isNounEntry(e) || isAdjectiveEntry(e);
}
export function isVerbEntry(e: T.Entry | T.DictionaryEntry): e is T.VerbEntry {
return "entry" in e && !!e.entry.c?.startsWith("v.");
}
export function isMascNounEntry(e: T.NounEntry | T.AdjectiveEntry): e is T.MascNounEntry {
return !!e.c && e.c.includes("n. m.");
}
export function isFemNounEntry(e: T.NounEntry | T.AdjectiveEntry): e is T.FemNounEntry {
return !!e.c && e.c.includes("n. f.");
}
export function isUnisexNounEntry(e: T.NounEntry | T.AdjectiveEntry): e is T.UnisexNounEntry {
return isNounEntry(e) && e.c.includes("unisex");
}
export function isAdjOrUnisexNounEntry(e: T.Entry): e is (T.AdjectiveEntry | T.UnisexNounEntry) {
return isAdjectiveEntry(e) || (
isNounEntry(e) && isUnisexNounEntry(e)
);
}
/**
* shows if a noun/adjective has the basic (consonant / ه) inflection pattern
*
* @param e
* @returns
*/
export function isPattern1Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern1Entry<T> {
if (e.noInf) return false;
if (e.infap) return false;
if (isFemNounEntry(e)) {
return (
endsWith([{ p: "ه", f: "a" }, { p: "ح", f: "a" }], e) ||
(endsWith({ p: pashtoConsonants }, e) && !e.c.includes("anim."))
);
}
return (
endsWith([{ p: pashtoConsonants }], e) ||
endsWith([{ p: "ه", f: "u" }, { p: "ه", f: "h" }], e) ||
endsWith([{ p: "ای", f: "aay" }, { p: "وی", f: "ooy" }], e)
);
}
/**
* shows if a noun/adjective has the unstressed ی inflection pattern
*
* @param e
* @returns T.T.T.T.
*/
export function isPattern2Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern2Entry<T> {
if (e.noInf) return false;
if (e.infap) return false;
if (isFemNounEntry(e)) {
return !e.c.includes("pl.") && endsWith({ p: "ې", f: "e" }, e, true);
}
// TODO: check if it's a single syllable word, in which case it would be pattern 1
return endsWith({ p: "ی", f: "ey" }, e, true) && (countSyllables(e.f) > 1);
}
/**
* shows if a noun/adjective has the stressed ی inflection pattern
*
* @param e
* @returns
*/
export function isPattern3Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern3Entry<T> {
if (e.noInf) return false;
if (e.infap) return false;
if (isFemNounEntry(e)) {
return endsWith({ p: "ۍ" }, e);
}
return (countSyllables(e.f) > 1)
? endsWith({ p: "ی", f: "éy" }, e, true)
: endsWith({ p: "ی", f: "ey" }, e)
}
/**
* shows if a noun/adjective has the "Pashtoon" inflection pattern
*
* @param e
* @returns
*/
export function isPattern4Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern4Entry<T> {
if (e.noInf) return false;
return (
!!(e.infap && e.infaf && e.infbp && e.infbf)
&&
(e.infap.slice(1).includes("ا") && e.infap.slice(-1) === "ه")
);
}
/**
* shows if a noun/adjective has the shorter squish inflection pattern
*
* @param e
* @returns
*/
export function isPattern5Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern5Entry<T> {
if (e.noInf) return false;
return (
!!(e.infap && e.infaf && e.infbp && e.infbf)
&&
(e.infaf.slice(-1) === "u")
&&
!e.infap.slice(1).includes("ا")
);
}
export function isPattern6FemEntry(e: T.FemNounEntry): e is T.Pattern6FemEntry<T.FemNounEntry> {
if (!isFemNounEntry(e)) return false;
if (e.c.includes("anim.")) return false;
return e.p.slice(-1) === "ي";
}
export function isPluralNounEntry<U extends T.NounEntry>(e: U): e is T.PluralNounEntry<U> {
return e.c.includes("pl.");
}
export function isSingularEntry<U extends T.NounEntry>(e: U): e is T.SingularEntry<U> {
return !isPluralNounEntry(e);
}
export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> {
return a.length > 0;
}

47
src/lib/useStickyState.ts Normal file
View File

@ -0,0 +1,47 @@
import { useEffect, useState } from "react";
/**
* replacement from the React useState hook that will persist the state in local storage
*
* @param defaultValue The default value to use if there was nothing saved previously OR
* a function that will take the saved value and return a modified new value to start with
* @param key a key for saving the state in locolStorage
* @returns
*/
export default function useStickyState<T extends string | object | boolean | undefined | null>(
defaultValue: T | ((old: T | undefined) => T),
key: string
): [
value: T,
setValue: React.Dispatch<React.SetStateAction<T>>,
] {
const [value, setValue] = useState<T>(() => {
const v = window.localStorage.getItem(key);
// nothing saved
if (v === null) {
if (typeof defaultValue === "function") {
return defaultValue(undefined);
}
return defaultValue;
}
// something saved before
try {
const old = JSON.parse(v) as T;
if (typeof defaultValue === "function") {
return defaultValue(old);
}
return defaultValue;
} catch (e) {
console.error("error parsting saved state from stickState");
return (typeof defaultValue === "function")
? defaultValue(undefined)
: defaultValue;
}
});
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}

View File

@ -24,11 +24,13 @@ import {
complementInflects,
concatInflections,
unisexInfToObjectMatrix,
inflectYey,
allOnePersonInflection,
psStringEquals,
makePsString,
} from "./p-text-helpers";
import { makePsString } from "./accent-and-ps-utils";
import {
inflectYey,
} from "./pashto-inflector";
import {
accentOnNFromEnd,
} from "./accent-helpers";

View File

@ -8,12 +8,10 @@
import {
concatPsString,
makePsString,
psStringEquals,
removeEndingL,
yulEndingInfinitive,
removeRetroflexR,
inflectYey,
unisexInfToObjectMatrix,
complementInflects,
beginsWithDirectionalPronoun,
@ -21,9 +19,15 @@ import {
removeStartingTick,
ensureShortWurShwaShift,
choosePersInf,
removeFVarients,
isUnisexSet,
} from "./p-text-helpers";
import {
makePsString,
removeFVarients,
} from "./accent-and-ps-utils";
import {
inflectYey,
} from "./pashto-inflector";
import {
accentOnFront,
accentOnNFromEnd,

View File

@ -6,7 +6,7 @@
*
*/
import {
import {
conjugateVerb,
} from "./lib/verb-conjugation";
import {
@ -15,6 +15,7 @@ import {
import {
getVerbInfo,
} from "./lib/verb-info";
import { makeVerbSelection } from "./components/vp-explorer/verb-selection";
import ConjugationViewer from "./components/ConjugationViewer";
import InflectionsTable from "./components/InflectionsTable";
import Pashto from "./components/Pashto";
@ -24,12 +25,18 @@ import ButtonSelect from "./components/ButtonSelect";
import VerbFormDisplay from "./components/VerbFormDisplay";
import VerbTable from "./components/VerbTable";
import Examples from "./components/Examples";
import Hider from "./components/Hider";
import EntrySelect from "./components/EntrySelect";
import VerbInfo, { RootsAndStems } from "./components/verb-info/VerbInfo";
import VPExplorer from "./components/vp-explorer/VPExplorer";
import useStickyState from "./lib/useStickyState";
import {
makePsString,
removeFVarients,
} from "./lib/accent-and-ps-utils";
import {
addToForm,
concatPsString,
makePsString,
removeFVarients,
isVerbBlock,
isImperativeBlock,
isPluralInflectionSet,
@ -39,6 +46,10 @@ import {
endsWith,
hasBaParticle,
psRemove,
firstVariation,
psStringFromEntry,
getLong,
capitalizeFirstLetter,
} from "./lib/p-text-helpers";
import {
getEnglishWord,
@ -48,6 +59,11 @@ import {
standardizePhonetics,
} from "./lib/standardize-pashto";
import { phoneticsToDiacritics } from "./lib/phonetics-to-diacritics";
import {
randomPerson,
isInvalidSubjObjCombo,
randomSubjObj,
} from "./lib/np-tools";
import {
convertSpelling,
revertSpelling,
@ -100,6 +116,7 @@ import defaultTextOptions from "./lib/default-text-options";
import * as grammarUnits from "./lib/grammar-units";
import genderColors from "./lib/gender-colors";
import * as Types from "./types";
import * as typePredicates from "./lib/type-predicates";
export {
// FUNCTIONS
@ -143,13 +160,23 @@ export {
countSyllables,
hasBaParticle,
psRemove,
firstVariation,
capitalizeFirstLetter,
psStringFromEntry,
getLong,
makeVerbSelection,
useStickyState,
randomPerson,
isInvalidSubjObjCombo,
randomSubjObj,
// protobuf helpers
readDictionary,
writeDictionary,
readDictionaryInfo,
writeDictionaryInfo,
// COMPONENTS
ConjugationViewer,
VPExplorer,
ConjugationViewer, // TODO: Deprecated - remove
Examples,
VerbFormDisplay,
VerbTable,
@ -160,7 +187,10 @@ export {
Phonetics,
InlinePs,
ButtonSelect,
Hider,
EntrySelect,
// OTHER
typePredicates,
grammarUnits,
pashtoConsonants,
defaultTextOptions,

13
src/nouns-adjs.ts Normal file

File diff suppressed because one or more lines are too long

View File

@ -473,3 +473,167 @@ export type DisplayFormSubgroup = {
}
export type AayTail = "ey" | "aay";
export type NounEntry = DictionaryEntry & { c: string } & { __brand: "a noun entry" };
export type MascNounEntry = NounEntry & { __brand2: "a masc noun entry" };
export type FemNounEntry = NounEntry & { __brand2: "a fem noun entry" };
export type UnisexNounEntry = MascNounEntry & { __brand3: "a unisex noun entry" };
export type AdverbEntry = DictionaryEntry & { c: string } & { __brand: "an adverb entry" };
export type LocativeAdverbEntry = AdverbEntry & { __brand2: "a locative adverb entry" };
export type AdjectiveEntry = DictionaryEntry & { c: string } & { __brand: "an adjective entry" };
export type VerbEntry = {
entry: DictionaryEntry & { __brand: "a verb entry" },
// TODO: the compliment could also be typed? Maybe?
complement?: DictionaryEntry,
};
export type SingularEntry<T extends NounEntry> = T & { __brand7: "a singular noun - as opposed to an always plural noun" };
export type PluralNounEntry<T extends NounEntry> = T & { __brand7: "a noun that is always plural" };
export type Pattern1Entry<T> = T & { __brand3: "basic inflection pattern" };
export type Pattern2Entry<T> = T & { __brand3: "ending in unstressed ی pattern" };
export type Pattern3Entry<T> = T & { __brand3: "ending in stressed ی pattern" };
export type Pattern4Entry<T> = T & { __brand3: "Pashtoon pattern" };
export type Pattern5Entry<T> = T & { __brand3: "short squish pattern" };
export type Pattern6FemEntry<T extends FemNounEntry> = T & { __brand3: "non anim. ending in ي" };
export type NonInflecting<T> = T & { __brand3: "non-inflecting" };
export type Entry = NounEntry | AdjectiveEntry | AdverbEntry | VerbEntry;
export type Words = {
nouns: NounEntry[],
adjectives: AdjectiveEntry[],
verbs: VerbEntry[],
adverbs: AdverbEntry[],
}
export type VPSelection = {
type: "VPSelection",
subject: NPSelection,
object: Exclude<VerbObject, undefined>,
verb: Exclude<VerbSelection, "object">,
};
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
export type VPRendered = {
type: "VPRendered",
king: "subject" | "object",
servant: "subject" | "object" | undefined,
isPast: boolean,
isTransitive: boolean,
isCompound: "stative" | "dynamic" | false,
subject: Rendered<NPSelection>,
object: Rendered<NPSelection> | ObjectNP,
verb: VerbRendered,
englishBase?: string[],
}
export type VerbTense = "presentVerb"
| "subjunctiveVerb"
| "perfectiveFuture"
| "imperfectiveFuture"
| "perfectivePast"
| "imperfectivePast"
| "habitualPerfectivePast"
| "habitualImperfectivePast";
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
export type NounNumber = "singular" | "plural";
export type PerfectTense = `${EquativeTense} perfect`;
export type VerbSelection = {
type: "verb",
verb: VerbEntry,
dynAuxVerb?: VerbEntry,
object: VerbObject, // TODO: should have a locked in (but number changeable noun) here for dynamic compounds
transitivity: Transitivity,
isCompound: "stative" | "dynamic" | false,
voice: "active" | "passive",
changeTransitivity?: (t: "transitive" | "grammatically transitive") => VerbSelection,
changeStatDyn?: (t: "stative" | "dynamic") => VerbSelection,
changeVoice?: (v: "active" | "passive", subj?: NPSelection) => VerbSelection,
// TODO: changeStativeDynamic
// TODO: add in aspect element here??
negative: boolean,
} & ({
tense: VerbTense,
tenseCategory: "basic" | "modal",
} | {
tense: PerfectTense,
tenseCategory: "perfect"
});
export type VerbRendered = Omit<VerbSelection, "object"> & {
ps: {
head: PsString | undefined,
rest: SingleOrLengthOpts<
PsString[]
>,
},
hasBa: boolean,
person: Person,
};
export type VerbObject =
// transitive verb - object not selected yet
undefined |
// transitive verb - obect selected
NPSelection |
// grammatically transitive verb with unspoken 3rd pers masc plur entity
// or intransitive "none"
ObjectNP;
export type NPSelection = NounSelection | PronounSelection | ParticipleSelection;
export type NPType = "noun" | "pronoun" | "participle";
export type ObjectNP = "none" | Person.ThirdPlurMale;
// TODO require/import Person and PsString
export type NounSelection = {
type: "noun",
entry: NounEntry,
gender: Gender,
number: NounNumber,
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,
};
// take an argument for subject/object in rendering English
export type PronounSelection = {
type: "pronoun",
person: Person,
distance: "near" | "far",
};
export type ParticipleSelection = {
type: "participle",
verb: VerbEntry,
};
// not object
// type Primitive = string | Function | number | boolean | Symbol | undefined | null;
// If T has key K ("user"), replace it
export type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ? (Omit<T, K> & Record<K, R>) : T;
export type FormVersion = { removeKing: boolean, shrinkServant: boolean };
export type Rendered<T extends NPSelection> = ReplaceKey<
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,
"e",
string
> & {
ps: PsString[],
e?: string,
inflected: boolean,
person: Person,
};
// TODO: recursive changing this down into the possesor etc.

163
yarn.lock
View File

@ -209,6 +209,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
"@babel/helper-plugin-utils@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.15.4":
version "7.15.4"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f"
@ -541,6 +546,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-jsx@^7.12.13":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-jsx@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201"
@ -1164,6 +1176,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.10.4", "@babel/template@^7.15.4", "@babel/template@^7.3.3":
version "7.15.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194"
@ -1219,6 +1238,89 @@
resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18"
integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==
"@emotion/babel-plugin@^11.7.1":
version "11.7.2"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0"
integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==
dependencies:
"@babel/helper-module-imports" "^7.12.13"
"@babel/plugin-syntax-jsx" "^7.12.13"
"@babel/runtime" "^7.13.10"
"@emotion/hash" "^0.8.0"
"@emotion/memoize" "^0.7.5"
"@emotion/serialize" "^1.0.2"
babel-plugin-macros "^2.6.1"
convert-source-map "^1.5.0"
escape-string-regexp "^4.0.0"
find-root "^1.1.0"
source-map "^0.5.7"
stylis "4.0.13"
"@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1":
version "11.7.1"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539"
integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/sheet" "^1.1.0"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
stylis "4.0.13"
"@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
"@emotion/react@^11.1.1":
version "11.9.0"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.0.tgz#b6d42b1db3bd7511e7a7c4151dc8bc82e14593b8"
integrity sha512-lBVSF5d0ceKtfKCDQJveNAtkC7ayxpVlgOohLgXqRwqWr9bOf4TZAFFyIcNngnV6xK6X4x2ZeXq7vliHkoVkxQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@emotion/babel-plugin" "^11.7.1"
"@emotion/cache" "^11.7.1"
"@emotion/serialize" "^1.0.3"
"@emotion/utils" "^1.1.0"
"@emotion/weak-memoize" "^0.2.5"
hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.0.2", "@emotion/serialize@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.3.tgz#99e2060c26c6292469fb30db41f4690e1c8fea63"
integrity sha512-2mSSvgLfyV3q+iVh3YWgNlUc2a9ZlDU7DjuP5MjK3AXRR0dYigCrP99aeFtaB2L/hjfEZdSThn5dsZ0ufqbvsA==
dependencies:
"@emotion/hash" "^0.8.0"
"@emotion/memoize" "^0.7.4"
"@emotion/unitless" "^0.7.5"
"@emotion/utils" "^1.0.0"
csstype "^3.0.2"
"@emotion/sheet@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2"
integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==
"@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf"
integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==
"@emotion/weak-memoize@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@ -1975,6 +2077,13 @@
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.0":
version "4.4.4"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.1":
version "4.4.3"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.3.tgz#b0994da0a7023d67dbb4a8910a62112bc00d5688"
@ -2798,7 +2907,7 @@ babel-plugin-jest-hoist@^26.6.2:
"@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6"
babel-plugin-macros@2.8.0:
babel-plugin-macros@2.8.0, babel-plugin-macros@^2.6.1:
version "2.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
@ -3670,7 +3779,7 @@ convert-source-map@^0.3.3:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
@ -5211,6 +5320,11 @@ find-cache-dir@^3.3.1:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@ -5664,6 +5778,13 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
@ -7326,6 +7447,11 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
memoize-one@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
memory-fs@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@ -9106,6 +9232,15 @@ prop-types-extra@^1.1.0:
react-is "^16.3.2"
warning "^4.0.0"
prop-types@^15.6.0:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.13.1"
prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
@ -9354,7 +9489,7 @@ react-error-overlay@^6.0.9:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
react-is@^16.3.2, react-is@^16.8.1:
react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -9454,7 +9589,20 @@ react-scripts@4.0.3:
optionalDependencies:
fsevents "^2.1.3"
react-transition-group@^4.4.1:
react-select@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.2.tgz#3d5edf0a60f1276fd5f29f9f90a305f0a25a5189"
integrity sha512-miGS2rT1XbFNjduMZT+V73xbJEeMzVkJOz727F6MeAr2hKE0uUSA8Ff7vD44H32x2PD3SRB6OXTY/L+fTV3z9w==
dependencies:
"@babel/runtime" "^7.12.0"
"@emotion/cache" "^11.4.0"
"@emotion/react" "^11.1.1"
"@types/react-transition-group" "^4.4.0"
memoize-one "^5.0.0"
prop-types "^15.6.0"
react-transition-group "^4.3.0"
react-transition-group@^4.3.0, react-transition-group@^4.4.1:
version "4.4.2"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==
@ -10305,7 +10453,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.5.0, source-map@^0.5.6:
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@ -10631,6 +10779,11 @@ stylehacks@^4.0.0:
postcss "^7.0.0"
postcss-selector-parser "^3.0.0"
stylis@4.0.13:
version "4.0.13"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"