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 +1 -1
- package/src/CodexParser.js +287 -51
- package/src/abbr.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codexparser",
|
|
3
|
-
"version": "0.1.
|
|
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": {
|
package/src/CodexParser.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
359
|
-
|
|
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
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
bookified
|
|
477
|
-
|
|
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
|
-
|
|
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
|