@helloao/tools 0.2.0 → 0.4.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.
- package/dist/cjs/generation/api.cjs +2213 -216
- package/dist/cjs/generation/api.cjs.map +3 -3
- package/dist/cjs/generation/audio.cjs +5 -5
- package/dist/cjs/generation/audio.cjs.map +1 -1
- package/dist/cjs/generation/book-order.cjs.map +1 -1
- package/dist/cjs/generation/common-types.cjs +782 -14
- package/dist/cjs/generation/common-types.cjs.map +2 -2
- package/dist/cjs/generation/dataset.cjs +13 -9
- package/dist/cjs/generation/dataset.cjs.map +2 -2
- package/dist/cjs/generation/index.cjs +8 -5
- package/dist/cjs/generation/index.cjs.map +2 -2
- package/dist/cjs/generation/simple.cjs +294 -0
- package/dist/cjs/generation/simple.cjs.map +7 -0
- package/dist/cjs/generation/theographic.cjs +446 -0
- package/dist/cjs/generation/theographic.cjs.map +7 -0
- package/dist/cjs/index.cjs +4 -4
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/log.cjs.map +1 -1
- package/dist/cjs/parser/codex-parser.cjs +3 -3
- package/dist/cjs/parser/codex-parser.cjs.map +3 -3
- package/dist/cjs/parser/commentary-csv-parser.cjs +14 -3
- package/dist/cjs/parser/commentary-csv-parser.cjs.map +3 -3
- package/dist/cjs/parser/index.cjs +1 -1
- package/dist/cjs/parser/iterators.cjs.map +1 -1
- package/dist/cjs/parser/lockman-parser.cjs +1 -1
- package/dist/cjs/parser/lockman-parser.cjs.map +1 -1
- package/dist/cjs/parser/tyndale-xml-parser.cjs +1 -1
- package/dist/cjs/parser/tyndale-xml-parser.cjs.map +1 -1
- package/dist/cjs/parser/types.cjs.map +1 -1
- package/dist/cjs/parser/usfm-parser.cjs +2 -2
- package/dist/cjs/parser/usfm-parser.cjs.map +1 -1
- package/dist/cjs/parser/usx-parser.cjs +122 -26
- package/dist/cjs/parser/usx-parser.cjs.map +2 -2
- package/dist/cjs/parser/words.cjs +187 -0
- package/dist/cjs/parser/words.cjs.map +7 -0
- package/dist/cjs/utils.cjs +1 -1
- package/dist/esm/generation/api.js +2155 -214
- package/dist/esm/generation/api.js.map +3 -3
- package/dist/esm/generation/audio.js +1 -1
- package/dist/esm/generation/audio.js.map +1 -1
- package/dist/esm/generation/book-order.js.map +1 -1
- package/dist/esm/generation/common-types.js +738 -14
- package/dist/esm/generation/common-types.js.map +2 -2
- package/dist/esm/generation/dataset.js +6 -2
- package/dist/esm/generation/dataset.js.map +2 -2
- package/dist/esm/generation/index.js +2 -1
- package/dist/esm/generation/index.js.map +2 -2
- package/dist/esm/generation/simple.js +260 -0
- package/dist/esm/generation/simple.js.map +7 -0
- package/dist/esm/generation/theographic.js +412 -0
- package/dist/esm/generation/theographic.js.map +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/log.js.map +1 -1
- package/dist/esm/parser/codex-parser.js +3 -3
- package/dist/esm/parser/codex-parser.js.map +3 -3
- package/dist/esm/parser/commentary-csv-parser.js +3 -2
- package/dist/esm/parser/commentary-csv-parser.js.map +2 -2
- package/dist/esm/parser/iterators.js.map +1 -1
- package/dist/esm/parser/lockman-parser.js +1 -1
- package/dist/esm/parser/lockman-parser.js.map +1 -1
- package/dist/esm/parser/tyndale-xml-parser.js +1 -1
- package/dist/esm/parser/tyndale-xml-parser.js.map +1 -1
- package/dist/esm/parser/usfm-parser.js +1 -1
- package/dist/esm/parser/usfm-parser.js.map +1 -1
- package/dist/esm/parser/usx-parser.js +130 -26
- package/dist/esm/parser/usx-parser.js.map +2 -2
- package/dist/esm/parser/words.js +149 -0
- package/dist/esm/parser/words.js.map +7 -0
- package/dist/types/generation/api.d.ts +9006 -1101
- package/dist/types/generation/common-types.d.ts +1318 -106
- package/dist/types/generation/dataset.d.ts +17 -1
- package/dist/types/generation/index.d.ts +2 -1
- package/dist/types/generation/simple.d.ts +110 -0
- package/dist/types/generation/theographic.d.ts +64 -0
- package/dist/types/parser/commentary-csv-parser.d.ts +1 -1
- package/dist/types/parser/lockman-parser.d.ts +1 -1
- package/dist/types/parser/tyndale-xml-parser.d.ts +1 -1
- package/dist/types/parser/types.d.ts +63 -0
- package/dist/types/parser/usx-parser.d.ts +6 -5
- package/dist/types/parser/words.d.ts +104 -0
- package/package.json +3 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../parser/codex-parser.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod';\r\nimport {\r\n Chapter,\r\n ChapterContent,\r\n ParseTree,\r\n Verse,\r\n VerseContent,\r\n} from './types.js';\r\nimport { getBookId, parseVerseReference, VerseRef } from '../utils.js';\r\nimport { ref } from 'process';\r\n\r\nexport const chapterHeadingSchema = z.object({\r\n type: z.literal('chapter-heading'),\r\n data: z.object({\r\n chapter: z.coerce.number().int(),\r\n }),\r\n});\r\n\r\nexport const verseSchema = z.object({\r\n type: z.literal('text'),\r\n id: z.string(),\r\n bookCode: z.string().optional(),\r\n chapter: z.number().optional(),\r\n verse: z.number().optional(),\r\n data: z\r\n .object({\r\n globalReferences: z.array(z.string()).optional(),\r\n })\r\n .optional(),\r\n});\r\n\r\nexport const paratextSchema = z.object({\r\n type: z.literal('paratext'),\r\n id: z.string(),\r\n});\r\n\r\nexport const metadataSchema = z.discriminatedUnion('type', [\r\n chapterHeadingSchema,\r\n verseSchema,\r\n paratextSchema,\r\n]);\r\n\r\nexport const codexSchema = z.object({\r\n cells: z.array(\r\n z.object({\r\n kind: z.number(),\r\n languageId: z.string(),\r\n value: z.string(),\r\n metadata: z\r\n .object({\r\n type: z.string(),\r\n })\r\n .passthrough()\r\n .nullable()\r\n .optional(),\r\n })\r\n ),\r\n});\r\n\r\n/**\r\n * Defines a parser for codex files.\r\n */\r\nexport class CodexParser {\r\n // TODO:\r\n // /**\r\n // * Whether to preserve markdown in the parsed content.\r\n // */\r\n // preserveMarkdown: boolean = true;\r\n\r\n private _noteCounter: number = 0;\r\n\r\n private _parser: DOMParser;\r\n\r\n constructor(parser: DOMParser) {\r\n this._parser = parser;\r\n }\r\n\r\n /**\r\n * Parses the specified codex content.\r\n *\r\n * @param codex The codex content to parse.\r\n * @returns The parse tree that was generated.\r\n */\r\n public parse(codex: string): ParseTree {\r\n const json = JSON.parse(codex);\r\n const data = codexSchema.parse(json);\r\n\r\n let root: ParseTree = {\r\n type: 'root',\r\n content: [],\r\n };\r\n\r\n let chapters: Map<number, Chapter> = new Map();\r\n let lastChapter: Chapter | null = null;\r\n\r\n function ensureChapter(chapterNumber: number) {\r\n let chapter = chapters.get(chapterNumber);\r\n if (!chapter) {\r\n chapter = {\r\n type: 'chapter',\r\n number: chapterNumber,\r\n content: [],\r\n footnotes: [],\r\n };\r\n lastChapter = chapter;\r\n chapters.set(chapterNumber, chapter);\r\n }\r\n\r\n return chapter;\r\n }\r\n\r\n function getDocumentContent(doc: Document): string {\r\n let content = '';\r\n for (let element of doc.childNodes) {\r\n content += element.textContent;\r\n }\r\n return content;\r\n }\r\n\r\n function addChapterContent(\r\n chapterNumber: number,\r\n content: ChapterContent[]\r\n ) {\r\n const chapter = ensureChapter(chapterNumber);\r\n chapter.content.push(...content);\r\n }\r\n\r\n function addChapterFootnote(\r\n chapterNumber: number,\r\n footnote: Chapter['footnotes'][0]\r\n ) {\r\n const chapter = ensureChapter(chapterNumber);\r\n chapter.footnotes.push(footnote);\r\n }\r\n\r\n function addReference(ref: VerseRef, content: Verse['content']) {\r\n addChapterContent(ref.chapter, [\r\n {\r\n type: 'verse',\r\n number: ref.verse,\r\n content: content,\r\n },\r\n ]);\r\n }\r\n\r\n function stripHTML(value: string) {\r\n return value.replace(/<[^>]*>/g, '');\r\n }\r\n\r\n function toHeading(content: string) {\r\n return {\r\n type: 'heading',\r\n content: [content],\r\n } satisfies ChapterContent;\r\n }\r\n\r\n function addLineBreaks(lines: Verse['content']) {\r\n return lines.reduce(\r\n (prev, current) => {\r\n if (typeof current === 'string' && current.trim() === '') {\r\n return prev; // skip empty lines\r\n }\r\n if (prev.length === 0) {\r\n return [current];\r\n } else {\r\n return [\r\n ...prev,\r\n {\r\n lineBreak: true,\r\n },\r\n current,\r\n ] satisfies Verse['content'];\r\n }\r\n },\r\n [] as Verse['content']\r\n );\r\n }\r\n\r\n let previousReference: VerseRef | null = null;\r\n let lines: Verse['content'] = [];\r\n\r\n for (let cell of data.cells) {\r\n if (cell.languageId === 'html' && cell.value) {\r\n if (!cell.metadata) continue; // ignore html cells without metadata\r\n\r\n const metadataResult = metadataSchema.safeParse(cell.metadata);\r\n\r\n if (!metadataResult.success) continue; // ignore cells with invalid/unknown metadata\r\n const metadata = metadataResult.data;\r\n if (metadata.type === 'text') {\r\n let reference = parseVerseReference(metadata.id);\r\n if (!reference) {\r\n if (metadata.bookCode && metadata.chapter) {\r\n const bookId = getBookId(metadata.bookCode);\r\n if (!bookId) {\r\n throw new Error(\r\n 'Could not find book ID for code: ' +\r\n metadata.bookCode\r\n );\r\n }\r\n\r\n if (metadata.verse) {\r\n reference = {\r\n book: bookId,\r\n chapter: metadata.chapter,\r\n verse: metadata.verse,\r\n };\r\n } else if (previousReference?.verse) {\r\n if (\r\n previousReference.chapter !==\r\n metadata.chapter ||\r\n previousReference.book !== bookId\r\n ) {\r\n throw new Error(\r\n 'Cannot infer verse number for non-consecutive verse reference.'\r\n );\r\n }\r\n\r\n // Sometimes codex doesn't include verse numbers for every cell, so we infer it from the previous reference\r\n reference = {\r\n book: bookId,\r\n chapter: metadata.chapter,\r\n verse: previousReference.verse,\r\n };\r\n } else {\r\n throw new Error(\r\n 'Could not find verse reference in metadata.'\r\n );\r\n }\r\n } else if (metadata.data?.globalReferences?.length) {\r\n reference = parseVerseReference(\r\n metadata.data.globalReferences[0]\r\n );\r\n if (!reference) {\r\n throw new Error(\r\n 'Could not find verse reference in globalReferences metadata.'\r\n );\r\n }\r\n } else {\r\n throw new Error(\r\n 'Could not find verse reference in metadata.'\r\n );\r\n }\r\n }\r\n\r\n if (\r\n previousReference &&\r\n (reference.book !== previousReference.book ||\r\n reference.chapter !== previousReference.chapter ||\r\n reference.verse !== previousReference.verse)\r\n ) {\r\n addReference(previousReference, addLineBreaks(lines));\r\n lines = [];\r\n }\r\n\r\n previousReference = reference;\r\n\r\n if (!root.id) root.id = reference.book; // set book id if not already set\r\n\r\n const doc = this._parser.parseFromString(\r\n cell.value,\r\n 'text/html'\r\n );\r\n\r\n for (let element of doc.children) {\r\n const allFootnotes = element.querySelectorAll(\r\n 'sup.footnote-marker[data-footnote]'\r\n );\r\n for (const footnote of allFootnotes) {\r\n const footnoteData =\r\n footnote.getAttribute('data-footnote');\r\n if (footnoteData) {\r\n const footnoteDoc =\r\n this._parser.parseFromString(\r\n footnoteData,\r\n 'text/html'\r\n );\r\n const footnoteText =\r\n getDocumentContent(footnoteDoc);\r\n if (footnoteText) {\r\n addChapterFootnote(reference.chapter, {\r\n noteId: this._noteCounter++,\r\n text: footnoteText,\r\n caller: null,\r\n });\r\n }\r\n }\r\n footnote.remove();\r\n }\r\n }\r\n\r\n const content = getDocumentContent(doc);\r\n\r\n if (content) {\r\n // add line breaks in heading if there are multiple lines\r\n const newLines = content.split('\\n');\r\n\r\n lines.push(...newLines);\r\n }\r\n } else if (metadata.type === 'paratext') {\r\n const reference = parseVerseReference(`${metadata.id}:1`); // chapter headings do not have a verse reference always default to 1\r\n if (reference) {\r\n const doc = this._parser.parseFromString(\r\n cell.value,\r\n 'text/html'\r\n );\r\n const content = getDocumentContent(doc);\r\n\r\n if (!content) {\r\n continue;\r\n }\r\n\r\n // add line breaks in heading if there are multiple lines\r\n const lines = content\r\n .split('\\n')\r\n .reduce<ChapterContent[]>((prev, current) => {\r\n if (prev.length === 0)\r\n return [toHeading(current)];\r\n else\r\n return [\r\n ...prev,\r\n {\r\n type: 'line_break',\r\n },\r\n toHeading(current),\r\n ] satisfies ChapterContent[];\r\n }, []);\r\n\r\n lines.forEach((line) =>\r\n addChapterContent(reference.chapter, [line])\r\n );\r\n } else {\r\n const doc = this._parser.parseFromString(\r\n cell.value,\r\n 'text/html'\r\n );\r\n const content = getDocumentContent(doc);\r\n // parse paratext that isn't a chapter reference as footnote\r\n // const content = stripHTML(cell.value);\r\n if (content && !cell.metadata) {\r\n if (lastChapter) {\r\n (lastChapter as Chapter).footnotes.push({\r\n noteId: this._noteCounter++,\r\n text: content,\r\n caller: null,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (previousReference) {\r\n addReference(previousReference, addLineBreaks(lines));\r\n }\r\n\r\n for (let chapter of chapters.values()) {\r\n root.content.push(chapter);\r\n }\r\n\r\n return root;\r\n }\r\n}\r\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAkB;AAQlB,mBAAyD;
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod';\r\nimport {\r\n Chapter,\r\n ChapterContent,\r\n ParseTree,\r\n Verse,\r\n VerseContent,\r\n} from './types.js';\r\nimport { getBookId, parseVerseReference, VerseRef } from '../utils.js';\r\n\r\nexport const chapterHeadingSchema = z.object({\r\n type: z.literal('chapter-heading'),\r\n data: z.object({\r\n chapter: z.coerce.number().int(),\r\n }),\r\n});\r\n\r\nexport const verseSchema = z.object({\r\n type: z.literal('text'),\r\n id: z.string(),\r\n bookCode: z.string().optional(),\r\n chapter: z.number().optional(),\r\n verse: z.number().optional(),\r\n data: z\r\n .object({\r\n globalReferences: z.array(z.string()).optional(),\r\n })\r\n .optional(),\r\n});\r\n\r\nexport const paratextSchema = z.object({\r\n type: z.literal('paratext'),\r\n id: z.string(),\r\n});\r\n\r\nexport const metadataSchema = z.discriminatedUnion('type', [\r\n chapterHeadingSchema,\r\n verseSchema,\r\n paratextSchema,\r\n]);\r\n\r\nexport const codexSchema = z.object({\r\n cells: z.array(\r\n z.object({\r\n kind: z.number(),\r\n languageId: z.string(),\r\n value: z.string(),\r\n metadata: z\r\n .object({\r\n type: z.string(),\r\n })\r\n .passthrough()\r\n .nullable()\r\n .optional(),\r\n })\r\n ),\r\n});\r\n\r\n/**\r\n * Defines a parser for codex files.\r\n */\r\nexport class CodexParser {\r\n // TODO:\r\n // /**\r\n // * Whether to preserve markdown in the parsed content.\r\n // */\r\n // preserveMarkdown: boolean = true;\r\n\r\n private _noteCounter: number = 0;\r\n\r\n private _parser: DOMParser;\r\n\r\n constructor(parser: DOMParser) {\r\n this._parser = parser;\r\n }\r\n\r\n /**\r\n * Parses the specified codex content.\r\n *\r\n * @param codex The codex content to parse.\r\n * @returns The parse tree that was generated.\r\n */\r\n public parse(codex: string): ParseTree {\r\n const json = JSON.parse(codex);\r\n const data = codexSchema.parse(json);\r\n\r\n let root: ParseTree = {\r\n type: 'root',\r\n content: [],\r\n };\r\n\r\n let chapters: Map<number, Chapter> = new Map();\r\n let lastChapter: Chapter | null = null;\r\n\r\n function ensureChapter(chapterNumber: number) {\r\n let chapter = chapters.get(chapterNumber);\r\n if (!chapter) {\r\n chapter = {\r\n type: 'chapter',\r\n number: chapterNumber,\r\n content: [],\r\n footnotes: [],\r\n };\r\n lastChapter = chapter;\r\n chapters.set(chapterNumber, chapter);\r\n }\r\n\r\n return chapter;\r\n }\r\n\r\n function getDocumentContent(doc: Document): string {\r\n let content = '';\r\n for (let element of doc.childNodes) {\r\n content += element.textContent;\r\n }\r\n return content;\r\n }\r\n\r\n function addChapterContent(\r\n chapterNumber: number,\r\n content: ChapterContent[]\r\n ) {\r\n const chapter = ensureChapter(chapterNumber);\r\n chapter.content.push(...content);\r\n }\r\n\r\n function addChapterFootnote(\r\n chapterNumber: number,\r\n footnote: Chapter['footnotes'][0]\r\n ) {\r\n const chapter = ensureChapter(chapterNumber);\r\n chapter.footnotes.push(footnote);\r\n }\r\n\r\n function addReference(ref: VerseRef, content: Verse['content']) {\r\n addChapterContent(ref.chapter, [\r\n {\r\n type: 'verse',\r\n number: ref.verse,\r\n content: content,\r\n },\r\n ]);\r\n }\r\n\r\n function stripHTML(value: string) {\r\n return value.replace(/<[^>]*>/g, '');\r\n }\r\n\r\n function toHeading(content: string) {\r\n return {\r\n type: 'heading',\r\n content: [content],\r\n } satisfies ChapterContent;\r\n }\r\n\r\n function addLineBreaks(lines: Verse['content']) {\r\n return lines.reduce(\r\n (prev, current) => {\r\n if (typeof current === 'string' && current.trim() === '') {\r\n return prev; // skip empty lines\r\n }\r\n if (prev.length === 0) {\r\n return [current];\r\n } else {\r\n return [\r\n ...prev,\r\n {\r\n lineBreak: true,\r\n },\r\n current,\r\n ] satisfies Verse['content'];\r\n }\r\n },\r\n [] as Verse['content']\r\n );\r\n }\r\n\r\n let previousReference: VerseRef | null = null;\r\n let lines: Verse['content'] = [];\r\n\r\n for (let cell of data.cells) {\r\n if (cell.languageId === 'html' && cell.value) {\r\n if (!cell.metadata) continue; // ignore html cells without metadata\r\n\r\n const metadataResult = metadataSchema.safeParse(cell.metadata);\r\n\r\n if (!metadataResult.success) continue; // ignore cells with invalid/unknown metadata\r\n const metadata = metadataResult.data;\r\n if (metadata.type === 'text') {\r\n let reference = parseVerseReference(metadata.id);\r\n if (!reference) {\r\n if (metadata.bookCode && metadata.chapter) {\r\n const bookId = getBookId(metadata.bookCode);\r\n if (!bookId) {\r\n throw new Error(\r\n 'Could not find book ID for code: ' +\r\n metadata.bookCode\r\n );\r\n }\r\n\r\n if (metadata.verse) {\r\n reference = {\r\n book: bookId,\r\n chapter: metadata.chapter,\r\n verse: metadata.verse,\r\n };\r\n } else if (previousReference?.verse) {\r\n if (\r\n previousReference.chapter !==\r\n metadata.chapter ||\r\n previousReference.book !== bookId\r\n ) {\r\n throw new Error(\r\n 'Cannot infer verse number for non-consecutive verse reference.'\r\n );\r\n }\r\n\r\n // Sometimes codex doesn't include verse numbers for every cell, so we infer it from the previous reference\r\n reference = {\r\n book: bookId,\r\n chapter: metadata.chapter,\r\n verse: previousReference.verse,\r\n };\r\n } else {\r\n throw new Error(\r\n 'Could not find verse reference in metadata.'\r\n );\r\n }\r\n } else if (metadata.data?.globalReferences?.length) {\r\n reference = parseVerseReference(\r\n metadata.data.globalReferences[0]\r\n );\r\n if (!reference) {\r\n throw new Error(\r\n 'Could not find verse reference in globalReferences metadata.'\r\n );\r\n }\r\n } else {\r\n throw new Error(\r\n 'Could not find verse reference in metadata.'\r\n );\r\n }\r\n }\r\n\r\n if (\r\n previousReference &&\r\n (reference.book !== previousReference.book ||\r\n reference.chapter !== previousReference.chapter ||\r\n reference.verse !== previousReference.verse)\r\n ) {\r\n addReference(previousReference, addLineBreaks(lines));\r\n lines = [];\r\n }\r\n\r\n previousReference = reference;\r\n\r\n if (!root.id) root.id = reference.book; // set book id if not already set\r\n\r\n const doc = this._parser.parseFromString(\r\n cell.value,\r\n 'text/html'\r\n );\r\n\r\n for (let element of doc.children) {\r\n const allFootnotes = element.querySelectorAll(\r\n 'sup.footnote-marker[data-footnote]'\r\n );\r\n for (const footnote of allFootnotes) {\r\n const footnoteData =\r\n footnote.getAttribute('data-footnote');\r\n if (footnoteData) {\r\n const footnoteDoc =\r\n this._parser.parseFromString(\r\n footnoteData,\r\n 'text/html'\r\n );\r\n const footnoteText =\r\n getDocumentContent(footnoteDoc);\r\n if (footnoteText) {\r\n addChapterFootnote(reference.chapter, {\r\n noteId: this._noteCounter++,\r\n text: footnoteText,\r\n caller: null,\r\n });\r\n }\r\n }\r\n footnote.remove();\r\n }\r\n }\r\n\r\n const content = getDocumentContent(doc);\r\n\r\n if (content) {\r\n // add line breaks in heading if there are multiple lines\r\n const newLines = content.split('\\n');\r\n\r\n lines.push(...newLines);\r\n }\r\n } else if (metadata.type === 'paratext') {\r\n const reference = parseVerseReference(`${metadata.id}:1`); // chapter headings do not have a verse reference always default to 1\r\n if (reference) {\r\n const doc = this._parser.parseFromString(\r\n cell.value,\r\n 'text/html'\r\n );\r\n const content = getDocumentContent(doc);\r\n\r\n if (!content) {\r\n continue;\r\n }\r\n\r\n // add line breaks in heading if there are multiple lines\r\n const lines = content\r\n .split('\\n')\r\n .reduce<ChapterContent[]>((prev, current) => {\r\n if (prev.length === 0)\r\n return [toHeading(current)];\r\n else\r\n return [\r\n ...prev,\r\n {\r\n type: 'line_break',\r\n },\r\n toHeading(current),\r\n ] satisfies ChapterContent[];\r\n }, []);\r\n\r\n lines.forEach((line) =>\r\n addChapterContent(reference.chapter, [line])\r\n );\r\n } else {\r\n const doc = this._parser.parseFromString(\r\n cell.value,\r\n 'text/html'\r\n );\r\n const content = getDocumentContent(doc);\r\n // parse paratext that isn't a chapter reference as footnote\r\n // const content = stripHTML(cell.value);\r\n if (content && !cell.metadata) {\r\n if (lastChapter) {\r\n (lastChapter as Chapter).footnotes.push({\r\n noteId: this._noteCounter++,\r\n text: content,\r\n caller: null,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (previousReference) {\r\n addReference(previousReference, addLineBreaks(lines));\r\n }\r\n\r\n for (let chapter of chapters.values()) {\r\n root.content.push(chapter);\r\n }\r\n\r\n return root;\r\n }\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["lines"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,19 +17,28 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var commentary_csv_parser_exports = {};
|
|
20
30
|
__export(commentary_csv_parser_exports, {
|
|
21
31
|
CommentaryCsvParser: () => CommentaryCsvParser
|
|
22
32
|
});
|
|
23
33
|
module.exports = __toCommonJS(commentary_csv_parser_exports);
|
|
24
|
-
var import_utils = require("../utils");
|
|
25
|
-
var import_papaparse = require("papaparse");
|
|
34
|
+
var import_utils = require("../utils.js");
|
|
35
|
+
var import_papaparse = __toESM(require("papaparse"), 1);
|
|
36
|
+
const { parse } = import_papaparse.default;
|
|
26
37
|
class CommentaryCsvParser {
|
|
27
38
|
parse(data) {
|
|
28
39
|
const firstLine = data.indexOf("\n");
|
|
29
40
|
data = data.substring(firstLine + 1);
|
|
30
|
-
const lines =
|
|
41
|
+
const lines = parse(data, {
|
|
31
42
|
header: false,
|
|
32
43
|
// transformHeader: (_, index) => {
|
|
33
44
|
// const headers = ['book', 'chapter', 'verse', 'commentaries'];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../parser/commentary-csv-parser.ts"],
|
|
4
|
-
"sourcesContent": ["import {\r\n CommentaryBookNode,\r\n CommentaryChapterNode,\r\n CommentaryParseTree,\r\n} from './types';\r\nimport { getBookId, parseVerseReference } from '../utils';\r\nimport { parse }
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import {\r\n CommentaryBookNode,\r\n CommentaryChapterNode,\r\n CommentaryParseTree,\r\n} from './types.js';\r\nimport { getBookId, parseVerseReference } from '../utils.js';\r\nimport papaparse from 'papaparse';\r\n\r\nconst { parse } = papaparse;\r\n\r\nexport interface CsvLine {\r\n book: string;\r\n chapter: string;\r\n verse: string;\r\n commentaries: string;\r\n}\r\n\r\nexport class CommentaryCsvParser {\r\n parse(data: string): CommentaryParseTree {\r\n // remove header automatically\r\n const firstLine = data.indexOf('\\n');\r\n data = data.substring(firstLine + 1);\r\n\r\n const lines = parse<string[]>(data, {\r\n header: false,\r\n // transformHeader: (_, index) => {\r\n // const headers = ['book', 'chapter', 'verse', 'commentaries'];\r\n // if (index < headers.length) {\r\n // return headers[index];\r\n // } else {\r\n // return '';\r\n // }\r\n // },\r\n delimiter: ',',\r\n escapeChar: '\"',\r\n quoteChar: '\"',\r\n });\r\n return this.parseLines(\r\n lines.data.map((line: string[]) => ({\r\n book: line[0],\r\n chapter: line[1],\r\n verse: line[2],\r\n commentaries: line[3],\r\n }))\r\n );\r\n }\r\n\r\n parseLines(data: CsvLine[]): CommentaryParseTree {\r\n let tree: CommentaryParseTree = {\r\n type: 'commentary/root',\r\n books: [],\r\n };\r\n\r\n let book: CommentaryBookNode | null = null;\r\n let chapter: CommentaryChapterNode | null = null;\r\n for (let line of data) {\r\n if (hasValue(line.book)) {\r\n const id = getBookId(line.book);\r\n if (!id) {\r\n throw new Error('Invalid book: ' + line.book);\r\n }\r\n\r\n book = tree.books.find((b) => b.book === id) ?? null;\r\n if (!book) {\r\n book = {\r\n type: 'book',\r\n book: id,\r\n introduction: null,\r\n chapters: [],\r\n };\r\n tree.books.push(book);\r\n }\r\n\r\n if (!book.introduction) {\r\n book.introduction = hasValue(line.commentaries)\r\n ? line.commentaries\r\n : null;\r\n }\r\n } else if (hasValue(line.chapter)) {\r\n const number = parseInt(line.chapter);\r\n if (isNaN(number)) {\r\n throw new Error('Invalid chapter number: ' + line.chapter);\r\n }\r\n\r\n if (!book) {\r\n throw new Error('Chapter without book');\r\n }\r\n\r\n chapter = {\r\n type: 'chapter',\r\n number,\r\n introduction: hasValue(line.commentaries)\r\n ? line.commentaries\r\n : null,\r\n verses: [],\r\n };\r\n book.chapters.push(chapter);\r\n } else if (hasValue(line.verse)) {\r\n const ref = parseVerseReference(line.verse);\r\n if (ref) {\r\n if (ref.book === book?.book) {\r\n // @ts-ignore\r\n if (ref.chapter === chapter?.number) {\r\n chapter.verses.push({\r\n type: 'verse',\r\n number: ref.verse,\r\n content: [line.commentaries],\r\n });\r\n } else {\r\n chapter = {\r\n type: 'chapter',\r\n number: ref.chapter,\r\n introduction: null,\r\n verses: [\r\n {\r\n type: 'verse',\r\n number: ref.verse,\r\n content: [line.commentaries],\r\n },\r\n ],\r\n };\r\n\r\n book.chapters.push(chapter);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return tree;\r\n }\r\n}\r\n\r\nfunction hasValue(value: string | null): boolean {\r\n return (\r\n value !== null &&\r\n value !== undefined &&\r\n value !== '' &&\r\n value.trim() !== ''\r\n );\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["papaparse"]
|
|
7
7
|
}
|
|
@@ -37,7 +37,7 @@ __reExport(parser_exports, require("./usfm-parser.js"), module.exports);
|
|
|
37
37
|
__reExport(parser_exports, require("./usx-parser.js"), module.exports);
|
|
38
38
|
__reExport(parser_exports, require("./codex-parser.js"), module.exports);
|
|
39
39
|
__reExport(parser_exports, require("./commentary-csv-parser.js"), module.exports);
|
|
40
|
-
var iterators = __toESM(require("./iterators.js"));
|
|
40
|
+
var iterators = __toESM(require("./iterators.js"), 1);
|
|
41
41
|
// Annotate the CommonJS export names for ESM import in node:
|
|
42
42
|
0 && (module.exports = {
|
|
43
43
|
iterators,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../parser/iterators.ts"],
|
|
4
|
-
"sourcesContent": ["import { getLogger } from '../log.js';\
|
|
4
|
+
"sourcesContent": ["import { getLogger } from '../log.js';\n\n/**\n * Defines an interface that represents an iterator that can be rewound.\n */\nexport interface RewindableIterator<T> extends IterableIterator<T> {\n /**\n * Rewinds the iterator by the specified number of elements.\n * @param number The number of elements to rewind.\n */\n rewind(number: number): void;\n}\n\n/**\n * Defines a class that implements an iterator that can be rewound.\n */\nexport class Rewindable<T> implements RewindableIterator<T> {\n buffer: T[] = [];\n\n private _bufferSize: number = 0;\n private _position: number = -1;\n private _iterator: IterableIterator<T>;\n\n constructor(iterator: IterableIterator<T>, bufferSize: number = 2) {\n this._iterator = iterator;\n this._bufferSize = bufferSize;\n\n if (this._iterator.return) {\n this.return = (value?: any) => {\n return this._iterator.return!(value);\n };\n }\n if (this._iterator.throw) {\n this.throw = (value?: any) => {\n return this._iterator.throw!(value);\n };\n }\n }\n\n rewind(number: number): void {\n this._position += number;\n }\n\n [Symbol.iterator](): IterableIterator<T> {\n return this;\n }\n\n next(...args: [] | [undefined]): IteratorResult<T, any> {\n if (this._position >= 0) {\n let item = this.buffer[this._position];\n this._position--;\n return {\n value: item,\n done: false,\n };\n }\n\n let result = this._iterator.next(...args);\n this.buffer.unshift(result.value);\n if (this.buffer.length > this._bufferSize) {\n this.buffer.splice(\n this._bufferSize,\n this.buffer.length - this._bufferSize\n );\n }\n return result;\n }\n\n return?(value?: any): IteratorResult<T, any>;\n throw?(e?: any): IteratorResult<T, any>;\n}\n\nexport function* debug(label: string, iterator: IterableIterator<any>) {\n const logger = getLogger();\n for (let value of uncompletable(iterator)) {\n if (value instanceof Element) {\n logger.log(label, value.outerHTML);\n } else if (value instanceof Node) {\n logger.log(label, value.textContent);\n } else {\n logger.log(label, value);\n }\n yield value;\n }\n}\n\n/**\n * Creates a new rewindable iterator from the given iterator.\n * @param iterator The iterator.\n * @param bufferSize The size of the buffer.\n */\nexport function rewindable<T>(\n iterator: IterableIterator<T>,\n bufferSize: number = 2\n): Rewindable<T> {\n return new Rewindable(iterator, bufferSize);\n}\n\nfunction* iterateNodes(node: Node) {\n for (let i = 0; i < node.childNodes.length; i++) {\n yield node.childNodes[i];\n }\n}\n\n/**\n * Gets the char element that is the parent of the given node.\n * @param node The node.\n */\nexport function parentChar(node: Node): Element | null {\n return matchingParent(\n node,\n (n) => n instanceof Element && n.nodeName === 'char'\n ) as Element | null;\n}\n\n/**\n * Gets the note element that is the parent of the given node.\n * @param node The node.\n */\nexport function parentNote(node: Node): Element | null {\n return matchingParent(\n node,\n (n) => n instanceof Element && n.nodeName === 'note'\n ) as Element | null;\n}\n\n/**\n * Gets the parent node that matches the given filter.\n * @param node The node to start the search from.\n * @param filter The filter that should be used.\n */\nexport function matchingParent(\n node: Node,\n filter: (node: Node) => boolean\n): Node | null {\n let parent = node.parentNode;\n while (parent) {\n if (filter(parent)) {\n return parent;\n }\n parent = parent.parentNode;\n }\n return null;\n}\n\n/**\n * Determines if the given node is a child of the parent node.\n * @param node The node to test.\n * @param parent The parent.\n * @returns\n */\nexport function isParent(node: Node, parent: Node): boolean {\n let parentNode = node.parentNode;\n while (parentNode) {\n if (parentNode === parent) {\n return true;\n }\n parentNode = parentNode.parentNode;\n }\n return false;\n}\n\n/**\n * Iterates through all of the nodes in the tree in a depth-first traversal.\n * @param node The node to start the traversal from.\n */\nexport function iterateAll(node: Node): RewindableIterator<Node> {\n return rewindable(_iterateAll(node));\n}\n\nexport function* iterateUntil<T>(\n iterator: IterableIterator<T>,\n predicate: (value: T) => boolean\n): IterableIterator<T> {\n for (let value of iterator) {\n if (predicate(value)) {\n return;\n }\n yield value;\n }\n}\n\nfunction* _iterateAll(node: Node): IterableIterator<Node> {\n for (let child of node.childNodes) {\n yield child;\n yield* iterateAll(child);\n }\n}\n\n/**\n * Iterates only the elements in the iterator.\n * @param iterator The iterator that should be used.\n */\nexport function* elements(\n iterator: IterableIterator<Node>\n): IterableIterator<Element> {\n for (let node of uncompletable(iterator)) {\n if (node instanceof Element) {\n yield node;\n }\n }\n}\n\n/**\n * Iterates only the children of the given node in the iterator.\n * @param iterator The iterator that should be used.\n * @param parent The parent node.\n */\nexport function* children(\n iterator: RewindableIterator<Node>,\n parent: Node\n): IterableIterator<Node> {\n for (let node of uncompletable(iterator)) {\n if (!isParent(node, parent)) {\n iterator.rewind(1);\n return;\n }\n\n yield node;\n }\n}\n\n/**\n * Wraps the given iterable in a generator that will prevent consumers from calling return() on the iterator.\n * @param iterable The iterable.\n */\nexport function* uncompletable<T>(\n iterable: IterableIterator<T>\n): IterableIterator<T> {\n while (true) {\n const { done, value } = iterable.next();\n if (done) {\n return;\n }\n yield value;\n }\n}\n\n/**\n * Converts the given iterable into an async iterable.\n * @param input The input iterable.\n */\nexport async function* toAsyncIterable<T>(\n input: Iterable<T>\n): AsyncIterable<T> {\n for (let item of input) {\n yield item;\n }\n}\n\n/**\n * Batches items from the given iterator.\n * @param input The input iterator.\n * @param batchSize The size of each batch.\n */\nexport function* batch<T>(\n input: Iterable<T>,\n batchSize: number\n): Iterable<T[]> {\n while (true) {\n let batch = [] as T[];\n for (let item of input) {\n batch.push(item);\n if (batch.length >= batchSize) {\n break;\n }\n }\n\n if (batch.length === 0) {\n return;\n }\n\n yield batch;\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["batch"]
|
|
7
7
|
}
|
|
@@ -22,7 +22,7 @@ __export(lockman_parser_exports, {
|
|
|
22
22
|
LockmanParser: () => LockmanParser
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(lockman_parser_exports);
|
|
25
|
-
var import_book_order = require("../generation/book-order");
|
|
25
|
+
var import_book_order = require("../generation/book-order.js");
|
|
26
26
|
const LOCKMAN_PARSER_VERSION = 3;
|
|
27
27
|
const bookNumberIdMap = /* @__PURE__ */ new Map();
|
|
28
28
|
for (const [id, order] of import_book_order.bookOrderMap) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../parser/lockman-parser.ts"],
|
|
4
|
-
"sourcesContent": ["import {\r\n ParseTree,\r\n Chapter,\r\n Verse,\r\n Heading,\r\n Footnote,\r\n Text,\r\n FootnoteReference,\r\n HebrewSubtitle,\r\n} from './types';\r\nimport { bookOrderMap } from '../generation/book-order';\r\n\r\nexport const LOCKMAN_PARSER_VERSION = 3;\r\n\r\nconst bookNumberIdMap = new Map<number, string>();\r\nfor (const [id, order] of bookOrderMap) {\r\n if (!bookNumberIdMap.has(order)) {\r\n bookNumberIdMap.set(order, id);\r\n }\r\n}\r\n\r\nexport class LockmanParser {\r\n parse(text: string): ParseTree[] {\r\n const roots: ParseTree[] = [];\r\n let currentRoot: ParseTree | null = null;\r\n let currentChapter: Chapter | null = null;\r\n let currentVerse: Verse | null = null;\r\n\r\n // Splits text into tokens based on structural tags\r\n // Identify major blocks: BN, CN, SH, and Verse Starters (V, C, PM, A, PO)\r\n // Note: SH and CN content is strictly inside the tag.\r\n // Verse content follows the tag.\r\n // We use a regex that captures the tag AND its \"attributes\" like {{..}}Num<T> for verses.\r\n\r\n // Regex for structural separators\r\n // Captures:\r\n // 1. Title: <BN>...</BN>\r\n // 2. Chapter Heading: <CN>...</CN> or <SN>...</SN>\r\n // 3. Section Heading: <SH>...</SH> or <SS>...</SS>\r\n // 4. Verse Start: (<V>|<C>|<CC>|<CP>|<PM>|<A>|<PO>|<P>|<PN>){{...}}Number<T>\r\n\r\n const structureRegex =\r\n /(<BN>.*?<\\/BN>)|((?:<CN>.*?<\\/CN>)|(?:<SN>.*?<\\/SN>))|((?:<SH>.*?<\\/SH>)|(?:<SS>.*?<\\/SS>))|((?:<V>|<C>|<CC>|<CP>|<PM>|<A>|<PO>|<P>|<PN>)\\{\\{.*?\\}\\}\\d+(?:<T>|\\^)(?:\\{.*?\\})?)/g;\r\n\r\n let lastIndex = 0;\r\n let match;\r\n let isPoem = false;\r\n\r\n while ((match = structureRegex.exec(text)) !== null) {\r\n const fullMatch = match[0];\r\n const startIndex = match.index;\r\n\r\n // Content belonging to the PREVIOUS structural element\r\n if (startIndex > lastIndex) {\r\n const content = text.substring(lastIndex, startIndex);\r\n if (currentVerse && currentChapter) {\r\n this.parseVerseContent(\r\n content,\r\n currentVerse,\r\n currentChapter,\r\n isPoem\r\n );\r\n }\r\n }\r\n\r\n lastIndex = startIndex + fullMatch.length;\r\n\r\n if (match[1]) {\r\n // <BN>Title</BN>\r\n // Start of a NEW Book\r\n const title = match[1].replace(/<\\/?BN>/g, '').trim();\r\n\r\n currentRoot = {\r\n type: 'root',\r\n title: title,\r\n content: [],\r\n };\r\n roots.push(currentRoot);\r\n\r\n // Reset context for new book\r\n currentChapter = null;\r\n currentVerse = null;\r\n } else if (match[2]) {\r\n // <CN>CHAPTER 1</CN> or <SN>PSALM 1</SN>\r\n // Start new Chapter\r\n // Ensure we have a root (handle case where no <BN> provided, implicitly create one? Or just attach to last root)\r\n if (!currentRoot) {\r\n // Fallback if no <BN> was found first\r\n currentRoot = {\r\n type: 'root',\r\n content: [],\r\n };\r\n roots.push(currentRoot);\r\n }\r\n\r\n // Remove tags: <CN>, </CN>, <SN>, </SN>\r\n const inner = match[2].replace(/<\\/?(CN|SN)>/g, '').trim();\r\n const numMatch = inner.match(/\\d+/);\r\n const num = numMatch ? parseInt(numMatch[0], 10) : 0;\r\n\r\n currentChapter = {\r\n type: 'chapter',\r\n number: num,\r\n content: [],\r\n footnotes: [],\r\n };\r\n currentRoot.content.push(currentChapter);\r\n currentVerse = null;\r\n } else if (match[3]) {\r\n // <SH>Heading</SH> or <SS>Subtitle</SS>\r\n if (!currentRoot) {\r\n currentRoot = { type: 'root', content: [] };\r\n roots.push(currentRoot);\r\n }\r\n\r\n const raw = match[3];\r\n if (raw.startsWith('<SS>')) {\r\n // Hebrew subtitle in Psalms\r\n const inner = raw.replace(/<\\/?SS>/g, '').trim();\r\n const subtitle: HebrewSubtitle = {\r\n type: 'hebrew_subtitle',\r\n content: [],\r\n };\r\n\r\n if (currentChapter) {\r\n this.parseHebrewSubtitleContent(\r\n inner,\r\n subtitle,\r\n currentChapter\r\n );\r\n currentChapter.content.push(subtitle);\r\n }\r\n } else {\r\n // Section heading\r\n const inner = raw.replace(/<\\/?SH>/g, '').trim();\r\n const normalized = inner.replace(/<\\\\>|<\\/?>|[{}]/g, '');\r\n const heading: Heading = {\r\n type: 'heading',\r\n content: [normalized],\r\n };\r\n if (currentChapter) {\r\n currentChapter.content.push(heading);\r\n } else {\r\n // Start of book heading? Not typical in this structure but possible\r\n currentRoot.content.push(heading);\r\n }\r\n }\r\n } else if (match[4]) {\r\n // Verse Start: <Tag>{{Ref}}Number<T>\r\n // Extract Verse Number\r\n const tagContent = match[4];\r\n if (currentRoot && !currentRoot.id) {\r\n const bookId = this.getBookIdFromVerseTag(tagContent);\r\n if (bookId) {\r\n currentRoot.id = bookId;\r\n }\r\n }\r\n // Regex to extract digits before <T>\r\n const vNumMatch = tagContent.match(/(\\d+)(?:<T>|\\^)/);\r\n const vNum = vNumMatch ? parseInt(vNumMatch[1], 10) : 0;\r\n\r\n if (currentChapter) {\r\n // Check for Paragraph Marker\r\n if (tagContent.startsWith('<PM>')) {\r\n currentChapter.content.push({ type: 'line_break' });\r\n }\r\n\r\n // Update global isPoem flag\r\n isPoem = /<(?:P|PO|PN|CC|CP)>/.test(tagContent);\r\n\r\n currentVerse = {\r\n type: 'verse',\r\n number: vNum,\r\n content: [],\r\n };\r\n currentChapter.content.push(currentVerse);\r\n }\r\n }\r\n }\r\n\r\n // Process remaining text after the last match\r\n if (lastIndex < text.length) {\r\n const content = text.substring(lastIndex);\r\n if (currentVerse && currentChapter) {\r\n this.parseVerseContent(\r\n content,\r\n currentVerse,\r\n currentChapter,\r\n isPoem\r\n );\r\n }\r\n }\r\n\r\n return roots;\r\n }\r\n\r\n private getBookIdFromVerseTag(tagContent: string): string | null {\r\n const match = tagContent.match(/\\{\\{(\\d+)::/);\r\n if (!match) {\r\n return null;\r\n }\r\n\r\n const bookNumber = parseInt(match[1], 10);\r\n if (isNaN(bookNumber)) {\r\n return null;\r\n }\r\n\r\n return bookNumberIdMap.get(bookNumber) ?? null;\r\n }\r\n\r\n private parseVerseContent(\r\n text: string,\r\n verse: Verse,\r\n chapter: Chapter,\r\n isPoem: boolean\r\n ) {\r\n // Remove line breaks that are just formatting in the source file\r\n // But keep spaces.\r\n // The source has newlines. We should arguably treat them as spaces.\r\n let cleanText = text.replace(/\\s+/g, ' ').trim();\r\n cleanText = cleanText.replace(/[\\+\\-][\u201C\u2018\"]/g, '');\r\n cleanText = cleanText.replace(/\\+\\[/g, '[').replace(/\\+\\]/g, ']');\r\n cleanText = cleanText.replace(/@\\[.*?@\\]/g, '');\r\n\r\n // Regex to separate text from special inline blocks:\r\n // 1. Footnotes: <$F ... $E>\r\n // 2. Cross References: <$R ... $RE> (To be removed)\r\n // 3. Formatting Tags: <RA>, <N1>, etc. (To be removed?)\r\n // 4. Italics in curly braces: {text}\r\n\r\n // Note: Curly braces are nested inside footnotes sometimes, but stripped there.\r\n // At the verse level, they denote italics.\r\n\r\n const segmentRegex =\r\n /(<\\$F.*?\\$E>)|(<\\$R.*?\\$RE>)|(<[^>]*>)|(\\{.*?\\})/g;\r\n\r\n let lastIdx = 0;\r\n let m;\r\n let wordsOfJesus = false;\r\n\r\n while ((m = segmentRegex.exec(cleanText)) !== null) {\r\n const snippet = cleanText.substring(lastIdx, m.index);\r\n if (snippet) {\r\n // Add plain text\r\n this.addText(verse, snippet, isPoem, wordsOfJesus);\r\n }\r\n\r\n if (m[1]) {\r\n // Footnote <$F ... $E>\r\n this.processFootnote(m[1], verse, chapter);\r\n } else if (m[2]) {\r\n // Cross Ref -> Ignore\r\n } else if (m[3]) {\r\n if (m[3] === '<PO>') {\r\n verse.content.push({ lineBreak: true });\r\n lastIdx = segmentRegex.lastIndex;\r\n continue;\r\n }\r\n // Handle words of Jesus markers\r\n if (m[3] === '<RS>') {\r\n wordsOfJesus = true;\r\n } else if (m[3] === '</RS>') {\r\n wordsOfJesus = false;\r\n }\r\n // Other tag -> Ignore (e.g. <RA>, <N1>, <FA>)\r\n // These are often just markers or anchors.\r\n } else if (m[4]) {\r\n // Italics {text}\r\n const content = m[4].substring(1, m[4].length - 1);\r\n // We push a Text object with italics: true\r\n // Check if we need to decode inside? Usually just text.\r\n if (content) {\r\n let text: Text = {\r\n text: content,\r\n italics: true,\r\n };\r\n\r\n if (isPoem) {\r\n text.poem = 1;\r\n }\r\n\r\n if (wordsOfJesus) {\r\n text.wordsOfJesus = true;\r\n }\r\n\r\n verse.content.push(text);\r\n }\r\n }\r\n\r\n lastIdx = segmentRegex.lastIndex;\r\n }\r\n\r\n const remaining = cleanText.substring(lastIdx);\r\n if (remaining) {\r\n this.addText(verse, remaining, isPoem, wordsOfJesus);\r\n }\r\n }\r\n\r\n private addText(\r\n verse: Verse,\r\n text: string,\r\n isPoem: boolean,\r\n wordsOfJesus: boolean\r\n ) {\r\n if (!text) return;\r\n\r\n if (isPoem || wordsOfJesus) {\r\n // When poem=1 or wordsOfJesus is true, use Text objects to carry attributes.\r\n const lastItem = verse.content[verse.content.length - 1];\r\n\r\n if (\r\n lastItem &&\r\n typeof lastItem !== 'string' &&\r\n !('noteId' in lastItem) &&\r\n (lastItem as Text).poem === (isPoem ? 1 : undefined) &&\r\n (lastItem as Text).wordsOfJesus ===\r\n (wordsOfJesus ? true : undefined) &&\r\n !(lastItem as Text).italics\r\n ) {\r\n (lastItem as Text).text += text;\r\n } else {\r\n const formatted: Text = {\r\n text: text,\r\n };\r\n if (isPoem) {\r\n formatted.poem = 1;\r\n }\r\n if (wordsOfJesus) {\r\n formatted.wordsOfJesus = true;\r\n }\r\n verse.content.push(formatted);\r\n }\r\n } else {\r\n // Merge with previous string if possible\r\n const lastItem = verse.content[verse.content.length - 1];\r\n if (typeof lastItem === 'string') {\r\n verse.content[verse.content.length - 1] = lastItem + text;\r\n } else {\r\n verse.content.push(text);\r\n }\r\n }\r\n }\r\n\r\n private parseHebrewSubtitleContent(\r\n text: string,\r\n subtitle: HebrewSubtitle,\r\n chapter: Chapter\r\n ) {\r\n let cleanText = text.replace(/\\s+/g, ' ').trim();\r\n cleanText = cleanText.replace(/[{}]/g, '');\r\n cleanText = cleanText.replace(/@\\[.*?@\\]/g, '');\r\n\r\n const segmentRegex =\r\n /(<\\$F.*?\\$E>)|(<\\$R.*?\\$RE>)|(<[^>]+>)|(\\{.*?\\})/g;\r\n\r\n let lastIdx = 0;\r\n let m;\r\n\r\n while ((m = segmentRegex.exec(cleanText)) !== null) {\r\n const snippet = cleanText.substring(lastIdx, m.index);\r\n if (snippet) {\r\n this.addSubtitleText(subtitle, snippet);\r\n }\r\n\r\n if (m[1]) {\r\n const ref = this.processFootnoteForSubtitle(m[1], chapter);\r\n if (ref) {\r\n subtitle.content.push(ref);\r\n }\r\n } else if (m[2]) {\r\n // Cross Ref -> Ignore\r\n } else if (m[3]) {\r\n // Other tag -> Ignore\r\n } else if (m[4]) {\r\n const content = m[4].substring(1, m[4].length - 1);\r\n if (content) {\r\n this.addSubtitleText(subtitle, content);\r\n }\r\n }\r\n\r\n lastIdx = segmentRegex.lastIndex;\r\n }\r\n\r\n const remaining = cleanText.substring(lastIdx);\r\n if (remaining) {\r\n this.addSubtitleText(subtitle, remaining);\r\n }\r\n }\r\n\r\n private addSubtitleText(subtitle: HebrewSubtitle, text: string) {\r\n if (!text) return;\r\n\r\n const lastItem = subtitle.content[subtitle.content.length - 1];\r\n if (typeof lastItem === 'string') {\r\n subtitle.content[subtitle.content.length - 1] = lastItem + text;\r\n } else {\r\n subtitle.content.push(text);\r\n }\r\n }\r\n\r\n private processFootnote(block: string, verse: Verse, chapter: Chapter) {\r\n // block is <$F...$E>\r\n // Inner content has tags like <FN>, <FNC>, <N1>...\r\n // We want the readable text.\r\n // Remove known technical tags.\r\n\r\n const text = this.extractFootnoteText(block);\r\n\r\n if (!text) return;\r\n\r\n const noteId = chapter.footnotes.length + 1;\r\n\r\n const fn: Footnote = {\r\n noteId: noteId,\r\n text: text,\r\n caller: '+',\r\n reference: {\r\n chapter: chapter.number,\r\n verse: verse.number,\r\n },\r\n };\r\n chapter.footnotes.push(fn);\r\n\r\n verse.content.push({\r\n noteId: noteId,\r\n } as FootnoteReference);\r\n }\r\n\r\n private processFootnoteForSubtitle(\r\n block: string,\r\n chapter: Chapter\r\n ): FootnoteReference | null {\r\n const text = this.extractFootnoteText(block);\r\n\r\n if (!text) return null;\r\n\r\n const noteId = chapter.footnotes.length + 1;\r\n\r\n const fn: Footnote = {\r\n noteId: noteId,\r\n text: text,\r\n caller: '+',\r\n reference: {\r\n chapter: chapter.number,\r\n verse: 0,\r\n },\r\n };\r\n chapter.footnotes.push(fn);\r\n\r\n return {\r\n noteId: noteId,\r\n } as FootnoteReference;\r\n }\r\n\r\n private extractFootnoteText(block: string): string {\r\n // Remove outer $F...$E\r\n let inner = block.replace(/^<\\$F/, '').replace(/\\$E>$/, '');\r\n\r\n // Remove internal technical tags\r\n // Remove <FN>...</FN> completely\r\n inner = inner.replace(/<FN>.*?<\\/FN>/g, '');\r\n\r\n // Remove other tags <N1>, <FA> but keep content\r\n // Also remove italics curly braces (keep content inside)\r\n return inner\r\n .replace(/<[^>]+>/g, '')\r\n .replace(/[\\{\\}]/g, '')\r\n .trim();\r\n }\r\n}\r\n"],
|
|
4
|
+
"sourcesContent": ["import {\r\n ParseTree,\r\n Chapter,\r\n Verse,\r\n Heading,\r\n Footnote,\r\n Text,\r\n FootnoteReference,\r\n HebrewSubtitle,\r\n} from './types.js';\r\nimport { bookOrderMap } from '../generation/book-order.js';\r\n\r\nexport const LOCKMAN_PARSER_VERSION = 3;\r\n\r\nconst bookNumberIdMap = new Map<number, string>();\r\nfor (const [id, order] of bookOrderMap) {\r\n if (!bookNumberIdMap.has(order)) {\r\n bookNumberIdMap.set(order, id);\r\n }\r\n}\r\n\r\nexport class LockmanParser {\r\n parse(text: string): ParseTree[] {\r\n const roots: ParseTree[] = [];\r\n let currentRoot: ParseTree | null = null;\r\n let currentChapter: Chapter | null = null;\r\n let currentVerse: Verse | null = null;\r\n\r\n // Splits text into tokens based on structural tags\r\n // Identify major blocks: BN, CN, SH, and Verse Starters (V, C, PM, A, PO)\r\n // Note: SH and CN content is strictly inside the tag.\r\n // Verse content follows the tag.\r\n // We use a regex that captures the tag AND its \"attributes\" like {{..}}Num<T> for verses.\r\n\r\n // Regex for structural separators\r\n // Captures:\r\n // 1. Title: <BN>...</BN>\r\n // 2. Chapter Heading: <CN>...</CN> or <SN>...</SN>\r\n // 3. Section Heading: <SH>...</SH> or <SS>...</SS>\r\n // 4. Verse Start: (<V>|<C>|<CC>|<CP>|<PM>|<A>|<PO>|<P>|<PN>){{...}}Number<T>\r\n\r\n const structureRegex =\r\n /(<BN>.*?<\\/BN>)|((?:<CN>.*?<\\/CN>)|(?:<SN>.*?<\\/SN>))|((?:<SH>.*?<\\/SH>)|(?:<SS>.*?<\\/SS>))|((?:<V>|<C>|<CC>|<CP>|<PM>|<A>|<PO>|<P>|<PN>)\\{\\{.*?\\}\\}\\d+(?:<T>|\\^)(?:\\{.*?\\})?)/g;\r\n\r\n let lastIndex = 0;\r\n let match;\r\n let isPoem = false;\r\n\r\n while ((match = structureRegex.exec(text)) !== null) {\r\n const fullMatch = match[0];\r\n const startIndex = match.index;\r\n\r\n // Content belonging to the PREVIOUS structural element\r\n if (startIndex > lastIndex) {\r\n const content = text.substring(lastIndex, startIndex);\r\n if (currentVerse && currentChapter) {\r\n this.parseVerseContent(\r\n content,\r\n currentVerse,\r\n currentChapter,\r\n isPoem\r\n );\r\n }\r\n }\r\n\r\n lastIndex = startIndex + fullMatch.length;\r\n\r\n if (match[1]) {\r\n // <BN>Title</BN>\r\n // Start of a NEW Book\r\n const title = match[1].replace(/<\\/?BN>/g, '').trim();\r\n\r\n currentRoot = {\r\n type: 'root',\r\n title: title,\r\n content: [],\r\n };\r\n roots.push(currentRoot);\r\n\r\n // Reset context for new book\r\n currentChapter = null;\r\n currentVerse = null;\r\n } else if (match[2]) {\r\n // <CN>CHAPTER 1</CN> or <SN>PSALM 1</SN>\r\n // Start new Chapter\r\n // Ensure we have a root (handle case where no <BN> provided, implicitly create one? Or just attach to last root)\r\n if (!currentRoot) {\r\n // Fallback if no <BN> was found first\r\n currentRoot = {\r\n type: 'root',\r\n content: [],\r\n };\r\n roots.push(currentRoot);\r\n }\r\n\r\n // Remove tags: <CN>, </CN>, <SN>, </SN>\r\n const inner = match[2].replace(/<\\/?(CN|SN)>/g, '').trim();\r\n const numMatch = inner.match(/\\d+/);\r\n const num = numMatch ? parseInt(numMatch[0], 10) : 0;\r\n\r\n currentChapter = {\r\n type: 'chapter',\r\n number: num,\r\n content: [],\r\n footnotes: [],\r\n };\r\n currentRoot.content.push(currentChapter);\r\n currentVerse = null;\r\n } else if (match[3]) {\r\n // <SH>Heading</SH> or <SS>Subtitle</SS>\r\n if (!currentRoot) {\r\n currentRoot = { type: 'root', content: [] };\r\n roots.push(currentRoot);\r\n }\r\n\r\n const raw = match[3];\r\n if (raw.startsWith('<SS>')) {\r\n // Hebrew subtitle in Psalms\r\n const inner = raw.replace(/<\\/?SS>/g, '').trim();\r\n const subtitle: HebrewSubtitle = {\r\n type: 'hebrew_subtitle',\r\n content: [],\r\n };\r\n\r\n if (currentChapter) {\r\n this.parseHebrewSubtitleContent(\r\n inner,\r\n subtitle,\r\n currentChapter\r\n );\r\n currentChapter.content.push(subtitle);\r\n }\r\n } else {\r\n // Section heading\r\n const inner = raw.replace(/<\\/?SH>/g, '').trim();\r\n const normalized = inner.replace(/<\\\\>|<\\/?>|[{}]/g, '');\r\n const heading: Heading = {\r\n type: 'heading',\r\n content: [normalized],\r\n };\r\n if (currentChapter) {\r\n currentChapter.content.push(heading);\r\n } else {\r\n // Start of book heading? Not typical in this structure but possible\r\n currentRoot.content.push(heading);\r\n }\r\n }\r\n } else if (match[4]) {\r\n // Verse Start: <Tag>{{Ref}}Number<T>\r\n // Extract Verse Number\r\n const tagContent = match[4];\r\n if (currentRoot && !currentRoot.id) {\r\n const bookId = this.getBookIdFromVerseTag(tagContent);\r\n if (bookId) {\r\n currentRoot.id = bookId;\r\n }\r\n }\r\n // Regex to extract digits before <T>\r\n const vNumMatch = tagContent.match(/(\\d+)(?:<T>|\\^)/);\r\n const vNum = vNumMatch ? parseInt(vNumMatch[1], 10) : 0;\r\n\r\n if (currentChapter) {\r\n // Check for Paragraph Marker\r\n if (tagContent.startsWith('<PM>')) {\r\n currentChapter.content.push({ type: 'line_break' });\r\n }\r\n\r\n // Update global isPoem flag\r\n isPoem = /<(?:P|PO|PN|CC|CP)>/.test(tagContent);\r\n\r\n currentVerse = {\r\n type: 'verse',\r\n number: vNum,\r\n content: [],\r\n };\r\n currentChapter.content.push(currentVerse);\r\n }\r\n }\r\n }\r\n\r\n // Process remaining text after the last match\r\n if (lastIndex < text.length) {\r\n const content = text.substring(lastIndex);\r\n if (currentVerse && currentChapter) {\r\n this.parseVerseContent(\r\n content,\r\n currentVerse,\r\n currentChapter,\r\n isPoem\r\n );\r\n }\r\n }\r\n\r\n return roots;\r\n }\r\n\r\n private getBookIdFromVerseTag(tagContent: string): string | null {\r\n const match = tagContent.match(/\\{\\{(\\d+)::/);\r\n if (!match) {\r\n return null;\r\n }\r\n\r\n const bookNumber = parseInt(match[1], 10);\r\n if (isNaN(bookNumber)) {\r\n return null;\r\n }\r\n\r\n return bookNumberIdMap.get(bookNumber) ?? null;\r\n }\r\n\r\n private parseVerseContent(\r\n text: string,\r\n verse: Verse,\r\n chapter: Chapter,\r\n isPoem: boolean\r\n ) {\r\n // Remove line breaks that are just formatting in the source file\r\n // But keep spaces.\r\n // The source has newlines. We should arguably treat them as spaces.\r\n let cleanText = text.replace(/\\s+/g, ' ').trim();\r\n cleanText = cleanText.replace(/[\\+\\-][\u201C\u2018\"]/g, '');\r\n cleanText = cleanText.replace(/\\+\\[/g, '[').replace(/\\+\\]/g, ']');\r\n cleanText = cleanText.replace(/@\\[.*?@\\]/g, '');\r\n\r\n // Regex to separate text from special inline blocks:\r\n // 1. Footnotes: <$F ... $E>\r\n // 2. Cross References: <$R ... $RE> (To be removed)\r\n // 3. Formatting Tags: <RA>, <N1>, etc. (To be removed?)\r\n // 4. Italics in curly braces: {text}\r\n\r\n // Note: Curly braces are nested inside footnotes sometimes, but stripped there.\r\n // At the verse level, they denote italics.\r\n\r\n const segmentRegex =\r\n /(<\\$F.*?\\$E>)|(<\\$R.*?\\$RE>)|(<[^>]*>)|(\\{.*?\\})/g;\r\n\r\n let lastIdx = 0;\r\n let m;\r\n let wordsOfJesus = false;\r\n\r\n while ((m = segmentRegex.exec(cleanText)) !== null) {\r\n const snippet = cleanText.substring(lastIdx, m.index);\r\n if (snippet) {\r\n // Add plain text\r\n this.addText(verse, snippet, isPoem, wordsOfJesus);\r\n }\r\n\r\n if (m[1]) {\r\n // Footnote <$F ... $E>\r\n this.processFootnote(m[1], verse, chapter);\r\n } else if (m[2]) {\r\n // Cross Ref -> Ignore\r\n } else if (m[3]) {\r\n if (m[3] === '<PO>') {\r\n verse.content.push({ lineBreak: true });\r\n lastIdx = segmentRegex.lastIndex;\r\n continue;\r\n }\r\n // Handle words of Jesus markers\r\n if (m[3] === '<RS>') {\r\n wordsOfJesus = true;\r\n } else if (m[3] === '</RS>') {\r\n wordsOfJesus = false;\r\n }\r\n // Other tag -> Ignore (e.g. <RA>, <N1>, <FA>)\r\n // These are often just markers or anchors.\r\n } else if (m[4]) {\r\n // Italics {text}\r\n const content = m[4].substring(1, m[4].length - 1);\r\n // We push a Text object with italics: true\r\n // Check if we need to decode inside? Usually just text.\r\n if (content) {\r\n let text: Text = {\r\n text: content,\r\n italics: true,\r\n };\r\n\r\n if (isPoem) {\r\n text.poem = 1;\r\n }\r\n\r\n if (wordsOfJesus) {\r\n text.wordsOfJesus = true;\r\n }\r\n\r\n verse.content.push(text);\r\n }\r\n }\r\n\r\n lastIdx = segmentRegex.lastIndex;\r\n }\r\n\r\n const remaining = cleanText.substring(lastIdx);\r\n if (remaining) {\r\n this.addText(verse, remaining, isPoem, wordsOfJesus);\r\n }\r\n }\r\n\r\n private addText(\r\n verse: Verse,\r\n text: string,\r\n isPoem: boolean,\r\n wordsOfJesus: boolean\r\n ) {\r\n if (!text) return;\r\n\r\n if (isPoem || wordsOfJesus) {\r\n // When poem=1 or wordsOfJesus is true, use Text objects to carry attributes.\r\n const lastItem = verse.content[verse.content.length - 1];\r\n\r\n if (\r\n lastItem &&\r\n typeof lastItem !== 'string' &&\r\n !('noteId' in lastItem) &&\r\n (lastItem as Text).poem === (isPoem ? 1 : undefined) &&\r\n (lastItem as Text).wordsOfJesus ===\r\n (wordsOfJesus ? true : undefined) &&\r\n !(lastItem as Text).italics\r\n ) {\r\n (lastItem as Text).text += text;\r\n } else {\r\n const formatted: Text = {\r\n text: text,\r\n };\r\n if (isPoem) {\r\n formatted.poem = 1;\r\n }\r\n if (wordsOfJesus) {\r\n formatted.wordsOfJesus = true;\r\n }\r\n verse.content.push(formatted);\r\n }\r\n } else {\r\n // Merge with previous string if possible\r\n const lastItem = verse.content[verse.content.length - 1];\r\n if (typeof lastItem === 'string') {\r\n verse.content[verse.content.length - 1] = lastItem + text;\r\n } else {\r\n verse.content.push(text);\r\n }\r\n }\r\n }\r\n\r\n private parseHebrewSubtitleContent(\r\n text: string,\r\n subtitle: HebrewSubtitle,\r\n chapter: Chapter\r\n ) {\r\n let cleanText = text.replace(/\\s+/g, ' ').trim();\r\n cleanText = cleanText.replace(/[{}]/g, '');\r\n cleanText = cleanText.replace(/@\\[.*?@\\]/g, '');\r\n\r\n const segmentRegex =\r\n /(<\\$F.*?\\$E>)|(<\\$R.*?\\$RE>)|(<[^>]+>)|(\\{.*?\\})/g;\r\n\r\n let lastIdx = 0;\r\n let m;\r\n\r\n while ((m = segmentRegex.exec(cleanText)) !== null) {\r\n const snippet = cleanText.substring(lastIdx, m.index);\r\n if (snippet) {\r\n this.addSubtitleText(subtitle, snippet);\r\n }\r\n\r\n if (m[1]) {\r\n const ref = this.processFootnoteForSubtitle(m[1], chapter);\r\n if (ref) {\r\n subtitle.content.push(ref);\r\n }\r\n } else if (m[2]) {\r\n // Cross Ref -> Ignore\r\n } else if (m[3]) {\r\n // Other tag -> Ignore\r\n } else if (m[4]) {\r\n const content = m[4].substring(1, m[4].length - 1);\r\n if (content) {\r\n this.addSubtitleText(subtitle, content);\r\n }\r\n }\r\n\r\n lastIdx = segmentRegex.lastIndex;\r\n }\r\n\r\n const remaining = cleanText.substring(lastIdx);\r\n if (remaining) {\r\n this.addSubtitleText(subtitle, remaining);\r\n }\r\n }\r\n\r\n private addSubtitleText(subtitle: HebrewSubtitle, text: string) {\r\n if (!text) return;\r\n\r\n const lastItem = subtitle.content[subtitle.content.length - 1];\r\n if (typeof lastItem === 'string') {\r\n subtitle.content[subtitle.content.length - 1] = lastItem + text;\r\n } else {\r\n subtitle.content.push(text);\r\n }\r\n }\r\n\r\n private processFootnote(block: string, verse: Verse, chapter: Chapter) {\r\n // block is <$F...$E>\r\n // Inner content has tags like <FN>, <FNC>, <N1>...\r\n // We want the readable text.\r\n // Remove known technical tags.\r\n\r\n const text = this.extractFootnoteText(block);\r\n\r\n if (!text) return;\r\n\r\n const noteId = chapter.footnotes.length + 1;\r\n\r\n const fn: Footnote = {\r\n noteId: noteId,\r\n text: text,\r\n caller: '+',\r\n reference: {\r\n chapter: chapter.number,\r\n verse: verse.number,\r\n },\r\n };\r\n chapter.footnotes.push(fn);\r\n\r\n verse.content.push({\r\n noteId: noteId,\r\n } as FootnoteReference);\r\n }\r\n\r\n private processFootnoteForSubtitle(\r\n block: string,\r\n chapter: Chapter\r\n ): FootnoteReference | null {\r\n const text = this.extractFootnoteText(block);\r\n\r\n if (!text) return null;\r\n\r\n const noteId = chapter.footnotes.length + 1;\r\n\r\n const fn: Footnote = {\r\n noteId: noteId,\r\n text: text,\r\n caller: '+',\r\n reference: {\r\n chapter: chapter.number,\r\n verse: 0,\r\n },\r\n };\r\n chapter.footnotes.push(fn);\r\n\r\n return {\r\n noteId: noteId,\r\n } as FootnoteReference;\r\n }\r\n\r\n private extractFootnoteText(block: string): string {\r\n // Remove outer $F...$E\r\n let inner = block.replace(/^<\\$F/, '').replace(/\\$E>$/, '');\r\n\r\n // Remove internal technical tags\r\n // Remove <FN>...</FN> completely\r\n inner = inner.replace(/<FN>.*?<\\/FN>/g, '');\r\n\r\n // Remove other tags <N1>, <FA> but keep content\r\n // Also remove italics curly braces (keep content inside)\r\n return inner\r\n .replace(/<[^>]+>/g, '')\r\n .replace(/[\\{\\}]/g, '')\r\n .trim();\r\n }\r\n}\r\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["text"]
|
|
7
7
|
}
|
|
@@ -23,7 +23,7 @@ __export(tyndale_xml_parser_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(tyndale_xml_parser_exports);
|
|
25
25
|
var import_log = require("../log.js");
|
|
26
|
-
var import_utils = require("../utils");
|
|
26
|
+
var import_utils = require("../utils.js");
|
|
27
27
|
var NodeType = /* @__PURE__ */ ((NodeType2) => {
|
|
28
28
|
NodeType2[NodeType2["Element"] = 1] = "Element";
|
|
29
29
|
NodeType2[NodeType2["Attribute"] = 2] = "Attribute";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../parser/tyndale-xml-parser.ts"],
|
|
4
|
-
"sourcesContent": ["import { getLogger } from '../log.js';\r\nimport { parseVerseReference } from '../utils';\r\nimport {\r\n CommentaryBookNode,\r\n CommentaryChapterNode,\r\n CommentaryParseTree,\r\n CommentaryVerseNode,\r\n} from './types';\r\n\r\nenum NodeType {\r\n Element = 1,\r\n Attribute = 2,\r\n Text = 3,\r\n}\r\n\r\nexport class TyndaleXmlParser {\r\n private _domParser: DOMParser;\r\n\r\n constructor(domParser: DOMParser) {\r\n this._domParser = domParser;\r\n }\r\n\r\n parse(xml: string): CommentaryParseTree {\r\n const logger = getLogger();\r\n const parser = this._domParser;\r\n const doc = parser.parseFromString(xml, 'application/xml');\r\n const rootElement = doc.documentElement;\r\n\r\n let tree: CommentaryParseTree = {\r\n type: 'commentary/root',\r\n books: [],\r\n };\r\n\r\n let books: Map<string, CommentaryBookNode> = new Map();\r\n\r\n function getBook(id: string): CommentaryBookNode {\r\n let bookNode = books.get(id);\r\n\r\n if (!bookNode) {\r\n bookNode = {\r\n type: 'book',\r\n book: id,\r\n introduction: null,\r\n chapters: [],\r\n };\r\n\r\n books.set(id, bookNode);\r\n tree.books.push(bookNode);\r\n }\r\n return bookNode;\r\n }\r\n\r\n function getChapter(\r\n book: CommentaryBookNode,\r\n number: number\r\n ): CommentaryChapterNode {\r\n let chapterNode = book.chapters.find(\r\n (chapter) => chapter.number === number\r\n );\r\n\r\n if (!chapterNode) {\r\n chapterNode = {\r\n type: 'chapter',\r\n number: number,\r\n introduction: null,\r\n verses: [],\r\n };\r\n\r\n book.chapters.push(chapterNode);\r\n }\r\n\r\n return chapterNode;\r\n }\r\n\r\n function getVerse(\r\n chapter: CommentaryChapterNode,\r\n number: number\r\n ): CommentaryVerseNode {\r\n let verseNode = chapter.verses.find(\r\n (verse) => verse.number === number\r\n );\r\n\r\n if (!verseNode) {\r\n verseNode = {\r\n type: 'verse',\r\n number: number,\r\n content: [],\r\n };\r\n\r\n chapter.verses.push(verseNode);\r\n }\r\n\r\n return verseNode;\r\n }\r\n\r\n function formatContent(node: Node, trim: boolean = true): string {\r\n let text: string;\r\n if (node.nodeName === 'p') {\r\n text = (node.textContent || '') + '\\n';\r\n } else if (node.nodeName === '#text') {\r\n text = node.textContent || '';\r\n } else if (node.nodeName === 'br') {\r\n text = '\\n';\r\n } else if (node.nodeType === NodeType.Element) {\r\n text = '';\r\n for (let child of node.childNodes) {\r\n text += formatContent(child, false);\r\n }\r\n } else {\r\n text = node.textContent || '';\r\n }\r\n\r\n if (trim) {\r\n const lines = text.split('\\n');\r\n for (let i = 0; i < lines.length; i++) {\r\n // Trim extra whitespace and replace multiple spaces with a single space\r\n lines[i] = lines[i].replace(/\\s+/g, ' ').trim();\r\n }\r\n text = lines.join('\\n').trim();\r\n }\r\n\r\n return text;\r\n }\r\n\r\n const items = rootElement.querySelectorAll('item');\r\n\r\n for (let item of items) {\r\n const typename = item.getAttribute('typename');\r\n\r\n if (typename === 'StudyNote') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n\r\n if (!refs || !body) {\r\n logger.warn(\r\n 'Skipping study note item without refs or body:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n const bookNode = getBook(ref.book);\r\n const chapterNode = getChapter(bookNode, ref.chapter);\r\n const verseNode = getVerse(chapterNode, ref.verse);\r\n verseNode.content.push(formatContent(body));\r\n } else if (typename === 'BookIntro') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n\r\n if (!refs || !body) {\r\n logger.warn(\r\n 'Skipping book item without refs or body:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n const bookNode = getBook(ref.book);\r\n\r\n bookNode.introduction = formatContent(body);\r\n } else if (typename === 'BookIntroSummary') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n\r\n if (!refs || !body) {\r\n logger.warn(\r\n 'Skipping book item without refs or body:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n const bookNode = getBook(ref.book);\r\n\r\n bookNode.introductionSummary = formatContent(body);\r\n } else if (typename === 'Profile') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n const title = item.querySelector('title')?.textContent;\r\n const name = item.getAttribute('name');\r\n\r\n if (!refs || !body || !title || !name) {\r\n logger.warn(\r\n 'Skipping profile item without refs, body, or title:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n if (!tree.profiles) {\r\n tree.profiles = [];\r\n }\r\n\r\n // convert camelCase to kebab-case\r\n const id = toKebabCase(name);\r\n tree.profiles.push({\r\n id,\r\n subject: title,\r\n content: [formatContent(body)],\r\n reference: ref,\r\n });\r\n }\r\n }\r\n\r\n return tree;\r\n }\r\n}\r\n\r\nexport function toKebabCase(camelCase: string): string {\r\n return camelCase.replace(/([a-z])\\s*([A-Z])/g, '$1-$2').toLowerCase();\r\n}\r\n"],
|
|
4
|
+
"sourcesContent": ["import { getLogger } from '../log.js';\r\nimport { parseVerseReference } from '../utils.js';\r\nimport {\r\n CommentaryBookNode,\r\n CommentaryChapterNode,\r\n CommentaryParseTree,\r\n CommentaryVerseNode,\r\n} from './types.js';\r\n\r\nenum NodeType {\r\n Element = 1,\r\n Attribute = 2,\r\n Text = 3,\r\n}\r\n\r\nexport class TyndaleXmlParser {\r\n private _domParser: DOMParser;\r\n\r\n constructor(domParser: DOMParser) {\r\n this._domParser = domParser;\r\n }\r\n\r\n parse(xml: string): CommentaryParseTree {\r\n const logger = getLogger();\r\n const parser = this._domParser;\r\n const doc = parser.parseFromString(xml, 'application/xml');\r\n const rootElement = doc.documentElement;\r\n\r\n let tree: CommentaryParseTree = {\r\n type: 'commentary/root',\r\n books: [],\r\n };\r\n\r\n let books: Map<string, CommentaryBookNode> = new Map();\r\n\r\n function getBook(id: string): CommentaryBookNode {\r\n let bookNode = books.get(id);\r\n\r\n if (!bookNode) {\r\n bookNode = {\r\n type: 'book',\r\n book: id,\r\n introduction: null,\r\n chapters: [],\r\n };\r\n\r\n books.set(id, bookNode);\r\n tree.books.push(bookNode);\r\n }\r\n return bookNode;\r\n }\r\n\r\n function getChapter(\r\n book: CommentaryBookNode,\r\n number: number\r\n ): CommentaryChapterNode {\r\n let chapterNode = book.chapters.find(\r\n (chapter) => chapter.number === number\r\n );\r\n\r\n if (!chapterNode) {\r\n chapterNode = {\r\n type: 'chapter',\r\n number: number,\r\n introduction: null,\r\n verses: [],\r\n };\r\n\r\n book.chapters.push(chapterNode);\r\n }\r\n\r\n return chapterNode;\r\n }\r\n\r\n function getVerse(\r\n chapter: CommentaryChapterNode,\r\n number: number\r\n ): CommentaryVerseNode {\r\n let verseNode = chapter.verses.find(\r\n (verse) => verse.number === number\r\n );\r\n\r\n if (!verseNode) {\r\n verseNode = {\r\n type: 'verse',\r\n number: number,\r\n content: [],\r\n };\r\n\r\n chapter.verses.push(verseNode);\r\n }\r\n\r\n return verseNode;\r\n }\r\n\r\n function formatContent(node: Node, trim: boolean = true): string {\r\n let text: string;\r\n if (node.nodeName === 'p') {\r\n text = (node.textContent || '') + '\\n';\r\n } else if (node.nodeName === '#text') {\r\n text = node.textContent || '';\r\n } else if (node.nodeName === 'br') {\r\n text = '\\n';\r\n } else if (node.nodeType === NodeType.Element) {\r\n text = '';\r\n for (let child of node.childNodes) {\r\n text += formatContent(child, false);\r\n }\r\n } else {\r\n text = node.textContent || '';\r\n }\r\n\r\n if (trim) {\r\n const lines = text.split('\\n');\r\n for (let i = 0; i < lines.length; i++) {\r\n // Trim extra whitespace and replace multiple spaces with a single space\r\n lines[i] = lines[i].replace(/\\s+/g, ' ').trim();\r\n }\r\n text = lines.join('\\n').trim();\r\n }\r\n\r\n return text;\r\n }\r\n\r\n const items = rootElement.querySelectorAll('item');\r\n\r\n for (let item of items) {\r\n const typename = item.getAttribute('typename');\r\n\r\n if (typename === 'StudyNote') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n\r\n if (!refs || !body) {\r\n logger.warn(\r\n 'Skipping study note item without refs or body:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n const bookNode = getBook(ref.book);\r\n const chapterNode = getChapter(bookNode, ref.chapter);\r\n const verseNode = getVerse(chapterNode, ref.verse);\r\n verseNode.content.push(formatContent(body));\r\n } else if (typename === 'BookIntro') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n\r\n if (!refs || !body) {\r\n logger.warn(\r\n 'Skipping book item without refs or body:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n const bookNode = getBook(ref.book);\r\n\r\n bookNode.introduction = formatContent(body);\r\n } else if (typename === 'BookIntroSummary') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n\r\n if (!refs || !body) {\r\n logger.warn(\r\n 'Skipping book item without refs or body:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n const bookNode = getBook(ref.book);\r\n\r\n bookNode.introductionSummary = formatContent(body);\r\n } else if (typename === 'Profile') {\r\n const refs = item.querySelector('refs')?.textContent;\r\n const body = item.querySelector('body');\r\n const title = item.querySelector('title')?.textContent;\r\n const name = item.getAttribute('name');\r\n\r\n if (!refs || !body || !title || !name) {\r\n logger.warn(\r\n 'Skipping profile item without refs, body, or title:',\r\n item\r\n );\r\n continue;\r\n }\r\n\r\n const ref = parseVerseReference(refs);\r\n\r\n if (!ref) {\r\n logger.warn('Failed to parse verse reference:', refs);\r\n continue;\r\n }\r\n\r\n if (!tree.profiles) {\r\n tree.profiles = [];\r\n }\r\n\r\n // convert camelCase to kebab-case\r\n const id = toKebabCase(name);\r\n tree.profiles.push({\r\n id,\r\n subject: title,\r\n content: [formatContent(body)],\r\n reference: ref,\r\n });\r\n }\r\n }\r\n\r\n return tree;\r\n }\r\n}\r\n\r\nexport function toKebabCase(camelCase: string): string {\r\n return camelCase.replace(/([a-z])\\s*([A-Z])/g, '$1-$2').toLowerCase();\r\n}\r\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["NodeType"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../parser/types.ts"],
|
|
4
|
-
"sourcesContent": ["import { VerseRef } from '../utils.js';\r\n\r\n/**\r\n * The parse tree that is gathered.\r\n */\r\nexport interface ParseTree {\r\n type: 'root';\r\n\r\n /**\r\n * The ID of the parse tree.\r\n */\r\n id?: string;\r\n\r\n /**\r\n * The header that was associated with the tree.\r\n */\r\n header?: string;\r\n\r\n /**\r\n * The major title that was associated with the tree.\r\n */\r\n title?: string;\r\n\r\n /**\r\n * The list of chapters for the tree.\r\n */\r\n content: (Heading | Chapter)[];\r\n\r\n /**\r\n * The list of messages that were generated during parsing.\r\n */\r\n parseMessages?: ParseMessage[];\r\n}\r\n\r\nexport interface ParseMessage {\r\n type: 'warning' | 'error';\r\n message: string;\r\n}\r\n\r\nexport interface Heading {\r\n type: 'heading';\r\n content: string[];\r\n}\r\n\r\nexport type ChapterContent = Heading | Verse | HebrewSubtitle | LineBreak;\r\n\r\nexport type VerseContent = string | FootnoteReference | Text;\r\n\r\n/**\r\n * Defines an interface that represents a chapter.\r\n */\r\nexport interface Chapter {\r\n type: 'chapter';\r\n number: number;\r\n\r\n /**\r\n * The contents of the chapter.\r\n */\r\n content: ChapterContent[];\r\n\r\n /**\r\n * The list of footnotes for the chapter.\r\n */\r\n footnotes: Footnote[];\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a hebrew subtitle.\r\n */\r\nexport interface HebrewSubtitle {\r\n type: 'hebrew_subtitle';\r\n\r\n /**\r\n * The contents of the subtitle.\r\n */\r\n content: (string | Text | FootnoteReference)[];\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a verse.\r\n */\r\nexport interface Verse {\r\n type: 'verse';\r\n\r\n number: number;\r\n\r\n /**\r\n * The contents of the verse.\r\n */\r\n content: (\r\n | string\r\n | Text\r\n | InlineHeading\r\n | InlineLineBreak\r\n | FootnoteReference\r\n )[];\r\n}\r\n\r\n/**\r\n * Defines an interface that represents text that has some markup attributes applied to it.\r\n */\r\nexport interface Text {\r\n /**\r\n * The text that is contained.\r\n */\r\n text: string;\r\n\r\n /**\r\n * Whether the text represents a poem.\r\n * The number indicates the level of indent.\r\n */\r\n poem?: number;\r\n\r\n /**\r\n * Whether the text contains the words of Jesus.\r\n */\r\n wordsOfJesus?: boolean;\r\n\r\n /**\r\n * Whether the text is descriptive.\r\n *\r\n * This is only used for \"hebrew subtitles\" that are included inside the verse markers.\r\n */\r\n descriptive?: boolean;\r\n\r\n /**\r\n * Whether the text should be displayed in italics.\r\n */\r\n italics?: boolean;\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a heading that is embedded in a verse.\r\n */\r\nexport interface InlineHeading {\r\n /**\r\n * The text of the heading.\r\n */\r\n heading: string;\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a line break that is embedded in a verse.\r\n */\r\nexport interface InlineLineBreak {\r\n lineBreak: true;\r\n}\r\n\r\nexport interface FootnoteReference {\r\n /**\r\n * The ID of the note that is referenced.\r\n */\r\n noteId: number;\r\n}\r\n\r\nexport interface Footnote {\r\n noteId: number;\r\n\r\n /**\r\n * The text of the footnote.\r\n */\r\n text: string;\r\n\r\n /**\r\n * The caller that should be used for the footnote.\r\n * For footnotes, a \"caller\" is the character that is used in the text to reference to footnote.\r\n *\r\n * For example, in the text:\r\n * Hello (a) World\r\n *\r\n * ----\r\n * (a) This is a footnote.\r\n *\r\n * The \"(a)\" is the caller.\r\n *\r\n * If \"+\", then the caller should be autogenerated.\r\n * If null, then the caller should be empty.\r\n * If a string, then the caller should be that string.\r\n */\r\n caller: '+' | string | null;\r\n\r\n /**\r\n * The verse reference for the footnote.\r\n */\r\n reference?: {\r\n chapter: number;\r\n verse: number;\r\n };\r\n}\r\n\r\nexport interface LineBreak {\r\n type: 'line_break';\r\n}\r\n\r\n/**\r\n * The parse tree that is gathered.\r\n */\r\nexport interface CommentaryParseTree {\r\n type: 'commentary/root';\r\n\r\n /**\r\n * The books that are contained in the commentary.\r\n */\r\n books: CommentaryBookNode[];\r\n\r\n /**\r\n * The profiles that are contained in the commentary.\r\n */\r\n profiles?: CommentaryProfileNode[];\r\n}\r\n\r\nexport interface CommentaryBookNode {\r\n type: 'book';\r\n book: string;\r\n introduction: string | null;\r\n introductionSummary?: string | null;\r\n chapters: CommentaryChapterNode[];\r\n}\r\n\r\nexport interface CommentaryProfileNode {\r\n /**\r\n * The ID of the profile.\r\n * Used to identify the profile within a commentary.\r\n */\r\n id: string;\r\n\r\n /**\r\n * The subject(s) of the profile.\r\n */\r\n subject: string;\r\n\r\n /**\r\n * The Bible reference that the profile is associated with.\r\n */\r\n reference: VerseRef | null;\r\n\r\n /**\r\n * The content of the profile.\r\n */\r\n content: string[];\r\n}\r\n\r\nexport interface CommentaryChapterNode {\r\n type: 'chapter';\r\n number: number;\r\n introduction: string | null;\r\n verses: CommentaryVerseNode[];\r\n}\r\n\r\nexport interface CommentaryVerseNode {\r\n type: 'verse';\r\n number: number;\r\n content: string[];\r\n}\r\n"],
|
|
4
|
+
"sourcesContent": ["import { VerseRef } from '../utils.js';\r\n\r\n/**\r\n * The parse tree that is gathered.\r\n */\r\nexport interface ParseTree {\r\n type: 'root';\r\n\r\n /**\r\n * The ID of the parse tree.\r\n */\r\n id?: string;\r\n\r\n /**\r\n * The header that was associated with the tree.\r\n */\r\n header?: string;\r\n\r\n /**\r\n * The major title that was associated with the tree.\r\n */\r\n title?: string;\r\n\r\n /**\r\n * The list of chapters for the tree.\r\n */\r\n content: (Heading | Chapter)[];\r\n\r\n /**\r\n * The list of messages that were generated during parsing.\r\n */\r\n parseMessages?: ParseMessage[];\r\n}\r\n\r\nexport interface ParseMessage {\r\n type: 'warning' | 'error';\r\n message: string;\r\n}\r\n\r\nexport interface Heading {\r\n type: 'heading';\r\n content: string[];\r\n}\r\n\r\nexport type ChapterContent = Heading | Verse | HebrewSubtitle | LineBreak;\r\n\r\nexport type VerseContent = string | FootnoteReference | Text;\r\n\r\n/**\r\n * Defines an interface that represents a chapter.\r\n */\r\nexport interface Chapter {\r\n type: 'chapter';\r\n number: number;\r\n\r\n /**\r\n * The contents of the chapter.\r\n */\r\n content: ChapterContent[];\r\n\r\n /**\r\n * The list of footnotes for the chapter.\r\n */\r\n footnotes: Footnote[];\r\n\r\n /**\r\n * The word-level annotations for the chapter's verses.\r\n * Undefined if the source didn't contain any word-level annotations.\r\n */\r\n words?: ChapterWords;\r\n}\r\n\r\n/**\r\n * Defines the word-level annotations for a chapter, keyed by verse number.\r\n */\r\nexport type ChapterWords = {\r\n [verseNumber: string]: ChapterWord[];\r\n};\r\n\r\n/**\r\n * Defines an interface that represents the annotations that a source associated\r\n * with a specific range of characters in a verse.\r\n *\r\n * The range is anchored to a single item of the verse's content array, so that\r\n * consumers can highlight the exact characters that an annotation applies to.\r\n */\r\nexport interface ChapterWord {\r\n /**\r\n * The index of the item in the verse's content array that the annotation applies to.\r\n */\r\n contentIndex: number;\r\n\r\n /**\r\n * The index of the first character of the annotated word in the content item's text.\r\n */\r\n start: number;\r\n\r\n /**\r\n * The index after the last character of the annotated word in the content item's text.\r\n * That is, `text.slice(start, end)` is the annotated word.\r\n */\r\n end: number;\r\n\r\n /**\r\n * The Strong's number(s) for the word.\r\n * Undefined if the source only provided other annotations for the word.\r\n */\r\n strongs?: string[];\r\n\r\n /**\r\n * The dictionary (citation) form of the word.\r\n * Taken from the `lemma` attribute.\r\n */\r\n lemma?: string;\r\n\r\n /**\r\n * The morphology parse code for the word.\r\n * Taken from the `x-morph` attribute.\r\n */\r\n morph?: string;\r\n\r\n /**\r\n * The pointer to the word in the source text, in the `<sourceName>:<location>` format.\r\n * Taken from the `srcloc` attribute.\r\n */\r\n srcloc?: string;\r\n\r\n /**\r\n * Which occurrence of the source word this word is. 1-based.\r\n * Taken from the `x-occurrence` attribute.\r\n */\r\n occurrence?: number;\r\n\r\n /**\r\n * The total number of times that the source word occurs.\r\n * Taken from the `x-occurrences` attribute.\r\n */\r\n occurrences?: number;\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a hebrew subtitle.\r\n */\r\nexport interface HebrewSubtitle {\r\n type: 'hebrew_subtitle';\r\n\r\n /**\r\n * The contents of the subtitle.\r\n */\r\n content: (string | Text | FootnoteReference)[];\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a verse.\r\n */\r\nexport interface Verse {\r\n type: 'verse';\r\n\r\n number: number;\r\n\r\n /**\r\n * The contents of the verse.\r\n */\r\n content: (\r\n | string\r\n | Text\r\n | InlineHeading\r\n | InlineLineBreak\r\n | FootnoteReference\r\n )[];\r\n}\r\n\r\n/**\r\n * Defines an interface that represents text that has some markup attributes applied to it.\r\n */\r\nexport interface Text {\r\n /**\r\n * The text that is contained.\r\n */\r\n text: string;\r\n\r\n /**\r\n * Whether the text represents a poem.\r\n * The number indicates the level of indent.\r\n */\r\n poem?: number;\r\n\r\n /**\r\n * Whether the text contains the words of Jesus.\r\n */\r\n wordsOfJesus?: boolean;\r\n\r\n /**\r\n * Whether the text is descriptive.\r\n *\r\n * This is only used for \"hebrew subtitles\" that are included inside the verse markers.\r\n */\r\n descriptive?: boolean;\r\n\r\n /**\r\n * Whether the text should be displayed in italics.\r\n */\r\n italics?: boolean;\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a heading that is embedded in a verse.\r\n */\r\nexport interface InlineHeading {\r\n /**\r\n * The text of the heading.\r\n */\r\n heading: string;\r\n}\r\n\r\n/**\r\n * Defines an interface that represents a line break that is embedded in a verse.\r\n */\r\nexport interface InlineLineBreak {\r\n lineBreak: true;\r\n}\r\n\r\nexport interface FootnoteReference {\r\n /**\r\n * The ID of the note that is referenced.\r\n */\r\n noteId: number;\r\n}\r\n\r\nexport interface Footnote {\r\n noteId: number;\r\n\r\n /**\r\n * The text of the footnote.\r\n */\r\n text: string;\r\n\r\n /**\r\n * The caller that should be used for the footnote.\r\n * For footnotes, a \"caller\" is the character that is used in the text to reference to footnote.\r\n *\r\n * For example, in the text:\r\n * Hello (a) World\r\n *\r\n * ----\r\n * (a) This is a footnote.\r\n *\r\n * The \"(a)\" is the caller.\r\n *\r\n * If \"+\", then the caller should be autogenerated.\r\n * If null, then the caller should be empty.\r\n * If a string, then the caller should be that string.\r\n */\r\n caller: '+' | string | null;\r\n\r\n /**\r\n * The verse reference for the footnote.\r\n */\r\n reference?: {\r\n chapter: number;\r\n verse: number;\r\n };\r\n}\r\n\r\nexport interface LineBreak {\r\n type: 'line_break';\r\n}\r\n\r\n/**\r\n * The parse tree that is gathered.\r\n */\r\nexport interface CommentaryParseTree {\r\n type: 'commentary/root';\r\n\r\n /**\r\n * The books that are contained in the commentary.\r\n */\r\n books: CommentaryBookNode[];\r\n\r\n /**\r\n * The profiles that are contained in the commentary.\r\n */\r\n profiles?: CommentaryProfileNode[];\r\n}\r\n\r\nexport interface CommentaryBookNode {\r\n type: 'book';\r\n book: string;\r\n introduction: string | null;\r\n introductionSummary?: string | null;\r\n chapters: CommentaryChapterNode[];\r\n}\r\n\r\nexport interface CommentaryProfileNode {\r\n /**\r\n * The ID of the profile.\r\n * Used to identify the profile within a commentary.\r\n */\r\n id: string;\r\n\r\n /**\r\n * The subject(s) of the profile.\r\n */\r\n subject: string;\r\n\r\n /**\r\n * The Bible reference that the profile is associated with.\r\n */\r\n reference: VerseRef | null;\r\n\r\n /**\r\n * The content of the profile.\r\n */\r\n content: string[];\r\n}\r\n\r\nexport interface CommentaryChapterNode {\r\n type: 'chapter';\r\n number: number;\r\n introduction: string | null;\r\n verses: CommentaryVerseNode[];\r\n}\r\n\r\nexport interface CommentaryVerseNode {\r\n type: 'verse';\r\n number: number;\r\n content: string[];\r\n}\r\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -29,7 +29,7 @@ __export(usfm_parser_exports, {
|
|
|
29
29
|
word: () => word
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(usfm_parser_exports);
|
|
32
|
-
var
|
|
32
|
+
var import_compat = require("es-toolkit/compat");
|
|
33
33
|
var import_log = require("../log.js");
|
|
34
34
|
class UsfmTokenizer {
|
|
35
35
|
_input = "";
|
|
@@ -161,7 +161,7 @@ class UsfmParser {
|
|
|
161
161
|
}
|
|
162
162
|
if (source.length === 1) {
|
|
163
163
|
if (isEnd) {
|
|
164
|
-
const startMarker = (0,
|
|
164
|
+
const startMarker = (0, import_compat.findLast)(
|
|
165
165
|
tokens,
|
|
166
166
|
(t3) => t3.kind === "marker" && t3.type === "start"
|
|
167
167
|
);
|