codexparser 0.1.90 → 0.1.91

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/CodexParser.js +212 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexparser",
3
- "version": "0.1.90",
3
+ "version": "0.1.91",
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": {
@@ -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}${passage.version ? " " + passage.version : ""}`
356
- : `${value} ${ref}${passage.version ? " " + passage.version : ""}`
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 = parser.combine(passages)
856
+ const combined = self.combine(passages)
855
857
  combinedPassages.push(combined)
856
858
  }
857
859
  }
858
860
  } else {
859
- const combined = parser.combine(bookPassages)
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.replace(/:/g, ".").replace(/[,;]/g, ".")}`,
1244
+ hash: `${combined.book.toLowerCase()}_${chapterString
1245
+ .replace(/:/g, ".")
1246
+ .replace(/-/g, ".")
1247
+ .replace(/[,;]/g, ".")}`,
1042
1248
  }
1043
1249
 
1044
1250
  combined.start = {