codexparser 0.1.23 → 0.1.25

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 +133 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexparser",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
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": {
@@ -232,6 +232,7 @@ class CodexParser {
232
232
 
233
233
  this.passages = this.found.map((passage) => {
234
234
  const book = this.bookify(passage.book)
235
+ const testament = this.bible.old.find((bible) => bible === book) ? "old" : "new"
235
236
  // Initialize the parsed passage object
236
237
  const parsedPassage = {
237
238
  original: passage.book + " " + passage.reference,
@@ -239,9 +240,9 @@ class CodexParser {
239
240
  chapter: null,
240
241
  verses: [], // Verse stored as an array
241
242
  type: null, // Set type based on reference
242
- testament: this.bible.old.find((bible) => bible === book) ? "old" : "new",
243
+ testament: testament,
243
244
  index: passage.index,
244
- version: this._handleVersion(passage.version),
245
+ version: this._handleVersion(passage.version, testament),
245
246
  }
246
247
 
247
248
  // Split reference by commas to handle multiple ranges or verses (e.g., "Ge 27:27-29,39-41")
@@ -504,6 +505,133 @@ class CodexParser {
504
505
  }
505
506
  }
506
507
 
508
+ /**
509
+ * Combine multiple passages into one. The method checks for duplicates, merges overlapping or adjacent ranges,
510
+ * and builds the original and scripture properties.
511
+ * **This method will always combine based on English versification. LXX and MT versifications will be reflected in the combined passage.passages.versification.**
512
+ * This method will fail if the passages are not to the same book and chapter.
513
+ * @param {array} passages - An array of passage objects to combine.
514
+ * @return {object} The combined passage object.
515
+ */
516
+ combine(passages) {
517
+ const noDuplicates = [...new Set(passages.map((p) => p.book + " " + p.chapter))]
518
+ if (noDuplicates.length > 1) {
519
+ throw new Error("Passages are not from the same book and chapter.")
520
+ }
521
+ const newPassages = []
522
+ passages.forEach((passageSet) => {
523
+ passageSet.passages.forEach((passage) => {
524
+ if (passage.versification) {
525
+ newPassages.push(passage.book + " " + passage.versification.eng)
526
+ } else {
527
+ newPassages.push(passage.book + " " + passage.chapter + ":" + passage.verse)
528
+ }
529
+ })
530
+ })
531
+ const noDuplicates2 = [...new Set(newPassages)]
532
+ const parsed = this.parse(noDuplicates2.join(" // ")).getPassages()
533
+ return this.join(parsed)
534
+ }
535
+
536
+ /**
537
+ * Combine multiple passages into one. The method checks for duplicates, merges overlapping or adjacent ranges,
538
+ * and builds the original and scripture properties.
539
+ *
540
+ * @param {array} passages - An array of passage objects to combine.
541
+ * @return {object} The combined passage object.
542
+ */
543
+ join(passages) {
544
+ const newObject = { ...passages[0] }
545
+
546
+ for (let i = 1; i < passages.length; i++) {
547
+ // Combine passages, but check for duplicates
548
+ passages[i].passages.forEach((passage) => {
549
+ // Add passage only if it's not already in newObject.passages
550
+ const isDuplicate = newObject.passages.some(
551
+ (p) => p.book === passage.book && p.chapter === passage.chapter && p.verse === passage.verse
552
+ )
553
+ if (!isDuplicate) {
554
+ newObject.passages = newObject.passages.concat(passage)
555
+ }
556
+ })
557
+ const verses = passages[i].verses
558
+ for (let j = 0; j < verses.length; j++) {
559
+ const verse = verses[j]
560
+ newObject.verses = newObject.verses.concat(verse)
561
+ }
562
+ }
563
+
564
+ // Remove lone numbers that are part of a range
565
+ newObject.verses = newObject.verses.filter((v, i, arr) => {
566
+ if (!v.includes("-")) {
567
+ const num = parseInt(v, 10)
568
+ return !arr.some((item) => {
569
+ if (item.includes("-")) {
570
+ const [start, end] = item.split("-").map(Number)
571
+ return num >= start && num <= end
572
+ }
573
+ return false
574
+ })
575
+ }
576
+ return true // Keep ranges
577
+ })
578
+
579
+ // Convert to a Set to remove duplicates
580
+ newObject.verses = [...new Set(newObject.verses)]
581
+
582
+ // Helper function to merge overlapping or adjacent ranges
583
+ const mergeRanges = (verses) => {
584
+ const rangeObjects = verses.map((v) => {
585
+ if (v.includes("-")) {
586
+ const [start, end] = v.split("-").map(Number)
587
+ return { start, end }
588
+ } else {
589
+ const num = Number(v)
590
+ return { start: num, end: num }
591
+ }
592
+ })
593
+
594
+ // Sort the ranges by starting number
595
+ rangeObjects.sort((a, b) => a.start - b.start)
596
+
597
+ const merged = []
598
+ let currentRange = rangeObjects[0]
599
+
600
+ for (let i = 1; i < rangeObjects.length; i++) {
601
+ const nextRange = rangeObjects[i]
602
+
603
+ if (currentRange.end >= nextRange.start - 1) {
604
+ // Overlapping or adjacent, merge the ranges
605
+ currentRange.end = Math.max(currentRange.end, nextRange.end)
606
+ } else {
607
+ // No overlap, push the current range and start a new one
608
+ merged.push(currentRange)
609
+ currentRange = nextRange
610
+ }
611
+ }
612
+
613
+ // Push the last range
614
+ merged.push(currentRange)
615
+
616
+ // Convert merged ranges back to strings
617
+ return merged.map(({ start, end }) => (start === end ? `${start}` : `${start}-${end}`))
618
+ }
619
+
620
+ // Merge and sort the ranges
621
+ newObject.verses = mergeRanges(newObject.verses)
622
+
623
+ // Build the original and scripture properties
624
+ newObject.original = newObject.book + " " + newObject.chapter + ":" + newObject.verses.join(",")
625
+ newObject.scripture = {
626
+ passage: newObject.book + " " + newObject.chapter + ":" + newObject.verses.join(","),
627
+ cv: newObject.chapter + ":" + newObject.verses.join(","),
628
+ hash: newObject.book + "_" + newObject.chapter + "." + newObject.verses.join("."),
629
+ }
630
+ newObject.scripture.hash = newObject.scripture.hash.toLowerCase()
631
+
632
+ return newObject
633
+ }
634
+
507
635
  _isValid(passage, reference) {
508
636
  const singleChapterBook = this.singleChapterBook.find((bible) => bible[passage.book])
509
637
  if (!passage.verses) {
@@ -541,11 +669,11 @@ class CodexParser {
541
669
  }
542
670
  return true
543
671
  }
544
- _handleVersion(version) {
672
+ _handleVersion(version, testament) {
545
673
  if (!version) {
546
674
  return null
547
675
  }
548
- if (version.toLowerCase() === "lxx") {
676
+ if (version.toLowerCase() === "lxx" && testament.toLowerCase() === "old") {
549
677
  return {
550
678
  name: "Septuagint",
551
679
  value: "LXX",
@@ -553,7 +681,7 @@ class CodexParser {
553
681
  }
554
682
  }
555
683
 
556
- if (version.toLowerCase() === "mt") {
684
+ if (version.toLowerCase() === "mt" && testament.toLowerCase() === "old") {
557
685
  return {
558
686
  name: "Masoretic Text",
559
687
  value: "MT",