beygla
Version:
<h1 align="center"> Beygla </h1>
254 lines (247 loc) • 18 kB
JavaScript
const NO_DECLENSION = "0;,,,";
const NO_DECLENSION_MARKER = "~";
const isChar = (c) => c === "-" || c.toLowerCase() !== c.toUpperCase();
const validTerminator = (c) => ["!", "_"].indexOf(c) !== -1;
function deserializeTrie(str) {
let i = 0;
const char = () => str.substr(i, 1);
const next = () => i++;
function deserializeLeaf() {
function returnValue(c, value) {
if (!validTerminator(c))
throw new Error("INV_TER: " + c);
return [{ value, children: {} }, c === "!"];
}
const firstChar = char();
if (firstChar === NO_DECLENSION_MARKER) {
next(); // Move beyond terminator
return returnValue(firstChar, NO_DECLENSION);
}
const parts = [];
for (let i = 0;; i++) {
let part = "";
let c = char();
while (isChar(c)) {
part += c;
next();
c = char();
}
// 'c' is terminator or separator
parts.push(part);
next(); // Move beyond terminator or separator
if (i === 3) {
return returnValue(c, parts.join(","));
}
// 'c' should be terminator
if (c !== ",")
throw new Error("INV_SEP: " + c);
}
}
function deserializeKey() {
let key = "";
let c = char();
while (isChar(c)) {
key += c;
next();
c = char();
}
if (c !== ":")
throw new Error("INV_COL: " + c);
next(); // Move past ':' to value
return key;
}
function deserializeObject() {
next(); // Move to first property
const children = {};
while (true) {
const key = deserializeKey();
const [child, done] = deserialize();
children[key] = child;
if (!done)
continue;
const c = char(); // Should be terminator
next(); // Move past terminator
if (!validTerminator(c))
throw new Error("INV_TER: " + c);
return [{ value: "", children }, c === "!"];
}
}
function deserialize() {
const c = char();
if (c === "{") {
return deserializeObject();
}
return deserializeLeaf();
}
return deserialize()[0];
}
function extractDeclension(trie, name) {
let node = trie;
for (const char of name.split("").reverse()) {
const next = node.children[char];
if (next) {
if (next.value) {
// We've reached a leaf node, return the value
return next.value;
}
// Non-leaf node. Keep traversing the trie
node = next;
continue;
}
// If there is no next node for the current character, and the
// current node is not a leaf node, we are either:
//
// 1. at a dead end
// 2. the next node is a "union leaf node"
//
// If 'node.children' looks like so:
//
// {
// abc: { ... },
// d: { ... },
// }
//
// Then 'abc' is an example of a union leaf node. If 'char' is
// one of the characters that comprises the key, then the union
// leaf node contains the value we're looking for.
//
for (const key of Object.keys(node.children)) {
for (let i = 0; i < key.length; i++) {
if (key.substr(i, 1) === char) {
return node.children[key].value;
}
}
}
// We are at a dead end.
break;
}
return null;
}
var serializedInput = "{e:{n:{ein:,,,_r:,,,s!_t:{t:,,,_n:,,,s!_cghim:,,,!_t:{r:{ö:{j:{b:ört,örtu,örtu,artar_B:ört,ört,ört,artar!!_aeo:,,,s!_n:{e:{r:{Aó:,,,s_e:,,i,s!_Bcv:,,,s!_a:,,,s!_ó:{j:,u,u,ar_Bn:,,,ar!_s:{ú:,,i,s_en:,,,s_iá:,,,ar!_e:{ijrí:,i,i,ar_b:,u,u,ar_f:,,i,s!_t:{ió:,,,ar_o:,,,s!_í:{mr:,,,ar_v:,i,i,ar!_iou:,,,ar_ak:,,,s_l:,,i,s_é:,i,i,ar!_n:{o:{m:{í:{S:,,i,ar_T:,,i,s!_Aað:,,i,s_ó:,,,s_r:,,i,ar!_l:{ií:,,,s_ó:,,i,s!_e:{d:,,,s_L:,,i,s!_s:{a:,,i,ar_m:,,,ar!_dr:,,i,s_tí:,,,s_k:,,i,ar_V:,,,ar!_a:{i:{l:{u:,,,s_l:,,,!_rt:,,,s!_j:{l:{i:{K:,,,s_L:,,i,s!!_m:,,,s!_v:{IÍ:,,i,s_S:,,,s!_t:{a:{n:,,,s_N:,,i,s!_s:{i:,,i,s_o:,,,s!_r:,,i,s!_DJeklrÍí:,,,s_fhm:,,i,s_d:,,i,ar!_r:{ö:{j:jörn,jörn,irni,jörns_H:örn,örn,örn,arnar_r:örn,örn,erni,arnar!_á:,,i,s_Ö:Örn,Örn,Erni,Arnar!_n:{i:{l:{a:inn,in,ni,ins_r:,,,ar!_e:n,,i,s_Ff:,,,s_rtáð:inn,in,ni,ins_gn:n,,,s!_u:{ð:{u:n,,i,s_Ii:,i,i,ar!_t:{ö:unn,un,ni,uns_ó:,i,i,ar!_glnrsÍæ:,i,i,ar!_a:{m:{t:{s:{u:,,,s_i:,,i,s!_r:,,i,s!_r:{euÁ:,,i,s_o:,,,s!_ð:{iu:,,i,s_r:,,,s!_glnsæíú:,,i,s_i:,,,s!_hó:,,i,s_ð:n,,i,s!_A:,,,_áú:n,,i,s_ö:önn,önn,önn,annar!_ú:{r:,u,u,ar_R:,,,ar!_i:{gtvw:,,,s_Veklr:,,,ar!_í:{r:{Aa:,,,ar_gt:,u,u,ar!_l:{a:{d:{n:,,,ar_í:,,,!_MSjt:,,,ar_g:,,,s!_k:{n:,,,s_s:,,,ar!_Hginrstyáðó:,,,ar_E:,u,u,ar!_m:{a:,,,s_s:,,,ar!_t:{s:,u,u,ar_n:,,,s!_LRk:,,,ar!_u:{ð:,,i,s_gj:,,,ar!_e:{r:{aÍ:,,,ar_ö:,,,s!_t:{s:,u,u,ar_r:,,,s!_lm:,,,ar_bghí:,,,s!_f:{ö:öfn,öfn,öfn,afnar_eo:,,,ar_a:,,i,s!_á:{r:{F:,,,ar_ð:,,i,s!_d:,,i,ar_fj:,,i,s_R:,,,ar!_g:{e:{r:,,,ar_R:,,i,s!_ö:ögn,ögn,ögn,agnar_a:,,i,s_Ö:Ögn,Ögn,Ögn,Agnar!_ó:,,i,s_h:,,,s_y:,,,jar!_a:{l:{g:{A:Agla,Öglu,Öglu,Öglu_EU:a,u,u,u!_l:{e:{b:{a:{n:Annabella,Önnubellu,Önnubellu,Önnubellu_rs:a,u,u,u!!_n:{iníóú:a,u,u,u_o:,u,u,u!_BHNstí:a,u,u,u!_A:Alla,Öllu,Öllu,Öllu_EiyÚ:a,u,u,u_a:alla,öllu,öllu,öllu!_t:{a:atla,ötlu,ötlu,ötlu_A:Atla,Ötlu,Ötlu,Ötlu_s:a,u,u,u!_r:{Eeu:a,u,u,u_a:arla,örlu,örlu,örlu!_beikosuyÓáæíóú:a,u,u,u_a:ala,ölu,ölu,ölu!_d:{d:{A:Adda,Öddu,Öddu,Öddu_EIOeio:a,u,u,u_a:adda,öddu,öddu,öddu!_l:{A:Alda,Öldu,Öldu,Öldu_iou:a,u,u,u_a:alda,öldu,öldu,öldu!_n:{a:anda,öndu,öndu,öndu_Iiu:a,u,u,u!_A:Ada,Ödu,Ödu,Ödu_IeiÍÓí:a,u,u,u_g:agda,ögdu,ögdu,ögdu!_n:{n:{A:Anna,Önnu,Önnu,Önnu_IUeiouú:a,u,u,u_a:anna,önnu,önnu,önnu!_r:{A:Arna,Örnu,Örnu,Örnu_EeiÁ:a,u,u,u_a:arna,örnu,örnu,örnu!_g:{iö:a,u,u,u_a:agna,ögnu,ögnu,ögnu!_IUefilotÍíðóú:a,u,u,u_a:ana,önu,önu,önu!_t:{r:{ei:a,u,u,u_a:arta,örtu,örtu,örtu!_n:{a:anta,öntu,öntu,öntu_e:a,u,u,u!_a:ata,ötu,ötu,ötu_egikstéíóú:a,u,u,u_l:alta,öltu,öltu,öltu!_h:{t:{r:{e:a,u,u,u_a:artha,örthu,örthu,örthu!_a:atha,öthu,öthu,öthu!!_ð:{r:{euó:a,u,u,u_a:arða,örðu,örðu,örðu!_g:Agða,Ögðu,Ögðu,Ögðu_Iiyíú:a,u,u,u!_b:{l:Alba,Ölbu,Ölbu,Ölbu_bem:a,u,u,u!_r:{d:{n:{a:andra,öndru,öndru,öndru_A:Andra,Öndru,Öndru,Öndru_Ii:a,u,u,u!!_t:{ekí:a,u,u,u_a:atra,ötru,ötru,ötru!_A:Ara,Öru,Öru,Öru_efiruáíóý:a,u,u,u_a:ara,öru,öru,öru_s:,,,!_í:{r:{a:{m:{a:Annamaría,Önnumaríu,Önnumaríu,Önnumaríu_i:a,u,u,u!_DM:a,u,u,u!_AKdeo:a,u,u,u!_DFMScdfghlmnpsvx:a,u,u,u!_f:{l:{A:Alfa,Ölfu,Ölfu,Ölfu_EYeiÚ:a,u,u,u!_eíóú:a,u,u,u_a:afa,öfu,öfu,öfu!_s:{í:{l:{AE:a,u,u,u_a:Annalísa,Önnulísu,Önnulísu,Önnulísu!_DLvú:a,u,u,u!_ó:{r:Annarósa,Önnurósu,Önnurósu,Önnurósu_R:a,u,u,u!_s:{A:Assa,Össu,Össu,Össu_ei:a,u,u,u!_n:{a:ansa,önsu,önsu,önsu_e:a,u,u,u!_r:{a:arsa,örsu,örsu,örsu_Yi:a,u,u,u!_eilÁÆÓ:a,u,u,u!_m:{l:{A:Alma,Ölmu,Ölmu,Ölmu_Eeiá:a,u,u,u_a:,,,!_r:{a:arma,örmu,örmu,örmu_Io:a,u,u,u!_m:{EIi:a,u,u,u_a:amma,ömmu,ömmu,ömmu!_eÍÝíó:a,u,u,u!_k:{l:{Eeio:a,u,u,u_a:alka,ölku,ölku,ölku!_n:{i:a,u,u,u_a:anka,önku,önku,önku!_eikrsáíó:a,u,u,u_a:aka,öku,öku,öku!_j:{n:{A:Anja,Önju,Önju,Önju_EYioy:a,u,u,u_a:anja,önju,önju,önju!_k:{s:{A:Askja,Öskju,Öskju,Öskju_E:a,u,u,u!_k:a,u,u,u!_r:{IYi:a,u,u,u_a:arja,örju,örju,örju!_aglsuyæð:a,u,u,u!_v:{l:{EYiö:a,u,u,u_a:alva,ölvu,ölvu,ölvu!_A:Ava,Övu,Övu,Övu_EegikrÍí:a,u,u,u_a:ava,övu,övu,övu!_g:{g:{eio:a,u,u,u_a:agga,öggu,öggu,öggu!_eilnou:a,u,u,u_a:aga,ögu,ögu,ögu!_ú:{D:a,u,u,u_s:,,,!_p:{r:{a:arpa,örpu,örpu,örpu_I:a,u,u,u!_mp:a,u,u,u!_ceizÚó:a,u,u,u_y:anya,önyu,önyu,önyu!_l:{e:{a:{g:,,,ar_fhkmnrs:,,,s!_d:{A:,,,s_E:,,,ar!_t:{r:,,,s_s:,,,ar!_ó:{B:,,,ar_J:,,,s!_inrsxíú:,,,s_bhk:,,,ar_v:,,i,s!_i:{b:{i:,,,_á:,,,ar!_cms:,,,s_d:,,,ar!_l:{i:{g:{E:Egill,Egil,Agli,Egils_nr:ill,il,li,ils!_B:,,,s_fkr:ill,il,li,ils_t:etill,etil,atli,etils_L:,,,ar!_eáæ:l,,i,s_u:ull,ul,li,uls_a:,,i,s_ö:öll,öll,öll,allar!_s:{í:{v:aldakvísl,öldukvísl,öldukvísl,öldukvíslar_g:,,i,s!!_mæíó:,,,ar_r:,,i,s_a:,,,s!_m:{a:{í:{L:,,,s_r:,,,ar!_i:{r:,,,ar_l:,,,s!_dhró:,,,s_j:,,,ar!_eilruí:,,,s_ó:,,,ar!_i:{r:{AadefgimrtÓáóúý:i,a,a,a_y:,,,!_g:{g:{e:{B:i,a,a,a_k:i,ja,ja,ja!_Uaiouö:i,a,a,a!_alnou:i,a,a,a!_x:{Ua:i,a,a,a_Ö:Öxi,Öxi,Öxi,Axar!_bdfjklmnpstvðóú:i,a,a,a_u:i,ja,ja,ja_a:,,,s!_ý:{n:{n:{e:{BDHV:,,,jar_J:,ju,ju,jar!_Aaiou:,,,jar_áó:,ju,ju,jar!_ó:{n:,,,s_J:,,,jar!_g:{a:{D:,ju,ju,jar_MR:,,,jar!_ir:,ju,ju,jar!_dfklrstæéð:,ju,ju,jar_o:,,,s!_v:{en:,,,s_l:,,,jar!_r:{r:{iu:,,,jar_a:,,,s!_n:,,,s_au:,,,jar!_dglmst:,,,jar!_f:{l:{ó:{d:{A:,,,s_ú:,,i,s!_ð:,,,s!_o:,,,s!_i:{e:{l:,,,ar_L:,,,s!_Ss:,,,jar!_í:,,,ar_aeu:,,,s_ú:,u,u,ar_ö:öf,öfu,öfu,afar!_h:{cp:,,,s_t:,,,ar!_g:{r:{e:{b:{n:{aeinrí:,,,s_u:,,i,s!_s:{Áíó:,,,s_s:,,i,s!_d:{l:,,i,s_n:,,,s!_m:{l:,,,s_u:,,i,s!_g:{n:{I:,,,s_y:,,i,s!_u:,,,s!_æ:{n:,,i,s_S:,,,s!_Efilrtyð:,,,s_ó:,,i,s!_B:,,,s!_o:{b:{dgilnrstyæð:,u,u,ar_ef:,,,ar!_B:,,,ar_e:,,,s!_ö:örg,örgu,örgu,argar_a:,,i,s!_i:{e:,u,u,ar_v:,,,s!_n:{i:{l:{l:,,,s_r:,,i,s!_mnr:,,,s!!_g:{ö:ögg,ögg,ögg,aggar_i:,,,jar!_u:,u,u,ar_í:,,,s!_r:{u:{g:{n:{iæ:ur,,i,s_e:ur,,,s!_g:{euy:ur,,i,s_ö:ur,,,s!_i:{e:ur,,i,s_V:,,,s!_ruy:ur,,i,s_a:agur,ag,egi,ags_í:ur,,,s!_ð:{i:{v:{lnty:ur,,i,ar_g:ur,,i,s!_e:ur,i,i,ar_Em:ur,,i,s_r:ur,,i,ar!_r:{a:{v:{ð:{u:ur,,i,s_áóö:ur,,i,ar!_lnrstá:ur,,i,ar_g:ur,,i,s!_bghkr:ur,,i,s!_ö:{HMVh:örður,örð,erði,arðar_j:jörður,jörð,irði,jarðar!_Ue:ur,i,i,ar_uáó:ur,,i,ar!_ö:{r:ur,,i,ar_l:ur,,,s_H:öður,öð,eði,aðar!_e:{r:{f:{gn:ur,,i,s_lð:ur,,i,ar!!!_u:{a:ur,i,i,ar_f:örfuður,örfuð,örfuði,arfaðar!_a:{k:ur,,i,ar_l:ur,,i,s!_íú:ur,i,i,ar_áó:ur,,i,s_ý:ur,,,s!_d:{n:{i:{v:ur,,i,ar_Tl:ur,,i,s!_uá:ur,,i,ar_ae:ur,,i,s!_l:{a:{n:{r:ur,,i,ar_ó:ur,,i,s!_v:{t:{s:{Á:ur,,i,ar_i:ur,,i,s!!_s:{Á:ur,,i,ar_Ó:ur,,i,s!_r:{i:ur,,i,s_o:ur,,i,ar!_giknæ:ur,,i,s!_BGb:ur,ur,ri,urs_jmró:ur,,i,s!_ei:ur,i,i,ar_E:ur,,i,s_u:ur,,i,ar_ö:jöldur,jöld,ildi,jaldar!_d:ur,,i,s!_k:{a:{lþ:ur,,i,s_V:ur,ur,ri,urs!_eisuáí:ur,,i,s_r:örkur,örk,erki,arkar!_n:{n:{i:ur,,i,s_Uu:ur,i,i,ar!_ay:ur,,i,s!_m:{l:{áó:ur,,i,s_I:ur,i,i,ar!_iruyíóú:ur,,i,s!_f:{l:{ÁÚóú:ur,,i,s_EYe:ur,i,i,ar!_í:{l:ur,,i,s_v:ur,ur,ri,urs!_aióú:ur,,i,s!_t:{r:{a:ur,,i,s_ö:jörtur,jört,irti,jartar!_s:{ae:ur,,i,s_ö:östur,öst,esti,astar!_t:{e:ur,,i,s_ö:öttur,ött,etti,attar_ó:ur,,i,ar!_afiuóú:ur,,i,s_Oeé:ur,ur,ri,urs!_l:{a:{D:ur,,,s_FV:ur,,i,s!_lo:ur,,i,s!_h:,,i,s_p:ur,,i,s_sz:,,i,ar!_a:{m:{n:{n:,,,s_iy:,,i,s!_t:{s:{eiu:,,i,s_Á:,,,s!_r:,,i,s!_s:{Á:,,,s_Í:,,i,s!_g:{r:,,,s_a:,,,ar_in:,,i,s!_i:{elr:,,i,s_dg:,,,s!_a:{h:ar,ar,ri,ars_H:,,i,s_T:,,,ar!_í:{l:,,,s_r:,,i,s!_ð:{i:{r:,,,s_e:,,i,s!_uóú:,,i,s!_dlryÓó:,,i,s_e:,,,s!_s:{eÁÍæó:,,i,s_a:,,,s!_dfghjklnprtvxðó:,,i,s_M:,,,s!_i:{e:{g:,,i,s_G:,,,s!_dgklmnrstvð:r,,,s!_e:{h:{t:{s:,,,ar_ú:,,,s!_p:,,,s!_t:{s:{E:,,,ar_i:,,,s!_x:,,i,s_elú:,,,s!_g:{gl:,,,s_n:,,,ar!_PVbdfnpsvz:,,,s!_o:{ghmní:,,,s_t:,,i,s!_r:{a:r,,i,s_ö:örr,örr,erri,arrar_y:r,,,s_Ý:r,i,i,ar!_ó:{dnþ:,,i,s_DThÞ:,,,s!_y:{e:{rÞ:r,,,s_R:,,,s!_t:,,,s!_ú:{ht:,,i,s_k:,,,s!_á:{Mr:r,,,s_k:,,i,s_KL:,,,s_V:,,,ar!_í:,,,s_æéý:r,,,s_ö:ör,öru,öru,arar_d:r,,i,s_ÍÝ:,i,i,ar!_s:{í:{d:{a:{n:,i,i,ar_r:,,,ar!_dfglmnrstyæéíðó:,i,i,ar!_l:{A:,i,i,ar_l:,,i,ar!_r:{A:,i,i,ar_a:,,,ar!_D:,,,ar!_e:{n:{r:{A:,,i,ar_a:,,i,s!_g:,i,i,ar_An:,,i,ar_f:,,i,s!_r:{d:,,i,ar_A:,,,ar!_l:{r:{a:{h:,,,_K:,,i,ar!!_ú:,,i,ar!_d:{e:,,i,s_í:,i,i,ar!_m:{a:,,,_r:,,i,!_s:{ó:,,,_m:,,i,ar!_J:,,,_tv:,,i,ar!_u:{m:{e:,,i,s_s:,,i,ar!_n:{aíú:,,i,ar_e:,,,ar!_defghprí:,,i,ar!_n:{e:{Jmr:,,,_t:,,i,!_o:,,,ar_a:,,,!_a:{l:{t:,,i,ar_o:,,i,!_m:{o:,,,_uó:,,i,ar!_ejkníóý:,,i,ar_t:,,,ar!_i:{r:{Ao:,,,ar_Í:,i,i,ar!_lms:,,,ar_n:,,,_v:,,i,s!_l:{i:{g:,,i,_GN:,,,!_e:{i:,,i,ar_í:,,,!_í:,,,!_s:{Á:,,,_o:,,i,!_á:{l:{u:,,i,ar_r:,,i,s!!_ó:,,,ar_oéú:,,i,ar_rt:,,,_Á:,,,s!_y:{e:{d:{l:,ju,ju,jar_n:,,,jar!_r:{Aauáó:,ju,ju,jar_r:,,,jar!_m:{girtð:,,,jar_lmuíó:,ju,ju,jar!_l:{ntx:,,,s_alrsáó:,ju,ju,jar_e:,,,jar!_g:{n:{I:,ju,ju,jar_i:,,,jar!_goru:,ju,ju,jar_l:,,,jar!_ð:{i:{r:,ju,ju,jar_V:,,,jar!_a:,ju,ju,jar!_Mfknstvó:,ju,ju,jar!_n:{o:,,,s_n:,,,jar!_r:{nr:,,,s_a:,,,jar!_l:{l:{o:,,,jar_i:,,,s!!_E:,,,jar!_d:{l:{a:{n:{r:,,i,ar_oó:,,,s_y:,,i,s!_v:{t:,,i,ar_nsæð:,,i,s_E:,,,s!_r:{e:,,,s_a:,,i,s!_m:,,,s_b:,,i,s!_o:{n:,,i,s_fs:,,,ar_hp:,,,s!_u:,,,ar_i:,i,i,ar!_n:{a:{l:,,i,s_n:,,,s!_iu:,,,ar_e:,,,s!_r:{a:{h:{n:{r:,,i,s_io:,,,s!_c:,,,s!_lnvw:,,,s_g:,,,ar!!_e:,,,s_im:,,,ar_d:ödd,ödd,ödd,addar!_ð:{r:{a:{ghv:,,i,s_n:,,,s!!_í:{v:,,,s_r:,i,i,ar!_á:{r:{l:,i,i,ar_n:,,i,s!_N:,,,ar!_e:,,,s_ö:öð,öð,öð,aðar_ó:,,,ar!_k:{r:{ö:örk,örk,örk,arkar_a:,,i,s_Ö:Örk,Örk,Örk,Arkar!_i:{r:{dlnð:,,i,s_Etú:,,,s!_n:,,,s_E:,,,ar_e:,,,ur!_e:{r:{bú:,,,s_t:,,i,s!!_í:{v:{ð:{ú:,,,s_i:,,,ur!_ry:,,,ur!!_ö:ök,öku,öku,akar_sá:,,,ar_acno:,,,s_l:,,i,s_k:ökk,ökk,ökk,akkar!_í:{n:{ó:{n:,,,s_J:,,,ar!_í:,,,ar!_m:{a:,,,ar_oó:,,,!_bdfrs:,,,ar_lv:,,,s!_ó:{k:{ik:,,,ar_r:,,,s!_g:{ó:,,,ar_gú:,,,s!_r:{a:,,,ar_e:,,,s!_dentí:,,,s_l:,,,ar!_p:{eio:,,,s_p:öpp,öpp,öpp,appar_s:Ösp,Ösp,Ösp,Aspar!_v:{i:{L:,,,ar_S:,,,jar!_a:,,,s_í:,,,ar!_xz:,,,_á:,,,r_bcjoé:,,,s!!";
// We can't hard-code this to something like "@@input@@" because
// rollup considers that to be dead code and eliminates it.
//
// Anyway, this will be replaced with a constant in builds.
var mode = "names"; // Set to either 'names' or 'addresses' in builds
const trie = deserializeTrie(serializedInput);
const casesIs = ["nf", "þf", "þgf", "ef"];
const casesEn = ["nom", "acc", "dat", "gen"];
function getCaseIndex(caseStr) {
const indexIs = casesIs.indexOf(caseStr);
if (indexIs !== -1)
return indexIs;
const indexEn = casesEn.indexOf(caseStr);
if (indexEn !== -1)
return indexEn;
return 0; // Fall back to 0 if an invalid case was provided
}
function declineName(name, declension, caseStr) {
const appendices = declension.split(",");
const subtraction = appendices[0].length;
const caseIndex = getCaseIndex(caseStr);
// Should not happen, but prefer being safe
if (!Number.isFinite(subtraction) || appendices.length !== 4)
return name;
const root = name.substr(0, name.length - subtraction);
return root + appendices[caseIndex];
}
let predicate;
function setPredicate(pred) {
predicate = pred;
}
function applyCaseToName(caseStr, name) {
if (mode === "names") {
const namesThatEndWithSon = ["Samson", "Jason"];
const endsWithSon = namesThatEndWithSon.indexOf(name) !== -1;
if (!endsWithSon) {
for (const [ending, declension] of [
["son", "on,on,yni,onar"],
["dóttir", "ir,ur,ur,ur"],
["bur", ",,i,s"],
]) {
if (!name.endsWith(ending))
continue;
name = name.split(ending)[0];
return name + declineName(ending, declension, caseStr);
}
}
}
const declension = getDeclensionForName(name);
if (declension && (!predicate || predicate(name)))
name = declineName(name, declension, caseStr);
return name;
}
/**
* Applies a case to a source name provided in the nominative
* case (nefnifall).
*
* @example
* ```tsx
* applyCase("ef", "Jóhann");
* //=> "Jóhannesar"
*
* applyCase("þgf", "Helga Fríða Smáradóttir");
* //=> "Helgu Fríðu Smáradóttur"
* ```
*
* The name provided must be an Icelandic name in the nominative case
* (nefnifall). Otherwise, an unexpected output is likely.
*
* The supported cases are:
*
* - Nominative `nom` (nefnifall `nf` in Icelandic)
* - Accusative `acc` (þolfall `þf` in Icelandic)
* - Dative `dat` (þágufall `þgf` in Icelandic)
* - Genitive `gen` (eignarfall `ef` in Icelandic)
*
* Note that superfluous whitespace is not retained:
*
* @example
* ```tsx
* applyCase("þf", " \n Hildigerður Oddný\tPatreksdóttir \n\n");
* //=> "Hildigerði Oddnýju Patreksdóttur"
* ```
*
* @param name - An Icelandic name in the nominative case (nefnifall)
* @param caseStr - The case to apply to the name to, e.g. `þf`
*/
function applyCase(caseStr, name) {
return name
.split(/\s+/)
.filter(Boolean)
.map((name) => {
if (mode === "names")
return applyCaseToName(caseStr, name);
return name
.split("-")
.map((name) => applyCaseToName(caseStr, name))
.join("-");
})
.join(" ");
}
function getDeclensionForName(name) {
if (name.split(/\s+/).length > 1)
throw new Error("Name must not include whitespace");
const declension = extractDeclension(trie, name);
if (declension) {
// Ensure that the declension applies to the name. This guard is useful when
// the subtraction is longer than the path to the declension.
//
// For example, consider this:
//
// {
// "path": "ya",
// "children": {},
// "keys": ["Tanya"],
// "value": "4;anya,önyu,önyu,önyu"
// }
//
// The name 'Maya' matches this path, but applying the declension erases the
// entire name.
const appendices = declension.split(",");
if (!name.endsWith(appendices[0]))
return null;
}
return declension;
}
export { applyCase, getDeclensionForName, setPredicate };