codexparser 0.1.97 → 0.3.0
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/.trunk/trunk.yaml +3 -3
- package/CHANGELOG.md +18 -0
- package/README.md +76 -0
- package/REFACTORING.md +214 -0
- package/RELEASE_NOTES_v0.2.0.md +5 -0
- package/index.js +1 -1
- package/package.json +4 -24
- package/src/{CodexParser.js → CodexParser.js.backup} +303 -247
- package/src/core/CodexParser.js +353 -0
- package/src/core/PassageCollection.js +404 -0
- package/src/core/PassageValidator.js +107 -0
- package/src/core/ReferenceParser.js +638 -0
- package/src/core/ScriptureScanner.js +235 -0
- package/src/core/VersificationHandler.js +143 -0
- package/src/core/VersionHandler.js +77 -0
- package/src/data/toc.js +7 -0
- package/src/format/osis.js +210 -0
- package/src/index.js +12 -0
- package/src/utils/PassageUtils.js +117 -0
- package/src/utils/chapterVerseCombine.js +65 -0
- package/.babelrc +0 -5
- package/src/chapterVerseCombine.js +0 -63
- package/src/toc.js +0 -2
- package/webpack.config.js +0 -38
- /package/src/{abbr → data/abbr}/sbl.js +0 -0
- /package/src/{bible.js → data/bible.js} +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1chronicles.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1corinthians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1john.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1kings.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1peter.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1samuel.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1thessalonians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/1timothy.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2chronicles.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2corinthians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2kings.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2peter.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2samuel.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2thessalonians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/2timothy.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/acts.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/amos.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/colossians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/daniel.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/deuteronomy.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/ecclesiastes.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/ephesians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/esther.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/exodus.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/ezekiel.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/ezra.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/galatians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/genesis.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/habakkuk.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/haggai.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/hebrews.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/hosea.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/isaiah.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/james.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/jeremiah.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/job.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/joel.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/john.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/jonah.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/joshua.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/judges.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/lamentations.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/leviticus.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/luke.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/malachi.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/mark.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/matthew.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/micah.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/nahum.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/nehemiah.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/numbers.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/philippians.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/proverbs.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/psalms.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/revelation.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/romans.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/ruth.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/songs.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/titus.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/zechariah.js +0 -0
- /package/src/{chapter_verses → data/chapter_verses}/zephaniah.js +0 -0
- /package/src/{esv.js → data/esv.js} +0 -0
- /package/src/{versifications → data/versifications}/1chronicles.js +0 -0
- /package/src/{versifications → data/versifications}/1kings.js +0 -0
- /package/src/{versifications → data/versifications}/1samuel.js +0 -0
- /package/src/{versifications → data/versifications}/2chronicles.js +0 -0
- /package/src/{versifications → data/versifications}/2samuel.js +0 -0
- /package/src/{versifications → data/versifications}/daniel.js +0 -0
- /package/src/{versifications → data/versifications}/deuteronomy.js +0 -0
- /package/src/{versifications → data/versifications}/ecclesiastes.js +0 -0
- /package/src/{versifications → data/versifications}/exodus.js +0 -0
- /package/src/{versifications → data/versifications}/ezekiel.js +0 -0
- /package/src/{versifications → data/versifications}/genesis.js +0 -0
- /package/src/{versifications → data/versifications}/hosea.js +0 -0
- /package/src/{versifications → data/versifications}/isaiah.js +0 -0
- /package/src/{versifications → data/versifications}/jeremiah.js +0 -0
- /package/src/{versifications → data/versifications}/job.js +0 -0
- /package/src/{versifications → data/versifications}/joel.js +0 -0
- /package/src/{versifications → data/versifications}/jonah.js +0 -0
- /package/src/{versifications → data/versifications}/joshua.js +0 -0
- /package/src/{versifications → data/versifications}/leviticus.js +0 -0
- /package/src/{versifications → data/versifications}/malachi.js +0 -0
- /package/src/{versifications → data/versifications}/micah.js +0 -0
- /package/src/{versifications → data/versifications}/nahum.js +0 -0
- /package/src/{versifications → data/versifications}/nehemiah.js +0 -0
- /package/src/{versifications → data/versifications}/numbers.js +0 -0
- /package/src/{versifications → data/versifications}/proverbs.js +0 -0
- /package/src/{versifications → data/versifications}/psalms.js +0 -0
- /package/src/{versifications → data/versifications}/song.js +0 -0
- /package/src/{versifications → data/versifications}/zechariah.js +0 -0
- /package/src/{versified.js → data/versified.js} +0 -0
- /package/src/{abbr.js → format/abbr.js} +0 -0
- /package/src/{functions.js → utils/functions.js} +0 -0
- /package/src/{regex.js → utils/regex.js} +0 -0
|
@@ -1,303 +1,359 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CodexParser.js
|
|
3
|
-
* A class for scanning and parsing scripture references from text
|
|
4
|
-
* (
|
|
5
|
-
*
|
|
3
|
+
* A modern ES6+ class for scanning and parsing scripture references from text.
|
|
4
|
+
* Supports various formats (single verses, ranges, multi-chapter references) with
|
|
5
|
+
* validation and version-specific versification.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const chapter_verses = require("./chapterVerseCombine")
|
|
8
|
+
const bible = require("./bible");
|
|
9
|
+
const { bookRegex, chapterRegex, verseRegex, scripturesRegex } = require("./regex");
|
|
10
|
+
const ScriptureScanner = require("./ScriptureScanner");
|
|
11
|
+
const ReferenceParser = require("./ReferenceParser");
|
|
12
|
+
const VersificationHandler = require("./VersificationHandler");
|
|
13
|
+
const PassageCollection = require("./PassageCollection");
|
|
14
|
+
const PassageUtils = require("./PassageUtils");
|
|
15
|
+
const VersionHandler = require("./VersionHandler");
|
|
16
|
+
const chapter_verses = require("./chapterVerseCombine");
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Main class for parsing and validating scripture references
|
|
20
20
|
* @class
|
|
21
21
|
*/
|
|
22
22
|
class CodexParser {
|
|
23
|
+
// Private fields using ES6+ syntax
|
|
24
|
+
#scanner;
|
|
25
|
+
#parser;
|
|
26
|
+
#versificationHandler;
|
|
27
|
+
#config;
|
|
28
|
+
#version;
|
|
29
|
+
#found;
|
|
30
|
+
#passages;
|
|
31
|
+
|
|
23
32
|
/**
|
|
24
|
-
* Initializes the parser with
|
|
33
|
+
* Initializes the parser with configuration
|
|
34
|
+
* @param {Object} config - Configuration options
|
|
25
35
|
*/
|
|
26
36
|
constructor(config = {}) {
|
|
27
|
-
this
|
|
28
|
-
this.passages = []
|
|
29
|
-
this.bible = bible
|
|
30
|
-
this.bookRegex = bookRegex
|
|
31
|
-
this.chapterRegex = chapterRegex
|
|
32
|
-
this.verseRegex = verseRegex
|
|
33
|
-
this.scripturesRegex = scripturesRegex
|
|
34
|
-
this.abbreviations = abbreviations
|
|
35
|
-
this.sblAbbreviations = sblAbbreviations
|
|
36
|
-
this.versificationDifferences = versified
|
|
37
|
-
this.singleChapterBook = [
|
|
38
|
-
sch("Jude", 25),
|
|
39
|
-
sch("2 John", 13),
|
|
40
|
-
sch("3 John", 15),
|
|
41
|
-
sch("Obadiah", 21),
|
|
42
|
-
sch("Philemon", 25),
|
|
43
|
-
]
|
|
44
|
-
this.chapterVerses = chapter_verses
|
|
45
|
-
this.error = false
|
|
46
|
-
this.version = null
|
|
47
|
-
this.SINGLE_CHAPTER = "single_chapter"
|
|
48
|
-
this.CHAPTER_VERSE = "chapter_verse"
|
|
49
|
-
this.CHAPTER_VERSE_RANGE = "chapter_verse_range"
|
|
50
|
-
this.COMMA_SEPARATED = "comma_separated_verses"
|
|
51
|
-
this.CHAPTER_RANGE = "chapter_range"
|
|
52
|
-
this.MULTI_CHAPTER_RANGE = "multi_chapter_verse_range"
|
|
53
|
-
this.config = {
|
|
37
|
+
this.#config = {
|
|
54
38
|
booksOnly: config.booksOnly ?? false,
|
|
55
39
|
invalid_sequence_strategy: config.invalid_sequence_strategy ?? "include",
|
|
56
40
|
invalid_passage_strategy: config.invalid_passage_strategy ?? "include",
|
|
57
|
-
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
this.#scanner = new ScriptureScanner(this.#config);
|
|
44
|
+
this.#parser = new ReferenceParser(this.#config);
|
|
45
|
+
this.#versificationHandler = new VersificationHandler();
|
|
46
|
+
this.#version = null;
|
|
47
|
+
this.#found = [];
|
|
48
|
+
this.#passages = [];
|
|
49
|
+
|
|
50
|
+
// Legacy public properties for backward compatibility
|
|
51
|
+
this.bible = bible;
|
|
52
|
+
this.bookRegex = bookRegex;
|
|
53
|
+
this.chapterRegex = chapterRegex;
|
|
54
|
+
this.verseRegex = verseRegex;
|
|
55
|
+
this.scripturesRegex = scripturesRegex;
|
|
56
|
+
this.chapterVerses = chapter_verses;
|
|
57
|
+
this.error = false;
|
|
58
|
+
|
|
59
|
+
// Legacy constants
|
|
60
|
+
this.SINGLE_CHAPTER = "single_chapter";
|
|
61
|
+
this.CHAPTER_VERSE = "chapter_verse";
|
|
62
|
+
this.CHAPTER_VERSE_RANGE = "chapter_verse_range";
|
|
63
|
+
this.COMMA_SEPARATED = "comma_separated_verses";
|
|
64
|
+
this.CHAPTER_RANGE = "chapter_range";
|
|
65
|
+
this.MULTI_CHAPTER_RANGE = "multi_chapter_verse_range";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Gets the found references (legacy getter)
|
|
70
|
+
*/
|
|
71
|
+
get found() {
|
|
72
|
+
return this.#found;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Sets the found references (legacy setter)
|
|
77
|
+
*/
|
|
78
|
+
set found(value) {
|
|
79
|
+
this.#found = value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Gets the parsed passages (legacy getter)
|
|
84
|
+
*/
|
|
85
|
+
get passages() {
|
|
86
|
+
return this.#passages;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Sets the parsed passages (legacy setter)
|
|
91
|
+
*/
|
|
92
|
+
set passages(value) {
|
|
93
|
+
this.#passages = value;
|
|
58
94
|
}
|
|
59
95
|
|
|
60
96
|
/**
|
|
61
|
-
*
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
97
|
+
* Gets the current version (legacy getter)
|
|
98
|
+
*/
|
|
99
|
+
get version() {
|
|
100
|
+
return this.#version;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Sets the current version (legacy setter)
|
|
105
|
+
*/
|
|
106
|
+
set version(value) {
|
|
107
|
+
this.#version = value;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Gets the current config (legacy getter)
|
|
112
|
+
*/
|
|
113
|
+
get config() {
|
|
114
|
+
return this.#config;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Sets the current config (legacy setter)
|
|
119
|
+
*/
|
|
120
|
+
set config(value) {
|
|
121
|
+
this.#config = value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sets configuration options for the parser
|
|
126
|
+
* @param {Object} config - Configuration options
|
|
127
|
+
* @param {boolean} [config.booksOnly=false] - Whether to capture book names without references
|
|
128
|
+
* @returns {CodexParser} The parser instance for method chaining
|
|
65
129
|
*/
|
|
66
130
|
options(config) {
|
|
67
|
-
this
|
|
68
|
-
booksOnly: config.booksOnly ??
|
|
69
|
-
invalid_sequence_strategy: config.invalid_sequence_strategy ?? this
|
|
70
|
-
invalid_passage_strategy: config.invalid_passage_strategy ?? this
|
|
71
|
-
}
|
|
72
|
-
|
|
131
|
+
this.#config = {
|
|
132
|
+
booksOnly: config.booksOnly ?? this.#config.booksOnly,
|
|
133
|
+
invalid_sequence_strategy: config.invalid_sequence_strategy ?? this.#config.invalid_sequence_strategy,
|
|
134
|
+
invalid_passage_strategy: config.invalid_passage_strategy ?? this.#config.invalid_passage_strategy,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Update scanner and parser configs
|
|
138
|
+
this.#scanner = new ScriptureScanner(this.#config);
|
|
139
|
+
this.#parser = new ReferenceParser(this.#config);
|
|
140
|
+
|
|
141
|
+
return this;
|
|
73
142
|
}
|
|
74
143
|
|
|
75
144
|
/**
|
|
76
|
-
* Retrieves available verses for a given book and chapter
|
|
77
|
-
* @param {string} book - The book name
|
|
78
|
-
* @param {number} chapter - The chapter number
|
|
79
|
-
* @returns {number[]} Array of valid verse numbers
|
|
145
|
+
* Retrieves available verses for a given book and chapter (legacy method)
|
|
146
|
+
* @param {string} book - The book name
|
|
147
|
+
* @param {number} chapter - The chapter number
|
|
148
|
+
* @returns {number[]} Array of valid verse numbers
|
|
80
149
|
*/
|
|
81
150
|
getChapterVerses(book, chapter) {
|
|
82
|
-
|
|
83
|
-
return singleChapterBook ? singleChapterBook[book][chapter] || [] : this.chapterVerses[book]?.[chapter] || []
|
|
151
|
+
return PassageUtils.getChapterVerses(book, chapter);
|
|
84
152
|
}
|
|
85
153
|
|
|
86
154
|
/**
|
|
87
|
-
* Scans text for scripture references
|
|
88
|
-
* @param {string} text - The text to scan
|
|
89
|
-
* @returns {CodexParser} The parser instance for method chaining
|
|
155
|
+
* Scans text for scripture references
|
|
156
|
+
* @param {string} text - The text to scan
|
|
157
|
+
* @returns {CodexParser} The parser instance for method chaining
|
|
90
158
|
*/
|
|
91
159
|
scan(text) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Minimal normalization: fix periods before numbers, remove trailing periods
|
|
96
|
-
let normalizedText = text.replace(/\.(?=\d)/g, ":").replace(/(\b[A-Za-z]+)\.(?=\s|$)/g, "$1")
|
|
97
|
-
const lowercaseBibleFullNames = fullNames.map((book) => book.toLowerCase())
|
|
98
|
-
const lowercaseBibleAbbreviations = abbreviations.map((abbr) => abbr.toLowerCase())
|
|
99
|
-
const lowerCaseText = normalizedText.toLowerCase()
|
|
100
|
-
let i = 0
|
|
101
|
-
|
|
102
|
-
const isValidChapterVerseChar = (char) => /[\d:,\-;\s]/.test(char)
|
|
103
|
-
const isNextBibleBook = (startIndex) => {
|
|
104
|
-
const textAfterCurrentPosition = lowerCaseText.substring(startIndex).trim()
|
|
105
|
-
return (
|
|
106
|
-
lowercaseBibleFullNames.some((book) => textAfterCurrentPosition.startsWith(book)) ||
|
|
107
|
-
lowercaseBibleAbbreviations.some((abbr) => textAfterCurrentPosition.startsWith(abbr))
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
const detectSuffix = (startIndex) => {
|
|
111
|
-
const suffixMatch = normalizedText.substring(startIndex).match(/\b(LXX|MT)\b/i)
|
|
112
|
-
return suffixMatch ? { suffix: suffixMatch[0].toUpperCase(), length: suffixMatch[0].length } : null
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
while (i < lowerCaseText.length) {
|
|
116
|
-
let foundBook = null
|
|
117
|
-
let bookStartIndex = -1
|
|
118
|
-
let matchedLength = 0
|
|
160
|
+
this.#found = this.#scanner.scan(text);
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
119
163
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
foundBook = fullNames[j]
|
|
130
|
-
bookStartIndex = i
|
|
131
|
-
matchedLength = book.length
|
|
132
|
-
}
|
|
133
|
-
}
|
|
164
|
+
/**
|
|
165
|
+
* Sets the Bible version for parsing
|
|
166
|
+
* @param {string} version - The version (e.g., "lxx", "mt", "eng")
|
|
167
|
+
* @returns {CodexParser} The parser instance
|
|
168
|
+
*/
|
|
169
|
+
bibleVersion(version) {
|
|
170
|
+
this.#version = VersionHandler.normalizeVersion(version);
|
|
171
|
+
return this;
|
|
172
|
+
}
|
|
134
173
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Parses a scripture reference into structured passage objects
|
|
176
|
+
* @param {string} reference - The reference to parse (e.g., "John 3:16")
|
|
177
|
+
* @returns {CodexParser} The parser instance
|
|
178
|
+
*/
|
|
179
|
+
parse(reference) {
|
|
180
|
+
this.scan(reference);
|
|
181
|
+
this.#passages = this.#parser.parse(this.#found, this.#version);
|
|
182
|
+
this.#passages = this.#versificationHandler.applyVersification(this.#passages);
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
145
185
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Returns parsed passages with utility methods
|
|
188
|
+
* @returns {PassageCollection} Collection of passages with utility methods
|
|
189
|
+
*/
|
|
190
|
+
getPassages() {
|
|
191
|
+
return PassageCollection.from(this.#passages);
|
|
192
|
+
}
|
|
152
193
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const refEndIndex = i
|
|
161
|
-
references.push({
|
|
162
|
-
ref: formattedReference,
|
|
163
|
-
start: refStartIndex,
|
|
164
|
-
end: refEndIndex,
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
chapterVerse = ""
|
|
168
|
-
refStartIndex = i + 1
|
|
169
|
-
const semicolonIndex = text.indexOf(";", originalRefStartIndex)
|
|
170
|
-
originalRefStartIndex = semicolonIndex !== -1 ? semicolonIndex + 1 : refStartIndex
|
|
171
|
-
i++
|
|
172
|
-
continue
|
|
173
|
-
}
|
|
174
|
-
chapterVerse += normalizedText[i]
|
|
175
|
-
i++
|
|
176
|
-
}
|
|
194
|
+
/**
|
|
195
|
+
* Returns the first parsed passage
|
|
196
|
+
* @returns {Object|null} The first passage or null
|
|
197
|
+
*/
|
|
198
|
+
first() {
|
|
199
|
+
return this.#passages.length > 0 ? this.#passages[0] : null;
|
|
200
|
+
}
|
|
177
201
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
})
|
|
187
|
-
}
|
|
188
|
-
}
|
|
202
|
+
/**
|
|
203
|
+
* Normalizes book names using abbreviations or full names (legacy method)
|
|
204
|
+
* @param {string|Array} book - The book name or array
|
|
205
|
+
* @returns {string} Normalized book name
|
|
206
|
+
*/
|
|
207
|
+
bookify(book) {
|
|
208
|
+
return this.#parser.constructor.prototype.normalizeBookName?.(book) || book;
|
|
209
|
+
}
|
|
189
210
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
let type
|
|
199
|
-
if (ref.includes(":")) {
|
|
200
|
-
if (ref.includes("-")) {
|
|
201
|
-
const [start, end] = ref.split("-")
|
|
202
|
-
const startParts = start.split(":")
|
|
203
|
-
const endParts = end.split(":")
|
|
204
|
-
type =
|
|
205
|
-
startParts.length > 1 &&
|
|
206
|
-
endParts.length > 1 &&
|
|
207
|
-
startParts[0].trim() !== endParts[0].trim()
|
|
208
|
-
? "multi_chapter_verse_range"
|
|
209
|
-
: "chapter_verse_range"
|
|
210
|
-
} else if (ref.includes(",")) {
|
|
211
|
-
type = "comma_separated_verses"
|
|
212
|
-
} else {
|
|
213
|
-
type = "chapter_verse"
|
|
214
|
-
}
|
|
215
|
-
} else if (ref.includes("-")) {
|
|
216
|
-
type = "chapter_range"
|
|
217
|
-
} else {
|
|
218
|
-
type = "single_chapter"
|
|
219
|
-
}
|
|
211
|
+
/**
|
|
212
|
+
* Combines multiple passages into a single reference
|
|
213
|
+
* @param {Object[]} [passages=this.passages] - Array of passages to combine
|
|
214
|
+
* @returns {Object} Combined passage object
|
|
215
|
+
*/
|
|
216
|
+
combine(passages = this.#passages) {
|
|
217
|
+
return PassageCollection.combinePassages(passages);
|
|
218
|
+
}
|
|
220
219
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
220
|
+
/**
|
|
221
|
+
* Merges verses into ranges or comma-separated lists (legacy method)
|
|
222
|
+
* @param {number[]} verses - Array of verse numbers
|
|
223
|
+
* @returns {string[]} Array of verse strings
|
|
224
|
+
*/
|
|
225
|
+
mergeRanges(verses) {
|
|
226
|
+
return PassageUtils.mergeRanges(verses);
|
|
227
|
+
}
|
|
230
228
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Generates a table of contents for the Bible
|
|
231
|
+
* @param {string} [version="ESV"] - The Bible version
|
|
232
|
+
* @returns {Object} TOC with book-chapter-verse mappings
|
|
233
|
+
*/
|
|
234
|
+
getToc(version = "ESV") {
|
|
235
|
+
const toc = {};
|
|
236
|
+
|
|
237
|
+
bible.old.forEach((book) => {
|
|
238
|
+
if (chapter_verses[book]) {
|
|
239
|
+
toc[book] = chapter_verses[book];
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
bible.new.forEach((book) => {
|
|
244
|
+
if (chapter_verses[book]) {
|
|
245
|
+
toc[book] = chapter_verses[book];
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
PassageUtils.SINGLE_CHAPTER_BOOKS.forEach((item) => {
|
|
250
|
+
Object.keys(item).forEach((book) => {
|
|
251
|
+
if (!toc[book]) {
|
|
252
|
+
toc[book] = item[book];
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const orderedToc = {};
|
|
258
|
+
const canonicalOrder = [...bible.old, ...bible.new];
|
|
259
|
+
canonicalOrder.forEach((book) => {
|
|
260
|
+
if (toc[book]) {
|
|
261
|
+
orderedToc[book] = toc[book];
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
return orderedToc;
|
|
266
|
+
}
|
|
236
267
|
|
|
237
|
-
|
|
238
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Replaces scripture references in text with formatted references
|
|
270
|
+
* @param {string} text - The original text
|
|
271
|
+
* @param {boolean} useAbbreviations - Whether to use abbreviated book names
|
|
272
|
+
* @returns {string} Text with replaced references
|
|
273
|
+
*/
|
|
274
|
+
replace(text, useAbbreviations = true) {
|
|
275
|
+
if (!this.#passages.length) {
|
|
276
|
+
return text;
|
|
277
|
+
}
|
|
239
278
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
279
|
+
let result = text;
|
|
280
|
+
for (let i = this.#passages.length - 1; i >= 0; i--) {
|
|
281
|
+
const passage = this.#passages[i];
|
|
282
|
+
const { originalText, abbr, original } = passage;
|
|
283
|
+
const newReference = useAbbreviations ? abbr : original;
|
|
245
284
|
|
|
246
|
-
|
|
247
|
-
while (originalEndIndex > originalStartIndex && /[\s]/.test(text[originalEndIndex - 1])) {
|
|
248
|
-
originalEndIndex--
|
|
249
|
-
originalText = text.slice(originalStartIndex, originalEndIndex)
|
|
250
|
-
}
|
|
285
|
+
const regex = new RegExp(`${originalText.replace(/([.*+?^${}()|[\]\\])/g, "\\$1")}`, "g");
|
|
251
286
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
287
|
+
const matches = [...result.matchAll(regex)];
|
|
288
|
+
if (matches.length > 0) {
|
|
289
|
+
for (let j = matches.length - 1; j >= 0; j--) {
|
|
290
|
+
const match = matches[j];
|
|
291
|
+
const startIndex = match.index;
|
|
292
|
+
const endIndex = startIndex + match[0].length;
|
|
293
|
+
const leadingSpace = match[1] || "";
|
|
294
|
+
const hasOpeningParen = match[2] === "(";
|
|
295
|
+
const hasClosingParen = match[3] === ")";
|
|
296
|
+
const trailingSpace = match[4] || " ";
|
|
297
|
+
const replacement =
|
|
298
|
+
hasOpeningParen && hasClosingParen
|
|
299
|
+
? `${leadingSpace}(${newReference})${trailingSpace}`
|
|
300
|
+
: `${leadingSpace}${newReference}${trailingSpace}`;
|
|
301
|
+
result = result.slice(0, startIndex) + replacement + result.slice(endIndex);
|
|
302
|
+
}
|
|
264
303
|
}
|
|
265
304
|
}
|
|
266
305
|
|
|
267
|
-
return
|
|
306
|
+
return result;
|
|
268
307
|
}
|
|
269
308
|
|
|
270
309
|
/**
|
|
271
|
-
*
|
|
272
|
-
* @
|
|
273
|
-
* @returns {CodexParser} The parser instance.
|
|
310
|
+
* Checks if all references in the passages array are from the same book
|
|
311
|
+
* @returns {boolean} True if all passages are from the same book
|
|
274
312
|
*/
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return this
|
|
313
|
+
same() {
|
|
314
|
+
if (this.#passages.length <= 1) {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const firstBook = this.#passages[0].book.toLowerCase();
|
|
319
|
+
return this.#passages.every((passage) => passage.book.toLowerCase() === firstBook);
|
|
282
320
|
}
|
|
283
321
|
|
|
322
|
+
// Legacy methods for backward compatibility
|
|
323
|
+
|
|
284
324
|
/**
|
|
285
|
-
*
|
|
286
|
-
* @param {string} reference - The reference to parse (e.g., "John 3:16").
|
|
287
|
-
* @returns {CodexParser} The parser instance.
|
|
325
|
+
* Expands verse references into individual verse objects (legacy)
|
|
288
326
|
*/
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
327
|
+
expandVerses(book, chapter, verses) {
|
|
328
|
+
return PassageUtils.expandVerses(book, chapter, verses);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Populates passage with expanded verse objects (legacy)
|
|
333
|
+
*/
|
|
334
|
+
populate(passage) {
|
|
335
|
+
return this.#parser.constructor.prototype._populatePassage?.(passage) || [];
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Formats a passage into a human-readable reference (legacy)
|
|
340
|
+
*/
|
|
341
|
+
scripturize(passage) {
|
|
342
|
+
return this.#parser.constructor.prototype._formatScripture?.(passage) || {};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Applies versification differences to parsed passages (legacy)
|
|
347
|
+
*/
|
|
348
|
+
versification() {
|
|
349
|
+
this.#passages = this.#versificationHandler.applyVersification(this.#passages);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
module.exports = CodexParser;
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
301
357
|
testament,
|
|
302
358
|
startIndex: passage.startIndex,
|
|
303
359
|
endIndex: passage.endIndex,
|