codexparser 0.1.38 → 0.1.39

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 +83 -65
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexparser",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
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": {
@@ -56,144 +56,163 @@ class CodexParser {
56
56
  * @return {CodexParser} - Returns the instance itself, enabling method chaining.
57
57
  */
58
58
  scan(text) {
59
- // Initialize the `found` property as an empty array to store matched references.
60
- this.found = []
61
-
62
- // Retrieve the full names of Bible books (both Old and New Testament).
59
+ // Combine Old and New Testament book names into a single array
63
60
  const fullNames = [...this.bible.old, ...this.bible.new]
64
61
 
65
- // Retrieve the abbreviations for Bible books from the `abbreviations` object.
62
+ // Retrieve all abbreviation keys from the abbreviations object
66
63
  const abbreviations = Object.keys(this.abbreviations)
67
64
 
68
- // Convert all Bible book names and abbreviations to lowercase for case-insensitive matching.
65
+ // Initialize the `found` array to store the results
66
+ this.found = []
67
+
68
+ // Convert Bible book names, abbreviations, and input text to lowercase for case-insensitive matching
69
69
  const lowercaseBibleFullNames = fullNames.map((book) => book.toLowerCase())
70
70
  const lowercaseBibleAbbreviations = abbreviations.map((abbr) => abbr.toLowerCase())
71
-
72
- // Convert the input text to lowercase for consistent comparison.
73
71
  const lowerCaseText = text.toLowerCase()
74
72
 
75
- // Initialize an index pointer `i` to iterate through the text.
76
- let i = 0
73
+ let i = 0 // Index pointer to iterate through the input text
77
74
 
78
- // Helper function to check if a character is valid for chapter or verse notation.
75
+ /**
76
+ * Helper function to check if a character is part of a chapter or verse reference.
77
+ * Non-word characters (anything not A-Z or a-z) are considered valid.
78
+ */
79
79
  const isValidChapterVerseChar = (char) => /[^A-Za-z]/.test(char)
80
80
 
81
- // Helper function to determine if the next sequence in the text matches a Bible book name or abbreviation.
81
+ /**
82
+ * Helper function to determine if the text starting at a given index contains
83
+ * the name of a new Bible book.
84
+ */
82
85
  const isNextBibleBook = (startIndex) => {
83
86
  const textAfterCurrentPosition = lowerCaseText.substring(startIndex).trim()
84
87
 
85
- // Check if the upcoming text starts with any full Bible book name.
88
+ // Check for full Bible book names
86
89
  for (const book of lowercaseBibleFullNames) {
87
90
  if (textAfterCurrentPosition.startsWith(book)) return true
88
91
  }
89
92
 
90
- // Check if the upcoming text starts with any Bible book abbreviation.
93
+ // Check for Bible book abbreviations
91
94
  for (const abbr of lowercaseBibleAbbreviations) {
92
95
  if (textAfterCurrentPosition.startsWith(abbr)) return true
93
96
  }
94
97
 
95
- // If no match is found, return false.
96
- return false
98
+ return false // No match found
97
99
  }
98
100
 
99
- // Helper function to detect suffixes like "LXX" or "MT" in the text after a given index.
101
+ /**
102
+ * Helper function to detect suffixes like "LXX" or "MT" in the text after a given index.
103
+ * These suffixes are case-insensitive and indicate the version of the Bible reference.
104
+ */
100
105
  const detectSuffix = (startIndex) => {
101
106
  const suffixMatch = text.substring(startIndex).match(/\b(LXX|MT)\b/i)
102
107
  return suffixMatch ? suffixMatch[0].toUpperCase() : null
103
108
  }
104
109
 
105
- // Main loop: Iterate through the input text to search for Bible references.
110
+ // Iterate through the input text to detect and process Bible references
106
111
  while (i < lowerCaseText.length) {
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.
112
+ let foundBook = null // Placeholder for the detected book name
113
+ let foundIndex = -1 // Index in the text where the book name starts
114
+ let matchedLength = 0 // Length of the matched book name or abbreviation
110
115
 
111
- // Check for matches against full Bible book names.
116
+ // Search for full Bible book names in the text
112
117
  for (let j = 0; j < lowercaseBibleFullNames.length; j++) {
113
118
  const book = lowercaseBibleFullNames[j]
114
-
115
- // If the text at the current index matches a book name and is longer than any previously matched name.
116
119
  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.
120
+ foundBook = fullNames[j] // Store the original book name (case-sensitive)
121
+ foundIndex = i
122
+ matchedLength = book.length // Update the match length
120
123
  }
121
124
  }
122
125
 
123
- // If no match was found against full names, try matching against abbreviations.
126
+ // If no full book name is found, search for abbreviations
124
127
  if (!foundBook) {
125
128
  for (let k = 0; k < lowercaseBibleAbbreviations.length; k++) {
126
129
  const abbreviation = lowercaseBibleAbbreviations[k]
127
-
128
- // If the text at the current index matches an abbreviation.
129
130
  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.
131
+ foundBook = abbreviations[k]
132
+ foundIndex = i
133
+ matchedLength = abbreviation.length
133
134
  }
134
135
  }
135
136
  }
136
137
 
137
- // If a Bible book is found.
138
+ // If a Bible book is found
138
139
  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.
140
+ i += matchedLength // Move the index pointer forward by the length of the book name
141
+ let chapterVerse = "" // Placeholder for chapter and verse data
142
+ const references = [] // Array to store multiple chapter/verse references for the same book
142
143
 
143
- // Secondary loop: Extract chapter and verse information after the book name.
144
+ // Extract chapter and verse references
144
145
  while (i < text.length && isValidChapterVerseChar(text[i])) {
145
- // Break if another Bible book starts at the current position.
146
- if (isNextBibleBook(i)) break
146
+ if (isNextBibleBook(i)) break // Stop if a new Bible book is detected
147
147
 
148
- // Handle semicolon-delimited references (e.g., "John 3:16; 4:5").
148
+ // Handle semicolon-separated references (indicates a new reference)
149
149
  if (text[i] === ";") {
150
150
  const formattedReference = chapterVerse
151
151
  .trim()
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.
152
+ .replace(/\./g, ":")
153
+ .replace(/[^a-zA-Z0-9]+$/, "")
154
+ if (formattedReference) references.push(formattedReference)
155
+ chapterVerse = "" // Reset for the next reference
156
+ i++
158
157
  continue
159
158
  }
160
159
 
161
- // Accumulate valid characters for the chapterVerse.
162
160
  chapterVerse += text[i]
163
161
  i++
164
162
  }
165
163
 
166
- // Handle any remaining chapterVerse after the loop ends.
164
+ // Process the last detected chapter/verse reference
167
165
  if (chapterVerse.trim().length > 0) {
168
166
  const formattedReference = chapterVerse
169
167
  .trim()
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.
168
+ .replace(/\./g, ":")
169
+ .replace(/[^a-zA-Z0-9]+$/, "")
170
+ if (formattedReference) references.push(formattedReference)
174
171
  }
175
172
 
176
- // Detect any suffix (e.g., "LXX" or "MT") after the chapter/verse reference.
173
+ // Detect any suffix (e.g., "LXX" or "MT") after the chapter/verse reference
177
174
  const suffix = detectSuffix(i)
178
175
 
179
- // Process each extracted reference to classify its type and store it in the `found` array.
176
+ // Add each reference as a separate object to the `found` array with type recognition
180
177
  references.forEach((ref) => {
178
+ let type
179
+
180
+ if (ref.includes(":")) {
181
+ if (ref.includes("-")) {
182
+ const [start, end] = ref.split("-")
183
+ const startParts = start.split(":")
184
+ const endParts = end.split(":")
185
+
186
+ if (startParts.length > 1 && endParts.length > 1 && startParts[0] !== endParts[0]) {
187
+ type = "multi_chapter_verse_range" // Example: "8:23-9:1"
188
+ } else {
189
+ type = "chapter_verse_range" // Example: "8:23-25"
190
+ }
191
+ } else if (ref.includes(",")) {
192
+ type = "comma_separated_verses" // Example: "8:23,24"
193
+ } else {
194
+ type = "chapter_verse" // Example: "8:23"
195
+ }
196
+ } else if (ref.includes("-")) {
197
+ type = "chapter_range" // Example: "8-9"
198
+ } else {
199
+ type = "single_chapter" // Example: "8"
200
+ }
201
+
181
202
  this.found.push({
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").
203
+ book: foundBook,
204
+ reference: ref,
205
+ index: foundIndex,
206
+ version: suffix || null,
207
+ type,
187
208
  })
188
209
  })
189
210
  } else {
190
- // If no book is found, move the pointer forward by one character.
191
- i++
211
+ i++ // Move to the next character if no book is found
192
212
  }
193
213
  }
194
214
 
195
- // Return the current instance for method chaining.
196
- return this
215
+ return this // Return the current instance for method chaining
197
216
  }
198
217
 
199
218
  bibleVersion(version) {
@@ -426,7 +445,6 @@ class CodexParser {
426
445
  }
427
446
  } else if (type === "multi_chapter_verse_range") {
428
447
  const { to } = parsedPassage
429
-
430
448
  // Create an array of reference objects for the start and end of the range
431
449
  const refs = [
432
450
  {