codexparser 0.1.59 → 0.1.61

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexparser",
3
- "version": "0.1.59",
3
+ "version": "0.1.61",
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": {
@@ -1,3 +1,10 @@
1
+ /**
2
+ * CodexParser.js
3
+ * A class for scanning and parsing scripture references from text, supporting various formats
4
+ * (e.g., single verses, ranges, multi-chapter references) with validation and version-specific
5
+ * versification. Handles book names, abbreviations, and SBL-style formatting.
6
+ */
7
+
1
8
  const versified = require("./versified")
2
9
  const bible = require("./bible")
3
10
  const { bookRegex, chapterRegex, verseRegex, scripturesRegex } = require("./regex")
@@ -8,28 +15,37 @@ const dd = require("./functions").dd
8
15
  const sch = require("./functions").sch
9
16
  const chapter_verses = require("./chapterVerseCombine")
10
17
 
18
+ /**
19
+ * Class for parsing and validating scripture references.
20
+ * @class
21
+ */
11
22
  class CodexParser {
23
+ /**
24
+ * Initializes the parser with default properties and data.
25
+ */
12
26
  constructor() {
13
- this.found = []
14
- this.passages = []
15
- this.bible = bible
16
- this.bookRegex = bookRegex
17
- this.chapterRegex = chapterRegex
18
- this.verseRegex = verseRegex
19
- this.scripturesRegex = scripturesRegex
20
- this.abbreviations = abbreviations
21
- this.sblAbbreviations = sblAbbreviations
22
- this.versificationDifferences = versified
27
+ this.found = [] // Array to store detected references
28
+ this.passages = [] // Array to store parsed passages
29
+ this.bible = bible // Bible data (Old/New Testament books)
30
+ this.bookRegex = bookRegex // Regex for book names
31
+ this.chapterRegex = chapterRegex // Regex for chapters
32
+ this.verseRegex = verseRegex // Regex for verses
33
+ this.scripturesRegex = scripturesRegex // Regex for full references
34
+ this.abbreviations = abbreviations // Book abbreviation mappings
35
+ this.sblAbbreviations = sblAbbreviations // SBL-style abbreviation mappings
36
+ this.versificationDifferences = versified // Version-specific verse differences
23
37
  this.singleChapterBook = [
38
+ // Books with a single chapter and their verse counts
24
39
  sch("Jude", 25),
25
40
  sch("2 John", 13),
26
41
  sch("3 John", 15),
27
42
  sch("Obadiah", 21),
28
43
  sch("Philemon", 25),
29
44
  ]
30
- this.chapterVerses = chapter_verses
31
- this.error = false
32
- this.version = null
45
+ this.chapterVerses = chapter_verses // Chapter-verse mappings
46
+ this.error = false // Error flag
47
+ this.version = null // Bible version (e.g., lxx, mt, eng)
48
+ // Reference type constants
33
49
  this.SINGLE_CHAPTER = "single_chapter"
34
50
  this.CHAPTER_VERSE = "chapter_verse"
35
51
  this.CHAPTER_VERSE_RANGE = "chapter_verse_range"
@@ -38,11 +54,22 @@ class CodexParser {
38
54
  this.MULTI_CHAPTER_RANGE = "multi_chapter_verse_range"
39
55
  }
40
56
 
57
+ /**
58
+ * Retrieves available verses for a given book and chapter.
59
+ * @param {string} book - The book name (e.g., "Genesis").
60
+ * @param {number} chapter - The chapter number.
61
+ * @returns {number[]} Array of valid verse numbers.
62
+ */
41
63
  getChapterVerses(book, chapter) {
42
64
  const singleChapterBook = this.singleChapterBook.find((b) => Object.keys(b)[0] === book)
43
65
  return singleChapterBook ? singleChapterBook[book][chapter] || [] : this.chapterVerses[book]?.[chapter] || []
44
66
  }
45
67
 
68
+ /**
69
+ * Scans text for scripture references and stores them in `this.found`.
70
+ * @param {string} text - The text to scan.
71
+ * @returns {CodexParser} The parser instance for method chaining.
72
+ */
46
73
  scan(text) {
47
74
  const fullNames = [...this.bible.old, ...this.bible.new]
48
75
  const abbreviations = Object.keys(this.abbreviations)
@@ -66,19 +93,25 @@ class CodexParser {
66
93
  }
67
94
  const detectSuffix = (startIndex) => {
68
95
  const suffixMatch = normalizedText.substring(startIndex).match(/\b(LXX|MT)\b/i)
69
- return suffixMatch ? suffixMatch[0].toUpperCase() : null
96
+ return suffixMatch
97
+ ? {
98
+ suffix: suffixMatch[0].toUpperCase(),
99
+ length:
100
+ suffixMatch[0].length + (normalizedText[startIndex + suffixMatch[0].length] === " " ? 1 : 0),
101
+ }
102
+ : null
70
103
  }
71
104
 
72
105
  while (i < lowerCaseText.length) {
73
106
  let foundBook = null
74
- let foundIndex = -1
107
+ let startIndex = -1
75
108
  let matchedLength = 0
76
109
 
77
110
  for (let j = 0; j < lowercaseBibleFullNames.length; j++) {
78
111
  const book = lowercaseBibleFullNames[j]
79
112
  if (lowerCaseText.startsWith(book, i) && book.length > matchedLength) {
80
113
  foundBook = fullNames[j]
81
- foundIndex = i
114
+ startIndex = i
82
115
  matchedLength = book.length
83
116
  }
84
117
  }
@@ -88,7 +121,7 @@ class CodexParser {
88
121
  const abbreviation = lowercaseBibleAbbreviations[k]
89
122
  if (lowerCaseText.startsWith(abbreviation, i) && abbreviation.length > matchedLength) {
90
123
  foundBook = this.abbreviations[abbreviations[k]]
91
- foundIndex = i
124
+ startIndex = i
92
125
  matchedLength = abbreviation.length
93
126
  }
94
127
  }
@@ -98,6 +131,7 @@ class CodexParser {
98
131
  i += matchedLength
99
132
  let chapterVerse = ""
100
133
  const references = []
134
+ const startOfReference = startIndex
101
135
 
102
136
  while (i < normalizedText.length && isValidChapterVerseChar(normalizedText[i])) {
103
137
  if (isNextBibleBook(i)) break
@@ -117,7 +151,15 @@ class CodexParser {
117
151
  if (formattedReference) references.push(formattedReference)
118
152
  }
119
153
 
120
- const suffix = detectSuffix(i)
154
+ const suffixData = detectSuffix(i)
155
+ const suffix = suffixData ? suffixData.suffix : null
156
+ if (suffixData) i += suffixData.length
157
+
158
+ // Adjust endIndex to exclude trailing space if present
159
+ let endIndex = i
160
+ if (endIndex > 0 && normalizedText[endIndex - 1] === " ") {
161
+ endIndex--
162
+ }
121
163
 
122
164
  references.forEach((ref) => {
123
165
  let type
@@ -146,9 +188,11 @@ class CodexParser {
146
188
  this.found.push({
147
189
  book: foundBook,
148
190
  reference: ref,
149
- index: foundIndex,
191
+ startIndex: startOfReference,
192
+ endIndex: endIndex,
150
193
  version: suffix || null,
151
194
  type,
195
+ originalText: normalizedText.slice(startOfReference, endIndex),
152
196
  })
153
197
  })
154
198
  } else {
@@ -159,6 +203,11 @@ class CodexParser {
159
203
  return this
160
204
  }
161
205
 
206
+ /**
207
+ * Sets the Bible version for parsing.
208
+ * @param {string} version - The version (e.g., "lxx", "mt", "eng").
209
+ * @returns {CodexParser} The parser instance.
210
+ */
162
211
  bibleVersion(version) {
163
212
  const lowerVersion = version.toLowerCase()
164
213
  this.version =
@@ -168,6 +217,11 @@ class CodexParser {
168
217
  return this
169
218
  }
170
219
 
220
+ /**
221
+ * Parses a scripture reference into structured passage objects.
222
+ * @param {string} reference - The reference to parse (e.g., "John 3:16").
223
+ * @returns {CodexParser} The parser instance.
224
+ */
171
225
  parse(reference) {
172
226
  this.scan(reference)
173
227
 
@@ -181,13 +235,16 @@ class CodexParser {
181
235
  verses: [],
182
236
  type: passage.type,
183
237
  testament,
184
- index: passage.index,
238
+ startIndex: passage.startIndex,
239
+ endIndex: passage.endIndex,
240
+ originalText: passage.originalText,
185
241
  version: this._handleVersion(passage.version, testament),
186
242
  passages: [],
187
243
  scripture: null,
188
244
  valid: true,
189
245
  start: null,
190
246
  end: null,
247
+ abbr: null,
191
248
  }
192
249
 
193
250
  this.parseReferenceParts(parsedPassage, passage.reference.split(","))
@@ -195,15 +252,13 @@ class CodexParser {
195
252
  parsedPassage.scripture = this.scripturize(parsedPassage)
196
253
  parsedPassage.valid = this._isValid(parsedPassage, passage.reference)
197
254
 
198
- // Add SBL abbreviation as full reference with en dashes and space after commas for comma-separated verses
199
- const sblEntry = this.sblAbbreviations[book] || { value: book, abbr: false }
200
- const sblBook = sblEntry.value + (sblEntry.abbr ? "." : "")
201
- let abbr = parsedPassage.scripture.passage.replace(book, sblBook).replace(/-/g, "–")
202
- if (parsedPassage.type === "comma_separated_verses") {
203
- const versePart = parsedPassage.verses.map((v) => `${v}`).join(", ")
204
- abbr = `${sblBook} ${parsedPassage.chapter}:${versePart}`
205
- }
206
- parsedPassage.abbr = abbr
255
+ // Set abbr property using SBL-style abbreviation
256
+ const abbrKey = Object.keys(this.abbreviations).find(
257
+ (abbr) => this.abbreviations[abbr].toLowerCase() === book.toLowerCase()
258
+ )
259
+ parsedPassage.abbr = abbrKey
260
+ ? `${abbrKey}. ${passage.reference}${passage.version ? " " + passage.version : ""}`
261
+ : parsedPassage.original
207
262
 
208
263
  if (parsedPassage.type === this.MULTI_CHAPTER_RANGE) {
209
264
  this.handleMultiChapterRange(parsedPassage, passage.reference)
@@ -211,6 +266,7 @@ class CodexParser {
211
266
  delete parsedPassage.to
212
267
  }
213
268
 
269
+ // Calculate start and end based on passages array
214
270
  if (parsedPassage.passages.length > 0) {
215
271
  const sortedPassages = parsedPassage.passages.slice().sort((a, b) => {
216
272
  if (a.chapter !== b.chapter) return a.chapter - b.chapter
@@ -238,11 +294,6 @@ class CodexParser {
238
294
  }
239
295
  }
240
296
 
241
- // Attach the reference method to this individual passage object
242
- parsedPassage.reference = function () {
243
- return this.scripture.passage
244
- }
245
-
246
297
  return parsedPassage
247
298
  })
248
299
 
@@ -250,6 +301,12 @@ class CodexParser {
250
301
  return this
251
302
  }
252
303
 
304
+ /**
305
+ * Parses reference parts into chapter and verse components.
306
+ * @param {Object} passage - The passage object to populate.
307
+ * @param {string[]} parts - Array of reference parts.
308
+ * @private
309
+ */
253
310
  parseReferenceParts(passage, parts) {
254
311
  const singleChapterBook = this.singleChapterBook.find((b) => Object.keys(b)[0] === passage.book)
255
312
 
@@ -269,6 +326,13 @@ class CodexParser {
269
326
  })
270
327
  }
271
328
 
329
+ /**
330
+ * Parses chapter-verse references (e.g., "3:16").
331
+ * @param {Object} passage - The passage object.
332
+ * @param {string} part - The reference part.
333
+ * @param {boolean} isFirstPart - Whether this is the first part.
334
+ * @private
335
+ */
272
336
  parseChapterVerse(passage, part, isFirstPart) {
273
337
  const [chapter, verse] = part.split(":")
274
338
  if (isFirstPart) passage.chapter = Number(chapter)
@@ -276,6 +340,13 @@ class CodexParser {
276
340
  passage.verses.push(verse.includes("-") ? verse : Number(verse))
277
341
  }
278
342
 
343
+ /**
344
+ * Parses references for single-chapter books (e.g., "Jude 5").
345
+ * @param {Object} passage - The passage object.
346
+ * @param {string} part - The reference part.
347
+ * @param {boolean} isWholeChapter - Whether the reference is for the whole chapter.
348
+ * @private
349
+ */
279
350
  parseSingleChapterBook(passage, part, isWholeChapter) {
280
351
  const verseCount = this.getChapterVerses(passage.book, 1).length
281
352
  if (part === "1" && isWholeChapter) {
@@ -296,6 +367,13 @@ class CodexParser {
296
367
  }
297
368
  }
298
369
 
370
+ /**
371
+ * Parses range references (e.g., "1-3").
372
+ * @param {Object} passage - The passage object.
373
+ * @param {string} part - The reference part.
374
+ * @param {boolean} isFirstPart - Whether this is the first part.
375
+ * @private
376
+ */
299
377
  parseRange(passage, part, isFirstPart) {
300
378
  if (!passage.chapter && isFirstPart) {
301
379
  const [start, end] = part.split("-").map(Number)
@@ -318,6 +396,13 @@ class CodexParser {
318
396
  }
319
397
  }
320
398
 
399
+ /**
400
+ * Parses single number references (e.g., "3" for chapter or verse).
401
+ * @param {Object} passage - The passage object.
402
+ * @param {string} part - The reference part.
403
+ * @param {boolean} isFirstPart - Whether this is the first part.
404
+ * @private
405
+ */
321
406
  parseSingleNumber(passage, part, isFirstPart) {
322
407
  if (isFirstPart && !passage.chapter) {
323
408
  passage.chapter = Number(part)
@@ -332,6 +417,12 @@ class CodexParser {
332
417
  }
333
418
  }
334
419
 
420
+ /**
421
+ * Handles multi-chapter range references (e.g., "3:16-4:5").
422
+ * @param {Object} passage - The passage object.
423
+ * @param {string} reference - The full reference string.
424
+ * @private
425
+ */
335
426
  handleMultiChapterRange(passage, reference) {
336
427
  const parts = reference.split(",")
337
428
  const lastPart = parts[parts.length - 1]
@@ -345,6 +436,13 @@ class CodexParser {
345
436
  }
346
437
  }
347
438
 
439
+ /**
440
+ * Generates a range of numbers.
441
+ * @param {number} start - Start number.
442
+ * @param {number} end - End number.
443
+ * @returns {number[]} Array of numbers.
444
+ * @private
445
+ */
348
446
  _generateRange(start, end) {
349
447
  const range = []
350
448
  for (let i = start; i <= end; i++) {
@@ -353,10 +451,47 @@ class CodexParser {
353
451
  return range
354
452
  }
355
453
 
454
+ /**
455
+ * Searches for versification differences for a book and chapter.
456
+ * @param {string} book - The book name.
457
+ * @param {number} chapter - The chapter number.
458
+ * @param {string} version - The Bible version.
459
+ * @returns {Object|undefined} Updated chapter verses or undefined.
460
+ * @private
461
+ */
356
462
  _searchVersificationDifferences(book, chapter, version) {
357
463
  version = version.toLowerCase()
358
- if (!this.chapterVerses[book][chapter]) return
359
- if (!this.versificationDifferences[book]) return
464
+
465
+ // Handle single-chapter book "Obadiah"
466
+ if (book === "Obadiah") {
467
+ const singleChapterBook = this.singleChapterBook.find((b) => Object.keys(b)[0] === "Obadiah")
468
+ if (!singleChapterBook || !singleChapterBook[book][chapter]) {
469
+ return // No data for Obadiah or chapter
470
+ }
471
+ if (!this.versificationDifferences[book]) {
472
+ return // No versification differences for Obadiah
473
+ }
474
+ // Process versification differences
475
+ for (const [key, value] of Object.entries(this.versificationDifferences[book])) {
476
+ if (value[version].startsWith(`${chapter}:`)) {
477
+ if (value[version]) {
478
+ const verse = value[version].split(":")[1]
479
+ singleChapterBook[book][chapter].push(Number(verse))
480
+ }
481
+ }
482
+ }
483
+ // Ensure unique verses and update the singleChapterBook entry
484
+ singleChapterBook[book][chapter] = Array.from(new Set(singleChapterBook[book][chapter]))
485
+ return singleChapterBook[book] // Return updated chapter data
486
+ }
487
+
488
+ // Handle all other books using chapterVerses
489
+ if (!this.chapterVerses[book][chapter]) {
490
+ return // No data for this book/chapter
491
+ }
492
+ if (!this.versificationDifferences[book]) {
493
+ return // No versification differences
494
+ }
360
495
  for (const [key, value] of Object.entries(this.versificationDifferences[book])) {
361
496
  if (value[version].startsWith(`${chapter}:`)) {
362
497
  if (value[version]) {
@@ -366,9 +501,16 @@ class CodexParser {
366
501
  }
367
502
  }
368
503
  this.chapterVerses[book][chapter] = Array.from(this.chapterVerses[book][chapter])
369
- return this.chapterVerses
504
+ return this.chapterVerses // Return updated chapterVerses
370
505
  }
371
506
 
507
+ /**
508
+ * Sets the Bible version and applies versification differences.
509
+ * @param {string} book - The book name.
510
+ * @param {number} chapter - The chapter number.
511
+ * @param {string} version - The Bible version.
512
+ * @private
513
+ */
372
514
  _setVersion(book, chapter, version) {
373
515
  this.version = version ? version : "eng"
374
516
  if (this.version !== "eng") {
@@ -376,6 +518,9 @@ class CodexParser {
376
518
  }
377
519
  }
378
520
 
521
+ /**
522
+ * Applies versification differences to parsed passages.
523
+ */
379
524
  versification() {
380
525
  this.passages.forEach((passage) => {
381
526
  const hasVersification = this.versificationDifferences[passage.book]
@@ -407,6 +552,11 @@ class CodexParser {
407
552
  })
408
553
  }
409
554
 
555
+ /**
556
+ * Populates passage with expanded verse objects.
557
+ * @param {Object} passage - The passage object.
558
+ * @returns {Object[]} Array of verse objects.
559
+ */
410
560
  populate(passage) {
411
561
  const { book, chapter, verses, type, to } = passage
412
562
  const version = passage.version?.abbreviation || "eng"
@@ -449,6 +599,13 @@ class CodexParser {
449
599
  return []
450
600
  }
451
601
 
602
+ /**
603
+ * Expands verse references into individual verse objects.
604
+ * @param {string} book - The book name.
605
+ * @param {number} chapter - The chapter number.
606
+ * @param {Array<string|number>} verses - Array of verses or ranges.
607
+ * @returns {Object[]} Array of verse objects.
608
+ */
452
609
  expandVerses(book, chapter, verses) {
453
610
  const passages = []
454
611
  const chapterVerses = this.getChapterVerses(book, chapter)
@@ -466,27 +623,31 @@ class CodexParser {
466
623
  return passages
467
624
  }
468
625
 
626
+ /**
627
+ * Normalizes book names using abbreviations or full names.
628
+ * @param {string|Array} book - The book name or array.
629
+ * @returns {string} Normalized book name.
630
+ */
469
631
  bookify(book) {
470
632
  if (typeof book !== "string") {
471
633
  book = book[0]
472
634
  }
473
- let bookified = Object.keys(this.abbreviations).find((abbr) => {
474
- return abbr.toLowerCase() === book.toLowerCase()
475
- })
476
- bookified = this.abbreviations[bookified]
477
- if (!bookified) {
478
- bookified = this.bible.new.find(
479
- (b) => b.toLowerCase() === book.toLowerCase() && b.toLowerCase().includes(book.toLowerCase())
480
- )
481
- if (!bookified) {
482
- bookified = this.bible.old.find(
483
- (b) => b.toLowerCase() === book.toLowerCase() && b.toLowerCase().includes(book.toLowerCase())
484
- )
485
- }
635
+ book = book.toLowerCase()
636
+ // Check if book is an abbreviation
637
+ let bookified = this.abbreviations[Object.keys(this.abbreviations).find((abbr) => abbr.toLowerCase() === book)]
638
+ if (bookified) {
639
+ return bookified
486
640
  }
487
- return bookified
641
+ // Check if book is a full name
642
+ bookified =
643
+ this.bible.new.find((b) => b.toLowerCase() === book) || this.bible.old.find((b) => b.toLowerCase() === book)
644
+ return bookified || book // Fallback to input if not found
488
645
  }
489
646
 
647
+ /**
648
+ * Returns parsed passages with utility methods.
649
+ * @returns {Object[]} Array of passages with methods.
650
+ */
490
651
  getPassages() {
491
652
  const passagesArray = [...this.passages]
492
653
 
@@ -553,10 +714,19 @@ class CodexParser {
553
714
  return passagesArray
554
715
  }
555
716
 
717
+ /**
718
+ * Returns the first parsed passage.
719
+ * @returns {Object|null} The first passage or null.
720
+ */
556
721
  first() {
557
722
  return this.passages.length > 0 ? this.passages[0] : null
558
723
  }
559
724
 
725
+ /**
726
+ * Formats a passage into a human-readable reference.
727
+ * @param {Object} passage - The passage object.
728
+ * @returns {Object} Formatted passage data.
729
+ */
560
730
  scripturize(passage) {
561
731
  const formatChapterVerse = (chapter, verses) => {
562
732
  if (!chapter || !verses || verses.length === 0) return ""
@@ -602,6 +772,11 @@ class CodexParser {
602
772
  }
603
773
  }
604
774
 
775
+ /**
776
+ * Combines multiple passages into a single reference.
777
+ * @param {Object[]} passages - Array of passages to combine.
778
+ * @returns {Object} Combined passage object.
779
+ */
605
780
  combine(passages) {
606
781
  if (!passages || passages.length === 0) {
607
782
  throw new Error("No passages provided to join.")
@@ -717,6 +892,11 @@ class CodexParser {
717
892
  return combined
718
893
  }
719
894
 
895
+ /**
896
+ * Merges verses into ranges or comma-separated lists.
897
+ * @param {number[]} verses - Array of verse numbers.
898
+ * @returns {string[]} Array of verse strings.
899
+ */
720
900
  mergeRanges(verses) {
721
901
  const sortedVerses = [...new Set(verses)].sort((a, b) => a - b)
722
902
  const merged = []
@@ -746,6 +926,11 @@ class CodexParser {
746
926
  return merged
747
927
  }
748
928
 
929
+ /**
930
+ * Generates a table of contents for the Bible.
931
+ * @param {string} [version="ESV"] - The Bible version.
932
+ * @returns {Object} TOC with book-chapter-verse mappings.
933
+ */
749
934
  getToc(version = "ESV") {
750
935
  const toc = {}
751
936
  this.bible.old.forEach((book) => {
@@ -775,6 +960,13 @@ class CodexParser {
775
960
  return orderedToc
776
961
  }
777
962
 
963
+ /**
964
+ * Validates a passage for correctness.
965
+ * @param {Object} passage - The passage object.
966
+ * @param {string} reference - The original reference.
967
+ * @returns {boolean|Object} True if valid, error object if invalid.
968
+ * @private
969
+ */
778
970
  _isValid(passage, reference) {
779
971
  const { book, chapter, verses, type } = passage
780
972
 
@@ -806,6 +998,15 @@ class CodexParser {
806
998
  return this.validateVerses(book, chapter, verses, reference)
807
999
  }
808
1000
 
1001
+ /**
1002
+ * Validates verse numbers for a chapter.
1003
+ * @param {string} book - The book name.
1004
+ * @param {number} chapter - The chapter number.
1005
+ * @param {Array<string|number>} verses - Array of verses or ranges.
1006
+ * @param {string} reference - The original reference.
1007
+ * @returns {boolean|Object} True if valid, error object if invalid.
1008
+ * @private
1009
+ */
809
1010
  validateVerses(book, chapter, verses, reference) {
810
1011
  const chapterVerses = this.getChapterVerses(book, chapter)
811
1012
  for (const verse of verses) {
@@ -826,6 +1027,13 @@ class CodexParser {
826
1027
  return true
827
1028
  }
828
1029
 
1030
+ /**
1031
+ * Creates an error object for validation failures.
1032
+ * @param {number} code - Error code.
1033
+ * @param {string} message - Error message.
1034
+ * @returns {Object} Error object.
1035
+ * @private
1036
+ */
829
1037
  validationError(code, message) {
830
1038
  return {
831
1039
  error: true,
@@ -834,6 +1042,13 @@ class CodexParser {
834
1042
  }
835
1043
  }
836
1044
 
1045
+ /**
1046
+ * Determines the Bible version for a passage.
1047
+ * @param {string} version - The version (e.g., "lxx").
1048
+ * @param {string} testament - The testament ("old" or "new").
1049
+ * @returns {Object} Version object.
1050
+ * @private
1051
+ */
837
1052
  _handleVersion(version, testament) {
838
1053
  const effectiveVersion = this.version || version || "eng"
839
1054
  const lowerVersion = effectiveVersion.toLowerCase()
@@ -846,6 +1061,27 @@ class CodexParser {
846
1061
  }
847
1062
  return { name: "English", value: "ENG", abbreviation: "eng" }
848
1063
  }
1064
+
1065
+ replace(text, useAbbreviations = true) {
1066
+ if (!this.passages.length) {
1067
+ console.log("No parsed passages to replace")
1068
+ return text
1069
+ }
1070
+
1071
+ let result = text
1072
+ // Process replacements in reverse order to avoid index shifting
1073
+ for (let i = this.passages.length - 1; i >= 0; i--) {
1074
+ const passage = this.passages[i]
1075
+ const { startIndex, endIndex, originalText, abbr, original } = passage
1076
+
1077
+ // Use abbreviated or full reference
1078
+ const newReference = useAbbreviations ? abbr : original
1079
+ console.log(`Replacing "${originalText}" with "${newReference}" at [${startIndex}, ${endIndex}]`) // Debug
1080
+ result = result.slice(0, startIndex) + newReference + result.slice(endIndex)
1081
+ }
1082
+
1083
+ return result
1084
+ }
849
1085
  }
850
1086
 
851
1087
  module.exports = CodexParser
package/src/abbr.js CHANGED
@@ -158,6 +158,7 @@ const abbrevations = {
158
158
  Mal: "Malachi",
159
159
  Ml: "Malachi",
160
160
  Matt: "Matthew",
161
+ Mat: "Matthew",
161
162
  Mt: "Matthew",
162
163
  Mark: "Mark",
163
164
  Mc: "Mark",