173 lines
4.8 KiB
TypeScript
173 lines
4.8 KiB
TypeScript
/**
|
|
* Book + chapter derivation for transcriptions.
|
|
*
|
|
* Transcriptions carry a free-text scripture `reference` (e.g. "SB 1.2.3",
|
|
* "BG Introduction", "CC Madhya-līlā 20.101") rather than structured
|
|
* book/chapter columns. This module is the single source of truth for turning
|
|
* those strings into a book identity and a chapter grouping, reused by the
|
|
* books grid, the listing page, and the book browser.
|
|
*
|
|
* The book registry mirrors `TranscriptionBooks` in the Go BFF
|
|
* (internal/repository/transcription_repo.go).
|
|
*/
|
|
|
|
export type BookCode = "SB" | "BG" | "CC" | "BS" | "NOD" | "ISO";
|
|
|
|
export const BOOKS: Record<BookCode, { title: string; order: number }> = {
|
|
SB: { title: "Śrīmad-Bhāgavatam", order: 1 },
|
|
BG: { title: "Bhagavad-gītā", order: 2 },
|
|
CC: { title: "Caitanya-caritāmṛta", order: 3 },
|
|
BS: { title: "Brahma-saṁhitā", order: 4 },
|
|
NOD: { title: "The Nectar of Devotion", order: 5 },
|
|
ISO: { title: "Śrī Īśopaniṣad", order: 6 },
|
|
};
|
|
|
|
/** Display title for a (possibly unknown) book code; "" if unknown. */
|
|
export function bookTitle(code: string): string {
|
|
const b = BOOKS[code.toUpperCase() as BookCode];
|
|
return b ? b.title : "";
|
|
}
|
|
|
|
/** A section is a canto (SB) or līlā (CC); null for books without that level. */
|
|
export type ChapterSection = {
|
|
key: string;
|
|
label: string;
|
|
order: number;
|
|
};
|
|
|
|
/** A chapter grouping for the accordion list. */
|
|
export type ChapterGroup = {
|
|
key: string;
|
|
label: string;
|
|
sort: [number, number];
|
|
/** Canto/līlā this chapter belongs to (SB, CC); null for flat books. */
|
|
section: ChapterSection | null;
|
|
};
|
|
|
|
// Caitanya-caritāmṛta līlā ordering (Ādi → Madhya → Antya).
|
|
const LILA_ORDER: Record<string, { label: string; order: number }> = {
|
|
ADI: { label: "Ādi-līlā", order: 1 },
|
|
MADHYA: { label: "Madhya-līlā", order: 2 },
|
|
ANTYA: { label: "Antya-līlā", order: 3 },
|
|
};
|
|
|
|
const OTHER: ChapterGroup = {
|
|
key: "other",
|
|
label: "Other",
|
|
sort: [9999, 0],
|
|
section: null,
|
|
};
|
|
|
|
/**
|
|
* Parse a transcription reference into its chapter group, given the book code.
|
|
* Tolerates the corpus's noise (en-dash vs hyphen, "Madhya" vs "Madhya-līlā",
|
|
* a stray "SB 7", etc.). Unparseable / missing references fall into "Other".
|
|
*/
|
|
export function parseChapter(code: string, reference: string | null): ChapterGroup {
|
|
const ref = (reference ?? "").trim();
|
|
if (!ref) return OTHER;
|
|
|
|
switch (code.toUpperCase() as BookCode) {
|
|
case "BG": {
|
|
if (/^BG\s+Introduction/i.test(ref)) {
|
|
return {
|
|
key: "bg-intro",
|
|
label: "Introduction",
|
|
sort: [0, 0],
|
|
section: null,
|
|
};
|
|
}
|
|
const m = ref.match(/^BG\s+(\d+)/);
|
|
if (m) {
|
|
const n = Number(m[1]);
|
|
return {
|
|
key: `bg-${n}`,
|
|
label: `Chapter ${n}`,
|
|
sort: [n, 0],
|
|
section: null,
|
|
};
|
|
}
|
|
return OTHER;
|
|
}
|
|
case "SB": {
|
|
const m = ref.match(/^SB\s+(\d+)\.(\d+)/);
|
|
if (m) {
|
|
const c = Number(m[1]);
|
|
const ch = Number(m[2]);
|
|
return {
|
|
key: `sb-${c}-${ch}`,
|
|
label: `Chapter ${ch}`,
|
|
sort: [c, ch],
|
|
section: { key: `sb-${c}`, label: `Canto ${c}`, order: c },
|
|
};
|
|
}
|
|
const cantoOnly = ref.match(/^SB\s+(\d+)\b/);
|
|
if (cantoOnly) {
|
|
const c = Number(cantoOnly[1]);
|
|
return {
|
|
key: `sb-${c}-0`,
|
|
label: "Other",
|
|
sort: [c, 0],
|
|
section: { key: `sb-${c}`, label: `Canto ${c}`, order: c },
|
|
};
|
|
}
|
|
return OTHER;
|
|
}
|
|
case "CC": {
|
|
const m = ref.match(/^CC\s+(Ādi|Adi|Madhya|Antya)(?:-līlā)?\s+(\d+)/i);
|
|
if (m) {
|
|
const lila = LILA_ORDER[m[1].toUpperCase().replace("Ā", "A")];
|
|
const ch = Number(m[2]);
|
|
if (lila) {
|
|
return {
|
|
key: `cc-${lila.order}-${ch}`,
|
|
label: `Chapter ${ch}`,
|
|
sort: [lila.order, ch],
|
|
section: {
|
|
key: `cc-${lila.order}`,
|
|
label: lila.label,
|
|
order: lila.order,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
return OTHER;
|
|
}
|
|
case "BS": {
|
|
const m = ref.match(/^BS\s+(\d+)/);
|
|
if (m) {
|
|
const n = Number(m[1]);
|
|
return {
|
|
key: `bs-${n}`,
|
|
label: `Chapter ${n}`,
|
|
sort: [n, 0],
|
|
section: null,
|
|
};
|
|
}
|
|
return OTHER;
|
|
}
|
|
case "ISO": {
|
|
const m = ref.match(/^ISO\s+Mantra\s+(\d+)/i);
|
|
if (m) {
|
|
const n = Number(m[1]);
|
|
return {
|
|
key: `iso-${n}`,
|
|
label: `Mantra ${n}`,
|
|
sort: [n, 0],
|
|
section: null,
|
|
};
|
|
}
|
|
return { key: "iso", label: "Śrī Īśopaniṣad", sort: [0, 0], section: null };
|
|
}
|
|
case "NOD":
|
|
return {
|
|
key: "nod",
|
|
label: "The Nectar of Devotion",
|
|
sort: [0, 0],
|
|
section: null,
|
|
};
|
|
default:
|
|
return OTHER;
|
|
}
|
|
}
|