diff --git a/package.json b/package.json index 0271330..f094b14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@idrw/bible-ref-parser", - "version": "2.0.0", + "version": "2.0.1", "main": "./build/index.js", "type": "module", "scripts": { diff --git a/src/books.ts b/src/books.ts index 59a06ae..63f71ba 100644 --- a/src/books.ts +++ b/src/books.ts @@ -38,7 +38,7 @@ export const books = [ { "name": "Haggai", "aliases": ["Hg","Hag"]}, { "name": "Zechariah", "aliases": ["Zc","Zech"]}, { "name": "Malachi", "aliases": ["Mal"]}, - { "name": "Matthew", "aliases": ["Mt","Matt"]}, + { "name": "Matthew", "aliases": ["Mt","Mat","Mth","Matt"]}, { "name": "Mark", "aliases": ["Mk"]}, { "name": "Luke", "aliases": ["Lk"]}, { "name": "John", "aliases": ["Jn"]}, diff --git a/src/index.ts b/src/index.ts index 543196d..448b177 100644 --- a/src/index.ts +++ b/src/index.ts @@ -85,11 +85,20 @@ function parseBook(query: string): ParseBookResult { return { book: null, error: bookName } } - let references = parseReferences(query.slice(chapterBeginIndex)) + // TODO : validate chapter numbers - return { - book: { name: validatedName, references }, - error: null + try { + let references = parseReferences(query.slice(chapterBeginIndex)) + + return { + book: { name: validatedName, references }, + error: null + } + } catch (e) { + return { + book: null, + error: (e as Error).message + } } } @@ -137,7 +146,8 @@ function replaceRomanNumbers(query: string) { function isValidQuery(q: string) { return ( !(new RegExp("[^a-z0-9 ,–;—:-]|I{4,}", "i").test(q)) && - !(new RegExp("([,:-]{2,})|(:,)|(,:)|(-:)|(:-)|(-,)|(,-)").test(q)) + !(new RegExp("([,:;-]\\s*?){2,}").test(q)) && + !(new RegExp(",\\s*(?![0-9])", "i").test(q)) ) } @@ -168,6 +178,8 @@ function parseBookName(query: string) { } } + let chapterNumberFound = false + for (let i = nameBeginIndex; i < query.length; i++) { const char = query[i] if (char === " " && char === bookName.charAt(bookName.length - 1)) { @@ -176,6 +188,7 @@ function parseBookName(query: string) { if (char.match(new RegExp("\\d+", 'i'))) { chapterBeginIndex = i + chapterNumberFound = true break } @@ -186,7 +199,9 @@ function parseBookName(query: string) { return { bookName, - chapterBeginIndex + chapterBeginIndex: chapterNumberFound + ? chapterBeginIndex + : query.length } } @@ -219,6 +234,28 @@ function parseReferences(query: string) { } +function queryPriorityIsByVerse(query: string) { + const firstCommaIndex = query.indexOf(",") + const firstColonIndex = query.indexOf(":") + + if (firstColonIndex < 0 && firstCommaIndex < 0) { + return false; + } + + if (firstCommaIndex < 0) { + return true + } + + if (firstColonIndex < 0) { + return false + } + + // 1, 2, 3:1, 4 — requests for chapter 1, 2, 3(v1) and 4 + // 1:1, 2 , 3:1 , 4 — requests for chapter 1(v1, v2), 3(v1, v4) + return firstColonIndex < firstCommaIndex +} + + function parseReferenceWithVersePriority(query: string) { let refs: ChapterData[] = [] let temp = "" @@ -265,9 +302,11 @@ function parseReferenceWithVersePriority(query: string) { temp += query[i] } - if (temp.length > 0 && currentChapter) { - currentChapter.verses.push(parseVerseRange(temp)) + if (currentChapter) { refs.push(currentChapter) + if (temp.length > 0) { + currentChapter.verses.push(parseVerseRange(temp)) + } } return refs @@ -291,7 +330,7 @@ function parseReferenceWithChapterPriority(query: string) { temp = "" continue } - +// John 3:16, Galatian 1 if (char === ",") { if (lookingForVerse) { currentChapter!.verses.push(parseVerseRange(temp)) @@ -317,31 +356,13 @@ function parseReferenceWithChapterPriority(query: string) { } else { currentChapter = { chapter: parseChapterNumber(temp), verses: [] } } - - if (currentChapter) { - refs.push(currentChapter) - } - } - - return refs; -} - - -function queryPriorityIsByVerse(query: string) { - const firstCommaIndex = query.indexOf(",") - const firstColonIndex = query.indexOf(":") - - if (firstCommaIndex < 0) { - return true } - if (firstColonIndex < 0) { - return false + if (currentChapter) { + refs.push(currentChapter) } - // 1, 2, 3:1, 4 — requests for chapter 1, 2, 3(v1) and 4 - // 1:1, 2 , 3:1 , 4 — requests for chapter 1(v1, v2), 3(v1, v4) - return firstColonIndex < firstCommaIndex + return refs; } diff --git a/test/app.test.ts b/test/app.test.ts index baa0e2b..da606a7 100644 --- a/test/app.test.ts +++ b/test/app.test.ts @@ -89,13 +89,13 @@ test('replaceRomanNumbers() should return the original string if no book number test('parseBookName() should return the book name (including sequence nr) along with the index at which first chapter reference begins', async (t) => { const cases = [ { input: "Genesis 1:1", expected: { bookName: "Genesis", chapterBeginIndex: 8 } }, - { input: "Genesis", expected: { bookName: "Genesis", chapterBeginIndex: 0 } }, + { input: "Genesis", expected: { bookName: "Genesis", chapterBeginIndex: 7 } }, { input: "1 Peter 1:1", expected: { bookName: "1 Peter", chapterBeginIndex: 8 } }, { input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 7 } }, { input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 10 } }, { input: "1 John 1", expected: { bookName: "1 John", chapterBeginIndex: 10 } }, - { input: "1John", expected: { bookName: "1 John", chapterBeginIndex: 0 } }, - { input: "Song of solomon", expected: { bookName: "Song of solomon", chapterBeginIndex: 0 } } + { input: "1John", expected: { bookName: "1 John", chapterBeginIndex: 5 } }, + { input: "Song of solomon", expected: { bookName: "Song of solomon", chapterBeginIndex: 15 } } ] for (const { input, expected } of cases) { @@ -121,7 +121,7 @@ test('isValidQuery(q) should return true for valid queries', async (t) => { } }); -test('isValidQuery(q) should return false for invalid queries', async (t) => { +test('isValidQuery(q) should return false for invalid queries', async (test) => { const tests = [ "Genesis 1,,", "Genesis 1:1--1", "Genesis 1::::1-2", "Genesis 1::1--2,4", @@ -131,11 +131,13 @@ test('isValidQuery(q) should return false for invalid queries', async (t) => { "Genesis 1,:,1-2,4-5", "Genesis 1,-1-2,4-5", "Genesis 1,-1-2,4-5", "John# 1:1", "Mark $1:2", "IIII Peter 1:1", "!\\ _/**;:_--:;:", - "##", "#!\"@,", + "##", "#!\"@,", "Genesis 1:2, Galatians 1:8", + "Genesis 1:2, Gal1:8", "Mat 1, Gal 1", + "Mat 1:2, Gal 1" ] for (const _test of tests) { - expect(Testing.isValidQuery(_test)).toBe(false) + expect(Testing.isValidQuery(_test), `failed ${_test}`).toBe(false) } }); @@ -264,12 +266,12 @@ test('parseBook() should return the expected bookData', async (t) => { } }, { input: "III John 1", expected: { - book: { name: "3 John", references: [] }, + book: { name: "3 John", references: [{ chapter: 1, verses: [] }] }, error: null }}, { input: "Gen 1", expected: { - book: { name: "Genesis", references: [] }, + book: { name: "Genesis", references: [{ chapter: 1, verses: [] }] }, error: null } }, @@ -283,6 +285,11 @@ test('parseBook() should return the expected bookData', async (t) => { error: null } }, + { input: "Mark 2", expected: { + book: { name: "Mark", references: [{ chapter: 2, verses: []}] }, + error: null + } }, + { input: "2nd Peter", expected: { book: { name: "2 Peter", references: [] }, error: null } }, { input: "First John", expected: { book: { name: "1 John", references: [] }, error: null } }, { input: "1 John", expected: { book: { name: "1 John", references: [] }, error: null } }, @@ -316,7 +323,7 @@ test('parseQuery() should return the expected bookData[]', async (t) => { { chapter: 1, verses: [{ from: 2, to: undefined }] } ] }, - { name: "3 John", references: [] } + { name: "3 John", references: [{ chapter: 1, verses: [] }] } ], errors: [] }