Skip to content

Commit a5401c8

Browse files
authored
Return query-errors in result (#3)
* return results with possible errors in an array * fix bug in name parsing * update readme * increment version
1 parent 998afdd commit a5401c8

4 files changed

Lines changed: 178 additions & 98 deletions

File tree

README.md

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44

5-
`bible-ref-parser` is a Node.js package that parses Bible references into structured objects. It supports complex references such as `Genesis 1:1-2; II Peter; John 1:1,3-5,8` and converts them into accessible data formats.
5+
A Node.js package to parses Bible references into structured objects. It supports complex references such as `Genesis 1:1-2; II Peter; John 1:1,3-5,8`.
66

77

88
## Installation
@@ -13,38 +13,73 @@ npm install @idrw/bible-ref-parser
1313

1414
## Usage
1515

16+
### Example query, with errors
1617
```typescript
17-
import { parseQuery } from 'bible-ref-parser';
18+
import { parseQuery } from '@idrw/bible-ref-parser';
1819

19-
const query = "Genesis 1:1-2; II Peter; John 1:1,3-5,8";
20-
const result: BookData[] = parseQuery(query);
20+
const result: QueryResult = parseQuery("! pasta;RM-RF/;1John1:2,2:1;IIPeter1:1;IJohn2:4;#--324;1 kebab 2:1;'_&%\"!\"¥");
21+
```
2122

22-
console.log(result);
23+
```json
24+
{
25+
"books": [
26+
{
27+
"name": "1 John",
28+
"references": [
29+
{ "chapter": 1, "verses": [{ "from": 2 }] },
30+
{ "chapter": 2, "verses": [{ "from": 1 }] }
31+
]
32+
},
33+
{
34+
"name": "2 Peter",
35+
"references": [
36+
{ "chapter": 1, "verses": [{ "from": 1 }] }
37+
]
38+
},
39+
{
40+
"name": "1 John",
41+
"references": [
42+
{ "chapter": 2, "verses": [{ "from": 4 }] }
43+
]
44+
}
45+
],
46+
"errors": ["! pasta", "RM-RF/", "#--324", "1 kebab", "'_&%\"!\"¥"]
47+
}
2348
```
2449

50+
### Example query, without errors
51+
```typescript
52+
import { parseQuery } from '@idrw/bible-ref-parser';
53+
54+
const result: QueryResult = parseQuery("Genesis 1:1-2; II Peter; John 1:1,3-5,8");
2555
```
26-
[
27-
{
28-
book: "Genesis",
29-
references: [
30-
{ chapter: 1, verses: [{ from: 1, to: 2 }] }
31-
]
32-
},
33-
{
34-
book: "2 Peter",
35-
references: []
36-
},
37-
{
38-
book: "John",
39-
references: [
40-
{ chapter: 1, verses: [
41-
{ from: 1, to: undefined },
42-
{ from: 3, to: 5 },
43-
{ from: 8, to: undefined }
44-
] }
45-
]
46-
}
47-
]
56+
57+
```json
58+
{
59+
"books": [
60+
{
61+
"name": "Genesis",
62+
"references": [
63+
{ "chapter": 1, "verses": [{ "from": 1, "to": 2 }] }
64+
]
65+
},
66+
{ "name": "2 Peter", "references": [] },
67+
{
68+
"name": "John",
69+
"references": [
70+
{
71+
"chapter": 1,
72+
"verses": [
73+
{ "from": 1 },
74+
{ "from": 3, "to": 5 },
75+
{ "from": 8 }
76+
]
77+
}
78+
]
79+
}
80+
],
81+
"errors": []
82+
}
4883
```
4984

5085
## Contributing

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@idrw/bible-ref-parser",
3-
"version": "1.0.1",
3+
"version": "2.0.0",
44
"main": "./build/index.js",
55
"type": "module",
66
"scripts": {

src/index.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@ import { books } from "./books.js"
22

33
const QUERY_SEPARATOR = ";"
44

5+
export type QueryResult = {
6+
books: BookData[],
7+
errors: string[]
8+
}
9+
10+
export type ParseBookResult = {
11+
book: BookData | null,
12+
error: string | null
13+
}
14+
15+
516
export type BookData = {
617
name: string,
718
references: ChapterData[]
@@ -20,24 +31,33 @@ export type VerseRange = {
2031
}
2132

2233

23-
export function parseQuery(query: string): BookData[] {
34+
export function parseQuery(query: string): QueryResult {
2435
const bookQueries = splitQueryByBooks(query)
36+
const queryResult: QueryResult = {
37+
books: [],
38+
errors: []
39+
}
2540

26-
let bookDataList: BookData[] = []
2741

2842
for (const bookQuery of bookQueries) {
2943
if (!isValidQuery(bookQuery)) {
44+
queryResult.errors.push(bookQuery)
3045
continue
3146
}
3247

33-
const bookData = parseBook(bookQuery)
48+
const parseResult = parseBook(bookQuery)
3449

35-
if (bookData) {
36-
bookDataList.push(bookData)
50+
if (parseResult.error) {
51+
queryResult.errors.push(parseResult.error)
52+
continue
53+
}
54+
55+
if (parseResult.book) {
56+
queryResult.books.push(parseResult.book)
3757
}
3858
}
3959

40-
return bookDataList
60+
return queryResult
4161
}
4262

4363

@@ -55,19 +75,22 @@ function isValidPositiveNumber(n: string) {
5575
}
5676

5777

58-
function parseBook(query: string): BookData | null {
78+
function parseBook(query: string): ParseBookResult {
5979
query = replaceRomanNumbers(query)
6080

6181
let { bookName, chapterBeginIndex } = parseBookName(query)
6282

6383
const validatedName = validateBookName(bookName)
6484
if (!validatedName) {
65-
return null
85+
return { book: null, error: bookName }
6686
}
6787

6888
let references = parseReferences(query.slice(chapterBeginIndex))
6989

70-
return { name: validatedName, references }
90+
return {
91+
book: { name: validatedName, references },
92+
error: null
93+
}
7194
}
7295

7396

@@ -147,7 +170,7 @@ function parseBookName(query: string) {
147170

148171
for (let i = nameBeginIndex; i < query.length; i++) {
149172
const char = query[i]
150-
if (char == " ") {
173+
if (char === " " && char === bookName.charAt(bookName.length - 1)) {
151174
continue
152175
}
153176

test/app.test.ts

Lines changed: 82 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ test('replaceRomanNumbers() should return the original string if no book number
8888

8989
test('parseBookName() should return the book name (including sequence nr) along with the index at which first chapter reference begins', async (t) => {
9090
const cases = [
91-
{ input: "Genesis 1:1", expected: { bookName: "Genesis", chapterBeginIndex: 8 } },
92-
{ input: "Genesis", expected: { bookName: "Genesis", chapterBeginIndex: 0 } },
93-
{ input: "1 Peter 1:1", expected: { bookName: "1 Peter", chapterBeginIndex: 8 } },
94-
{ input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 7 } },
95-
{ input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 10 } },
96-
{ input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 10 } },
97-
{ input: "1John", expected: { bookName: "1 John", chapterBeginIndex: 0 } },
91+
{ input: "Genesis 1:1", expected: { bookName: "Genesis", chapterBeginIndex: 8 } },
92+
{ input: "Genesis", expected: { bookName: "Genesis", chapterBeginIndex: 0 } },
93+
{ input: "1 Peter 1:1", expected: { bookName: "1 Peter", chapterBeginIndex: 8 } },
94+
{ input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 7 } },
95+
{ input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 10 } },
96+
{ input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 10 } },
97+
{ input: "1John", expected: { bookName: "1 John", chapterBeginIndex: 0 } },
98+
{ input: "Song of solomon", expected: { bookName: "Song of solomon", chapterBeginIndex: 0 } }
9899
]
99100

100101
for (const { input, expected } of cases) {
@@ -258,35 +259,43 @@ test('validateBookName() should return true for books that are in the list', asy
258259
test('parseBook() should return the expected bookData', async (t) => {
259260
const cases = [
260261
{ input: "1Kings1:2", expected: {
261-
name: "1 Kings",
262-
references: [
263-
{ chapter: 1, verses: [{ from: 2, to: undefined }] }
264-
]
262+
book: { name: "1 Kings", references: [{ chapter: 1, verses: [{ from: 2, to: undefined }] }] },
263+
error: null
264+
} },
265+
266+
{ input: "III John 1", expected: {
267+
book: { name: "3 John", references: [] },
268+
error: null
265269
}},
266270

267-
{ input: "III John 1", expected: { name: "3 John", references: [] }},
268-
269-
{ input: "Gen 1", expected: { name: "Genesis", references: [] } },
270-
271-
{ input: "2 Pt 1:2", expected: { name: "2 Peter", references: [
272-
{ chapter: 1, verses: [{ from: 2, to: undefined }]}
273-
] } },
274-
275-
{ input: "2 Pet 1:2", expected: { name: "2 Peter", references: [
276-
{ chapter: 1, verses: [{ from: 2, to: undefined }]}
277-
] } },
278-
279-
{ input: "2nd Peter", expected: { name: "2 Peter", references: [] } },
280-
{ input: "First John", expected: { name: "1 John", references: [] } },
281-
{ input: "1 John", expected: { name: "1 John", references: [] } },
282-
{ input: "1st John", expected: { name: "1 John", references: [] } },
283-
{ input: "first JOHN", expected: { name: "1 John", references: [] } },
284-
{ input: "2ndtim", expected: { name: "2 Timothy", references: [] } },
285-
{ input: "isa", expected: { name: "Isaiah", references: [] } },
286-
{ input: "isam", expected: { name: "1 Samuel", references: [] } },
287-
{ input: "Ism", expected: { name: "1 Samuel", references: [] } },
288-
{ input: "IIsm", expected: { name: "2 Samuel", references: [] } },
289-
{ input: "iSaIAH", expected: { name: "Isaiah", references: [] } },
271+
{ input: "Gen 1", expected: {
272+
book: { name: "Genesis", references: [] },
273+
error: null
274+
} },
275+
276+
{ input: "2 Pt 1:2", expected: {
277+
book: { name: "2 Peter", references: [{ chapter: 1, verses: [{ from: 2, to: undefined }]}] },
278+
error: null
279+
} },
280+
281+
{ input: "2 Pet 1:2", expected: {
282+
book: { name: "2 Peter", references: [{ chapter: 1, verses: [{ from: 2, to: undefined }]}] },
283+
error: null
284+
} },
285+
286+
{ input: "2nd Peter", expected: { book: { name: "2 Peter", references: [] }, error: null } },
287+
{ input: "First John", expected: { book: { name: "1 John", references: [] }, error: null } },
288+
{ input: "1 John", expected: { book: { name: "1 John", references: [] }, error: null } },
289+
{ input: "1st John", expected: { book: { name: "1 John", references: [] }, error: null } },
290+
{ input: "first JOHN", expected: { book: { name: "1 John", references: [] }, error: null } },
291+
{ input: "2ndtim", expected: { book: { name: "2 Timothy", references: [] }, error: null } },
292+
{ input: "isa", expected: { book: { name: "Isaiah", references: [] }, error: null } },
293+
{ input: "isam", expected: { book: { name: "1 Samuel", references: [] }, error: null } },
294+
{ input: "Ism", expected: { book: { name: "1 Samuel", references: [] }, error: null } },
295+
{ input: "IIsm", expected: { book: { name: "2 Samuel", references: [] }, error: null } },
296+
{ input: "iSaIAH", expected: { book: { name: "Isaiah", references: [] }, error: null } },
297+
298+
// { input: "! Genesis", expected: { book: null, error: "!Genesis" } },
290299
]
291300

292301
for (const { input, expected } of cases) {
@@ -299,39 +308,52 @@ test('parseQuery() should return the expected bookData[]', async (t) => {
299308
const cases = [
300309
{
301310
input: "1Kings1:2;IIIJohn1",
302-
expected: [
303-
{
304-
name: "1 Kings",
305-
references: [
306-
{ chapter: 1, verses: [{ from: 2, to: undefined }] }
307-
]
308-
},
309-
{ name: "3 John", references: [] }
310-
]
311+
expected: {
312+
books: [
313+
{
314+
name: "1 Kings",
315+
references: [
316+
{ chapter: 1, verses: [{ from: 2, to: undefined }] }
317+
]
318+
},
319+
{ name: "3 John", references: [] }
320+
],
321+
errors: []
322+
}
311323
},
312324

313325
{
314326
input: "III John 1:1-2;Genesis 1:10-12",
315-
expected: [
316-
{
317-
name: "3 John",
318-
references: [{ chapter: 1, verses: [{ from: 1, to: 2 }] }]
319-
},
320-
{
321-
name: "Genesis",
322-
references: [{ chapter: 1, verses: [{ from: 10, to: 12 }] }]
323-
}
324-
]
327+
expected: {
328+
books: [
329+
{
330+
name: "3 John",
331+
references: [{ chapter: 1, verses: [{ from: 1, to: 2 }] }]
332+
},
333+
{
334+
name: "Genesis",
335+
references: [{ chapter: 1, verses: [{ from: 10, to: 12 }] }]
336+
}
337+
],
338+
errors: []
339+
}
325340
},
326341

327342
{
328-
input: ";##;#!\"@,;Genesis 1:10-12",
329-
expected: [
330-
{
331-
name: "Genesis",
332-
references: [{ chapter: 1, verses: [{ from: 10, to: 12 }] }]
333-
}
334-
]
343+
input: ";##;#!\"@,;Genesis 1:10-12;song of solomon",
344+
expected: {
345+
books: [
346+
{
347+
name: "Genesis",
348+
references: [{ chapter: 1, verses: [{ from: 10, to: 12 }] }]
349+
},
350+
{
351+
name: "Song of Solomon",
352+
references: []
353+
}
354+
],
355+
errors: ["##", "#!\"@,"]
356+
}
335357
}
336358
]
337359

0 commit comments

Comments
 (0)