codexparser 0.1.53 → 0.1.54

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 +146 -56
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexparser",
3
- "version": "0.1.53",
3
+ "version": "0.1.54",
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": {
@@ -191,6 +191,7 @@ class CodexParser {
191
191
  this.passages = this.found.map((passage) => {
192
192
  const book = this.bookify(passage.book)
193
193
  const testament = this.bible.old.includes(book) ? "old" : "new"
194
+ const singleChapterBook = this.singleChapterBook.find((b) => Object.keys(b)[0] === book)
194
195
  const parsedPassage = {
195
196
  original: passage.book + " " + passage.reference,
196
197
  book: book,
@@ -202,42 +203,72 @@ class CodexParser {
202
203
  version: this._handleVersion(passage.version, testament),
203
204
  }
204
205
 
205
- // Split reference into parts (e.g., "40:3-5,8-9" -> ["40:3-5", "8-9"])
206
+ // Split reference into parts (e.g., "2 John 1", "2 John 2", "2 John 1:1-3,5")
206
207
  const parts = passage.reference.split(",")
207
208
 
208
209
  parts.forEach((part, partIndex) => {
209
210
  part = part.trim()
210
211
 
211
212
  if (part.includes(":")) {
212
- // Explicit chapter:verse (e.g., "40:3-5")
213
+ // Explicit chapter:verse (e.g., "1:1-3")
213
214
  const [chapterPart, versePart] = part.split(":")
214
215
  if (partIndex === 0) {
215
216
  parsedPassage.chapter = Number(chapterPart) // Set chapter only on first part
216
217
  }
217
218
 
218
219
  if (versePart.includes("-")) {
219
- // Verse range (e.g., "3-5")
220
- parsedPassage.verses.push(versePart)
220
+ parsedPassage.verses.push(versePart) // Add range (e.g., "1-3")
221
221
  } else {
222
- parsedPassage.verses.push(Number(versePart))
222
+ parsedPassage.verses.push(Number(versePart)) // Add single verse
223
223
  }
224
- } else if (part.includes("-")) {
225
- // Verse range without chapter (e.g., "8-9")
226
- if (parsedPassage.chapter === null) {
227
- // Assume chapter 1 for single-chapter books if no chapter yet
228
- const singleChapterBook = this.singleChapterBook.find((b) => b[book])
229
- parsedPassage.chapter = singleChapterBook ? 1 : Number(part.split("-")[0])
230
- parsedPassage.verses.push(part)
224
+ parsedPassage.type = versePart.includes("-") ? "chapter_verse_range" : "chapter_verse"
225
+ } else if (singleChapterBook) {
226
+ // Handle single-chapter books
227
+ const verseCount = singleChapterBook[book][1].length
228
+ if (part === "1" && parts.length === 1 && partIndex === 0) {
229
+ // "2 John 1" means the whole chapter
230
+ parsedPassage.chapter = 1
231
+ parsedPassage.type = "single_chapter"
232
+ parsedPassage.verses = [`1-${verseCount}`] // e.g., "1-13"
233
+ } else if (part.includes("-")) {
234
+ // "2 John 3-5" → "2 John 1:3-5"
235
+ parsedPassage.chapter = 1
236
+ parsedPassage.verses.push(part) // e.g., "3-5"
237
+ parsedPassage.type = "chapter_verse_range"
231
238
  } else {
232
- parsedPassage.verses.push(part) // Add as verse range in current chapter
239
+ // "2 John 2" "2 John 1:2"
240
+ const num = Number(part)
241
+ if (num > 1 || (num === 1 && parts.length > 1)) {
242
+ parsedPassage.chapter = 1
243
+ parsedPassage.verses.push(num) // Treat as verse number
244
+ parsedPassage.type = "chapter_verse"
245
+ }
233
246
  }
247
+ } else if (part.includes("-") && !parsedPassage.chapter) {
248
+ // Range without chapter for multi-chapter books (e.g., "Isaiah 3-5")
249
+ const [start, end] = part.split("-").map(Number)
250
+ parsedPassage.chapter = start
251
+ parsedPassage.verses = [
252
+ `${this.chapterVerses[book][start][0]}-${this.chapterVerses[book][start].slice(-1)[0]}`,
253
+ ]
254
+ parsedPassage.to = {
255
+ book,
256
+ chapter: end,
257
+ verses: [`${this.chapterVerses[book][end][0]}-${this.chapterVerses[book][end].slice(-1)[0]}`],
258
+ }
259
+ parsedPassage.type = "chapter_range"
260
+ } else if (part.includes("-")) {
261
+ // Verse range in current chapter (e.g., "8-9" after "40:3-5")
262
+ parsedPassage.verses.push(part)
263
+ parsedPassage.type = "chapter_verse_range"
234
264
  } else {
235
- // Single verse without chapter (e.g., "8")
236
- if (parsedPassage.chapter === null) {
237
- const singleChapterBook = this.singleChapterBook.find((b) => b[book])
238
- parsedPassage.chapter = singleChapterBook ? 1 : Number(part)
265
+ // Single number (chapter or verse) for multi-chapter books
266
+ if (partIndex === 0 && !parsedPassage.chapter) {
267
+ parsedPassage.chapter = Number(part)
268
+ parsedPassage.type = "single_chapter"
239
269
  } else {
240
270
  parsedPassage.verses.push(Number(part))
271
+ parsedPassage.type = "comma_separated_verses"
241
272
  }
242
273
  }
243
274
  })
@@ -260,7 +291,7 @@ class CodexParser {
260
291
  verses: endVerse.includes("-") ? [endVerse] : [Number(endVerse)],
261
292
  }
262
293
  } else {
263
- delete parsedPassage.to // Ensure no erroneous 'to' property
294
+ delete parsedPassage.to // Remove erroneous 'to' property
264
295
  }
265
296
 
266
297
  return parsedPassage
@@ -345,20 +376,6 @@ class CodexParser {
345
376
  })
346
377
  }
347
378
 
348
- /**
349
- * Populate a Set of passages from entities.start.v to entities.end.v,
350
- * and then add any additional verses from the verses array.
351
- *
352
- * @param {Object} entities - Entities object from the bible-passage-reference-parser
353
- * @param {Array} verses - Array of verse numbers to add to the set of passages
354
- * @return {Array} Array of passage objects
355
- */
356
- /**
357
- * Populate all verses from a parsed passage, including all verses in ranges or chapters.
358
- *
359
- * @param {Object} parsedPassage - The parsed passage object containing book, chapter, and verses information.
360
- * @return {Array} An array of passage objects with individual verses.
361
- */
362
379
  /**
363
380
  * Populate all verses from a parsed passage, including all verses in ranges or chapters.
364
381
  *
@@ -371,15 +388,24 @@ class CodexParser {
371
388
  const version = parsedPassage.version ? parsedPassage.version.abbreviation : "eng"
372
389
  this._setVersion(book, chapter, version) // Set version data if needed
373
390
 
391
+ const singleChapterBook = this.singleChapterBook.find((b) => Object.keys(b)[0] === book)
392
+
374
393
  if (type === "single_chapter") {
375
- // Handle entire chapter references (e.g., "Isaiah 40")
376
- if (this.chapterVerses[book] && this.chapterVerses[book][chapter]) {
394
+ // Handle entire chapter references (e.g., "Isaiah 40" or "2 John 1")
395
+ if (singleChapterBook) {
396
+ // Single-chapter book: populate all verses from singleChapterBook
397
+ const verseCount = singleChapterBook[book][1].length
398
+ for (let verse = 1; verse <= verseCount; verse++) {
399
+ passages.push({ book, chapter: 1, verse })
400
+ }
401
+ } else if (this.chapterVerses[book] && this.chapterVerses[book][chapter]) {
402
+ // Multi-chapter book: populate all verses in the chapter
377
403
  this.chapterVerses[book][chapter].forEach((verse) => {
378
404
  passages.push({ book, chapter: Number(chapter), verse: Number(verse) })
379
405
  })
380
406
  }
381
407
  } else if (type === "comma_separated_verses" || type === "chapter_verse_range") {
382
- // Handle comma-separated verses or single-chapter verse ranges (e.g., "Isaiah 40:3-5,8-9" or "Isaiah 40:3-5")
408
+ // Handle comma-separated verses or single-chapter verse ranges (e.g., "Isaiah 40:3-5,8-9" or "2 John 1:1-3")
383
409
  verses.forEach((verse) => {
384
410
  if (typeof verse === "string" && verse.includes("-")) {
385
411
  const [start, end] = verse.split("-").map(Number)
@@ -419,7 +445,7 @@ class CodexParser {
419
445
  }
420
446
  }
421
447
  } else if (type === "chapter_verse") {
422
- // Handle single chapter:verse references (e.g., "Isaiah 40:3")
448
+ // Handle single chapter:verse references (e.g., "2 John 1:1")
423
449
  verses.forEach((verse) => {
424
450
  passages.push({ book, chapter: Number(chapter), verse: Number(verse) })
425
451
  })
@@ -727,31 +753,35 @@ class CodexParser {
727
753
  return orderedToc
728
754
  }
729
755
 
756
+ /**
757
+ * Validates a parsed passage to ensure the chapter and verses exist.
758
+ *
759
+ * @param {Object} passage - The parsed passage object to validate.
760
+ * @param {string} reference - The original reference string for error messaging.
761
+ * @return {boolean|Object} True if valid, or an error object if invalid.
762
+ */
730
763
  _isValid(passage, reference) {
731
- const singleChapterBook = this.singleChapterBook.find((bible) => bible[passage.book])
732
- if (!passage.verses) {
733
- return {
734
- error: true,
735
- code: 101,
736
- message: {
737
- chapter_exists: false,
738
- content: "Possible invalid chapter: " + reference,
739
- },
740
- }
741
- }
742
- if (!singleChapterBook) {
743
- if (!this.chapterVerses[passage.book][passage.chapter]) {
764
+ const singleChapterBook = this.singleChapterBook.find((b) => Object.keys(b)[0] === passage.book)
765
+
766
+ // Check if verses exist at all
767
+ if (!passage.verses || passage.verses.length === 0) {
768
+ if (passage.type !== "single_chapter") {
744
769
  return {
745
770
  error: true,
746
- code: 102,
771
+ code: 101,
747
772
  message: {
748
773
  chapter_exists: false,
749
- content: `Chapter ${passage.chapter} does not exist in ${passage.book}`,
774
+ content: "Possible invalid chapter: " + reference,
750
775
  },
751
776
  }
752
777
  }
753
- } else {
754
- if (!singleChapterBook[passage.book][passage.chapter]) {
778
+ }
779
+
780
+ // Handle single-chapter books
781
+ if (singleChapterBook) {
782
+ const verseCount = singleChapterBook[passage.book][1].length
783
+
784
+ if (passage.chapter !== 1) {
755
785
  return {
756
786
  error: true,
757
787
  code: 103,
@@ -761,19 +791,78 @@ class CodexParser {
761
791
  },
762
792
  }
763
793
  }
794
+
795
+ if (passage.type === "single_chapter") {
796
+ // For "2 John 1", validate the full range
797
+ const [range] = passage.verses // e.g., "1-13"
798
+ if (range) {
799
+ const [start, end] = range.split("-").map(Number)
800
+ if (start < 1 || end > verseCount) {
801
+ return {
802
+ error: true,
803
+ code: 104,
804
+ message: {
805
+ verse_exists: false,
806
+ content: `Verse range ${start}-${end} exceeds available verses (1-${verseCount}) in ${passage.book} 1`,
807
+ },
808
+ }
809
+ }
810
+ }
811
+ return true // If no specific verses or range matches, it’s valid
812
+ }
813
+
814
+ // For specific verses in single-chapter books (e.g., "2 John 1:1-3")
815
+ for (let i = 0; i < passage.verses.length; i++) {
816
+ const verseRange = String(passage.verses[i])
817
+ let versesToCheck = verseRange.includes("-") ? verseRange.split("-").map(Number) : [Number(verseRange)]
818
+
819
+ if (versesToCheck.length === 2) {
820
+ const [start, end] = versesToCheck
821
+ versesToCheck = Array.from({ length: end - start + 1 }, (_, idx) => start + idx)
822
+ }
823
+
824
+ for (const verse of versesToCheck) {
825
+ if (verse < 1 || verse > verseCount) {
826
+ return {
827
+ error: true,
828
+ code: 104,
829
+ message: {
830
+ verse_exists: false,
831
+ content: `Verse number ${verse} does not exist in ${passage.book} 1`,
832
+ },
833
+ }
834
+ }
835
+ }
836
+ }
837
+ return true
838
+ }
839
+
840
+ // Handle multi-chapter books
841
+ if (!this.chapterVerses[passage.book] || !this.chapterVerses[passage.book][passage.chapter]) {
842
+ return {
843
+ error: true,
844
+ code: 102,
845
+ message: {
846
+ chapter_exists: false,
847
+ content: `Chapter ${passage.chapter} does not exist in ${passage.book}`,
848
+ },
849
+ }
764
850
  }
851
+
852
+ if (passage.type === "single_chapter") {
853
+ return true // For multi-chapter books, whole chapter is valid if it exists
854
+ }
855
+
765
856
  for (let i = 0; i < passage.verses.length; i++) {
766
857
  const passageVerses = String(passage.verses[i])
767
- let verses = passageVerses.split("-").map(Number)
858
+ let verses = passageVerses.includes("-") ? passageVerses.split("-").map(Number) : [Number(passageVerses)]
768
859
 
769
860
  if (verses.length === 2) {
770
861
  // Expand the range if there are two numbers
771
862
  verses = Array.from({ length: verses[1] - verses[0] + 1 }, (_, index) => verses[0] + index)
772
863
  }
773
864
 
774
- // The verses array now contains all values between the range or remains as a single value
775
865
  for (const verse of verses) {
776
- // Check if the verse exists in the chapterVerses structure
777
866
  const isValidVerse =
778
867
  this.chapterVerses[passage.book] &&
779
868
  this.chapterVerses[passage.book][passage.chapter] &&
@@ -791,6 +880,7 @@ class CodexParser {
791
880
  }
792
881
  }
793
882
  }
883
+
794
884
  return true
795
885
  }
796
886
  _handleVersion(version, testament) {