codexparser 0.1.35 → 0.1.37
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 +232 -238
- package/src/versifications/isaiah.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codexparser",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
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
|
@@ -46,189 +46,164 @@ class CodexParser {
|
|
|
46
46
|
]
|
|
47
47
|
this.chapterVerses = chapter_verses
|
|
48
48
|
this.error = false
|
|
49
|
-
this.version =
|
|
49
|
+
this.version = null
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
* Scans the given text for Bible references
|
|
54
|
-
*
|
|
55
|
-
* @
|
|
53
|
+
* Scans the given text for Bible references and stores all found references in the `found` property of the instance.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} text - The text to scan for Bible references.
|
|
56
|
+
* @return {CodexParser} - Returns the instance itself, enabling method chaining.
|
|
56
57
|
*/
|
|
57
58
|
scan(text) {
|
|
58
|
-
|
|
59
|
-
const abbreviations = Object.keys(this.abbreviations) // Abbreviations for Bible books
|
|
60
|
-
|
|
59
|
+
// Initialize the `found` property as an empty array to store matched references.
|
|
61
60
|
this.found = []
|
|
62
61
|
|
|
63
|
-
//
|
|
62
|
+
// Retrieve the full names of Bible books (both Old and New Testament).
|
|
63
|
+
const fullNames = [...this.bible.old, ...this.bible.new]
|
|
64
|
+
|
|
65
|
+
// Retrieve the abbreviations for Bible books from the `abbreviations` object.
|
|
66
|
+
const abbreviations = Object.keys(this.abbreviations)
|
|
67
|
+
|
|
68
|
+
// Convert all Bible book names and abbreviations to lowercase for case-insensitive matching.
|
|
64
69
|
const lowercaseBibleFullNames = fullNames.map((book) => book.toLowerCase())
|
|
65
70
|
const lowercaseBibleAbbreviations = abbreviations.map((abbr) => abbr.toLowerCase())
|
|
71
|
+
|
|
72
|
+
// Convert the input text to lowercase for consistent comparison.
|
|
66
73
|
const lowerCaseText = text.toLowerCase()
|
|
67
74
|
|
|
75
|
+
// Initialize an index pointer `i` to iterate through the text.
|
|
68
76
|
let i = 0
|
|
69
77
|
|
|
70
|
-
//
|
|
71
|
-
const isValidChapterVerseChar = (char) =>
|
|
72
|
-
return /[^A-Za-z]/.test(char) // Allow any non-word characters
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Function to check if a character at a given index is non-alphabetic or at the boundary of the text
|
|
76
|
-
const isBoundaryOrNonAlphabetic = (index, text) => {
|
|
77
|
-
return index < 0 || index >= text.length || /[^a-z]/i.test(text[index])
|
|
78
|
-
}
|
|
78
|
+
// Helper function to check if a character is valid for chapter or verse notation.
|
|
79
|
+
const isValidChapterVerseChar = (char) => /[^A-Za-z]/.test(char)
|
|
79
80
|
|
|
80
|
-
//
|
|
81
|
+
// Helper function to determine if the next sequence in the text matches a Bible book name or abbreviation.
|
|
81
82
|
const isNextBibleBook = (startIndex) => {
|
|
82
83
|
const textAfterCurrentPosition = lowerCaseText.substring(startIndex).trim()
|
|
83
84
|
|
|
84
|
-
// Check if the
|
|
85
|
-
for (
|
|
86
|
-
if (textAfterCurrentPosition.startsWith(
|
|
87
|
-
return true // Found another Bible book
|
|
88
|
-
}
|
|
85
|
+
// Check if the upcoming text starts with any full Bible book name.
|
|
86
|
+
for (const book of lowercaseBibleFullNames) {
|
|
87
|
+
if (textAfterCurrentPosition.startsWith(book)) return true
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
90
|
+
// Check if the upcoming text starts with any Bible book abbreviation.
|
|
91
|
+
for (const abbr of lowercaseBibleAbbreviations) {
|
|
92
|
+
if (textAfterCurrentPosition.startsWith(abbr)) return true
|
|
95
93
|
}
|
|
96
94
|
|
|
95
|
+
// If no match is found, return false.
|
|
97
96
|
return false
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
//
|
|
99
|
+
// Helper function to detect suffixes like "LXX" or "MT" in the text after a given index.
|
|
101
100
|
const detectSuffix = (startIndex) => {
|
|
102
101
|
const suffixMatch = text.substring(startIndex).match(/\b(LXX|MT)\b/i)
|
|
103
102
|
return suffixMatch ? suffixMatch[0].toUpperCase() : null
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
//
|
|
105
|
+
// Main loop: Iterate through the input text to search for Bible references.
|
|
107
106
|
while (i < lowerCaseText.length) {
|
|
108
|
-
let foundBook = null
|
|
109
|
-
let foundIndex = -1
|
|
110
|
-
let matchedLength = 0
|
|
107
|
+
let foundBook = null // Stores the matched Bible book name.
|
|
108
|
+
let foundIndex = -1 // Tracks the index where the match starts.
|
|
109
|
+
let matchedLength = 0 // Tracks the length of the matched book name.
|
|
111
110
|
|
|
112
|
-
// Check
|
|
111
|
+
// Check for matches against full Bible book names.
|
|
113
112
|
for (let j = 0; j < lowercaseBibleFullNames.length; j++) {
|
|
114
113
|
const book = lowercaseBibleFullNames[j]
|
|
115
114
|
|
|
116
|
-
//
|
|
117
|
-
if (lowerCaseText.startsWith(book, i)) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
matchedLength = book.length // Update the length of the match
|
|
122
|
-
}
|
|
115
|
+
// If the text at the current index matches a book name and is longer than any previously matched name.
|
|
116
|
+
if (lowerCaseText.startsWith(book, i) && book.length > matchedLength) {
|
|
117
|
+
foundBook = fullNames[j] // Store the original case-sensitive book name.
|
|
118
|
+
foundIndex = i // Update the starting index of the match.
|
|
119
|
+
matchedLength = book.length // Update the length of the match.
|
|
123
120
|
}
|
|
124
121
|
}
|
|
125
122
|
|
|
126
|
-
// If no
|
|
123
|
+
// If no match was found against full names, try matching against abbreviations.
|
|
127
124
|
if (!foundBook) {
|
|
128
125
|
for (let k = 0; k < lowercaseBibleAbbreviations.length; k++) {
|
|
129
126
|
const abbreviation = lowercaseBibleAbbreviations[k]
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
isBoundaryOrNonAlphabetic(i + abbreviationWithDot.length, lowerCaseText)
|
|
137
|
-
) {
|
|
138
|
-
// Look ahead to check if a number or space + number follows the abbreviation
|
|
139
|
-
const afterAbbreviation = lowerCaseText.substring(i + abbreviationWithDot.length).trim()
|
|
140
|
-
if (/^\d+/.test(afterAbbreviation)) {
|
|
141
|
-
// Check if there is a number (chapter/verse)
|
|
142
|
-
foundBook = abbreviations[k] // Store the abbreviation without the dot
|
|
143
|
-
foundIndex = i // Record the index where the abbreviation is found
|
|
144
|
-
matchedLength = abbreviationWithDot.length // Update the length of the match to include the dot
|
|
145
|
-
break // Exit once found
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
} else if (lowerCaseText.startsWith(abbreviation, i)) {
|
|
149
|
-
if (
|
|
150
|
-
isBoundaryOrNonAlphabetic(i - 1, lowerCaseText) &&
|
|
151
|
-
isBoundaryOrNonAlphabetic(i + abbreviation.length, lowerCaseText)
|
|
152
|
-
) {
|
|
153
|
-
// Look ahead to check if a number or space + number follows the abbreviation
|
|
154
|
-
const afterAbbreviation = lowerCaseText.substring(i + abbreviation.length).trim()
|
|
155
|
-
if (/^\d+/.test(afterAbbreviation)) {
|
|
156
|
-
// Check if there is a number (chapter/verse)
|
|
157
|
-
if (abbreviation.length > matchedLength) {
|
|
158
|
-
foundBook = abbreviations[k] // Store the abbreviation without the dot
|
|
159
|
-
foundIndex = i // Record the index where the abbreviation is found
|
|
160
|
-
matchedLength = abbreviation.length // Update the length of the match
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
127
|
+
|
|
128
|
+
// If the text at the current index matches an abbreviation.
|
|
129
|
+
if (lowerCaseText.startsWith(abbreviation, i)) {
|
|
130
|
+
foundBook = abbreviations[k] // Store the original abbreviation.
|
|
131
|
+
foundIndex = i // Update the starting index of the match.
|
|
132
|
+
matchedLength = abbreviation.length // Update the length of the match.
|
|
164
133
|
}
|
|
165
134
|
}
|
|
166
135
|
}
|
|
167
136
|
|
|
168
|
-
// If a book
|
|
169
|
-
if (foundBook
|
|
170
|
-
i += matchedLength //
|
|
171
|
-
let chapterVerse = ""
|
|
172
|
-
const references = []
|
|
137
|
+
// If a Bible book is found.
|
|
138
|
+
if (foundBook) {
|
|
139
|
+
i += matchedLength // Move the pointer past the matched book name.
|
|
140
|
+
let chapterVerse = "" // Initialize a variable to accumulate chapter and verse information.
|
|
141
|
+
const references = [] // Array to store individual chapter and verse references.
|
|
173
142
|
|
|
174
|
-
//
|
|
143
|
+
// Secondary loop: Extract chapter and verse information after the book name.
|
|
175
144
|
while (i < text.length && isValidChapterVerseChar(text[i])) {
|
|
176
|
-
//
|
|
177
|
-
if (isNextBibleBook(i))
|
|
178
|
-
break // Stop adding to chapterVerse if a new Bible book is found
|
|
179
|
-
}
|
|
145
|
+
// Break if another Bible book starts at the current position.
|
|
146
|
+
if (isNextBibleBook(i)) break
|
|
180
147
|
|
|
181
|
-
//
|
|
182
|
-
// || text[i] === " "
|
|
148
|
+
// Handle semicolon-delimited references (e.g., "John 3:16; 4:5").
|
|
183
149
|
if (text[i] === ";") {
|
|
184
150
|
const formattedReference = chapterVerse
|
|
185
151
|
.trim()
|
|
186
|
-
.replace(
|
|
187
|
-
.replace(/[^a-zA-Z0-9]+$/, "")
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
i++
|
|
152
|
+
.replace(/\.+/g, ":") // Replace dots (.) with colons (:).
|
|
153
|
+
.replace(/[^a-zA-Z0-9:]+$/, "") // Remove trailing invalid characters.
|
|
154
|
+
|
|
155
|
+
if (formattedReference) references.push(formattedReference) // Add the formatted reference to the list.
|
|
156
|
+
chapterVerse = "" // Reset the chapterVerse accumulator.
|
|
157
|
+
i++ // Move past the semicolon.
|
|
193
158
|
continue
|
|
194
159
|
}
|
|
195
160
|
|
|
161
|
+
// Accumulate valid characters for the chapterVerse.
|
|
196
162
|
chapterVerse += text[i]
|
|
197
163
|
i++
|
|
198
164
|
}
|
|
199
165
|
|
|
200
|
-
//
|
|
166
|
+
// Handle any remaining chapterVerse after the loop ends.
|
|
201
167
|
if (chapterVerse.trim().length > 0) {
|
|
202
168
|
const formattedReference = chapterVerse
|
|
203
169
|
.trim()
|
|
204
|
-
.replace(
|
|
205
|
-
.replace(/[^a-zA-Z0-9]+$/, "")
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
170
|
+
.replace(/\.+/g, ":") // Replace dots (.) with colons (:).
|
|
171
|
+
.replace(/[^a-zA-Z0-9:]+$/, "") // Remove trailing invalid characters.
|
|
172
|
+
|
|
173
|
+
if (formattedReference) references.push(formattedReference) // Add the formatted reference to the list.
|
|
209
174
|
}
|
|
210
175
|
|
|
211
|
-
// Detect
|
|
176
|
+
// Detect any suffix (e.g., "LXX" or "MT") after the chapter/verse reference.
|
|
212
177
|
const suffix = detectSuffix(i)
|
|
213
178
|
|
|
214
|
-
//
|
|
179
|
+
// Process each extracted reference to classify its type and store it in the `found` array.
|
|
215
180
|
references.forEach((ref) => {
|
|
216
181
|
this.found.push({
|
|
217
|
-
book: foundBook,
|
|
218
|
-
reference: ref,
|
|
219
|
-
index: foundIndex,
|
|
220
|
-
|
|
182
|
+
book: foundBook, // The matched book name.
|
|
183
|
+
reference: ref.replace(/^:/, "").trim().replace(/\s+/gim, ""), // Format the reference.
|
|
184
|
+
index: foundIndex, // The starting index of the match in the original text.
|
|
185
|
+
type: ref.includes(":") ? "chapter_verse" : "single_chapter", // Determine the type of reference.
|
|
186
|
+
version: suffix || null, // Add detected suffix (e.g., "LXX" or "MT").
|
|
221
187
|
})
|
|
222
188
|
})
|
|
223
189
|
} else {
|
|
190
|
+
// If no book is found, move the pointer forward by one character.
|
|
224
191
|
i++
|
|
225
192
|
}
|
|
226
193
|
}
|
|
227
194
|
|
|
228
|
-
|
|
195
|
+
// Return the current instance for method chaining.
|
|
196
|
+
return this
|
|
229
197
|
}
|
|
230
198
|
|
|
231
|
-
|
|
199
|
+
bibleVersion(version) {
|
|
200
|
+
const lowerVersion = version.toLowerCase()
|
|
201
|
+
this.version =
|
|
202
|
+
lowerVersion === "lxx" || lowerVersion === "eng" || lowerVersion === "bhs" || lowerVersion === "mt"
|
|
203
|
+
? lowerVersion
|
|
204
|
+
: null
|
|
205
|
+
return this
|
|
206
|
+
}
|
|
232
207
|
|
|
233
208
|
/**
|
|
234
209
|
* Parses a given reference and returns an object with the parsed passage,
|
|
@@ -238,145 +213,106 @@ class CodexParser {
|
|
|
238
213
|
* @returns {object} An object with the parsed passage.
|
|
239
214
|
*/
|
|
240
215
|
parse(reference) {
|
|
241
|
-
// Call scan to populate this.found
|
|
242
216
|
this.scan(reference)
|
|
243
217
|
|
|
244
218
|
this.passages = this.found.map((passage) => {
|
|
245
|
-
// Clean up spaces and remove any dots from the reference
|
|
246
|
-
passage.reference =
|
|
247
|
-
passage.reference.match(/[:]/g)?.length > 1 ? passage.reference.replace(/[:]/, "") : passage.reference
|
|
248
219
|
const book = this.bookify(passage.book)
|
|
249
|
-
const testament = this.bible.old.
|
|
250
|
-
|
|
220
|
+
const testament = this.bible.old.includes(book) ? "old" : "new"
|
|
221
|
+
|
|
251
222
|
const parsedPassage = {
|
|
252
|
-
original: passage.book
|
|
253
|
-
book
|
|
223
|
+
original: `${passage.book} ${passage.reference}`,
|
|
224
|
+
book,
|
|
254
225
|
chapter: null,
|
|
255
|
-
verses: [],
|
|
256
|
-
type:
|
|
257
|
-
testament
|
|
226
|
+
verses: [],
|
|
227
|
+
type: passage.type,
|
|
228
|
+
testament,
|
|
258
229
|
index: passage.index,
|
|
259
230
|
version: this._handleVersion(passage.version, testament),
|
|
260
231
|
}
|
|
261
232
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// Check for single chapter books
|
|
266
|
-
const singleChapterBook = this.singleChapterBook.find((bible) => bible[book])
|
|
233
|
+
const parts = passage.reference.split(",")
|
|
234
|
+
const isSingleChapter = this.singleChapterBook.some((singleChapterBook) => singleChapterBook[book])
|
|
267
235
|
|
|
268
236
|
parts.forEach((part) => {
|
|
269
|
-
part = part.trim()
|
|
270
|
-
// Detect whether it uses ":" or "." for chapter:verse separation
|
|
237
|
+
part = part.trim()
|
|
271
238
|
const separator = part.includes(":") ? ":" : "."
|
|
272
239
|
|
|
273
240
|
if (part.includes("-")) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
this.chapterVerses[book][startChapter].indexOf(Number(startVerse))
|
|
288
|
-
)
|
|
289
|
-
}
|
|
290
|
-
// Handle same-chapter ranges (e.g., "27:27-29") and multi-chapter ranges (e.g., "Ex 2:1-3:4")
|
|
291
|
-
if (end.includes(separator)) {
|
|
292
|
-
let [endChapter, endVerse] = end.split(separator)
|
|
293
|
-
if (Number(endChapter) !== Number(startChapter)) {
|
|
294
|
-
// Cross-chapter range, set 'to' property
|
|
295
|
-
parsedPassage.to = {
|
|
296
|
-
book: book,
|
|
297
|
-
chapter: Number(endChapter), // End chapter
|
|
298
|
-
}
|
|
299
|
-
if (endVerse > 1) {
|
|
300
|
-
parsedPassage.to.verses = this.chapterVerses[book][Number(endChapter)].slice(
|
|
301
|
-
0,
|
|
302
|
-
this.chapterVerses[book][Number(endChapter)].indexOf(Number(endVerse)) + 1
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
parsedPassage.type = "chapter_verse_range" // Set type to chapter range
|
|
306
|
-
} else {
|
|
307
|
-
// Same-chapter range, just add to the verse array
|
|
308
|
-
parsedPassage.verses.push(`${startVerse}-${endVerse}`)
|
|
309
|
-
}
|
|
310
|
-
} else {
|
|
311
|
-
// Single-chapter range (e.g., "27:27-29" or "39-41")
|
|
312
|
-
if (!singleChapterBook) {
|
|
313
|
-
if (!startChapter) {
|
|
314
|
-
// Then we have a chapter range with no verses
|
|
315
|
-
parsedPassage.chapter = start
|
|
316
|
-
parsedPassage.verses = this.chapterVerses[book][start]
|
|
241
|
+
if (!isSingleChapter) {
|
|
242
|
+
if (part.includes(":")) {
|
|
243
|
+
let [start, end] = part.split("-")
|
|
244
|
+
const [startChapter, startVerse] = start.includes(separator)
|
|
245
|
+
? start.split(separator).map(Number)
|
|
246
|
+
: [parsedPassage.chapter, Number(start)]
|
|
247
|
+
const [endChapter, endVerse] = end.includes(separator)
|
|
248
|
+
? end.split(separator).map(Number)
|
|
249
|
+
: [startChapter, Number(end)]
|
|
250
|
+
|
|
251
|
+
parsedPassage.chapter = startChapter
|
|
252
|
+
|
|
253
|
+
if (startChapter !== endChapter) {
|
|
317
254
|
parsedPassage.to = {
|
|
318
|
-
book
|
|
319
|
-
chapter:
|
|
320
|
-
verses:
|
|
255
|
+
book,
|
|
256
|
+
chapter: endChapter,
|
|
257
|
+
verses: [endVerse],
|
|
321
258
|
}
|
|
259
|
+
parsedPassage.verses.push(startVerse)
|
|
322
260
|
} else {
|
|
323
|
-
|
|
324
|
-
parsedPassage.verses.push(`${startVerse}-${end}`)
|
|
261
|
+
parsedPassage.verses.push(...this._generateRange(startVerse, endVerse))
|
|
325
262
|
}
|
|
326
263
|
} else {
|
|
327
|
-
|
|
328
|
-
parsedPassage.
|
|
264
|
+
const [start, end] = part.split("-")
|
|
265
|
+
parsedPassage.chapter = Number(start)
|
|
266
|
+
parsedPassage.to = {
|
|
267
|
+
book,
|
|
268
|
+
chapter: Number(end),
|
|
269
|
+
verses: [],
|
|
270
|
+
}
|
|
329
271
|
}
|
|
272
|
+
} else {
|
|
273
|
+
part = part.replace(/\d+:/gim, "")
|
|
274
|
+
const [singleChapterStartVerse, singleChapterEndVerse] = part.split("-")
|
|
275
|
+
parsedPassage.chapter = 1
|
|
276
|
+
parsedPassage.verses = [`${singleChapterStartVerse}-${singleChapterEndVerse}`]
|
|
277
|
+
parsedPassage.type = "single_chapter_book_verse_range"
|
|
330
278
|
}
|
|
279
|
+
} else if (part.includes(separator)) {
|
|
280
|
+
const [chapterPart, versePart] = part.split(separator).map(Number)
|
|
281
|
+
parsedPassage.chapter = chapterPart
|
|
282
|
+
if (versePart) parsedPassage.verses.push(versePart)
|
|
331
283
|
} else {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (singleChapterBook) {
|
|
337
|
-
if (!chapterPart) {
|
|
338
|
-
parsedPassage.chapter = 1
|
|
339
|
-
parsedPassage.verses.push(versePart) // Add single verse to array
|
|
340
|
-
} else {
|
|
341
|
-
parsedPassage.chapter = Number(chapterPart)
|
|
342
|
-
parsedPassage.verses.push(versePart) // Add single verse to array
|
|
284
|
+
if (!isSingleChapter) {
|
|
285
|
+
const number = Number(part)
|
|
286
|
+
if (!parsedPassage.verses.length) {
|
|
287
|
+
parsedPassage.chapter = number
|
|
343
288
|
}
|
|
289
|
+
parsedPassage.verses.push(Number(part))
|
|
344
290
|
} else {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
// verses from this.chapterVerses
|
|
348
|
-
if (chapterPart) {
|
|
349
|
-
parsedPassage.chapter = Number(chapterPart)
|
|
350
|
-
parsedPassage.verses.push(versePart) // Add single verse to array
|
|
351
|
-
} else {
|
|
352
|
-
parsedPassage.chapter = Number(versePart)
|
|
353
|
-
if (!this.chapterVerses[book][parsedPassage.chapter]) {
|
|
354
|
-
parsedPassage.valid = this._isValid(parsedPassage, passage.reference)
|
|
355
|
-
} else {
|
|
356
|
-
// Need to set the version of the passage here, i.e. LXX, MT, English
|
|
357
|
-
this._setVersion(parsedPassage)
|
|
358
|
-
parsedPassage.verses = [
|
|
359
|
-
this.chapterVerses[book][parsedPassage.chapter][0] +
|
|
360
|
-
"-" +
|
|
361
|
-
this.chapterVerses[book][parsedPassage.chapter][
|
|
362
|
-
this.chapterVerses[book][parsedPassage.chapter].length - 1
|
|
363
|
-
],
|
|
364
|
-
]
|
|
365
|
-
parsedPassage.type = "single_chapter"
|
|
366
|
-
}
|
|
367
|
-
}
|
|
291
|
+
parsedPassage.chapter = 1
|
|
292
|
+
parsedPassage.verses.push(Number(part))
|
|
368
293
|
}
|
|
369
294
|
}
|
|
370
|
-
parsedPassage.passages = this.populate(parsedPassage)
|
|
371
|
-
parsedPassage.scripture = this.scripturize(parsedPassage)
|
|
372
295
|
})
|
|
373
296
|
|
|
297
|
+
parsedPassage.passages = this.populate(parsedPassage)
|
|
298
|
+
parsedPassage.scripture = this.scripturize(parsedPassage)
|
|
374
299
|
parsedPassage.valid = this._isValid(parsedPassage, passage.reference)
|
|
375
300
|
|
|
376
301
|
return parsedPassage
|
|
377
302
|
})
|
|
303
|
+
|
|
378
304
|
this.versification()
|
|
379
|
-
return this
|
|
305
|
+
return this
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Generates an array of numbers representing a range from start to end, inclusive.
|
|
309
|
+
*/
|
|
310
|
+
_generateRange(start, end) {
|
|
311
|
+
const range = []
|
|
312
|
+
for (let i = start; i <= end; i++) {
|
|
313
|
+
range.push(i)
|
|
314
|
+
}
|
|
315
|
+
return range
|
|
380
316
|
}
|
|
381
317
|
|
|
382
318
|
_searchVersificationDifferences(passage) {
|
|
@@ -399,8 +335,11 @@ class CodexParser {
|
|
|
399
335
|
}
|
|
400
336
|
|
|
401
337
|
_setVersion(passage) {
|
|
402
|
-
this.version = passage.version.abbreviation
|
|
403
|
-
|
|
338
|
+
this.version = passage.version ? passage.version.abbreviation : "eng"
|
|
339
|
+
|
|
340
|
+
if (this.version !== "eng") {
|
|
341
|
+
this._searchVersificationDifferences(passage)
|
|
342
|
+
}
|
|
404
343
|
}
|
|
405
344
|
|
|
406
345
|
versification() {
|
|
@@ -449,33 +388,84 @@ class CodexParser {
|
|
|
449
388
|
* @param {Array} verses - Array of verse numbers to add to the set of passages
|
|
450
389
|
* @return {Array} Array of passage objects
|
|
451
390
|
*/
|
|
391
|
+
/**
|
|
392
|
+
* Populate all verses from a parsed passage, including all verses in ranges or chapters.
|
|
393
|
+
*
|
|
394
|
+
* @param {Object} parsedPassage - The parsed passage object containing book, chapter, and verses information.
|
|
395
|
+
* @return {Array} An array of passage objects with individual verses.
|
|
396
|
+
*/
|
|
452
397
|
populate(parsedPassage) {
|
|
453
398
|
const passages = []
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
399
|
+
const { book, chapter, verses, type } = parsedPassage
|
|
400
|
+
if (type === "single_chapter") {
|
|
401
|
+
// Handle single chapter references
|
|
402
|
+
if (this.chapterVerses[book] && this.chapterVerses[book][chapter]) {
|
|
403
|
+
this.chapterVerses[book][chapter].forEach((verse) => {
|
|
404
|
+
passages.push({ book, chapter: Number(chapter), verse: Number(verse) })
|
|
405
|
+
})
|
|
460
406
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
passages.push({ book, chapter: Number(chapter), verse: i })
|
|
466
|
-
}
|
|
467
|
-
} else {
|
|
407
|
+
} else if (type === "comma_separated_verses") {
|
|
408
|
+
// Handle only the explicitly mentioned verses
|
|
409
|
+
if (verses && this.chapterVerses[book] && this.chapterVerses[book][chapter]) {
|
|
410
|
+
verses.forEach((verse) => {
|
|
468
411
|
passages.push({ book, chapter: Number(chapter), verse: Number(verse) })
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
} else if (type === "chapter_range") {
|
|
415
|
+
const { to } = parsedPassage
|
|
416
|
+
|
|
417
|
+
for (let i = chapter; i <= to.chapter; i++) {
|
|
418
|
+
const verses = this.chapterVerses[book][i]
|
|
419
|
+
for (let j = verses[0]; j < verses.length; j++) {
|
|
420
|
+
passages.push({
|
|
421
|
+
book,
|
|
422
|
+
chapter: i,
|
|
423
|
+
verse: j,
|
|
424
|
+
})
|
|
469
425
|
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
426
|
+
}
|
|
427
|
+
} else if (type === "multi_chapter_verse_range") {
|
|
428
|
+
const { to } = parsedPassage
|
|
429
|
+
|
|
430
|
+
// Create an array of reference objects for the start and end of the range
|
|
431
|
+
const refs = [
|
|
432
|
+
{
|
|
433
|
+
chapter: Number(parsedPassage.chapter),
|
|
434
|
+
verse: Number(parsedPassage.verses[0]),
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
chapter: Number(to.chapter),
|
|
438
|
+
verse: Number(to.verses[to.verses.length - 1]),
|
|
439
|
+
},
|
|
440
|
+
]
|
|
441
|
+
|
|
442
|
+
// Iterate over the range of chapters and verses
|
|
443
|
+
for (let i = refs[0].chapter; i <= refs[1].chapter; i++) {
|
|
444
|
+
const startVerse = i === refs[0].chapter ? refs[0].verse : 1
|
|
445
|
+
const endVerse = i === refs[1].chapter ? refs[1].verse : this.chapterVerses[book][i].length
|
|
446
|
+
|
|
447
|
+
for (let j = startVerse; j <= endVerse; j++) {
|
|
448
|
+
passages.push({
|
|
449
|
+
book,
|
|
450
|
+
chapter: i,
|
|
451
|
+
verse: j,
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
} else if (type === "chapter_verse" || type === "chapter_verse_range") {
|
|
456
|
+
// Handle chapter:verse or chapter:verse-range references
|
|
457
|
+
if (verses && this.chapterVerses[book] && this.chapterVerses[book][chapter]) {
|
|
458
|
+
verses.forEach((verse) => {
|
|
459
|
+
if (typeof verse === "string" && verse.includes("-")) {
|
|
460
|
+
const [start, end] = verse.split("-").map(Number)
|
|
461
|
+
for (let i = start; i <= end; i++) {
|
|
462
|
+
passages.push({ book, chapter: Number(chapter), verse: i })
|
|
463
|
+
}
|
|
464
|
+
} else {
|
|
465
|
+
passages.push({ book, chapter: Number(chapter), verse: Number(verse) })
|
|
466
|
+
}
|
|
467
|
+
})
|
|
468
|
+
}
|
|
479
469
|
}
|
|
480
470
|
|
|
481
471
|
return passages
|
|
@@ -589,6 +579,7 @@ class CodexParser {
|
|
|
589
579
|
* and builds the original and scripture properties.
|
|
590
580
|
* **This method will always combine based on English versification. LXX and MT versifications will be reflected in the combined passage.passages.versification.**
|
|
591
581
|
* This method will fail if the passages are not to the same book and chapter.
|
|
582
|
+
* TODO: Add support for MT and LXX
|
|
592
583
|
* @param {array} passages - An array of passage objects to combine.
|
|
593
584
|
* @return {object} The combined passage object.
|
|
594
585
|
*/
|
|
@@ -816,8 +807,11 @@ class CodexParser {
|
|
|
816
807
|
return true
|
|
817
808
|
}
|
|
818
809
|
_handleVersion(version, testament) {
|
|
810
|
+
if (this.version) {
|
|
811
|
+
version = this.version
|
|
812
|
+
}
|
|
819
813
|
if (!version) {
|
|
820
|
-
|
|
814
|
+
version = "eng"
|
|
821
815
|
}
|
|
822
816
|
if (version.toLowerCase() === "lxx" && testament.toLowerCase() === "old") {
|
|
823
817
|
return {
|