json-bible 1.0.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.
Binary file
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ <img align="right" width="150" height="150" src="JSON_bible_icon.png">
2
+
3
+ # JSON Bible Format
4
+
5
+ > A universal digital Bible format in JSON that can be used with any language.
6
+
7
+ ## Format
8
+
9
+ ```json
10
+ {
11
+ "name": "Bible Name",
12
+ "metadata": { "publisher": "" },
13
+ "books": [
14
+ {
15
+ "number": 1,
16
+ "name": "Genesis",
17
+ "chapters": [
18
+ {
19
+ "number": 1,
20
+ "verses": [
21
+ {
22
+ "number": 1,
23
+ "text": "In the beginning God created..."
24
+ },
25
+ ...
26
+ ]
27
+ },
28
+ ...
29
+ ]
30
+ },
31
+ ...
32
+ ]
33
+ }
34
+ ```
35
+
36
+ ### Types
37
+
38
+ This is a selection of the [types found here](./lib/Bible.ts).
39
+
40
+ ```js
41
+ type Bible = {
42
+ name: string
43
+ metadata: Metadata
44
+ books: Book[]
45
+ }
46
+
47
+ type Book = {
48
+ number: number
49
+ name: string
50
+ chapters: Chapter[]
51
+ }
52
+
53
+ type Chapter = {
54
+ number: number
55
+ header?: string // chapter header
56
+ verses: Verse[]
57
+ }
58
+
59
+ type Verse = {
60
+ number: number
61
+ endNumber?: number // multiple combined verses
62
+ text: string
63
+ }
64
+ ```
65
+
66
+ ### Markdown:
67
+
68
+ > Markdown formatting should be used instead of HTML as it is more universal!
69
+
70
+ Check out the [MD regex parsing here](./lib/markdown.ts).
71
+
72
+ - Undertitle: # Text #
73
+ - Cross Reference & Notes: \*{text}\* | \*{\[reference](id) text}\*
74
+ - Jesus Red Words: !{text}!
75
+ - Uncertain: \[text]
76
+ - Bold: \*\*text\*\* or \_\_text\_\_
77
+ - Italic: \*text\* or \_text\_
78
+ - Underline: ++text++
79
+ - Strikethrough: \~~text~~
80
+ - Quote: "text"
81
+ - Line Break: \n
82
+ - Paragraph: ¶
83
+
84
+ ## Module
85
+
86
+ Use this NPM module to simplify the use/rendering of the JSON Bible Format! It has a Markdown to HTML parser, search & lots of more helpful utility features!
87
+
88
+ ```js
89
+ import Bible from "json-bible"
90
+
91
+ const bible = Bible("file-path") // path/url/object
92
+
93
+ bible.data // JSON data
94
+
95
+ const book = bible.getBook("Romans")
96
+ const chapter = book.getChapter(5)
97
+ const verse = chapter.getVerse() // get first verse
98
+ const verses = chapter.getVerses([1, 15]).getReference() // "Romans 5:1+15"
99
+
100
+ verse.getText() // verse text
101
+ verse.getHTML() // HTML formatted verse text
102
+
103
+ bible.bookSearch("John 3:16-20+22") // book search with auto complete
104
+ bible.textSearch("Jesus") // text search in entire Bible, or one book
105
+
106
+ // and lots more...
107
+ ```
108
+
109
+ See also [bible.html](./preview/bible.html) as a preview and use example!
110
+
111
+ ## Converter
112
+
113
+ Use [this converter](https://github.com/vassbo/bible-converter) to convert from other formats like XML Zefania, OSIS, OpenSong, etc.
114
+
115
+ ---
116
+
117
+ Currently used by [FreeShow Presentation Software](https://freeshow.app).
118
+
119
+ You are granted the permission to use this in any project!
@@ -0,0 +1,42 @@
1
+ import fs from "fs"
2
+ import path from "path"
3
+ import { fileURLToPath } from "url"
4
+
5
+ function addJsExtension(dir) {
6
+ fs.readdirSync(dir).forEach((file) => {
7
+ const fullPath = path.join(dir, file)
8
+
9
+ if (fs.lstatSync(fullPath).isDirectory()) {
10
+ if (file.includes("node_modules")) return
11
+ addJsExtension(fullPath)
12
+ return
13
+ }
14
+
15
+ if (file.endsWith(".js") && !file.includes("add-js-extension")) {
16
+ let content = fs.readFileSync(fullPath, "utf-8")
17
+
18
+ // update require statements
19
+ content = content.replace(/(require\(["'])([^'"]+?)(["']\))/g, (match, p1, p2, p3) => {
20
+ if (!p2.endsWith(".js") && !p2.startsWith(".") && !p2.startsWith("/")) {
21
+ return match
22
+ }
23
+ return `${p1}${p2}.js${p3}`
24
+ })
25
+
26
+ // update import statements
27
+ content = content.replace(/(import\s.*?from\s["'])([^'"]+?)(["'];?)/g, (match, p1, p2, p3) => {
28
+ if (!p2.endsWith(".js") && (p2.startsWith(".") || p2.startsWith("/"))) {
29
+ return `${p1}${p2}.js${p3}`
30
+ }
31
+ return match
32
+ })
33
+
34
+ fs.writeFileSync(fullPath, content, "utf-8")
35
+ }
36
+ })
37
+ }
38
+
39
+ const __filename = fileURLToPath(import.meta.url) // get the resolved path to the file
40
+ const __dirname = path.dirname(__filename) // get the name of the directory
41
+ const directoryPath = path.join(__dirname)
42
+ addJsExtension(directoryPath)
package/index.ts ADDED
@@ -0,0 +1,243 @@
1
+ import { Bible } from "./lib/Bible"
2
+ import { BIBLE_SIZE, getBookCategory, getDefault, getDefaultBooks, NT_SIZE, OT_SIZE } from "./lib/defaults"
3
+ import { _getBible, _getBook, _getChapter, _getCloseChapter, _getHTML, _getMetadata, _getRandomVerse, _getShortName, _getText, _getVerse, formatText, getBookIndex, getChapterIndex, getVerseIndex } from "./lib/get"
4
+ import { getReferenceString, getVerseReferences } from "./lib/reference"
5
+ import { _bookSearch, _textSearch } from "./lib/search"
6
+
7
+ /**
8
+ * JSON Bible Helper
9
+ * @param bibleOrPath path to Bible file or a Bible JSON object
10
+ */
11
+ export default async function Bible(bibleOrPath: Bible | string) {
12
+ const bible = await _getBible(bibleOrPath)
13
+
14
+ return { data: bible, getBook, getAbbreviation, getMetadata, getDefaultBooks, getDefault, getOT, getNT, getRandom, getFromReference, bookSearch, textSearch }
15
+
16
+ /**
17
+ * Get a specified book or the first one if not provided
18
+ * @param number book number/name/id
19
+ * @return book data
20
+ */
21
+ function getBook(numberOrName?: string | number) {
22
+ if (numberOrName === undefined) numberOrName = bible.books[0].number
23
+ let bookIndex = getBookIndex(bible, numberOrName)
24
+ const book = _getBook(bible, bookIndex)
25
+
26
+ return { data: book, index: bookIndex, number: book.number, name: book.name, getChapter, getAbbreviation: getNameShort, getCategory }
27
+
28
+ /**
29
+ * Get a specified chapter or the first one if no number provided
30
+ * @param number chapter number
31
+ * @return chapter data
32
+ */
33
+ function getChapter(number?: number) {
34
+ if (number === undefined) number = book.chapters[0].number
35
+ let chapterIndex = getChapterIndex(book, number)
36
+ const chapter = _getChapter(book, chapterIndex)
37
+
38
+ return { data: chapter, index: chapterIndex, number, getVerse, getVerses, getNext, getPrevious, getReference }
39
+
40
+ /**
41
+ * Get a specified verse or the first one if no number provided
42
+ * @param number verse number
43
+ * @return verse data
44
+ */
45
+ function getVerse(number?: number) {
46
+ if (number === undefined) number = chapter.verses[0].number
47
+ let verseIndex = getVerseIndex(chapter, number)
48
+ const verse = _getVerse(chapter, verseIndex)
49
+
50
+ return { data: verse, index: verseIndex, number, getText, getHTML, getReference }
51
+
52
+ /**
53
+ * A plain text string of the verse
54
+ * @param includeNumbers should verse numbers be included
55
+ * @return verse text
56
+ */
57
+ function getText(includeNumber: boolean = false) {
58
+ return _getText(verse, includeNumber)
59
+ }
60
+
61
+ /**
62
+ * A HTML string of the verse with parsed markdown
63
+ * @param includeNumbers should verse numbers be included
64
+ * @return HTML string value
65
+ */
66
+ function getHTML(includeNumber: boolean = false) {
67
+ return _getHTML(verse, includeNumber)
68
+ }
69
+
70
+ /**
71
+ * Get verse reference
72
+ * @param addBibleVersion add Bible abbreviation at the end of the reference
73
+ * @return reference string, e.g. "Genesis 1:1"
74
+ */
75
+ function getReference(addBibleVersion: boolean = false) {
76
+ return _getReference([verse.number], addBibleVersion)
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Get a selection of verses based in an array of numbers
82
+ * @param verseNumbers verse numbers
83
+ * @param html should markdown text be parsed to HTML
84
+ * @return verses data
85
+ */
86
+ function getVerses(verseNumbers: number[] = [], html: boolean = false) {
87
+ let verses = chapter.verses
88
+ if (verseNumbers.length) verses = verses.filter((a) => verseNumbers.includes(a.number))
89
+
90
+ const data = verses.reduce((obj, { number, text }) => ({ ...obj, [number]: formatText(text, html) }), {} as { [key: number]: string })
91
+ const numbers = verseNumbers.length ? verseNumbers : verses.map((a) => a.number)
92
+
93
+ return { data, numbers, getText, getHTML, getReference }
94
+
95
+ /**
96
+ * A plain text string of the verses
97
+ * @param includeNumbers should verse numbers be included
98
+ * @return verse text
99
+ */
100
+ function getText(includeNumbers: boolean = false) {
101
+ return verses.map((v) => _getText(v, includeNumbers)).join(" ")
102
+ }
103
+
104
+ /**
105
+ * A HTML string of the verses with parsed markdown
106
+ * @param includeNumbers should verse numbers be included
107
+ * @return HTML string value
108
+ */
109
+ function getHTML(includeNumbers: boolean = false) {
110
+ return verses.map((v, i) => _getHTML(v, includeNumbers, i === 0)).join(" ")
111
+ }
112
+
113
+ /**
114
+ * Get verses reference
115
+ * @param addBibleVersion add Bible abbreviation at the end of the reference
116
+ * @return reference string, e.g. "Genesis 1:1-3"
117
+ */
118
+ function getReference(addBibleVersion: boolean = false) {
119
+ return _getReference(numbers, addBibleVersion)
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Get next chapter relative to the one currently selected
125
+ * @return a reference to the next chapter, including possibly changed book - null if none available
126
+ */
127
+ function getNext() {
128
+ return _getCloseChapter(bible, book.number, chapter.number, true)
129
+ }
130
+
131
+ /**
132
+ * Get previous chapter relative to the one currently selected
133
+ * @return a reference to the previous chapter, including possibly changed book - null if none available
134
+ */
135
+ function getPrevious() {
136
+ return _getCloseChapter(bible, book.number, chapter.number, false)
137
+ }
138
+
139
+ /**
140
+ * Get chapter reference
141
+ * @param addBibleVersion add Bible abbreviation at the end of the reference
142
+ * @return reference string, e.g. "Genesis 1"
143
+ */
144
+ function getReference(addBibleVersion: boolean = false) {
145
+ return _getReference([], addBibleVersion)
146
+ }
147
+
148
+ // HELPER
149
+ function _getReference(verses: number[], addBibleVersion: boolean = false) {
150
+ return getReferenceString({ book: book.number, chapter: chapter.number, verses }, bible) + (addBibleVersion ? ` ${getAbbreviation()}` : "")
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Get three letter book abbreviation/short name
156
+ * @return e.g. "Genesis" = "Gen"
157
+ */
158
+ function getNameShort() {
159
+ const abbr = getDefaultBooks().ids[book.number - 1]
160
+ return abbr[0] + abbr.slice(1).toLowerCase()
161
+ }
162
+
163
+ /**
164
+ * Get current book category name/color, all categories are:
165
+ * "The Law", "History", "Poetry & Wisdom", "Prophets", "The Gospels & Acts", "Letters" & "Apocalyptic"
166
+ * @return book category object
167
+ */
168
+ function getCategory() {
169
+ return getBookCategory(book)
170
+ }
171
+ }
172
+
173
+ /**
174
+ * @return bible name abbreviation/identifier
175
+ */
176
+ function getAbbreviation() {
177
+ return _getShortName(bible)
178
+ }
179
+
180
+ /**
181
+ * @return trimmed metadata object
182
+ */
183
+ function getMetadata() {
184
+ return _getMetadata(bible)
185
+ }
186
+
187
+ /**
188
+ * Get all books in the Bible from the Old Testament
189
+ * @return list of max 39 books
190
+ */
191
+ function getOT() {
192
+ if (bible.books.length === OT_SIZE) return bible.books
193
+ if (bible.books.length === BIBLE_SIZE) return bible.books.slice(0, OT_SIZE)
194
+ return bible.books.filter((a) => a.number >= 1 && a.number <= OT_SIZE)
195
+ }
196
+
197
+ /**
198
+ * Get all books in the Bible from the New Testament
199
+ * @return list of max 27 books
200
+ */
201
+ function getNT() {
202
+ if (bible.books.length === NT_SIZE) return bible.books
203
+ if (bible.books.length === BIBLE_SIZE) return bible.books.slice(OT_SIZE)
204
+ return bible.books.filter((a) => a.number > OT_SIZE && a.number <= BIBLE_SIZE)
205
+ }
206
+
207
+ /**
208
+ * Get a random verse
209
+ * @return random verse
210
+ */
211
+ function getRandom() {
212
+ return _getRandomVerse(bible)
213
+ }
214
+
215
+ /**
216
+ * Get book/chapter/verses from a string reference
217
+ * @param value e.g. "Genesis 1:1-3" / "GEN.1.2-3" / "1.1.1"
218
+ * @return matching content
219
+ */
220
+ function getFromReference(value: string) {
221
+ return getVerseReferences(bible, value)
222
+ }
223
+
224
+ /**
225
+ * Search for book/chapter/verses with autocomplete
226
+ * @param value e.g. "Genesis 1:1-3"
227
+ * @return matching content
228
+ */
229
+ function bookSearch(value: string) {
230
+ return _bookSearch(bible, value)
231
+ }
232
+
233
+ /**
234
+ * Search for text content in the entire Bible
235
+ * @param value search string
236
+ * @param limit max results, lower number means quicker search
237
+ * @param bookNumber search only in a specified book
238
+ * @return an array of verses
239
+ */
240
+ function textSearch(value: string, limit: number = 500, bookNumber?: number) {
241
+ return _textSearch(bible, value, limit, bookNumber)
242
+ }
243
+ }
package/lib/Bible.ts ADDED
@@ -0,0 +1,45 @@
1
+ export interface Bible {
2
+ name: string // e.g. "King James Version"
3
+ abbreviation?: string // e.g. "KJV"
4
+ metadata: Metadata
5
+
6
+ books: Book[]
7
+ }
8
+
9
+ export type Book = {
10
+ number: number // starting from 1
11
+ name: string // e.g. "Genesis"
12
+ id?: string // e.g. "GEN"
13
+
14
+ chapters: Chapter[]
15
+ }
16
+
17
+ export type Chapter = {
18
+ number: number // starting from 1
19
+ header?: string // e.g. "Book I" / "A Psalm by David"
20
+
21
+ verses: Verse[]
22
+ }
23
+
24
+ export type Verse = {
25
+ number: number // starting from 1
26
+ endNumber?: number // if multiple verses are combined (end verse is different than start "number") enter value here
27
+
28
+ text: string // verse text with markdown supported formatting!
29
+ }
30
+
31
+ export type Metadata = {
32
+ title?: string // e.g. "King James Version"
33
+ identifier?: string // e.g. "KJV"
34
+ description?: string // e.g. "In 1604, King James I of England authorized that a new translation of the Bible into English be started. It was finished in 1611..."
35
+ language?: string // e.g. "en"
36
+
37
+ publisher?: string // e.g. "FREE BIBLE SOFTWARE GROUP"
38
+ publishDate?: string // e.g. "2009-01-23"
39
+ contributors?: string[]
40
+
41
+ copyright?: string
42
+
43
+ // custom keys allowed
44
+ [key: string]: any
45
+ }
@@ -0,0 +1,136 @@
1
+ import { Bible, Book, Chapter, Metadata, Verse } from "./Bible"
2
+ import { clone } from "./util"
3
+
4
+ export const BIBLE_SIZE = 66
5
+ export const OT_SIZE = 39
6
+ export const NT_SIZE = 27
7
+
8
+ export function getDefault() {
9
+ const bible: Bible = { name: "", metadata: {}, books: [] }
10
+ const book: Book = { number: 0, name: "", chapters: [] }
11
+ const chapter: Chapter = { number: 0, verses: [] }
12
+ const verse: Verse = { number: 0, text: "" }
13
+
14
+ return { bible, book, chapter, verse }
15
+ }
16
+
17
+ export function getDefaultMetadata() {
18
+ const metadata: Metadata = {
19
+ title: "",
20
+ identifier: "",
21
+ description: "",
22
+ language: "",
23
+ publisher: "",
24
+ contributors: [],
25
+ date: 0,
26
+ copyright: ""
27
+ }
28
+
29
+ return metadata
30
+ }
31
+
32
+ // BOOKS
33
+
34
+ const BOOKS = {
35
+ GEN: "Genesis",
36
+ EXO: "Exodus",
37
+ LEV: "Leviticus",
38
+ NUM: "Numbers",
39
+ DEU: "Deuteronomy",
40
+ JOS: "Joshua",
41
+ JDG: "Judges",
42
+ RUT: "Ruth",
43
+ "1SA": "1 Samuel",
44
+ "2SA": "2 Samuel",
45
+ "1KI": "1 Kings",
46
+ "2KI": "2 Kings",
47
+ "1CH": "1 Chronicles",
48
+ "2CH": "2 Chronicles",
49
+ EZR: "Ezra",
50
+ NEH: "Nehemiah",
51
+ EST: "Esther",
52
+ JOB: "Job",
53
+ PSA: "Psalms",
54
+ PRO: "Proverbs",
55
+ ECC: "Ecclesiastes",
56
+ SNG: "Song of Solomon",
57
+ ISA: "Isaiah",
58
+ JER: "Jeremiah",
59
+ LAM: "Lamentations",
60
+ EZE: "Ezekiel",
61
+ DAN: "Daniel",
62
+ HOS: "Hosea",
63
+ JOE: "Joel",
64
+ AMO: "Amos",
65
+ OBA: "Obadiah",
66
+ JON: "Jonah",
67
+ MIC: "Micah",
68
+ NAH: "Nahum",
69
+ HAB: "Habakkuk",
70
+ ZEP: "Zephaniah",
71
+ HAG: "Haggai",
72
+ ZEC: "Zechariah",
73
+ MAL: "Malachi",
74
+
75
+ MAT: "Matthew",
76
+ MRK: "Mark",
77
+ LUK: "Luke",
78
+ JHN: "John",
79
+ ACT: "Acts",
80
+ ROM: "Romans",
81
+ "1CO": "1 Corinthians",
82
+ "2CO": "2 Corinthians",
83
+ GAL: "Galatians",
84
+ EPH: "Ephesians",
85
+ PHP: "Philippians",
86
+ COL: "Colossians",
87
+ "1TH": "1 Thessalonians",
88
+ "2TH": "2 Thessalonians",
89
+ "1TI": "1 Timothy",
90
+ "2TI": "2 Timothy",
91
+ TIT: "Titus",
92
+ PHM: "Philemon",
93
+ HEB: "Hebrews",
94
+ JAS: "James",
95
+ "1PE": "1 Peter",
96
+ "2PE": "2 Peter",
97
+ "1JN": "1 John",
98
+ "2JN": "2 John",
99
+ "3JN": "3 John",
100
+ JUD: "Jude",
101
+ REV: "Revelation"
102
+ }
103
+ type BookId = keyof typeof BOOKS
104
+
105
+ const categories = [
106
+ { id: "law", start: "GEN", name: "The Law", color: "#e84242" },
107
+ { id: "history", start: "JOS", name: "History", color: "#e89d42" },
108
+ { id: "poetry", start: "JOB", name: "Poetry & Wisdom", color: "#b542e8" }, // #e8de42
109
+ { id: "prophets", start: "ISA", name: "Prophets", color: "#42e84d" },
110
+ { id: "gospels", start: "MAT", name: "The Gospels & Acts", color: "#42c4e8" },
111
+ { id: "letters", start: "ROM", name: "Letters", color: "#e8de42" }, // #b542e8
112
+ { id: "prophecy", start: "REV", name: "Apocalyptic", color: "#e842e5" }
113
+ ]
114
+
115
+ export function getDefaultBooks() {
116
+ const ids = Object.keys(BOOKS) as BookId[]
117
+ const names = Object.values(BOOKS)
118
+
119
+ return { data: clone(BOOKS), ids, names, byId, byNumber }
120
+
121
+ function byId(id: string) {
122
+ return BOOKS[id as BookId] || ""
123
+ }
124
+
125
+ function byNumber(number: number) {
126
+ return names[number - 1] || ""
127
+ }
128
+ }
129
+
130
+ export function getBookCategory(book: Book) {
131
+ return categories.find((a, i) => {
132
+ const startNumber = Object.keys(BOOKS).indexOf(a.start) + 1
133
+ const endNumber = Object.keys(BOOKS).indexOf(categories[i + 1]?.start) + 1 || startNumber + 1
134
+ return book.number >= startNumber && book.number < endNumber
135
+ })
136
+ }