@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.
Files changed (81) hide show
  1. package/dist/cjs/generation/api.cjs +2213 -216
  2. package/dist/cjs/generation/api.cjs.map +3 -3
  3. package/dist/cjs/generation/audio.cjs +5 -5
  4. package/dist/cjs/generation/audio.cjs.map +1 -1
  5. package/dist/cjs/generation/book-order.cjs.map +1 -1
  6. package/dist/cjs/generation/common-types.cjs +782 -14
  7. package/dist/cjs/generation/common-types.cjs.map +2 -2
  8. package/dist/cjs/generation/dataset.cjs +13 -9
  9. package/dist/cjs/generation/dataset.cjs.map +2 -2
  10. package/dist/cjs/generation/index.cjs +8 -5
  11. package/dist/cjs/generation/index.cjs.map +2 -2
  12. package/dist/cjs/generation/simple.cjs +294 -0
  13. package/dist/cjs/generation/simple.cjs.map +7 -0
  14. package/dist/cjs/generation/theographic.cjs +446 -0
  15. package/dist/cjs/generation/theographic.cjs.map +7 -0
  16. package/dist/cjs/index.cjs +4 -4
  17. package/dist/cjs/index.cjs.map +1 -1
  18. package/dist/cjs/log.cjs.map +1 -1
  19. package/dist/cjs/parser/codex-parser.cjs +3 -3
  20. package/dist/cjs/parser/codex-parser.cjs.map +3 -3
  21. package/dist/cjs/parser/commentary-csv-parser.cjs +14 -3
  22. package/dist/cjs/parser/commentary-csv-parser.cjs.map +3 -3
  23. package/dist/cjs/parser/index.cjs +1 -1
  24. package/dist/cjs/parser/iterators.cjs.map +1 -1
  25. package/dist/cjs/parser/lockman-parser.cjs +1 -1
  26. package/dist/cjs/parser/lockman-parser.cjs.map +1 -1
  27. package/dist/cjs/parser/tyndale-xml-parser.cjs +1 -1
  28. package/dist/cjs/parser/tyndale-xml-parser.cjs.map +1 -1
  29. package/dist/cjs/parser/types.cjs.map +1 -1
  30. package/dist/cjs/parser/usfm-parser.cjs +2 -2
  31. package/dist/cjs/parser/usfm-parser.cjs.map +1 -1
  32. package/dist/cjs/parser/usx-parser.cjs +122 -26
  33. package/dist/cjs/parser/usx-parser.cjs.map +2 -2
  34. package/dist/cjs/parser/words.cjs +187 -0
  35. package/dist/cjs/parser/words.cjs.map +7 -0
  36. package/dist/cjs/utils.cjs +1 -1
  37. package/dist/esm/generation/api.js +2155 -214
  38. package/dist/esm/generation/api.js.map +3 -3
  39. package/dist/esm/generation/audio.js +1 -1
  40. package/dist/esm/generation/audio.js.map +1 -1
  41. package/dist/esm/generation/book-order.js.map +1 -1
  42. package/dist/esm/generation/common-types.js +738 -14
  43. package/dist/esm/generation/common-types.js.map +2 -2
  44. package/dist/esm/generation/dataset.js +6 -2
  45. package/dist/esm/generation/dataset.js.map +2 -2
  46. package/dist/esm/generation/index.js +2 -1
  47. package/dist/esm/generation/index.js.map +2 -2
  48. package/dist/esm/generation/simple.js +260 -0
  49. package/dist/esm/generation/simple.js.map +7 -0
  50. package/dist/esm/generation/theographic.js +412 -0
  51. package/dist/esm/generation/theographic.js.map +7 -0
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/log.js.map +1 -1
  54. package/dist/esm/parser/codex-parser.js +3 -3
  55. package/dist/esm/parser/codex-parser.js.map +3 -3
  56. package/dist/esm/parser/commentary-csv-parser.js +3 -2
  57. package/dist/esm/parser/commentary-csv-parser.js.map +2 -2
  58. package/dist/esm/parser/iterators.js.map +1 -1
  59. package/dist/esm/parser/lockman-parser.js +1 -1
  60. package/dist/esm/parser/lockman-parser.js.map +1 -1
  61. package/dist/esm/parser/tyndale-xml-parser.js +1 -1
  62. package/dist/esm/parser/tyndale-xml-parser.js.map +1 -1
  63. package/dist/esm/parser/usfm-parser.js +1 -1
  64. package/dist/esm/parser/usfm-parser.js.map +1 -1
  65. package/dist/esm/parser/usx-parser.js +130 -26
  66. package/dist/esm/parser/usx-parser.js.map +2 -2
  67. package/dist/esm/parser/words.js +149 -0
  68. package/dist/esm/parser/words.js.map +7 -0
  69. package/dist/types/generation/api.d.ts +9006 -1101
  70. package/dist/types/generation/common-types.d.ts +1318 -106
  71. package/dist/types/generation/dataset.d.ts +17 -1
  72. package/dist/types/generation/index.d.ts +2 -1
  73. package/dist/types/generation/simple.d.ts +110 -0
  74. package/dist/types/generation/theographic.d.ts +64 -0
  75. package/dist/types/parser/commentary-csv-parser.d.ts +1 -1
  76. package/dist/types/parser/lockman-parser.d.ts +1 -1
  77. package/dist/types/parser/tyndale-xml-parser.d.ts +1 -1
  78. package/dist/types/parser/types.d.ts +63 -0
  79. package/dist/types/parser/usx-parser.d.ts +6 -5
  80. package/dist/types/parser/words.d.ts +104 -0
  81. package/package.json +3 -2
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var simple_exports = {};
20
+ __export(simple_exports, {
21
+ simplifyChapter: () => simplifyChapter,
22
+ simplifyCommentaryChapter: () => simplifyCommentaryChapter,
23
+ simplifyHebrewSubtitle: () => simplifyHebrewSubtitle,
24
+ simplifyVerse: () => simplifyVerse,
25
+ simplifyVerseContent: () => simplifyVerseContent
26
+ });
27
+ module.exports = __toCommonJS(simple_exports);
28
+ function simplifyVerseContent(content, footnotes = /* @__PURE__ */ new Map(), usedFootnotes = /* @__PURE__ */ new Set(), words = []) {
29
+ let text = "";
30
+ const verseFootnotes = [];
31
+ const headings = [];
32
+ const wordsOfJesus = [];
33
+ const poem = [];
34
+ const verseWords = [];
35
+ const wordsByContentIndex = /* @__PURE__ */ new Map();
36
+ for (let word of words) {
37
+ let arr = wordsByContentIndex.get(word.contentIndex);
38
+ if (!arr) {
39
+ arr = [];
40
+ wordsByContentIndex.set(word.contentIndex, arr);
41
+ }
42
+ arr.push(word);
43
+ }
44
+ const truncateTo = (length) => {
45
+ if (length >= text.length) {
46
+ return;
47
+ }
48
+ text = text.slice(0, length);
49
+ for (let footnote of verseFootnotes) {
50
+ footnote.offset = Math.min(footnote.offset, length);
51
+ }
52
+ for (let heading of headings) {
53
+ heading.offset = Math.min(heading.offset, length);
54
+ }
55
+ for (let range of [...wordsOfJesus, ...poem, ...verseWords]) {
56
+ range.start = Math.min(range.start, length);
57
+ range.end = Math.min(range.end, length);
58
+ }
59
+ };
60
+ const addWordsForContent = (contentIndex, contentStart, contentLength) => {
61
+ const contentWords = wordsByContentIndex.get(contentIndex);
62
+ if (!contentWords) {
63
+ return;
64
+ }
65
+ for (let { contentIndex: _index, ...word } of contentWords) {
66
+ verseWords.push({
67
+ ...word,
68
+ start: contentStart + Math.min(word.start, contentLength),
69
+ end: contentStart + Math.min(word.end, contentLength)
70
+ });
71
+ }
72
+ };
73
+ const startNewLine = () => {
74
+ truncateTo(text.replace(/[^\S\n]+$/, "").length);
75
+ text += "\n";
76
+ };
77
+ const needsSeparator = (next) => {
78
+ if (text.length <= 0 || /\s$/.test(text) || !next) {
79
+ return false;
80
+ }
81
+ if (typeof next === "string") {
82
+ return next.length > 0 && !/^\s/.test(next);
83
+ }
84
+ if ("text" in next) {
85
+ return typeof next.poem !== "number" && next.text.length > 0 && !/^\s/.test(next.text);
86
+ }
87
+ return false;
88
+ };
89
+ for (let i = 0; i < content.length; i++) {
90
+ const part = content[i];
91
+ if (typeof part === "string") {
92
+ addWordsForContent(i, text.length, part.length);
93
+ text += part;
94
+ continue;
95
+ }
96
+ if ("text" in part) {
97
+ if (typeof part.poem === "number" && text.length > 0 && !text.endsWith("\n")) {
98
+ startNewLine();
99
+ }
100
+ const start = text.length;
101
+ addWordsForContent(i, start, part.text.length);
102
+ text += part.text;
103
+ const end = text.length;
104
+ if (end > start) {
105
+ if (part.wordsOfJesus) {
106
+ wordsOfJesus.push({ start, end });
107
+ }
108
+ if (typeof part.poem === "number") {
109
+ poem.push({ start, end, level: part.poem });
110
+ }
111
+ }
112
+ } else if ("lineBreak" in part) {
113
+ if (text.length > 0 && !text.endsWith("\n")) {
114
+ startNewLine();
115
+ }
116
+ } else if ("noteId" in part) {
117
+ const footnote = footnotes.get(part.noteId);
118
+ if (footnote) {
119
+ usedFootnotes.add(part.noteId);
120
+ verseFootnotes.push({
121
+ noteId: footnote.noteId,
122
+ offset: text.length,
123
+ text: footnote.text,
124
+ caller: footnote.caller
125
+ });
126
+ }
127
+ if (needsSeparator(content[i + 1])) {
128
+ text += " ";
129
+ }
130
+ } else if ("heading" in part) {
131
+ headings.push({
132
+ offset: text.length,
133
+ text: part.heading
134
+ });
135
+ if (needsSeparator(content[i + 1])) {
136
+ text += " ";
137
+ }
138
+ }
139
+ }
140
+ truncateTo(text.replace(/\s+$/, "").length);
141
+ const leading = text.length - text.replace(/^\s+/, "").length;
142
+ if (leading > 0) {
143
+ text = text.slice(leading);
144
+ for (let footnote of verseFootnotes) {
145
+ footnote.offset = Math.max(0, footnote.offset - leading);
146
+ }
147
+ for (let heading of headings) {
148
+ heading.offset = Math.max(0, heading.offset - leading);
149
+ }
150
+ for (let range of [...wordsOfJesus, ...poem, ...verseWords]) {
151
+ range.start = Math.max(0, range.start - leading);
152
+ range.end = Math.max(0, range.end - leading);
153
+ }
154
+ }
155
+ return {
156
+ text,
157
+ footnotes: verseFootnotes,
158
+ headings,
159
+ wordsOfJesus: mergeAdjacentRanges(wordsOfJesus, text),
160
+ poem: poem.filter((range) => range.start < range.end),
161
+ words: verseWords.filter((word) => word.start < word.end)
162
+ };
163
+ }
164
+ function mergeAdjacentRanges(ranges, text) {
165
+ const merged = [];
166
+ for (let range of ranges) {
167
+ if (range.start >= range.end) {
168
+ continue;
169
+ }
170
+ const previous = merged[merged.length - 1];
171
+ if (previous && range.start >= previous.end && !/\S/.test(text.slice(previous.end, range.start))) {
172
+ previous.end = range.end;
173
+ } else {
174
+ merged.push(range);
175
+ }
176
+ }
177
+ return merged;
178
+ }
179
+ function simplifyVerse(verse, footnotes, usedFootnotes, words, remappedWords) {
180
+ const simplified = simplifyVerseContent(
181
+ verse.content,
182
+ footnotes,
183
+ usedFootnotes,
184
+ words
185
+ );
186
+ if (remappedWords) {
187
+ remappedWords.push(...simplified.words);
188
+ }
189
+ return {
190
+ type: "verse",
191
+ number: verse.number,
192
+ ...omitEmptyProperties(simplified)
193
+ };
194
+ }
195
+ function simplifyHebrewSubtitle(subtitle, footnotes, usedFootnotes) {
196
+ const simplified = simplifyVerseContent(
197
+ subtitle.content,
198
+ footnotes,
199
+ usedFootnotes
200
+ );
201
+ return {
202
+ type: "hebrew_subtitle",
203
+ ...omitEmptyProperties(simplified)
204
+ };
205
+ }
206
+ function omitEmptyProperties(content) {
207
+ return {
208
+ text: content.text,
209
+ footnotes: content.footnotes,
210
+ ...content.headings.length > 0 ? { headings: content.headings } : {},
211
+ ...content.wordsOfJesus.length > 0 ? { wordsOfJesus: content.wordsOfJesus } : {},
212
+ ...content.poem.length > 0 ? { poem: content.poem } : {}
213
+ };
214
+ }
215
+ function simplifyChapter(chapter, words) {
216
+ const footnotes = /* @__PURE__ */ new Map();
217
+ for (let footnote of chapter.footnotes) {
218
+ footnotes.set(footnote.noteId, footnote);
219
+ }
220
+ const usedFootnotes = /* @__PURE__ */ new Set();
221
+ const content = [];
222
+ const versesByNumber = /* @__PURE__ */ new Map();
223
+ const simpleWords = {};
224
+ for (let c of chapter.content) {
225
+ if (c.type === "verse") {
226
+ const verseWords = words?.[String(c.number)];
227
+ const remappedWords = [];
228
+ const verse = simplifyVerse(
229
+ c,
230
+ footnotes,
231
+ usedFootnotes,
232
+ verseWords,
233
+ remappedWords
234
+ );
235
+ if (remappedWords.length > 0) {
236
+ simpleWords[String(c.number)] = remappedWords;
237
+ }
238
+ versesByNumber.set(verse.number, verse);
239
+ content.push(verse);
240
+ } else if (c.type === "hebrew_subtitle") {
241
+ content.push(simplifyHebrewSubtitle(c, footnotes, usedFootnotes));
242
+ } else if (c.type === "heading") {
243
+ content.push({
244
+ type: "heading",
245
+ text: c.content.join(" ")
246
+ });
247
+ } else if (c.type === "line_break") {
248
+ content.push({
249
+ type: "line_break"
250
+ });
251
+ }
252
+ }
253
+ const unreferencedFootnotes = [];
254
+ for (let footnote of chapter.footnotes) {
255
+ if (usedFootnotes.has(footnote.noteId)) {
256
+ continue;
257
+ }
258
+ const verse = footnote.reference ? versesByNumber.get(footnote.reference.verse) : void 0;
259
+ if (verse) {
260
+ verse.footnotes.push({
261
+ noteId: footnote.noteId,
262
+ offset: verse.text.length,
263
+ text: footnote.text,
264
+ caller: footnote.caller
265
+ });
266
+ } else {
267
+ unreferencedFootnotes.push(footnote);
268
+ }
269
+ }
270
+ return {
271
+ chapter: {
272
+ number: chapter.number,
273
+ content,
274
+ footnotes: unreferencedFootnotes
275
+ },
276
+ words: simpleWords
277
+ };
278
+ }
279
+ function simplifyCommentaryChapter(chapter) {
280
+ return {
281
+ number: chapter.number,
282
+ ...chapter.introduction !== void 0 ? { introduction: chapter.introduction } : {},
283
+ content: chapter.content.map((verse) => simplifyVerse(verse))
284
+ };
285
+ }
286
+ // Annotate the CommonJS export names for ESM import in node:
287
+ 0 && (module.exports = {
288
+ simplifyChapter,
289
+ simplifyCommentaryChapter,
290
+ simplifyHebrewSubtitle,
291
+ simplifyVerse,
292
+ simplifyVerseContent
293
+ });
294
+ //# sourceMappingURL=simple.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../generation/simple.ts"],
4
+ "sourcesContent": ["import {\r\n ChapterData,\r\n ChapterFootnote,\r\n ChapterHebrewSubtitle,\r\n ChapterVerse,\r\n ChapterWord,\r\n CommentaryChapterData,\r\n SimpleChapterContent,\r\n SimpleChapterData,\r\n SimpleChapterHebrewSubtitle,\r\n SimpleChapterVerse,\r\n SimpleChapterWord,\r\n SimpleCommentaryChapterData,\r\n SimpleInlineHeading,\r\n SimplePoemRange,\r\n SimpleTextRange,\r\n SimpleVerseFootnote,\r\n TranslationBookChapterWords,\r\n SimpleTranslationBookChapterWords,\r\n} from './common-types.js';\r\n\r\n/**\r\n * The types of content that can be contained in a verse or Hebrew Subtitle.\r\n */\r\ntype VerseContent =\r\n | ChapterVerse['content'][number]\r\n | ChapterHebrewSubtitle['content'][number];\r\n\r\n/**\r\n * The result of flattening the content of a verse into a single string.\r\n */\r\nexport interface SimplifiedVerseContent {\r\n /**\r\n * The text of the verse.\r\n */\r\n text: string;\r\n\r\n /**\r\n * The footnotes that occur in the verse.\r\n */\r\n footnotes: SimpleVerseFootnote[];\r\n\r\n /**\r\n * The headings that occur in the middle of the verse.\r\n */\r\n headings: SimpleInlineHeading[];\r\n\r\n /**\r\n * The ranges of text that represent the Words of Jesus.\r\n */\r\n wordsOfJesus: SimpleTextRange[];\r\n\r\n /**\r\n * The ranges of text that represent lines of poetry.\r\n */\r\n poem: SimplePoemRange[];\r\n\r\n /**\r\n * The word-level annotations for the verse, with their offsets remapped onto the text.\r\n */\r\n words: SimpleChapterWord[];\r\n}\r\n\r\n/**\r\n * Flattens the content of a verse into a single string, recording the positions of the\r\n * footnotes, headings, and formatting that occur in it.\r\n *\r\n * The rules used to build the text are:\r\n * - Strings and formatted text are appended as-is. The source data already contains the\r\n * spacing that is needed between them.\r\n * - Lines of poetry and line breaks start a new line.\r\n * - Footnote and heading markers are replaced with a single space when one is needed to\r\n * keep the surrounding words apart.\r\n *\r\n * All of the recorded offsets are measured in UTF-16 code units, which is what\r\n * `String.prototype.slice()` and `String.prototype.length` use.\r\n *\r\n * Word-level annotations are anchored to a range of characters in a single item of the\r\n * content array. Since the simplified format replaces that array with a single string,\r\n * their offsets are remapped onto the text that is built here.\r\n *\r\n * @param content The content of the verse.\r\n * @param footnotes The footnotes for the chapter, keyed by note ID.\r\n * @param usedFootnotes A set that the IDs of the referenced footnotes are added to.\r\n * @param words The word-level annotations for the verse.\r\n */\r\nexport function simplifyVerseContent(\r\n content: readonly VerseContent[],\r\n footnotes: Map<number, ChapterFootnote> = new Map(),\r\n usedFootnotes: Set<number> = new Set(),\r\n words: readonly ChapterWord[] = []\r\n): SimplifiedVerseContent {\r\n let text = '';\r\n const verseFootnotes: SimpleVerseFootnote[] = [];\r\n const headings: SimpleInlineHeading[] = [];\r\n const wordsOfJesus: SimpleTextRange[] = [];\r\n const poem: SimplePoemRange[] = [];\r\n const verseWords: SimpleChapterWord[] = [];\r\n\r\n const wordsByContentIndex = new Map<number, ChapterWord[]>();\r\n for (let word of words) {\r\n let arr = wordsByContentIndex.get(word.contentIndex);\r\n if (!arr) {\r\n arr = [];\r\n wordsByContentIndex.set(word.contentIndex, arr);\r\n }\r\n arr.push(word);\r\n }\r\n\r\n /**\r\n * Removes the given number of characters from the end of the text and moves any\r\n * offsets that pointed into the removed region back to the new end of the text.\r\n */\r\n const truncateTo = (length: number) => {\r\n if (length >= text.length) {\r\n return;\r\n }\r\n text = text.slice(0, length);\r\n for (let footnote of verseFootnotes) {\r\n footnote.offset = Math.min(footnote.offset, length);\r\n }\r\n for (let heading of headings) {\r\n heading.offset = Math.min(heading.offset, length);\r\n }\r\n for (let range of [...wordsOfJesus, ...poem, ...verseWords]) {\r\n range.start = Math.min(range.start, length);\r\n range.end = Math.min(range.end, length);\r\n }\r\n };\r\n\r\n /**\r\n * Moves the annotations for the content item at the given index onto the text that\r\n * the item was appended to.\r\n */\r\n const addWordsForContent = (\r\n contentIndex: number,\r\n contentStart: number,\r\n contentLength: number\r\n ) => {\r\n const contentWords = wordsByContentIndex.get(contentIndex);\r\n if (!contentWords) {\r\n return;\r\n }\r\n\r\n for (let { contentIndex: _index, ...word } of contentWords) {\r\n verseWords.push({\r\n ...word,\r\n start: contentStart + Math.min(word.start, contentLength),\r\n end: contentStart + Math.min(word.end, contentLength),\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Starts a new line, first removing any spaces that were left at the end of the\r\n * current one.\r\n */\r\n const startNewLine = () => {\r\n truncateTo(text.replace(/[^\\S\\n]+$/, '').length);\r\n text += '\\n';\r\n };\r\n\r\n /**\r\n * Determines whether a space needs to be inserted in place of a marker in order to\r\n * keep the text that surrounds it apart.\r\n */\r\n const needsSeparator = (next: VerseContent | undefined) => {\r\n if (text.length <= 0 || /\\s$/.test(text) || !next) {\r\n return false;\r\n }\r\n if (typeof next === 'string') {\r\n return next.length > 0 && !/^\\s/.test(next);\r\n }\r\n if ('text' in next) {\r\n // Poem lines always start a new line, so they never need a separator.\r\n return (\r\n typeof next.poem !== 'number' &&\r\n next.text.length > 0 &&\r\n !/^\\s/.test(next.text)\r\n );\r\n }\r\n // Line breaks start their own line, and consecutive markers only ever need\r\n // a single separator between them.\r\n return false;\r\n };\r\n\r\n for (let i = 0; i < content.length; i++) {\r\n const part = content[i];\r\n\r\n if (typeof part === 'string') {\r\n addWordsForContent(i, text.length, part.length);\r\n text += part;\r\n continue;\r\n }\r\n\r\n if ('text' in part) {\r\n if (\r\n typeof part.poem === 'number' &&\r\n text.length > 0 &&\r\n !text.endsWith('\\n')\r\n ) {\r\n startNewLine();\r\n }\r\n\r\n const start = text.length;\r\n addWordsForContent(i, start, part.text.length);\r\n text += part.text;\r\n const end = text.length;\r\n\r\n if (end > start) {\r\n if (part.wordsOfJesus) {\r\n wordsOfJesus.push({ start, end });\r\n }\r\n if (typeof part.poem === 'number') {\r\n poem.push({ start, end, level: part.poem });\r\n }\r\n }\r\n } else if ('lineBreak' in part) {\r\n if (text.length > 0 && !text.endsWith('\\n')) {\r\n startNewLine();\r\n }\r\n } else if ('noteId' in part) {\r\n const footnote = footnotes.get(part.noteId);\r\n if (footnote) {\r\n usedFootnotes.add(part.noteId);\r\n verseFootnotes.push({\r\n noteId: footnote.noteId,\r\n offset: text.length,\r\n text: footnote.text,\r\n caller: footnote.caller,\r\n });\r\n }\r\n if (needsSeparator(content[i + 1])) {\r\n text += ' ';\r\n }\r\n } else if ('heading' in part) {\r\n headings.push({\r\n offset: text.length,\r\n text: part.heading,\r\n });\r\n if (needsSeparator(content[i + 1])) {\r\n text += ' ';\r\n }\r\n }\r\n }\r\n\r\n // Trim the whitespace that line breaks and separators can leave behind.\r\n truncateTo(text.replace(/\\s+$/, '').length);\r\n\r\n const leading = text.length - text.replace(/^\\s+/, '').length;\r\n if (leading > 0) {\r\n text = text.slice(leading);\r\n for (let footnote of verseFootnotes) {\r\n footnote.offset = Math.max(0, footnote.offset - leading);\r\n }\r\n for (let heading of headings) {\r\n heading.offset = Math.max(0, heading.offset - leading);\r\n }\r\n for (let range of [...wordsOfJesus, ...poem, ...verseWords]) {\r\n range.start = Math.max(0, range.start - leading);\r\n range.end = Math.max(0, range.end - leading);\r\n }\r\n }\r\n\r\n return {\r\n text,\r\n footnotes: verseFootnotes,\r\n headings,\r\n wordsOfJesus: mergeAdjacentRanges(wordsOfJesus, text),\r\n poem: poem.filter((range) => range.start < range.end),\r\n words: verseWords.filter((word) => word.start < word.end),\r\n };\r\n}\r\n\r\n/**\r\n * Merges the ranges that are only separated by whitespace into single ranges.\r\n * @param ranges The ranges to merge. Must be sorted by their start offset.\r\n * @param text The text that the ranges point into.\r\n */\r\nfunction mergeAdjacentRanges(\r\n ranges: SimpleTextRange[],\r\n text: string\r\n): SimpleTextRange[] {\r\n const merged: SimpleTextRange[] = [];\r\n for (let range of ranges) {\r\n if (range.start >= range.end) {\r\n continue;\r\n }\r\n const previous = merged[merged.length - 1];\r\n if (\r\n previous &&\r\n range.start >= previous.end &&\r\n !/\\S/.test(text.slice(previous.end, range.start))\r\n ) {\r\n previous.end = range.end;\r\n } else {\r\n merged.push(range);\r\n }\r\n }\r\n return merged;\r\n}\r\n\r\n/**\r\n * Converts the given verse into its simplified representation.\r\n * @param verse The verse to convert.\r\n * @param footnotes The footnotes for the chapter, keyed by note ID.\r\n * @param usedFootnotes A set that the IDs of the referenced footnotes are added to.\r\n * @param words The word-level annotations for the verse.\r\n * @param remappedWords An array that the remapped word-level annotations are added to.\r\n */\r\nexport function simplifyVerse(\r\n verse: ChapterVerse,\r\n footnotes?: Map<number, ChapterFootnote>,\r\n usedFootnotes?: Set<number>,\r\n words?: readonly ChapterWord[],\r\n remappedWords?: SimpleChapterWord[]\r\n): SimpleChapterVerse {\r\n const simplified = simplifyVerseContent(\r\n verse.content,\r\n footnotes,\r\n usedFootnotes,\r\n words\r\n );\r\n\r\n if (remappedWords) {\r\n remappedWords.push(...simplified.words);\r\n }\r\n\r\n return {\r\n type: 'verse',\r\n number: verse.number,\r\n ...omitEmptyProperties(simplified),\r\n };\r\n}\r\n\r\n/**\r\n * Converts the given Hebrew Subtitle into its simplified representation.\r\n * @param subtitle The subtitle to convert.\r\n * @param footnotes The footnotes for the chapter, keyed by note ID.\r\n * @param usedFootnotes A set that the IDs of the referenced footnotes are added to.\r\n */\r\nexport function simplifyHebrewSubtitle(\r\n subtitle: ChapterHebrewSubtitle,\r\n footnotes?: Map<number, ChapterFootnote>,\r\n usedFootnotes?: Set<number>\r\n): SimpleChapterHebrewSubtitle {\r\n const simplified = simplifyVerseContent(\r\n subtitle.content,\r\n footnotes,\r\n usedFootnotes\r\n );\r\n\r\n return {\r\n type: 'hebrew_subtitle',\r\n ...omitEmptyProperties(simplified),\r\n };\r\n}\r\n\r\n/**\r\n * Omits the optional properties of the given simplified content when they are empty.\r\n * @param content The content to omit the empty properties from.\r\n */\r\nfunction omitEmptyProperties(content: SimplifiedVerseContent) {\r\n return {\r\n text: content.text,\r\n footnotes: content.footnotes,\r\n ...(content.headings.length > 0 ? { headings: content.headings } : {}),\r\n ...(content.wordsOfJesus.length > 0\r\n ? { wordsOfJesus: content.wordsOfJesus }\r\n : {}),\r\n ...(content.poem.length > 0 ? { poem: content.poem } : {}),\r\n };\r\n}\r\n\r\n/**\r\n * The result of converting a chapter into the simplified chapter format.\r\n */\r\nexport interface SimplifiedChapter {\r\n /**\r\n * The simplified chapter.\r\n */\r\n chapter: SimpleChapterData;\r\n\r\n /**\r\n * The word-level annotations for the chapter, with their offsets remapped onto the\r\n * text of each simplified verse. Empty if the chapter has no annotations.\r\n */\r\n words: SimpleTranslationBookChapterWords;\r\n}\r\n\r\n/**\r\n * Converts the given chapter into the simplified chapter format.\r\n *\r\n * In the simplified format, the content of each verse is a single string instead of a list\r\n * of formatted content, and the footnotes are available on the verse that they occur in,\r\n * along with the offset that they occur at.\r\n *\r\n * The word-level annotations are returned separately, since they are published in their\r\n * own file. They are converted here because their offsets have to be remapped onto the\r\n * text that is built for each verse.\r\n *\r\n * @param chapter The chapter to convert.\r\n * @param words The word-level annotations for the chapter, keyed by verse number.\r\n */\r\nexport function simplifyChapter(\r\n chapter: ChapterData,\r\n words?: TranslationBookChapterWords\r\n): SimplifiedChapter {\r\n const footnotes = new Map<number, ChapterFootnote>();\r\n for (let footnote of chapter.footnotes) {\r\n footnotes.set(footnote.noteId, footnote);\r\n }\r\n\r\n const usedFootnotes = new Set<number>();\r\n const content: SimpleChapterContent[] = [];\r\n const versesByNumber = new Map<number, SimpleChapterVerse>();\r\n const simpleWords: SimpleTranslationBookChapterWords = {};\r\n\r\n for (let c of chapter.content) {\r\n if (c.type === 'verse') {\r\n const verseWords = words?.[String(c.number)];\r\n const remappedWords: SimpleChapterWord[] = [];\r\n const verse = simplifyVerse(\r\n c,\r\n footnotes,\r\n usedFootnotes,\r\n verseWords,\r\n remappedWords\r\n );\r\n if (remappedWords.length > 0) {\r\n simpleWords[String(c.number)] = remappedWords;\r\n }\r\n versesByNumber.set(verse.number, verse);\r\n content.push(verse);\r\n } else if (c.type === 'hebrew_subtitle') {\r\n content.push(simplifyHebrewSubtitle(c, footnotes, usedFootnotes));\r\n } else if (c.type === 'heading') {\r\n content.push({\r\n type: 'heading',\r\n text: c.content.join(' '),\r\n });\r\n } else if (c.type === 'line_break') {\r\n content.push({\r\n type: 'line_break',\r\n });\r\n }\r\n }\r\n\r\n // Footnotes that aren't referenced by any verse content, but that do reference a\r\n // verse, get attached to the end of that verse.\r\n const unreferencedFootnotes: ChapterFootnote[] = [];\r\n for (let footnote of chapter.footnotes) {\r\n if (usedFootnotes.has(footnote.noteId)) {\r\n continue;\r\n }\r\n\r\n const verse = footnote.reference\r\n ? versesByNumber.get(footnote.reference.verse)\r\n : undefined;\r\n\r\n if (verse) {\r\n verse.footnotes.push({\r\n noteId: footnote.noteId,\r\n offset: verse.text.length,\r\n text: footnote.text,\r\n caller: footnote.caller,\r\n });\r\n } else {\r\n unreferencedFootnotes.push(footnote);\r\n }\r\n }\r\n\r\n return {\r\n chapter: {\r\n number: chapter.number,\r\n content,\r\n footnotes: unreferencedFootnotes,\r\n },\r\n words: simpleWords,\r\n };\r\n}\r\n\r\n/**\r\n * Converts the given commentary chapter into the simplified chapter format.\r\n * @param chapter The chapter to convert.\r\n */\r\nexport function simplifyCommentaryChapter(\r\n chapter: CommentaryChapterData\r\n): SimpleCommentaryChapterData {\r\n return {\r\n number: chapter.number,\r\n ...(chapter.introduction !== undefined\r\n ? { introduction: chapter.introduction }\r\n : {}),\r\n content: chapter.content.map((verse) => simplifyVerse(verse)),\r\n };\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }