grab-bcv
v0.1.4
Published
Parse and normalize Bible passage references (OSIS, natural text, and shared links).
Downloads
894
Maintainers
Readme
grab-bcv
Parse and normalize Bible passage references from natural text, OSIS strings, and shared links.
Install
pnpm add grab-bcvUsage
import {
parseToCanonicalRef,
parseToDisplayRef,
parseToResolverPath,
parseToResolverUrl,
findAnyPassage,
parsePassage,
parseAnyPassage,
tryParseAnyPassage,
formatPassageForDisplay,
autocompletePassage
} from "grab-bcv";
const parsed = parsePassage("John 3:16-18");
parsed.canonical; // "JHN.3.16-18"
parsed.rangeType; // "same_chapter"
formatPassageForDisplay(parsed); // "John 3:16-18"
parseToCanonicalRef("logosres:bible+niv.61.3.16"); // "JHN.3.16"
parseToDisplayRef("JHN.3.16-18"); // "John 3:16-18"
parseToResolverPath("John 3:16-18"); // "/jhn.3.16-18"
parseToResolverUrl("https://www.route.bible", "John 3:16-18"); // "https://www.route.bible/jhn.3.16-18"
parseAnyPassage("https://www.bible.com/bible/111/JHN.3.16");
// ParsedPassage (throws PassageParseError on invalid input)
parseAnyPassage("Read John 3:16 and Romans 8:28", { multiple: true }).map((p) => p.canonical);
// ["JHN.3.16", "ROM.8.28"]
findAnyPassage("not a passage");
// null
tryParseAnyPassage("Read John 3:16 and Romans 8:28", { multiple: true });
// { ok: true, value: ParsedPassage[] }
autocompletePassage("john 3:1", { limit: 3 });
// [
// { label: "John 3:1", insertText: "John 3:1", canonical: "JHN.3.1", kind: "verse" },
// { label: "John 3:10", insertText: "John 3:10", canonical: "JHN.3.10", kind: "verse" },
// { label: "John 3:11", insertText: "John 3:11", canonical: "JHN.3.11", kind: "verse" }
// ]API
parsePassage(input: string): ParsedPassagetryParsePassage(input: string): { ok: true; value: ParsedPassage } | { ok: false; error: PassageParseError }parseAnyPassage(input: string, options?: { multiple?: boolean }): ParsedPassage | ParsedPassage[]findAnyPassage(input: string, options?: { multiple?: boolean }): ParsedPassage | ParsedPassage[] | nulltryParseAnyPassage(input: string, options?: { multiple?: boolean }): { ok: true; value: ParsedPassage | ParsedPassage[] } | { ok: false; error: PassageParseError }extractSharedCanonical(payload: SharePayload): string | nullparseSharedPassage(payload: SharePayload): ParsedPassage | nulltryParseSharedPassage(payload: SharePayload): { ok: true; value: ParsedPassage } | { ok: false; error: PassageParseError }formatPassageForDisplay(parsed: ParsedPassage): stringtoCanonicalRef(parsed: ParsedPassage): stringtoDisplayRef(parsed: ParsedPassage): stringtoResolverPath(parsed: ParsedPassage, options?): stringtoResolverUrl(baseUrl: string | URL, parsed: ParsedPassage, options?): stringparseToCanonicalRef(input: string | ParsedPassage): stringparseToDisplayRef(input: string | ParsedPassage): stringparseToResolverPath(input: string | ParsedPassage, options?): stringparseToResolverUrl(baseUrl: string | URL, input: string | ParsedPassage, options?): stringautocompletePassage(input: string, options?: { limit?: number }): Array<{ label: string; insertText: string; canonical: string; kind: "book" | "chapter" | "verse" | "range" }>resolveBookAlias(input: string): OsisBookCode | nullgetChapterCount(book: OsisBookCode): numbergetVerseCount(book: OsisBookCode, chapter: number): number | nullOSIS_BOOK_CODES,OSIS_BOOK_NAMES,BOOK_CHAPTER_COUNTS,BOOK_VERSE_COUNTS
Support
Local Development
pnpm install
pnpm build
pnpm test
pnpm typecheckStandalone UI is now in apps/grab-bcv-ui and consumes the published grab-bcv package.
Production Readiness
- Node.js
18+is required. - CI runs on push and pull requests via GitHub Actions.
prepackenforces build + typecheck + tests before publish.- npm publishing supports both local deploy scripts and GitHub Actions (with provenance).
Deploy
- Publish npm package:
pnpm run deploy:npm.- Runs
prepackfirst, bumps patch only when local matches npm latest, then publishes. - If publish fails after an automatic bump, the bump is reverted.
- For npm accounts with 2FA
auth-and-writesand passkeys, use a token withbypass_2fa=true:NPM_TOKEN=... pnpm run deploy:npm
- OTP fallback:
NPM_OTP=123456 pnpm run deploy:npm
- Runs
- Publish + deploy UI in lockstep:
pnpm run deploy:stack.- Requires a clean git working tree (use
--allow-dirtyto bypass). - Publishes
grab-bcvto npm. - Waits for npm registry propagation of the published version.
- Syncs all consumer manifests under
apps/*tograb-bcv@^<published-version>. - Refreshes root and app-local lockfiles (including
--ignore-workspacerefresh for app lockfiles). - Builds + deploys
apps/grab-bcv-ui.
- Requires a clean git working tree (use
- Sync consumers without deploying:
pnpm run sync:consumers- Useful after manual publish or when only dependency/lockfile updates are needed.
Notes
- Book aliases use exact matching first, then conservative fuzzy fallback for common misspellings.
- Ambiguous short aliases return
null.
