codexparser 0.1.28 → 0.1.30

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 +107 -74
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexparser",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
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": {
@@ -223,7 +223,7 @@ class CodexParser {
223
223
  i++
224
224
  }
225
225
  }
226
-
226
+ dump(this.found)
227
227
  return this // Return this instance for method chaining
228
228
  }
229
229
 
@@ -476,7 +476,20 @@ class CodexParser {
476
476
  * @return {array} The passages stored in the object.
477
477
  */
478
478
  getPassages() {
479
- return this.passages
479
+ // Return the array of passages and add a custom first() method to it
480
+ const passagesArray = [...this.passages] // Clone the array to avoid mutation
481
+
482
+ // Add first() method directly to the array
483
+ passagesArray.first = function () {
484
+ return this.length > 0 ? this[0] : null
485
+ }
486
+
487
+ return passagesArray
488
+ }
489
+
490
+ // New first() method that can be chained after getPassages()
491
+ first() {
492
+ return this.passages.length > 0 ? this.passages[0] : null
480
493
  }
481
494
 
482
495
  /**
@@ -542,10 +555,12 @@ class CodexParser {
542
555
  * @return {object} The combined passage object.
543
556
  */
544
557
  combine(passages) {
545
- const noDuplicates = [...new Set(passages.map((p) => p.book + " " + p.chapter))]
558
+ // Only check if passages are from the same book
559
+ const noDuplicates = [...new Set(passages.map((p) => p.book))]
546
560
  if (noDuplicates.length > 1) {
547
- throw new Error("Passages are not from the same book and chapter.")
561
+ throw new Error("Passages are not from the same book.")
548
562
  }
563
+
549
564
  const newPassages = []
550
565
  passages.forEach((passageSet) => {
551
566
  passageSet.passages.forEach((passage) => {
@@ -556,6 +571,7 @@ class CodexParser {
556
571
  }
557
572
  })
558
573
  })
574
+
559
575
  const noDuplicates2 = [...new Set(newPassages)]
560
576
  const parsed = this.parse(noDuplicates2.join(" // ")).getPassages()
561
577
  return this.join(parsed)
@@ -569,96 +585,113 @@ class CodexParser {
569
585
  * @return {object} The combined passage object.
570
586
  */
571
587
  join(passages) {
572
- const newObject = { ...passages[0] }
573
-
574
- for (let i = 1; i < passages.length; i++) {
575
- // Combine passages, but check for duplicates
576
- passages[i].passages.forEach((passage) => {
577
- // Add passage only if it's not already in newObject.passages
578
- const isDuplicate = newObject.passages.some(
579
- (p) => p.book === passage.book && p.chapter === passage.chapter && p.verse === passage.verse
580
- )
581
- if (!isDuplicate) {
582
- newObject.passages = newObject.passages.concat(passage)
583
- }
584
- })
585
- const verses = passages[i].verses
586
- for (let j = 0; j < verses.length; j++) {
587
- const verse = verses[j]
588
- newObject.verses = newObject.verses.concat(verse)
589
- }
590
- }
588
+ const newObject = { ...passages[0] } // Start with the first passage
591
589
 
592
- // Remove lone numbers that are part of a range
593
- newObject.verses = newObject.verses.filter((v, i, arr) => {
594
- if (!v.includes("-")) {
595
- const num = parseInt(v, 10)
596
- return !arr.some((item) => {
597
- if (item.includes("-")) {
598
- const [start, end] = item.split("-").map(Number)
599
- return num >= start && num <= end
600
- }
601
- return false
602
- })
603
- }
604
- return true // Keep ranges
590
+ const chapters = {} // Store verses by chapters
591
+ const uniquePassages = new Set() // Track unique passages to prevent duplicates
592
+
593
+ // Add initial passages to the unique set to avoid duplication
594
+ newObject.passages.forEach((p) => {
595
+ const passageKey = `${p.book}-${p.chapter}-${p.verse}`
596
+ uniquePassages.add(passageKey)
605
597
  })
606
598
 
607
- // Convert to a Set to remove duplicates
608
- newObject.verses = [...new Set(newObject.verses)]
599
+ // Iterate through all the passages and group verses by chapter
600
+ passages.forEach((passage) => {
601
+ if (!chapters[passage.chapter]) {
602
+ chapters[passage.chapter] = new Set() // Use Set to avoid duplicates
603
+ }
609
604
 
610
- // Helper function to merge overlapping or adjacent ranges
611
- const mergeRanges = (verses) => {
612
- const rangeObjects = verses.map((v) => {
613
- if (v.includes("-")) {
614
- const [start, end] = v.split("-").map(Number)
615
- return { start, end }
616
- } else {
617
- const num = Number(v)
618
- return { start: num, end: num }
605
+ // Add verses to their corresponding chapter
606
+ passage.passages.forEach((p) => {
607
+ chapters[p.chapter].add(p.verse)
608
+
609
+ // Create a unique key for each passage (book-chapter-verse)
610
+ const passageKey = `${p.book}-${p.chapter}-${p.verse}`
611
+
612
+ // Add to the passages array if it hasn't been added yet
613
+ if (!uniquePassages.has(passageKey)) {
614
+ newObject.passages.push(p) // Add the passage
615
+ uniquePassages.add(passageKey) // Mark it as added
619
616
  }
620
617
  })
618
+ })
621
619
 
622
- // Sort the ranges by starting number
623
- rangeObjects.sort((a, b) => a.start - b.start)
620
+ // Prepare to build the final result
621
+ const chapterStrings = []
622
+ let firstChapter = null
623
+ let lastChapter = null
624
624
 
625
- const merged = []
626
- let currentRange = rangeObjects[0]
625
+ for (const chapter in chapters) {
626
+ const verses = Array.from(chapters[chapter]).sort((a, b) => a - b)
627
+ const mergedVerses = this.mergeRanges(verses) // Merge adjacent verses into ranges
628
+ chapterStrings.push(`${chapter}:${mergedVerses.join(",")}`)
627
629
 
628
- for (let i = 1; i < rangeObjects.length; i++) {
629
- const nextRange = rangeObjects[i]
630
+ // Track the first and last chapters for the 'to' key
631
+ if (!firstChapter) firstChapter = Number(chapter) // Ensure chapter is a number
632
+ lastChapter = Number(chapter) // Always update to the current chapter as a number
630
633
 
631
- if (currentRange.end >= nextRange.start - 1) {
632
- // Overlapping or adjacent, merge the ranges
633
- currentRange.end = Math.max(currentRange.end, nextRange.end)
634
- } else {
635
- // No overlap, push the current range and start a new one
636
- merged.push(currentRange)
637
- currentRange = nextRange
638
- }
634
+ // Update the newObject.verses with the merged ranges for the current chapter
635
+ if (Number(chapter) === firstChapter) {
636
+ newObject.verses = mergedVerses
639
637
  }
638
+ }
640
639
 
641
- // Push the last range
642
- merged.push(currentRange)
640
+ // Build the final combined object with `to` key for multi-chapter passages
641
+ newObject.original = `${newObject.book} ${firstChapter}:${newObject.verses.join(",")}`
643
642
 
644
- // Convert merged ranges back to strings
645
- return merged.map(({ start, end }) => (start === end ? `${start}` : `${start}-${end}`))
643
+ if (firstChapter !== lastChapter) {
644
+ newObject.to = {
645
+ book: newObject.book,
646
+ chapter: lastChapter,
647
+ verses: this.mergeRanges(Array.from(chapters[lastChapter])), // Ensure merged range
648
+ }
646
649
  }
647
650
 
648
- // Merge and sort the ranges
649
- newObject.verses = mergeRanges(newObject.verses)
650
-
651
- // Build the original and scripture properties
652
- newObject.original = newObject.book + " " + newObject.chapter + ":" + newObject.verses.join(",")
651
+ // Build the scripture string with combined chapters (without spaces after commas)
652
+ const chapterString = chapterStrings.join(",") // No space after comma
653
653
  newObject.scripture = {
654
- passage: newObject.book + " " + newObject.chapter + ":" + newObject.verses.join(","),
655
- cv: newObject.chapter + ":" + newObject.verses.join(","),
656
- hash: newObject.book + "_" + newObject.chapter + "." + newObject.verses.join("."),
654
+ passage: `${newObject.book} ${chapterString}`,
655
+ cv: chapterString,
656
+ hash: `${newObject.book.toLowerCase()}_${chapterString.replace(/:/g, ".").replace(/,/g, ".")}`,
657
657
  }
658
- newObject.scripture.hash = newObject.scripture.hash.toLowerCase()
659
658
 
660
659
  return newObject
661
660
  }
661
+ mergeRanges(verses) {
662
+ const sortedVerses = [...new Set(verses)].sort((a, b) => a - b)
663
+ const merged = []
664
+ let start = sortedVerses[0]
665
+ let end = sortedVerses[0]
666
+
667
+ for (let i = 1; i < sortedVerses.length; i++) {
668
+ if (sortedVerses[i] === end + 1) {
669
+ end = sortedVerses[i]
670
+ } else {
671
+ // Push the current range if it's more than 2 consecutive numbers, otherwise separate by commas
672
+ if (start === end) {
673
+ merged.push(`${start}`)
674
+ } else if (end === start + 1) {
675
+ merged.push(`${start},${end}`)
676
+ } else {
677
+ merged.push(`${start}-${end}`)
678
+ }
679
+ start = sortedVerses[i]
680
+ end = sortedVerses[i]
681
+ }
682
+ }
683
+
684
+ // Push the final range or pair
685
+ if (start === end) {
686
+ merged.push(`${start}`)
687
+ } else if (end === start + 1) {
688
+ merged.push(`${start},${end}`)
689
+ } else {
690
+ merged.push(`${start}-${end}`)
691
+ }
692
+
693
+ return merged
694
+ }
662
695
 
663
696
  _isValid(passage, reference) {
664
697
  const singleChapterBook = this.singleChapterBook.find((bible) => bible[passage.book])