UNPKG

sedra-parse

Version:

Parse Sedra 3 text database records and build JavaScript representation

447 lines (431 loc) 16.2 kB
/** * @file Parse Sedra 3 text database records and return their JavaScript representation * @version 1.1.8 * @author Greg Borota * @copyright (c) 2017 Greg Borota. * @license MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // https://peshitta.github.io // https://sedra.bethmardutho.org/about/fonts // http://cal1.cn.huc.edu/searching/fullbrowser.html (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('sedra-cal')) : typeof define === 'function' && define.amd ? define(['exports', 'sedra-cal'], factory) : (factory((global.sedraParse = {}),global.sedraCal)); }(this, (function (exports,sedraCal) { 'use strict'; /** @module sedraParse */ /** * Regex to remove ids from root rows and extract relevant information * @const * @type { RegExp } */ var rootRegex = /0:\d+,("[A-Z;/*-]+")(,.+)\r\n/gm; /** * Build roots javascript from root records e.g. 0:2,"AB","ab |A",0 * @static * @param { string } content Sedra root records * @returns { string } JavaScript root representation */ var getRoots = function (content) { var lines = content.replace( rootRegex, function (match, root, line) { return (",r(" + (sedraCal.toCal(root)) + line + ")"); } ); return ("Object.freeze([" + lines + "]);"); }; /** * Regex to remove ids from lexeme records and extract relevant information * @const * @type { RegExp } */ var lexemeRegex = /1:\d+,(?:0:(\d+,)|(NULL,))("[A-Z;/ -]+")(,.+)\r\n/gm; /** * Build lexemes javascript from lexeme records e.g. 1:2,0:2,"ABA",41960448,16 * @static * @param { string } content Lexeme text records * @returns { string } Lexeme javascript records */ var getLexemes = function (content) { var lines = content.replace( lexemeRegex, function (match, id, noId, lexeme, line) { return (",l(" + (noId ? 'null,' : id) + (sedraCal.toCal(lexeme.replace(' "', '"'))) + line + ")"); } ); return ("Object.freeze([" + lines + "]);"); }; /** * Regex to remove ids from word records and extract wanted information * @const * @type { RegExp } */ var wordRegex = /2:(\d+),(?:1:(\d+)|(NULL)),("[A-Z;/a' -]+"),(".+"),(.+)\r\n/gm; /** * Regex to find vocalized words with i vowels without supporting y * @const * @type { RegExp } */ var noYRegex = /.*(([^;]+[i]+[^;]+)|([^;]+[i]+[;]+[aoeiu]+)).*/; /** * Regex to find vocalized words with u vowels without supporting w * @const * @type { RegExp } */ var noWRegex = /.*(([^O]+[u]+[^O]+)|([^O]+[u]+[O]+[aoeiu]+)).*/; /** * Remove id from word file as id will be given by the position in the array. * Word file has 432 gaps with largest ones being 45 (see sedrajs unit tests). * @const * @param { string } content Input word records * @returns { object } hash of parsed word records and no Y/W words */ var parseWords = function (content) { var pid = 0; var parse = Object.create(null, { words: { value: '', enumerable: true, writable: true }, noY: { value: '', enumerable: true, writable: true }, noW: { value: '', enumerable: true, writable: true } }); parse.words = content.replace( wordRegex, function (match, id, lexemeId, noLexemeId, word, vocalised, line) { var cid = parseInt(id, 10); var sb = ''; while (pid < cid) { sb += ','; ++pid; } if (noYRegex.test(vocalised)) { parse.noY += (parse.noY ? ',' : '') + cid; } if (noWRegex.test(vocalised)) { parse.noW += (parse.noW ? ',' : '') + cid; } return (sb + "w(" + (noLexemeId ? 'null' : lexemeId) + "," + (sedraCal.toCal( word.replace(' "', '"') )) + "," + (sedraCal.toCal(vocalised)) + "," + line + ")"); } ); parse.words = "Object.freeze([" + (parse.words) + "]);"; parse.noY = "Object.freeze([" + (parse.noY) + "]);"; parse.noW = "Object.freeze([" + (parse.noW) + "]);"; return parse; }; /** * Build word JavaScript from word records * e.g. 2:31070,1:2055,"DMSBRNOTA","D'aMSaB'RoNuOT,oA",6915072,128 * @static * @param { string } content Word text records * @returns { string } Word JavaScript records */ var getWords = function (content) { return Object.freeze(parseWords(content)); }; var englishComments = { ',"w/ &YuORoA&"': ',"w/ &Twuro)&"', ',"w/ &Ya;BuOT,oA&"': ',"w/ &Taybwut,o)&"', ',"w/ &XuOM&"': ',"w/ &qwum&"', ',"w/ &XoLoA&"': ',"w/ &qolo)&"', ',"w/ &XaR/oA&"': ',"w/ &qarco)&"', ',"w/ &XD,oM&"': ',"w/ &qd,om&"', ',"w/ &WaAeL&"': ',"w/ &$a)el&"', ',"w/ &WLoMoA&"': ',"w/ &$lomo)&"', ',"w/ &T\'LoT,&"': ',"w/ &t\'lot,&"', ',"w/ &RuOKoA&"': ',"w/ &rwuxo)&"', ',"w/ &NuORoA& "': ',"w/ &nwuro)&"', ',"w/ &NoSeB&"': ',"w/ &noseb&"', ',"w/ &MeN&"': ',"w/ &men&"', ',"w/ &LoA&"': ',"w/ &lo)&"', ',"w/ &LKeM&"': ',"w/ &lxem&"', ',"w/ &L&"': ',"w/ &l&"', ',"w/ &KaSi;R&"': ',"w/ &xasyir&"', ',"w/ &EaL&"': ',"w/ &(al&"', ',"w/ &EaL& "': ',"w/ &(al&"', ',"w/ &Ea;NoA&"': ',"w/ &(ayno)&"', ',"w/ &EBaD&"': ',"w/ &(bad&"', ',"w/ &D\'LoA&"': ',"w/ &d\'lo)&"', ',"w/ &D\'B,a;T\'oA&"': ',"w/ &d\'b,ayt\'o)&"', ',"w/ &D\'&"': ',"w/ &d\'&"', ',"w/ &Be;T,&"': ',"w/ &byet,&"', ',"w/ &B\'e;T,&"': ',"w/ &b\'yet,&"', ',"w/ &B\'RuOK&"': ',"w/ &b\'rwux&"', ',"w/ &B\'LeB,oA&"': ',"w/ &b\'leb,o)&"', ',"w/ &B\'G,eN&"': ',"w/ &b\'g,en&"', ',"w/ &B\'+&"': ',"w/ &b\'+&"', ',"w/ &B\'&"': ',"w/ &b\'&"', ',"w/ &AaIe+*A&"': ',"w/ &)ape+*)&"', ',"w/ &AaI\'e+*A&"': ',"w/ &)ap\'e+*)&"', ',"w/ &AKD&"': ',"w/ &)xd&"', ',"w/ &;aMoA&"': ',"w/ &yamo)&"', ',"constr. w/ &YaENoA&"': ',"constr. w/ &Ta(no)&"', ',"constr. w/ &XoLoA&"': ',"constr. w/ &qolo)&"', ',"constr. w/ &WaB,*YeA&"': ',"constr. w/ &$ab,*Te)&"', ',"constr. w/ &RuOKoA&"': ',"constr. w/ &rwuxo)&"', ',"constr. w/ &Mi;*T,eA&"': ',"constr. w/ &myi*t,e)&"', ',"constr. w/ &IuOMoA&"': ',"constr. w/ &pwumo)&"', ',"constr. w/ &C\'oHNuOT,oA&"': ',"constr. w/ &k\'ohnwut,o)&"', ',"constr. w/ &B\'eSRoA&"': ',"constr. w/ &b\'esro)&"', ',"constr. w/ &Ai;Da;*oA&"': ',"constr. w/ &)yiday*o)&"', ',"constr. w/ &Ai;D,oA&"': ',"constr. w/ &)yid,o)&"', ',"constr. w/ &AaIe+*A&"': ',"constr. w/ &)ape+*)&"', ',"constr. w/ &;iD,aET\'oA&"': ',"constr. w/ &yid,a(t\'o)&"', ',"always w/ &AeC,aL&"': ',"always w/ &)ek,al&"', ',"abs. w/ &MeN&"': ',"abs. w/ &men&"', ',"= &MoNoA& + &H_uO&"': ',"= &mono)& + &h_wu&"', ',"= &MeN& + &C\'oA&, of time:"': ',"= &men& + &k\'o)&, of time:"', ',"= &MaN& + &H_uO&"': ',"= &man& + &h_wu&"', ',"= &LoA& + &HuO&"': ',"= &lo)& + &hwu&"', ',"= &HuO& + &HuO&"': ',"= &hwu& + &hwu&"', ',"= &HoNoA& + &HuO&"': ',"= &hono)& + &hwu&"', ',"= &C\'uL& + &A_NoW&"': ',"= &k\'ul& + &)_no$&"', ',"= &C\'aD,& + &HuO&"': ',"= &k\'ad,& + &hwu&"', ',"= &B\'aR& + &A_NoWoA&"': ',"= &b\'ar& + &)_no$o)&"', ',"= &AoI,& + &LoA&"': ',"= &)op,& + &lo)&"', ',"= &AoI,& + &LaN&"': ',"= &)op,& + &lan&"', ',"= &Aa;C\'oA& + &H_uO&"': ',"= &)ayk\'o)& + &h_wu&"', ',"(w/*L*)"': ',"(w/*l*)"', ',"(w/*DLA*)"': ',"(w/*dl)*)"', ',"(w/*D*)"': ',"(w/*d*)"', ',"(w/*A;DA*)"': ',"(w/*)yd)*)"', ',"(w/*;XDA*)"': ',"(w/*yqd)*)"', ',"(w/ *RB*)"': ',"(w/ *rb*)"', ',"(w/ *M/A*)"': ',"(w/ *mc)*)"', ',"(w/ *D*)"': ',"(w/ *d*)"', ',"(w/ *AIA*)"': ',"(w/ *)p)*)"', ',"(*CL-KD___KD*) "': ',"(*kl-xd___xd*)"', ',"(*A;T D__OA;T*)"': ',"(*)yt d__w)yt*)"', ',"&YoB,& as adv."': ',"&Tob,& as adv."', ',"&WoX*La; WaB,*YeA&"': ',"&$oq*lay $ab,*Te)&"', ",\"&T'iT'oA I,aC'i;HT'oA&\"": ",\"&t'it'o) p,ak'yiht'o)&\"", ',"&MoR;oA /B,aAOuT,&"': ',"&moryo) cb,a)wut,&"', ',"&MeC\'oA OMeC\'oA&"': ',"&mek\'o) wmek\'o)&"', ',"&KaD, KaD,&"': ',"&xad, xad,&"', ',"&DMeN ;uOLI,oNeH DeAI;XoORoS&"': ',"&dmen ywulp,oneh de)pyqwOros&"' }; /** * Regex to remove ids from english records and extract relevant information * only * @const * @type { RegExp } */ var englishRegex = /3:(\d+),(?:1:(\d+)|(NULL))(,".*")(,".*")(,".*")(,".*")(,-?\d+,)([01])\r\n/gm; /** * Build english javascript from english records * e.g. 3:165,1:97,"cause","without","","",0,0 * @static * @param { string } content English text content * @returns { string } English JavaScript content */ var getEnglish = function (content) { var curId = null; var parse = Object.create(null, { english: { value: '', enumerable: true, writable: true }, lids: { value: '', enumerable: true, writable: true } }); var lids = {}; var lines = content.replace( englishRegex, function (match, id, lid, noLid, word, before, after, comment, attrib, flag) { curId = noLid ? curId : lid; if (!lids[curId]) { lids[curId] = []; } lids[curId].push(id); var com = comment === ',""' ? comment : englishComments[comment] || comment; return (",e(" + curId + word + before + after + com + attrib + (flag === '1' ? 'true' : 'false') + ")"); } ); parse.english = "Object.freeze([" + lines + "]);"; parse.lids = "Object.freeze(" + (JSON.stringify(lids).replace(/"/g, '')) + ");"; return Object.freeze(parse); }; /** * Regex to remove ids from etymology records and extract useful info only * @const * @type { RegExp } */ var etymologyRegex = /4:(\d+),(?:1:(\d+)|(NULL))(,.+)\r\n/gm; /** * Remove id from etymology records as id will be given by the array position. * Etymology file has 3 gaps but difference is 1 only (see sedrajs unit tests). * @const * @param { string } content Input etymology text records * @returns { object } Parsed etymology content + reference */ var parseEtymology = function (content) { var pid = 0; var parse = Object.create(null, { etymology: { value: '', enumerable: true, writable: true }, lids: { value: '', enumerable: true, writable: true } }); var lids = {}; var lines = content.replace( etymologyRegex, function (match, id, lexemeId, noLexemeId, line) { if (lexemeId) { lids[lexemeId] = id; } var sb = ",t(" + (noLexemeId ? 'null' : lexemeId) + (line.replace( /\\/g, '\\\\' )) + ")"; var cid = parseInt(id, 10); if (pid + 1 !== cid) { sb = "," + sb; } pid = cid; return sb; } ); parse.etymology = "Object.freeze([" + lines + "]);"; parse.lids = "Object.freeze(" + (JSON.stringify(lids).replace(/"/g, '')) + ");"; return parse; }; /** * Build etymology JavaScript from etymology records e.g. 4:10,1:75,"eu\310",5 * @static * @param { string } content Etymology text file records * @returns { object } Etymology JavaScript records + reference */ var getEtymology = function (content) { return Object.freeze(parseEtymology(content)); }; /** * Regex to remove ids from Ubs records and extract parsed information * book - Left 2 digits represent the book (52=Matt, 53=Mark, 54=Luke, etc.) * chapter - Next 2 digits = chapter * verse - Next 3 digits = verse * index - Next 2 digits = word * wordId - the two most significant bits are always 02 which represents the * database file number * @const * @type { RegExp } */ var ubsRegex = /^0:-?\d+,(\d{2})(\d{2})(\d{3})(\d{2}),(\d+),.+$/; /** * Build parsed Usb object from the ubsRegex match * @const * @param { Object } match regex match result * @returns { Object } object created from match result */ var buildUbs = function (match) { return Object.freeze( Object.create(null, { book: { value: parseInt(match[1], 10), enumerable: true }, chapter: { value: parseInt(match[2], 10), enumerable: true }, verse: { value: parseInt(match[3], 10), enumerable: true }, index: { value: parseInt(match[4], 10), enumerable: true }, wordId: { value: parseInt(match[5], 10) & 0x00ffffff, enumerable: true } }) ); }; /** * Remove id from Ubs records as it is not being used and it * is also messed up - it overflows and becomes negative a number of times. * To get verse only index -> reference, filter out entries with verse as 0. * @const * @param { string } content Input Ubs text records * @returns { Object } Parsed JavaScript Ubs/reference records */ var parseUbs = function (content) { var reference = []; var map = Object.create(null, { books: { value: 0, enumerable: true, writable: true }, chapters: { value: 0, enumerable: true, writable: true }, verses: { value: 0, enumerable: true, writable: true }, words: { value: 0, enumerable: true, writable: true } }); var lines = content.split(/\r\n/); for (var i = 0, len = lines.length - 1; i < len; i++) { var parse = buildUbs(ubsRegex.exec(lines[i])); var book = map[parse.book]; if (!book) { book = Object.create(null, { chapters: { value: 0, enumerable: true, writable: true }, verses: { value: 0, enumerable: true, writable: true }, words: { value: 0, enumerable: true, writable: true }, rollupBooks: { value: map.books, enumerable: true, writable: true }, rollupChapters: { value: map.chapters, enumerable: true, writable: true }, rollupVerses: { value: map.verses, enumerable: true, writable: true }, rollupWords: { value: map.words, enumerable: true, writable: true } }); map[parse.book] = book; map.books += 1; } var chapter = book[parse.chapter]; if (!chapter) { chapter = Object.create(null, { verses: { value: 0, enumerable: true, writable: true }, words: { value: 0, enumerable: true, writable: true }, rollupChapters: { value: map.chapters, enumerable: true, writable: true }, rollupVerses: { value: map.verses, enumerable: true, writable: true }, rollupWords: { value: map.words, enumerable: true, writable: true } }); book[parse.chapter] = chapter; book.chapters += 1; map.chapters += 1; reference.push([parse.book, parse.chapter, 0]); } var verse = chapter[parse.verse]; if (!verse) { verse = []; chapter[parse.verse] = verse; chapter.verses += 1; book.verses += 1; map.verses += 1; reference.push([parse.book, parse.chapter, parse.verse]); } map.words += 1; book.words += 1; chapter.words += 1; verse[parse.index - 1] = parse.wordId; } return Object.freeze( Object.create(null, { ubs: { value: ((JSON.stringify(map).replace(/"/g, '')) + ";"), enumerable: true }, reference: { value: ((JSON.stringify(reference).replace(/"/g, '')) + ";"), enumerable: true } }) ); }; /** * Build Ubs JavaScript from ubs records e.g. 0:8,520100108,33554599,36 and * index to reference map. To get verse only index -> reference, filter out * entries where verse is 0. * @static * @param { string } content Ubs text database records * @returns { object } { ubs, reference } JavaScript */ var getUbs = function (content) { return parseUbs(content); }; exports.getRoots = getRoots; exports.getLexemes = getLexemes; exports.getWords = getWords; exports.getEnglish = getEnglish; exports.getEtymology = getEtymology; exports.getUbs = getUbs; Object.defineProperty(exports, '__esModule', { value: true }); })));