codexparser 0.1.90 → 0.1.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/CodexParser.js +349 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codexparser",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.92",
|
|
4
4
|
"description": "This is a Javascript Bible parser and text scanner. It will search through texts and collate all scripture references into an array and parse them into objects, and it will parse passages into objects by book, chapter, verse, and testament. ",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
package/src/CodexParser.js
CHANGED
|
@@ -352,8 +352,10 @@ class CodexParser {
|
|
|
352
352
|
const { value, abbr } = sblEntry[1]
|
|
353
353
|
const ref = passage.reference.replace(/\s*(LXX|MT)$/i, "").trim()
|
|
354
354
|
parsedPassage.abbr = abbr
|
|
355
|
-
? `${value}. ${ref}${
|
|
356
|
-
|
|
355
|
+
? `${value}. ${ref}${
|
|
356
|
+
parsedPassage.version.value !== "ENG" ? " " + parsedPassage.version.value : ""
|
|
357
|
+
}`
|
|
358
|
+
: `${value} ${ref}${parsedPassage.version.value !== "ENG" ? " " + parsedPassage.version.value : ""}`
|
|
357
359
|
} else {
|
|
358
360
|
parsedPassage.abbr = parsedPassage.original
|
|
359
361
|
}
|
|
@@ -803,6 +805,7 @@ class CodexParser {
|
|
|
803
805
|
*/
|
|
804
806
|
getPassages() {
|
|
805
807
|
const passagesArray = [...this.passages]
|
|
808
|
+
const self = this
|
|
806
809
|
|
|
807
810
|
passagesArray.first = function () {
|
|
808
811
|
return this.length > 0 ? this[0] : null
|
|
@@ -823,7 +826,6 @@ class CodexParser {
|
|
|
823
826
|
return [...this]
|
|
824
827
|
}
|
|
825
828
|
|
|
826
|
-
const parser = new CodexParser()
|
|
827
829
|
const groupedByBook = new Map()
|
|
828
830
|
|
|
829
831
|
this.forEach((passage) => {
|
|
@@ -851,12 +853,12 @@ class CodexParser {
|
|
|
851
853
|
if (passages.length === 1) {
|
|
852
854
|
combinedPassages.push({ ...passages[0] })
|
|
853
855
|
} else {
|
|
854
|
-
const combined =
|
|
856
|
+
const combined = self.combine(passages)
|
|
855
857
|
combinedPassages.push(combined)
|
|
856
858
|
}
|
|
857
859
|
}
|
|
858
860
|
} else {
|
|
859
|
-
const combined =
|
|
861
|
+
const combined = self.combine(bookPassages)
|
|
860
862
|
combinedPassages.push(combined)
|
|
861
863
|
}
|
|
862
864
|
}
|
|
@@ -864,6 +866,207 @@ class CodexParser {
|
|
|
864
866
|
return combinedPassages
|
|
865
867
|
}
|
|
866
868
|
|
|
869
|
+
passagesArray.getVersion = function (targetVersion) {
|
|
870
|
+
const targetAbbr = targetVersion.toLowerCase() === "bhs" ? "mt" : targetVersion.toLowerCase()
|
|
871
|
+
let versionObj
|
|
872
|
+
if (targetAbbr === "eng") {
|
|
873
|
+
versionObj = { name: "English", value: "ENG", abbreviation: "eng" }
|
|
874
|
+
} else if (targetAbbr === "mt") {
|
|
875
|
+
versionObj = { name: "Masoretic Text", value: "MT", abbreviation: "mt" }
|
|
876
|
+
} else if (targetAbbr === "lxx") {
|
|
877
|
+
versionObj = { name: "Septuagint", value: "LXX", abbreviation: "lxx" }
|
|
878
|
+
} else {
|
|
879
|
+
throw new Error("Invalid version: must be one of 'eng', 'mt', 'bhs', 'lxx'")
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const converted = this.map((passage) => {
|
|
883
|
+
const cloned = JSON.parse(JSON.stringify(passage))
|
|
884
|
+
cloned.version = versionObj
|
|
885
|
+
|
|
886
|
+
cloned.passages.forEach((sub) => {
|
|
887
|
+
if (sub.versification && sub.versification[targetAbbr]) {
|
|
888
|
+
const [ch, v] = sub.versification[targetAbbr].split(":").map(Number)
|
|
889
|
+
sub.chapter = ch
|
|
890
|
+
sub.verse = v
|
|
891
|
+
}
|
|
892
|
+
// else remain unchanged
|
|
893
|
+
})
|
|
894
|
+
|
|
895
|
+
// Recompute summary fields
|
|
896
|
+
cloned.passages.sort((a, b) => a.chapter - b.chapter || a.verse - b.verse)
|
|
897
|
+
|
|
898
|
+
if (cloned.passages.length > 0) {
|
|
899
|
+
cloned.start = {
|
|
900
|
+
book: cloned.book,
|
|
901
|
+
chapter: cloned.passages[0].chapter,
|
|
902
|
+
verse: cloned.passages[0].verse,
|
|
903
|
+
}
|
|
904
|
+
cloned.end = {
|
|
905
|
+
book: cloned.book,
|
|
906
|
+
chapter: cloned.passages[cloned.passages.length - 1].chapter,
|
|
907
|
+
verse: cloned.passages[cloned.passages.length - 1].verse,
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const chapterVersesMap = {}
|
|
912
|
+
cloned.passages.forEach((p) => {
|
|
913
|
+
if (!chapterVersesMap[p.chapter]) chapterVersesMap[p.chapter] = new Set()
|
|
914
|
+
chapterVersesMap[p.chapter].add(p.verse)
|
|
915
|
+
})
|
|
916
|
+
|
|
917
|
+
const sortedChs = Object.keys(chapterVersesMap)
|
|
918
|
+
.map(Number)
|
|
919
|
+
.sort((a, b) => a - b)
|
|
920
|
+
const chapterStrs = []
|
|
921
|
+
|
|
922
|
+
const mergeFunc = (verses) => {
|
|
923
|
+
const sorted = [...verses].sort((a, b) => a - b)
|
|
924
|
+
const merged = []
|
|
925
|
+
if (sorted.length === 0) return merged
|
|
926
|
+
let start = sorted[0]
|
|
927
|
+
let end = sorted[0]
|
|
928
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
929
|
+
if (sorted[i] === end + 1) {
|
|
930
|
+
end = sorted[i]
|
|
931
|
+
} else {
|
|
932
|
+
merged.push(start === end ? `${start}` : `${start}-${end}`)
|
|
933
|
+
start = end = sorted[i]
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
merged.push(start === end ? `${start}` : `${start}-${end}`)
|
|
937
|
+
return merged
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
sortedChs.forEach((ch) => {
|
|
941
|
+
const vs = Array.from(chapterVersesMap[ch])
|
|
942
|
+
.filter((v) => v > 0)
|
|
943
|
+
.sort((a, b) => a - b)
|
|
944
|
+
if (vs.length > 0) {
|
|
945
|
+
const merged = mergeFunc(vs)
|
|
946
|
+
chapterStrs.push(`${ch}:${merged.join(",")}`)
|
|
947
|
+
}
|
|
948
|
+
})
|
|
949
|
+
|
|
950
|
+
if (chapterStrs.length === 0) {
|
|
951
|
+
return cloned // no verses, perhaps error but return as is
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
const firstCh = sortedChs[0]
|
|
955
|
+
const lastCh = sortedChs[sortedChs.length - 1]
|
|
956
|
+
cloned.chapter = firstCh
|
|
957
|
+
|
|
958
|
+
const mergedFirst = mergeFunc(chapterVersesMap[firstCh] || new Set())
|
|
959
|
+
cloned.verses = mergedFirst
|
|
960
|
+
|
|
961
|
+
if (firstCh !== lastCh) {
|
|
962
|
+
cloned.type = this.MULTI_CHAPTER_RANGE
|
|
963
|
+
cloned.to = {
|
|
964
|
+
book: cloned.book,
|
|
965
|
+
chapter: lastCh,
|
|
966
|
+
verses: mergeFunc(chapterVersesMap[lastCh] || new Set()),
|
|
967
|
+
}
|
|
968
|
+
cloned.original = `${cloned.book} ${chapterStrs.join("; ")}`
|
|
969
|
+
} else {
|
|
970
|
+
const hasRangeOrMultiple =
|
|
971
|
+
mergedFirst.length > 1 || (mergedFirst.length === 1 && mergedFirst[0].includes("-"))
|
|
972
|
+
cloned.type = hasRangeOrMultiple ? this.CHAPTER_VERSE_RANGE : this.CHAPTER_VERSE
|
|
973
|
+
if (cloned.to) delete cloned.to
|
|
974
|
+
cloned.original = `${cloned.book} ${chapterStrs[0]}`
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
const chString = chapterStrs.join("; ")
|
|
978
|
+
cloned.scripture = {
|
|
979
|
+
passage: `${cloned.book} ${chString}`,
|
|
980
|
+
cv: chString,
|
|
981
|
+
hash: `${cloned.book.toLowerCase()}_${chString
|
|
982
|
+
.replace(/:/g, ".")
|
|
983
|
+
.replace(/-/g, ".")
|
|
984
|
+
.replace(/[,; ]/g, ".")}`,
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Set abbr
|
|
988
|
+
const sblEntry = Object.entries(self.sblAbbreviations).find(
|
|
989
|
+
([key]) => key.toLowerCase() === cloned.book.toLowerCase()
|
|
990
|
+
)
|
|
991
|
+
const suffix = versionObj.abbreviation === "eng" ? "" : ` ${versionObj.value}`
|
|
992
|
+
if (sblEntry) {
|
|
993
|
+
const { value, abbr } = sblEntry[1]
|
|
994
|
+
cloned.abbr = abbr
|
|
995
|
+
? `${value}. ${cloned.scripture.cv}${suffix}`
|
|
996
|
+
: `${value} ${cloned.scripture.cv}${suffix}`
|
|
997
|
+
} else {
|
|
998
|
+
cloned.abbr = `${cloned.book} ${cloned.scripture.cv}${suffix}`
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
return cloned
|
|
1002
|
+
})
|
|
1003
|
+
|
|
1004
|
+
const newArray = [...converted]
|
|
1005
|
+
|
|
1006
|
+
newArray.first = function () {
|
|
1007
|
+
return this.length > 0 ? this[0] : null
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
newArray.oldTestament = function () {
|
|
1011
|
+
return this.filter((passage) => passage.testament === "old")
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
newArray.newTestament = function () {
|
|
1015
|
+
return this.filter((passage) => passage.testament === "new")
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
newArray.combine = function (options = {}) {
|
|
1019
|
+
const { book = true, chapter = true } = options
|
|
1020
|
+
|
|
1021
|
+
if (!book) {
|
|
1022
|
+
return [...this]
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
const groupedByBook = new Map()
|
|
1026
|
+
|
|
1027
|
+
this.forEach((passage) => {
|
|
1028
|
+
const bookKey = passage.book
|
|
1029
|
+
if (!groupedByBook.has(bookKey)) {
|
|
1030
|
+
groupedByBook.set(bookKey, [])
|
|
1031
|
+
}
|
|
1032
|
+
groupedByBook.get(bookKey).push(passage)
|
|
1033
|
+
})
|
|
1034
|
+
|
|
1035
|
+
const combinedPassages = []
|
|
1036
|
+
|
|
1037
|
+
for (const [book, bookPassages] of groupedByBook) {
|
|
1038
|
+
if (chapter) {
|
|
1039
|
+
const groupedByChapter = new Map()
|
|
1040
|
+
bookPassages.forEach((passage) => {
|
|
1041
|
+
const chapterKey = `${passage.book}-${passage.chapter}`
|
|
1042
|
+
if (!groupedByChapter.has(chapterKey)) {
|
|
1043
|
+
groupedByChapter.set(chapterKey, [])
|
|
1044
|
+
}
|
|
1045
|
+
groupedByChapter.get(chapterKey).push(passage)
|
|
1046
|
+
})
|
|
1047
|
+
|
|
1048
|
+
for (const passages of groupedByChapter.values()) {
|
|
1049
|
+
if (passages.length === 1) {
|
|
1050
|
+
combinedPassages.push({ ...passages[0] })
|
|
1051
|
+
} else {
|
|
1052
|
+
const combined = self.combine(passages)
|
|
1053
|
+
combinedPassages.push(combined)
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
} else {
|
|
1057
|
+
const combined = self.combine(bookPassages)
|
|
1058
|
+
combinedPassages.push(combined)
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
return combinedPassages
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
newArray.getVersion = passagesArray.getVersion
|
|
1066
|
+
|
|
1067
|
+
return newArray
|
|
1068
|
+
}
|
|
1069
|
+
|
|
867
1070
|
return passagesArray
|
|
868
1071
|
}
|
|
869
1072
|
|
|
@@ -1038,7 +1241,10 @@ class CodexParser {
|
|
|
1038
1241
|
combined.scripture = {
|
|
1039
1242
|
passage: `${combined.book} ${chapterString}`,
|
|
1040
1243
|
cv: chapterString,
|
|
1041
|
-
hash: `${combined.book.toLowerCase()}_${chapterString
|
|
1244
|
+
hash: `${combined.book.toLowerCase()}_${chapterString
|
|
1245
|
+
.replace(/:/g, ".")
|
|
1246
|
+
.replace(/-/g, ".")
|
|
1247
|
+
.replace(/[,;]/g, ".")}`,
|
|
1042
1248
|
}
|
|
1043
1249
|
|
|
1044
1250
|
combined.start = {
|
|
@@ -1080,6 +1286,143 @@ class CodexParser {
|
|
|
1080
1286
|
combined.abbr = `${combined.book} ${combined.scripture.cv}`
|
|
1081
1287
|
}
|
|
1082
1288
|
|
|
1289
|
+
const self = this
|
|
1290
|
+
combined.getVersion = function (targetVersion) {
|
|
1291
|
+
const cloned = JSON.parse(JSON.stringify(this))
|
|
1292
|
+
const targetAbbr = targetVersion.toLowerCase() === "bhs" ? "mt" : targetVersion.toLowerCase()
|
|
1293
|
+
let versionObj
|
|
1294
|
+
if (targetAbbr === "eng") {
|
|
1295
|
+
versionObj = { name: "English", value: "ENG", abbreviation: "eng" }
|
|
1296
|
+
} else if (targetAbbr === "mt") {
|
|
1297
|
+
versionObj = { name: "Masoretic Text", value: "MT", abbreviation: "mt" }
|
|
1298
|
+
} else if (targetAbbr === "lxx") {
|
|
1299
|
+
versionObj = { name: "Septuagint", value: "LXX", abbreviation: "lxx" }
|
|
1300
|
+
} else {
|
|
1301
|
+
throw new Error("Invalid version: must be one of 'eng', 'mt', 'bhs', 'lxx'")
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
cloned.version = versionObj
|
|
1305
|
+
|
|
1306
|
+
cloned.passages.forEach((sub) => {
|
|
1307
|
+
if (sub.versification && sub.versification[targetAbbr]) {
|
|
1308
|
+
const [ch, v] = sub.versification[targetAbbr].split(":").map(Number)
|
|
1309
|
+
sub.chapter = ch
|
|
1310
|
+
sub.verse = v
|
|
1311
|
+
}
|
|
1312
|
+
// else remain unchanged
|
|
1313
|
+
})
|
|
1314
|
+
|
|
1315
|
+
// Recompute summary fields
|
|
1316
|
+
cloned.passages.sort((a, b) => a.chapter - b.chapter || a.verse - b.verse)
|
|
1317
|
+
|
|
1318
|
+
if (cloned.passages.length > 0) {
|
|
1319
|
+
cloned.start = {
|
|
1320
|
+
book: cloned.book,
|
|
1321
|
+
chapter: cloned.passages[0].chapter,
|
|
1322
|
+
verse: cloned.passages[0].verse,
|
|
1323
|
+
}
|
|
1324
|
+
cloned.end = {
|
|
1325
|
+
book: cloned.book,
|
|
1326
|
+
chapter: cloned.passages[cloned.passages.length - 1].chapter,
|
|
1327
|
+
verse: cloned.passages[cloned.passages.length - 1].verse,
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
const chapterVersesMap = {}
|
|
1332
|
+
cloned.passages.forEach((p) => {
|
|
1333
|
+
if (!chapterVersesMap[p.chapter]) chapterVersesMap[p.chapter] = new Set()
|
|
1334
|
+
chapterVersesMap[p.chapter].add(p.verse)
|
|
1335
|
+
})
|
|
1336
|
+
|
|
1337
|
+
const sortedChs = Object.keys(chapterVersesMap)
|
|
1338
|
+
.map(Number)
|
|
1339
|
+
.sort((a, b) => a - b)
|
|
1340
|
+
const chapterStrs = []
|
|
1341
|
+
|
|
1342
|
+
const mergeFunc = (verses) => {
|
|
1343
|
+
const sorted = [...verses].sort((a, b) => a - b)
|
|
1344
|
+
const merged = []
|
|
1345
|
+
if (sorted.length === 0) return merged
|
|
1346
|
+
let start = sorted[0]
|
|
1347
|
+
let end = sorted[0]
|
|
1348
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
1349
|
+
if (sorted[i] === end + 1) {
|
|
1350
|
+
end = sorted[i]
|
|
1351
|
+
} else {
|
|
1352
|
+
merged.push(start === end ? `${start}` : `${start}-${end}`)
|
|
1353
|
+
start = end = sorted[i]
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
merged.push(start === end ? `${start}` : `${start}-${end}`)
|
|
1357
|
+
return merged
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
sortedChs.forEach((ch) => {
|
|
1361
|
+
const vs = Array.from(chapterVersesMap[ch])
|
|
1362
|
+
.filter((v) => v > 0)
|
|
1363
|
+
.sort((a, b) => a - b)
|
|
1364
|
+
if (vs.length > 0) {
|
|
1365
|
+
const merged = mergeFunc(vs)
|
|
1366
|
+
chapterStrs.push(`${ch}:${merged.join(",")}`)
|
|
1367
|
+
}
|
|
1368
|
+
})
|
|
1369
|
+
|
|
1370
|
+
if (chapterStrs.length === 0) {
|
|
1371
|
+
return cloned // no verses, perhaps error but return as is
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
const firstCh = sortedChs[0]
|
|
1375
|
+
const lastCh = sortedChs[sortedChs.length - 1]
|
|
1376
|
+
cloned.chapter = firstCh
|
|
1377
|
+
|
|
1378
|
+
const mergedFirst = mergeFunc(chapterVersesMap[firstCh] || new Set())
|
|
1379
|
+
cloned.verses = mergedFirst
|
|
1380
|
+
|
|
1381
|
+
if (firstCh !== lastCh) {
|
|
1382
|
+
cloned.type = "multi_chapter_verse_range"
|
|
1383
|
+
cloned.to = {
|
|
1384
|
+
book: cloned.book,
|
|
1385
|
+
chapter: lastCh,
|
|
1386
|
+
verses: mergeFunc(chapterVersesMap[lastCh] || new Set()),
|
|
1387
|
+
}
|
|
1388
|
+
cloned.original = `${cloned.book} ${chapterStrs.join("; ")}`
|
|
1389
|
+
} else {
|
|
1390
|
+
const hasRangeOrMultiple =
|
|
1391
|
+
mergedFirst.length > 1 || (mergedFirst.length === 1 && mergedFirst[0].includes("-"))
|
|
1392
|
+
cloned.type = hasRangeOrMultiple ? "chapter_verse_range" : "chapter_verse"
|
|
1393
|
+
if (cloned.to) delete cloned.to
|
|
1394
|
+
cloned.original = `${cloned.book} ${chapterStrs[0]}`
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
const chString = chapterStrs.join("; ")
|
|
1398
|
+
cloned.scripture = {
|
|
1399
|
+
passage: `${cloned.book} ${chString}`,
|
|
1400
|
+
cv: chString,
|
|
1401
|
+
hash: `${cloned.book.toLowerCase()}_${chString
|
|
1402
|
+
.replace(/:/g, ".")
|
|
1403
|
+
.replace(/-/g, ".")
|
|
1404
|
+
.replace(/[,; ]/g, ".")}`,
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// Set abbr
|
|
1408
|
+
const sblEntry = Object.entries(self.sblAbbreviations).find(
|
|
1409
|
+
([key]) => key.toLowerCase() === cloned.book.toLowerCase()
|
|
1410
|
+
)
|
|
1411
|
+
const suffix = versionObj.abbreviation === "eng" ? "" : ` ${versionObj.value}`
|
|
1412
|
+
if (sblEntry) {
|
|
1413
|
+
const { value, abbr } = sblEntry[1]
|
|
1414
|
+
cloned.abbr = abbr
|
|
1415
|
+
? `${value}. ${cloned.scripture.cv}${suffix}`
|
|
1416
|
+
: `${value} ${cloned.scripture.cv}${suffix}`
|
|
1417
|
+
} else {
|
|
1418
|
+
cloned.abbr = `${cloned.book} ${cloned.scripture.cv}${suffix}`
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
cloned.getVersion = this.getVersion
|
|
1422
|
+
|
|
1423
|
+
return cloned
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1083
1426
|
return combined
|
|
1084
1427
|
}
|
|
1085
1428
|
|