@cbop-dev/aland-gospel-synopsis
Version:
ES Javascript module for looking up parallel texts from the NT gospels, based on Aland's 'Quattuor Synopsis Evangeliorum'
380 lines (328 loc) • 14.5 kB
JavaScript
import { mylog } from "./lib/env/env.js";
import { alandSynopsis, gospels } from "./alandSections.js";
import { ntBooksDict } from "./ntbooks.js";
import bibleRefUtils from "./lib/utils/bibleRefUtils.js";
//const mylog=log.mylog;
/**
*
* @param {string} refString -- a NT book name of some sort
* @returns {number|null} - the TF node id of the book, if a matching one is found! 0 otherwise.
*/
export function getBookID(refString) {
refString = refString.replaceAll(/\s+/g,' ').trim();
const found = Object.keys(ntBooksDict).find((k)=>(ntBooksDict[k].name.toLowerCase() == refString.toLowerCase()) || ntBooksDict[k].syn.map((s)=>s.toLowerCase().replaceAll("_", " ")).includes(refString.toLowerCase().replaceAll("_"," ")));
if (found)
return parseInt(found);
else
return 0;
}
/**
*
* @param {string} refString -- a NT book name
* @returns {string} the abbreviation of the book we're using, standardize searches and grouping, etc. If none, returns empty string.
*/
export function getBookAbbrev(refString){
const bookID = getBookID(refString);
if(bookID)
return ntBooksDict[bookID].abbrev;
else
return '';
}
//mylog("importing gospelPars...");
/**
*
* @param {string} gospelRef -- the reference to a gospel verse (E.g., "Matt 3:17")
* @param {number} primaryGospel -- which gospels, if any, to treat as "primary", which affects the sorting order of the results.
* This Should be assigned to one of the enum values of the "gospels" const above. Default is "gospels.NONE" (=4),
* which uses the order in which Aland arranged the pericopes.
* If set to another option, the results will be sorted according to the order of that gospel's texts.
* @param {boolean} hideSolos - if true, results will exclude Aland's pericope groups which have only one column (no parallels)
* @returns {number[]} an array of integers, each of which corresponds to the pericope numbers assigned by
* Aland's Synopsis Quattuor Evangeliorum, which contain the given NT text.
*/
export function getAlandPericopeNumbers(gospelRef, primaryGospel=gospels.NONE, hideNonPrimary=false, hideSolos=false, hideNonPrimarySolos=false){
//mylog("getAlandPericopeNumbers("+ gospelRef+")");
const bookObj = bibleRefUtils.getBookChapVerseFromRef(gospelRef);
const bookAbbrev = getBookAbbrev(bookObj.book);
//mylog("trying to get bookabbrev from " + bookObj.book + ", and got: " + bookAbbrev);
const found = filterSortAlandPericopes(alandSynopsis.pericopes.filter((obj)=>{
//mylog("...checking alandSynopsis.pericopes[" + k + "][" + bookAbbrev +"].ref")
//mylog(alandSynopsis.pericopes[k][bookAbbrev]);
if (obj[bookAbbrev] && obj[bookAbbrev].ref){
const refsMinusBook = obj[bookAbbrev].ref.split(";")
//mylog('refsMinusBook = ' + refsMinusBook)
for (const theSynRef of refsMinusBook){
if (bibleRefUtils.refIncludes(bookAbbrev+" "+theSynRef,bookAbbrev + " " +bookObj.chap + (bookObj.v ? ":" +bookObj.v : '')))
return true;
else{
// mylog("..." + gospelRef +" NOT found in " +bookAbbrev+" "+theSynRef)
// return false;
}
}
// mylog("didn't find match for " + gospelRef)
return false;
}
else {
//check "other" refs
// mylog("checking 'other' for "+ gospelRef);
let otherArray = obj.other.ref ? obj.other.ref.split(";") : [];
//mylog("other array = ");
//mylog(otherArray);
if (otherArray.filter((otherRef)=>bibleRefUtils.refIncludes(otherRef,gospelRef)).length > 0) {
// mylog("found 'other' ref for " +gospelRef + " in " + obj.pericope)
//mylog(otherArray)
return true;
}
else {
// mylog("Failed to find gospel or 'other' for pericope " + gospelRef)
return false;
}
}
}).map((p)=>p.pericope),primaryGospel,hideNonPrimary,hideSolos);
mylog("AlandNumbers found: " + found.join(','));
return found ? found : [];
}
//NB: in place!
/**
* @description Sorts, in place, an array of Aland pericope numbers according to the arrangement of the selected gospel.
* For pericopes which lack a text from the given gospel, these are placed at the end of the list
* @param {number[]} alandArray -- array of pericope numbers, using the numbering system of Aland.
* @param {number} primaryGospel -- one of the enum values in `gospels` enum in the alandSynopsis.js module.
* @returns
*/
export function sortAlandPericopes(alandArray,primaryGospel=gospels.NONE ){
return alandArray.sort((a,b)=>{
//mylog("sortAlandPericopes.sort("+a+","+b+")");
// mylog("sortAlandPericopes.sort/lookedup("+alandSynopsis.lookupPericope(a).pericope+","+alandSynopsis.lookupPericope(b).pericope+")");
return sortByPrimaryFunc(alandSynopsis.lookupPericope(a),
alandSynopsis.lookupPericope(b),
primaryGospel)});
}
//not in place!
/**
*
* @param {number[]} alandArray
* @param {number} primaryGospel
* @param {boolean} hideNonPrimary
* @param {boolean} hideSolos
* @param {boolean} hideNonPrimarySolos
* @returns {number[]}
*/
export function filterAlandPericopes(alandArray,primaryGospel=gospels.NONE,
hideNonPrimary=true,hideSolos=false,hideNonPrimarySolos=false){
return alandArray.filter(
(pNum)=>!hideNonPrimary || alandSynopsis.isPrimaryPericope(pNum,primaryGospel)).filter((pNum=>{
let retVal = true;
if ((!hideSolos) && primaryGospel==gospels.NONE && hideNonPrimarySolos) {
//same as hideSolos:
hideSolos=true
}
if( hideSolos || hideNonPrimarySolos) {
const p = alandSynopsis.lookupPericope(pNum);
// mylog('filterSortPers: checking for solos for pericope ' +pNum);
if (hideSolos || (
primaryGospel==gospels.MATTHEW && !p.Matt.primary ||
primaryGospel==gospels.MARK && !p.Mark.primary ||
primaryGospel==gospels.LUKE && !p.Luke.primary ||
primaryGospel==gospels.JOHN && !p.John.primary
) ) { //eliminate all single-column sections:
let numCols = 0;
for (const ref of [p.Matt.ref, p.Mark.ref, p.Luke.ref, p.John.ref]) {
if (ref && ref.length) {
numCols++;
}
}
if (numCols <= 1) {
retVal = false;
}
}
// mylog("hideSolos filter for pericope + " + pNum +" --> " + numCols + " cols found.")
}
return retVal;
}));
}
//not in place!
/**
*
* @param {number[]} alandArray
* @param {number} primaryGospel
* @param {boolean} hideNonPrimary
* @param {boolean} hideSolos
* @param {boolean} hideNonPrimarySolos
* @returns {number[]}
*/
export function filterSortAlandPericopes(alandArray,primaryGospel=gospels.NONE,
hideNonPrimary=true,hideSolos=false,hideNonPrimarySolos=false){
return filterAlandPericopes(sortAlandPericopes([...alandArray],primaryGospel),primaryGospel,
hideNonPrimary,hideSolos,hideNonPrimarySolos);
}
/**
*
* @param {{pericope: number, title: string,
* Matt: { ref: string, primary: boolean },
* Mark: { ref: string , primary: boolean },
* Luke: { ref: string , primary: boolean },
* John: { ref:string , primary: boolean },
* other: { ref:string }}} a
* @param {{pericope: number, title: string,
* Matt: { ref: string, primary: boolean },
* Mark: { ref: string , primary: boolean },
* Luke: { ref: string , primary: boolean },
* John: { ref:string , primary: boolean },
* other: { ref:string }}} b
* @param {number} primary - one of the alandSynopsis.gospels enum values.
* @returns
*/
export function sortByPrimaryFunc(a,b, primaryGospel=gospels.NONE){
let retVal = 0;
// const logMsg = "sortByPrimaryFunc("+[a,b].join(",")+")";
let logMsg = "sortByPrimaryFunc(";
//mylog(logMsg);
if (primaryGospel==gospels.MATTHEW){
if (a.Matt && a.Matt.ref && b.Matt && b.Matt.ref ) {
retVal = bibleRefUtils.sortChapVerseRefs(a.Matt.ref.split(";")[0],
b.Matt.ref.split(";")[0]);
}
else {
if (!b.Matt || ! b.Matt.ref){
retVal = 0; //a, but no b; leave the same
}
else {
retVal = 1; // b, but no a. reverse.
}
}
logMsg += ("[Matt " + a.Mark.ref+"], [Matt "+b.Mark.ref+"])");
}
else if (primaryGospel==gospels.MARK) {
if (a.Mark && a.Mark.ref && b.Mark && b.Mark.ref){
retVal = bibleRefUtils.sortChapVerseRefs(a.Mark.ref.split(";")[0],
b.Mark.ref.split(";")[0]);
}
else {
if (!b.Mark || ! b.Mark.ref){
retVal = 0; //no b, maybe a; leave the same
}
else {
retVal = 1; // b, but no a. reverse.
}
}
logMsg += ("[Mk " + a.Mark.ref+"], [Mark "+b.Mark.ref+"])");
// mylog(logMsg+"-->"+ retVal);
}
else if (primaryGospel==gospels.LUKE){
if (a.Luke && a.Luke.ref && b.Luke && b.Luke.ref){
retVal = bibleRefUtils.sortChapVerseRefs(a.Luke.ref.split(";")[0], b.Luke.ref.split(";")[0]);
logMsg+="Luke ("+[a.Luke.ref,b.Luke.ref].join(",") + ")";
}
else {
if (!b.Luke || ! b.Luke.ref){
retVal = 0; //a, but no b; leave the same
// mylog(logMsg+": HERE");
}
else {
retVal = 1; // b, but no a. reverse.
// mylog(logMsg+": THERE")
}
}
// mylog(logMsg + "w/ Lucan primacy, result = " + retVal);
logMsg += ("[Luke " + a.Mark.ref+"], [Luke "+b.Mark.ref+"])");
}
else if (primaryGospel==gospels.JOHN){
if (a.John && a.John.ref && b.John && b.John.ref) {
retVal = bibleRefUtils.sortChapVerseRefs(a.John.ref.split(";")[0], b.John.ref.split(";")[0]);
}
else {
if (!b.John || ! b.John.ref){
retVal = 0; //a, but no b; leave the same
}
else {
retVal = 1; // b, but no a. reverse.
}
}
logMsg += ("[John " + a.Mark.ref+"], [John "+b.Mark.ref+"])");
}
else{
retVal = parseInt(a.pericope) - parseInt(b.pericope);
}
// mylog(logMsg+" -- > " + retVal);
return retVal;
}
/**
*
* @param {number} alandPericopeNum
* @param {boolean} ignoreOthers - if true (default), we'll exclude any non-gospel NT parallels from return value. If false, other non-gospel NT parallels will be included.
* @returns {string[]} -- array of strings, each of which is an NT/gospels reference
*/
export function getAlandPericopeRefs(alandPericopeNum, ignoreOthers=true){
const pericope = alandSynopsis.pericopes.find((obj)=>obj.pericope == alandPericopeNum);
const refs = [];
if (pericope) {
for (const gospelAbbrev of ["Matt","Mark","Luke","John"]) {
if (pericope[gospelAbbrev].ref){
pericope[gospelAbbrev].ref.split(";").forEach((theRef)=>{
refs.push(gospelAbbrev.trim()+" "+theRef.trim());
})
}
}
if (!ignoreOthers){
if(pericope.other.ref){
pericope.other.ref.split(";").forEach((theRef)=>{
refs.push(theRef.trim());
})
}
}
}
else {
mylog("getAlandPericopeRefs("+alandPericopeNum+") found NO RESULTS!")
}
return refs;
}
/**
*
* @param {string} refString -- a reference to a NT single verse, e.g., "1 Cor 2:11"
* @returns {number[]} An array of numbers, each of which is a section (1-18) in Aland's Synopsis where the verse appears, if at all.
* If the verse appears in no such section, returns an empty array.
*/
export function getAlandSection(refString,sortByGospel=gospels.NONE){
mylog("getAlandSection("+refString+")");
refString = bibleRefUtils.cleanString(refString);
const found = alandSynopsis.sections.filter(
(sec)=>sec.refs.split(';').find(
(secRef)=>secRef ? bibleRefUtils.refIncludes(secRef,refString) : false));
if (found)
return found.map((sec)=>sec.section).sort((a,b)=>{
return sortByPrimaryFunc(a,b,sortByGospel)
});
else return [];
}
export function getBookNameBySyn(syn){
const id = getBookID(syn)
const name = getBookName(id);
mylog("getBookNameBySyn("+syn+")->id:"+id+", name:" +name)
return name;
}
//move to alandSynopsis object!
/**
*
* @param {number} node
* @returns {string}
*/
export function getBookName(node){
//console.log("=========================================================");
//mylog("HERE WE ARE!!========")
// mylog("=========================================================");
if (!ntBooksDict[String(node)]){
// mylog("did not find " + node + " in ntBooksDict");
}
const name = ntBooksDict[node] ? ntBooksDict[node].name : ''
//mylog("getBookName("+node+")-->'" + name+"'");
return name;
}
export {ntBooksDict, alandSynopsis, gospels}
/*export default {
getBookName, getAlandSection, getAlandPericopeRefs, getBookChapVerseFromRef, getBookID, getBookAbbrev, getAlandPericopeNumbers, ntBooksDict, alandSynopsis
}*/
export const testing = {
// getBookChapVerseFromRef, createNumArrayFromStringListRange, cleanNumString, splitBookChap,sortChapVerseFunc, refIncludes
}
export const utils = testing