@helloao/tools 0.2.0 → 0.3.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 (75) hide show
  1. package/dist/cjs/generation/api.cjs +856 -36
  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 +359 -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/index.cjs +4 -4
  15. package/dist/cjs/index.cjs.map +1 -1
  16. package/dist/cjs/log.cjs.map +1 -1
  17. package/dist/cjs/parser/codex-parser.cjs +3 -3
  18. package/dist/cjs/parser/codex-parser.cjs.map +3 -3
  19. package/dist/cjs/parser/commentary-csv-parser.cjs +14 -3
  20. package/dist/cjs/parser/commentary-csv-parser.cjs.map +3 -3
  21. package/dist/cjs/parser/index.cjs +1 -1
  22. package/dist/cjs/parser/iterators.cjs.map +1 -1
  23. package/dist/cjs/parser/lockman-parser.cjs +1 -1
  24. package/dist/cjs/parser/lockman-parser.cjs.map +1 -1
  25. package/dist/cjs/parser/tyndale-xml-parser.cjs +1 -1
  26. package/dist/cjs/parser/tyndale-xml-parser.cjs.map +1 -1
  27. package/dist/cjs/parser/types.cjs.map +1 -1
  28. package/dist/cjs/parser/usfm-parser.cjs +2 -2
  29. package/dist/cjs/parser/usfm-parser.cjs.map +1 -1
  30. package/dist/cjs/parser/usx-parser.cjs +122 -26
  31. package/dist/cjs/parser/usx-parser.cjs.map +2 -2
  32. package/dist/cjs/parser/words.cjs +187 -0
  33. package/dist/cjs/parser/words.cjs.map +7 -0
  34. package/dist/cjs/utils.cjs +1 -1
  35. package/dist/esm/generation/api.js +835 -37
  36. package/dist/esm/generation/api.js.map +3 -3
  37. package/dist/esm/generation/audio.js +1 -1
  38. package/dist/esm/generation/audio.js.map +1 -1
  39. package/dist/esm/generation/book-order.js.map +1 -1
  40. package/dist/esm/generation/common-types.js +327 -14
  41. package/dist/esm/generation/common-types.js.map +2 -2
  42. package/dist/esm/generation/dataset.js +6 -2
  43. package/dist/esm/generation/dataset.js.map +2 -2
  44. package/dist/esm/generation/index.js +2 -1
  45. package/dist/esm/generation/index.js.map +2 -2
  46. package/dist/esm/generation/simple.js +260 -0
  47. package/dist/esm/generation/simple.js.map +7 -0
  48. package/dist/esm/index.js.map +1 -1
  49. package/dist/esm/log.js.map +1 -1
  50. package/dist/esm/parser/codex-parser.js +3 -3
  51. package/dist/esm/parser/codex-parser.js.map +3 -3
  52. package/dist/esm/parser/commentary-csv-parser.js +3 -2
  53. package/dist/esm/parser/commentary-csv-parser.js.map +2 -2
  54. package/dist/esm/parser/iterators.js.map +1 -1
  55. package/dist/esm/parser/lockman-parser.js +1 -1
  56. package/dist/esm/parser/lockman-parser.js.map +1 -1
  57. package/dist/esm/parser/tyndale-xml-parser.js +1 -1
  58. package/dist/esm/parser/tyndale-xml-parser.js.map +1 -1
  59. package/dist/esm/parser/usfm-parser.js +1 -1
  60. package/dist/esm/parser/usfm-parser.js.map +1 -1
  61. package/dist/esm/parser/usx-parser.js +130 -26
  62. package/dist/esm/parser/usx-parser.js.map +2 -2
  63. package/dist/esm/parser/words.js +149 -0
  64. package/dist/esm/parser/words.js.map +7 -0
  65. package/dist/types/generation/api.d.ts +6879 -918
  66. package/dist/types/generation/common-types.d.ts +432 -2
  67. package/dist/types/generation/index.d.ts +2 -1
  68. package/dist/types/generation/simple.d.ts +110 -0
  69. package/dist/types/parser/commentary-csv-parser.d.ts +1 -1
  70. package/dist/types/parser/lockman-parser.d.ts +1 -1
  71. package/dist/types/parser/tyndale-xml-parser.d.ts +1 -1
  72. package/dist/types/parser/types.d.ts +63 -0
  73. package/dist/types/parser/usx-parser.d.ts +6 -5
  74. package/dist/types/parser/words.d.ts +104 -0
  75. package/package.json +3 -2
@@ -23,12 +23,13 @@ __export(usx_parser_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(usx_parser_exports);
25
25
  var import_iterators = require("./iterators.js");
26
+ var import_words = require("./words.js");
26
27
  var import_utils = require("../utils.js");
27
28
  var NodeType = /* @__PURE__ */ ((NodeType2) => {
28
29
  NodeType2[NodeType2["Text"] = 3] = "Text";
29
30
  return NodeType2;
30
31
  })(NodeType || {});
31
- const PARSER_VERSION = 3;
32
+ const PARSER_VERSION = 4;
32
33
  class USXParser {
33
34
  _domParser;
34
35
  _noteCounter = 0;
@@ -205,12 +206,15 @@ class USXParser {
205
206
  descriptive = true;
206
207
  }
207
208
  }
208
- for (let content of this.iterateNodeTextContent(
209
+ for (let value of this.iterateNodeTextContent(
209
210
  nodes,
210
211
  node,
211
212
  chapter,
212
213
  verse
213
214
  )) {
215
+ const words = (0, import_words.isAnnotatedContent)(value) ? value.words : null;
216
+ const content = (0, import_words.isAnnotatedContent)(value) ? value.annotatedContent : value;
217
+ let result = content;
214
218
  if (poem !== null || descriptive !== null) {
215
219
  if (typeof content === "string") {
216
220
  let text = {
@@ -222,7 +226,7 @@ class USXParser {
222
226
  if (descriptive !== null) {
223
227
  text.descriptive = true;
224
228
  }
225
- yield text;
229
+ result = text;
226
230
  } else {
227
231
  let text = {
228
232
  ...content
@@ -235,10 +239,16 @@ class USXParser {
235
239
  text.descriptive = true;
236
240
  }
237
241
  }
238
- yield text;
242
+ result = text;
239
243
  }
244
+ }
245
+ if (words) {
246
+ yield {
247
+ annotatedContent: result,
248
+ words
249
+ };
240
250
  } else {
241
- yield content;
251
+ yield result;
242
252
  }
243
253
  }
244
254
  }
@@ -272,15 +282,26 @@ class USXParser {
272
282
  }
273
283
  }
274
284
  const previousVerse = this._currentChapter?.number === chapter.number ? this._lastVerse : null;
285
+ const words = [];
275
286
  for (let content of this.iterateVerseContent(
276
287
  chapter,
277
288
  verse,
278
289
  nodes,
279
290
  previousVerse
280
291
  )) {
281
- addOrJoin(verse.content, content);
292
+ if ((0, import_words.isAnnotatedContent)(content)) {
293
+ addOrJoin(
294
+ verse.content,
295
+ content.annotatedContent,
296
+ content.words,
297
+ words
298
+ );
299
+ } else {
300
+ addOrJoin(verse.content, content);
301
+ }
282
302
  }
283
- trimContent(verse.content);
303
+ trimContent(verse.content, words);
304
+ (0, import_words.addChapterWords)(chapter, verse.number, words);
284
305
  this._lastVerse = verse;
285
306
  return verse;
286
307
  }
@@ -298,7 +319,10 @@ class USXParser {
298
319
  yield content;
299
320
  continue;
300
321
  }
301
- addOrJoin(subtitle.content, content);
322
+ addOrJoin(
323
+ subtitle.content,
324
+ (0, import_words.isAnnotatedContent)(content) ? content.annotatedContent : content
325
+ );
302
326
  }
303
327
  trimContent(subtitle.content);
304
328
  if (subtitle.content.length > 0) {
@@ -384,18 +408,48 @@ class USXParser {
384
408
  *iterateChar(nodes, node) {
385
409
  const style = node.getAttribute("style");
386
410
  let text = "";
411
+ const words = [];
412
+ let currentWord = null;
413
+ let currentAnnotations = null;
414
+ let currentStart = 0;
415
+ const endCurrentWord = () => {
416
+ if (currentAnnotations) {
417
+ const range = (0, import_words.trimWordRange)(text, currentStart, text.length);
418
+ if (range) {
419
+ words.push({
420
+ ...range,
421
+ annotations: currentAnnotations
422
+ });
423
+ }
424
+ }
425
+ currentWord = null;
426
+ currentAnnotations = null;
427
+ };
387
428
  for (let char of (0, import_iterators.children)(nodes, node)) {
388
- if (char.nodeType === 3 /* Text */) {
389
- text += char.textContent || "";
429
+ if (char.nodeType !== 3 /* Text */) {
430
+ continue;
431
+ }
432
+ const word = wordElementFor(char, node);
433
+ if (word !== currentWord) {
434
+ endCurrentWord();
435
+ currentWord = word;
436
+ currentStart = text.length;
437
+ currentAnnotations = word ? (0, import_words.readWordAnnotations)(word) : null;
390
438
  }
439
+ text += char.textContent || "";
391
440
  }
392
- if (style === "wj") {
441
+ endCurrentWord();
442
+ const content = style === "wj" ? {
443
+ text,
444
+ wordsOfJesus: true
445
+ } : text;
446
+ if (words.length > 0) {
393
447
  yield {
394
- text,
395
- wordsOfJesus: true
448
+ annotatedContent: content,
449
+ words
396
450
  };
397
451
  } else {
398
- yield text;
452
+ yield content;
399
453
  }
400
454
  }
401
455
  }
@@ -491,40 +545,82 @@ function* iterateCharContent(char) {
491
545
  function trimText(text) {
492
546
  return text.replace(/\s+/g, " ");
493
547
  }
494
- function trimContent(content) {
548
+ function wordElementFor(node, root) {
549
+ let element = node.parentElement;
550
+ while (element) {
551
+ if (element.nodeName === "char" && element.getAttribute("style") === "w") {
552
+ return element;
553
+ }
554
+ if (element === root) {
555
+ return null;
556
+ }
557
+ element = element.parentElement;
558
+ }
559
+ return null;
560
+ }
561
+ function trimContent(content, words) {
495
562
  for (let i = 0; i < content.length; i++) {
496
563
  const value = content[i];
564
+ let text = null;
497
565
  if (typeof value === "string") {
498
- content[i] = trimText(value).trim();
499
- if (content[i] === "") {
500
- content.splice(i, 1);
501
- i--;
502
- continue;
566
+ const collapsed = (0, import_words.collapseWhitespaceMap)(value);
567
+ content[i] = collapsed.text;
568
+ text = collapsed.text;
569
+ if (words) {
570
+ (0, import_words.remapChapterWords)(words, i, collapsed.map);
503
571
  }
504
572
  } else if (isVerseText(value)) {
505
- value.text = trimText(value.text).trim();
506
- if (value.text === "") {
507
- content.splice(i, 1);
508
- i--;
509
- continue;
573
+ const collapsed = (0, import_words.collapseWhitespaceMap)(value.text);
574
+ value.text = collapsed.text;
575
+ text = collapsed.text;
576
+ if (words) {
577
+ (0, import_words.remapChapterWords)(words, i, collapsed.map);
578
+ }
579
+ }
580
+ if (text === "") {
581
+ content.splice(i, 1);
582
+ if (words) {
583
+ (0, import_words.removeChapterWordsForContent)(words, i);
510
584
  }
585
+ i--;
586
+ continue;
511
587
  }
512
588
  }
513
589
  return content;
514
590
  }
515
- function addOrJoin(array, value) {
591
+ function addOrJoin(array, value, ranges, words) {
592
+ let contentIndex;
593
+ let offset;
516
594
  if (array.length === 0) {
595
+ contentIndex = 0;
596
+ offset = 0;
517
597
  array.push(value);
518
598
  } else {
519
599
  const last = array[array.length - 1];
520
600
  if (typeof last === "string" && typeof value === "string") {
601
+ contentIndex = array.length - 1;
602
+ offset = last.length;
521
603
  array[array.length - 1] = last + value;
522
604
  } else if (isVerseText(last) && isVerseText(value) && hasSameFormatting(last, value)) {
605
+ contentIndex = array.length - 1;
606
+ offset = last.text.length;
523
607
  last.text += value.text;
524
608
  } else {
609
+ contentIndex = array.length;
610
+ offset = 0;
525
611
  array.push(value);
526
612
  }
527
613
  }
614
+ if (ranges && words) {
615
+ for (let range of ranges) {
616
+ words.push({
617
+ contentIndex,
618
+ start: offset + range.start,
619
+ end: offset + range.end,
620
+ ...range.annotations
621
+ });
622
+ }
623
+ }
528
624
  }
529
625
  function isVerseText(value) {
530
626
  return typeof value === "object" && value !== null && "text" in value;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../parser/usx-parser.ts"],
4
- "sourcesContent": ["import {\r\n Chapter,\r\n ChapterContent,\r\n Footnote,\r\n FootnoteReference,\r\n ParseTree,\r\n Verse,\r\n Text,\r\n HebrewSubtitle,\r\n InlineLineBreak,\r\n InlineHeading,\r\n ParseMessage,\r\n} from './types.js';\r\nimport {\r\n iterateAll,\r\n children,\r\n RewindableIterator,\r\n isParent,\r\n} from './iterators.js';\r\nimport { KNOWN_SKIPPED_VERSES } from '../utils.js';\r\n\r\nenum NodeType {\r\n Text = 3,\r\n}\r\n\r\n/**\r\n * The version of the parser.\r\n * Used to determine whether input files need to be re-parsed.\r\n */\r\nexport const PARSER_VERSION = 3;\r\n\r\n/**\r\n * Defines a class that is able to parse USX content.\r\n */\r\nexport class USXParser {\r\n private _domParser: DOMParser;\r\n private _noteCounter: number = 0;\r\n private _messages: ParseMessage[] = [];\r\n private _lastVerse: Verse | null = null;\r\n private _currentChapter: Chapter | null = null;\r\n private _bookId: string | null = null;\r\n\r\n constructor(domParser: DOMParser) {\r\n this._domParser = domParser;\r\n }\r\n\r\n /**\r\n * Parses the specified USX content.\r\n *\r\n * @param usx The USX content to parse.\r\n * @returns The parse tree that was generated.\r\n */\r\n public parse(usx: string): ParseTree {\r\n this._noteCounter = 0;\r\n this._messages = [];\r\n this._lastVerse = null;\r\n this._currentChapter = null;\r\n this._bookId = null;\r\n const parser = this._domParser;\r\n const doc = parser.parseFromString(usx, 'application/xml');\r\n const usxElement = doc.documentElement;\r\n\r\n let root: ParseTree = {\r\n type: 'root',\r\n content: [],\r\n };\r\n\r\n const bookElement = usxElement.querySelector('book[code]');\r\n\r\n if (!bookElement) {\r\n throw new Error('The USX content does not contain a book element.');\r\n }\r\n\r\n const bookCode = bookElement.getAttribute('code') || '';\r\n\r\n if (!bookCode) {\r\n throw new Error(\r\n 'The book element does not contain a code attribute.'\r\n );\r\n }\r\n\r\n this._bookId = root.id = bookCode;\r\n\r\n const header = usxElement.querySelector('para[style=\"h\"]');\r\n if (header) {\r\n root.header = header.textContent || '';\r\n }\r\n\r\n const titles = usxElement.querySelectorAll(\r\n 'para[style=\"mt1\"], para[style=\"mt2\"], para[style=\"mt3\"]'\r\n );\r\n // const title2 = usxElement.querySelector('para[style=\"mt2\"]');\r\n // const title3 = usxElement.querySelector('para[style=\"mt3\"]');\r\n\r\n if (titles.length > 0) {\r\n root.title = [...titles]\r\n .map((t) => t.textContent)\r\n .filter((t) => t)\r\n .join(' ');\r\n }\r\n\r\n for (let content of this.iterateRootContent(usxElement)) {\r\n root.content.push(content);\r\n }\r\n\r\n if (this._messages.length > 0) {\r\n root.parseMessages = this._messages.slice();\r\n }\r\n\r\n return root;\r\n }\r\n\r\n *iterateRootContent(\r\n usxElement: Element\r\n ): Generator<ParseTree['content'][0]> {\r\n const iterator = iterateAll(usxElement);\r\n while (true) {\r\n const { done, value: child } = iterator.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (!(child instanceof Element)) {\r\n continue;\r\n }\r\n\r\n if (child.nodeName === 'chapter') {\r\n if (child.hasAttribute('eid')) {\r\n continue;\r\n }\r\n\r\n const chapter: Chapter = {\r\n type: 'chapter',\r\n number: parseInt(child.getAttribute('number') || '0', 10),\r\n content: [],\r\n footnotes: [],\r\n };\r\n this._currentChapter = chapter;\r\n\r\n for (let content of this.iterateChapterContent(\r\n chapter,\r\n iterator\r\n )) {\r\n chapter.content.push(content);\r\n }\r\n\r\n yield chapter;\r\n } else if (child.nodeName === 'para') {\r\n const style = child.getAttribute('style');\r\n if (\r\n style === 's1' ||\r\n style === 's2' ||\r\n style === 's3' ||\r\n style === 's4'\r\n ) {\r\n yield {\r\n type: 'heading',\r\n content: child.textContent ? [child.textContent] : [],\r\n };\r\n }\r\n }\r\n }\r\n }\r\n\r\n *iterateChapterContent(\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): IterableIterator<ChapterContent> {\r\n while (true) {\r\n const { done, value: element } = nodes.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (!(element instanceof Element)) {\r\n continue;\r\n }\r\n\r\n if (element.nodeName === 'chapter') {\r\n break;\r\n } else if (element.nodeName === 'para') {\r\n const style = element.getAttribute('style');\r\n if (\r\n style === 's1' ||\r\n style === 's2' ||\r\n style === 's3' ||\r\n style === 's4'\r\n ) {\r\n yield {\r\n type: 'heading',\r\n content: element.textContent\r\n ? [element.textContent]\r\n : [],\r\n };\r\n } else if (style === 'b') {\r\n yield {\r\n type: 'line_break',\r\n };\r\n } else if (style === 'd') {\r\n yield* this.parseHebrewSubtitle(element, chapter, nodes);\r\n }\r\n } else if (element.nodeName === 'verse') {\r\n if (element.hasAttribute('eid')) {\r\n continue;\r\n }\r\n\r\n yield this.parseVerse(element, chapter, nodes);\r\n }\r\n }\r\n }\r\n\r\n *iterateVerseContent(\r\n chapter: Chapter,\r\n verse: Verse,\r\n nodes: RewindableIterator<Node>,\r\n previousVerse?: Verse | null\r\n ): IterableIterator<string | FootnoteReference | Text | InlineLineBreak> {\r\n let lastParent: Element | null = null;\r\n while (true) {\r\n const { done, value: node } = nodes.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (node.nodeName === 'verse') {\r\n if (!(node instanceof Element) || !node.hasAttribute('eid')) {\r\n nodes.rewind(1);\r\n }\r\n break;\r\n }\r\n\r\n const parent = node.parentElement!;\r\n let poem: number | null = null;\r\n let descriptive: boolean | null = null;\r\n\r\n if (parent.nodeName === 'para') {\r\n const style = parent.getAttribute('style');\r\n if (\r\n style === 'q1' ||\r\n style === 'q2' ||\r\n style === 'q3' ||\r\n style === 'q4'\r\n ) {\r\n poem =\r\n style === 'q1'\r\n ? 1\r\n : style === 'q2'\r\n ? 2\r\n : style === 'q3'\r\n ? 3\r\n : 4;\r\n\r\n // Send explicit line breaks\r\n // if we are in a new paragraph but the previous paragraph had the same poem style\r\n if (parent.previousElementSibling?.nodeName === 'para') {\r\n const previousStyle =\r\n parent.previousElementSibling?.getAttribute(\r\n 'style'\r\n );\r\n if (previousStyle === style && lastParent !== parent) {\r\n lastParent = parent;\r\n\r\n const firstChild = parent.firstElementChild;\r\n const startsWithVerse =\r\n firstChild?.nodeName === 'verse' &&\r\n !firstChild.hasAttribute('eid') &&\r\n parseInt(\r\n firstChild.getAttribute('number') || '0',\r\n 10\r\n ) === verse.number;\r\n\r\n if (\r\n startsWithVerse &&\r\n previousVerse &&\r\n previousVerse.number !== verse.number\r\n ) {\r\n addOrJoin(previousVerse.content, {\r\n lineBreak: true,\r\n });\r\n } else {\r\n yield {\r\n lineBreak: true,\r\n };\r\n }\r\n }\r\n }\r\n } else if (style === 'd') {\r\n descriptive = true;\r\n }\r\n }\r\n\r\n for (let content of this.iterateNodeTextContent(\r\n nodes,\r\n node,\r\n chapter,\r\n verse\r\n )) {\r\n if (poem !== null || descriptive !== null) {\r\n if (typeof content === 'string') {\r\n let text: Text = {\r\n text: content,\r\n };\r\n\r\n if (poem !== null) {\r\n text.poem = poem;\r\n }\r\n\r\n if (descriptive !== null) {\r\n text.descriptive = true;\r\n }\r\n\r\n yield text;\r\n } else {\r\n let text:\r\n | InlineLineBreak\r\n | InlineHeading\r\n | FootnoteReference\r\n | Text = {\r\n ...content,\r\n };\r\n\r\n if ('text' in text) {\r\n if (poem !== null) {\r\n text.poem = poem;\r\n }\r\n\r\n if (descriptive !== null) {\r\n text.descriptive = true;\r\n }\r\n }\r\n yield text;\r\n }\r\n } else {\r\n yield content;\r\n }\r\n }\r\n }\r\n }\r\n\r\n parseVerse(\r\n element: Element,\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): Verse {\r\n const verse: Verse = {\r\n type: 'verse',\r\n number: parseInt(element.getAttribute('number') || '0', 10),\r\n content: [],\r\n };\r\n\r\n if (this._currentChapter && this._lastVerse) {\r\n if (this._currentChapter.number === chapter.number) {\r\n // We're parsing the same chapter as the last one\r\n const delta = verse.number - this._lastVerse.number;\r\n if (delta > 1) {\r\n // Delta is greater than 1, so we might have missed some verses\r\n for (\r\n let v = this._lastVerse.number + 1;\r\n v < verse.number;\r\n v++\r\n ) {\r\n let isExpected = false;\r\n if (this._bookId) {\r\n const missingVerse = `${this._bookId} ${chapter.number}:${v}`;\r\n if (KNOWN_SKIPPED_VERSES.has(missingVerse)) {\r\n isExpected = true;\r\n }\r\n }\r\n\r\n if (!isExpected) {\r\n this._messages.push({\r\n type: 'warning',\r\n message: `Verse ${this._bookId ?? '(null)'} ${chapter.number}:${v} is missing.`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n const previousVerse =\r\n this._currentChapter?.number === chapter.number\r\n ? this._lastVerse\r\n : null;\r\n\r\n for (let content of this.iterateVerseContent(\r\n chapter,\r\n verse,\r\n nodes,\r\n previousVerse\r\n )) {\r\n addOrJoin(verse.content, content);\r\n }\r\n\r\n trimContent(verse.content);\r\n this._lastVerse = verse;\r\n return verse;\r\n }\r\n\r\n *parseHebrewSubtitle(\r\n para: Element,\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): IterableIterator<HebrewSubtitle | Verse> {\r\n const subtitle: HebrewSubtitle = {\r\n type: 'hebrew_subtitle',\r\n content: [],\r\n };\r\n\r\n for (let content of this.iterateHebrewSubtitleContent(\r\n para,\r\n chapter,\r\n nodes\r\n )) {\r\n if (typeof content === 'object' && 'number' in content) {\r\n yield content;\r\n continue;\r\n }\r\n addOrJoin(subtitle.content, content);\r\n }\r\n\r\n trimContent(subtitle.content);\r\n if (subtitle.content.length > 0) {\r\n yield subtitle;\r\n }\r\n }\r\n\r\n *iterateHebrewSubtitleContent(\r\n element: Element,\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): IterableIterator<\r\n Verse | string | Text | FootnoteReference | InlineLineBreak\r\n > {\r\n while (true) {\r\n const { done, value: node } = nodes.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (!isParent(node, element)) {\r\n nodes.rewind(1);\r\n break;\r\n }\r\n\r\n if (node instanceof Element && node.nodeName === 'verse') {\r\n yield this.parseVerse(node, chapter, nodes);\r\n } else {\r\n yield* this.iterateNodeTextContent(nodes, node, chapter);\r\n }\r\n }\r\n }\r\n\r\n *iterateNodeTextContent(\r\n nodes: RewindableIterator<Node>,\r\n node: Node,\r\n chapter: Chapter,\r\n verse?: Verse\r\n ): IterableIterator<string | Text | FootnoteReference | InlineLineBreak> {\r\n if (node instanceof Element && node.nodeName === 'note') {\r\n yield* this.iterateNote(nodes, node, chapter, verse);\r\n } else if (node instanceof Element && node.nodeName === 'char') {\r\n yield* this.iterateChar(nodes, node);\r\n } else if (\r\n node instanceof Element &&\r\n node.nodeName === 'para' &&\r\n node.getAttribute('style') === 'b'\r\n ) {\r\n for (let _ of children(nodes, node)) {\r\n // iterate through all the children to prevent iterating over them multiple times\r\n }\r\n yield {\r\n lineBreak: true,\r\n };\r\n } else if (node.nodeType === NodeType.Text) {\r\n yield node.textContent || '';\r\n }\r\n }\r\n\r\n *iterateCharContent(char: Element): IterableIterator<string | Text> {\r\n const style = char.getAttribute('style');\r\n const text = trimText(char.textContent || '');\r\n if (style === 'wj') {\r\n yield {\r\n text,\r\n wordsOfJesus: true,\r\n };\r\n } else {\r\n yield text;\r\n }\r\n }\r\n\r\n *iterateNote(\r\n nodes: RewindableIterator<Node>,\r\n node: Element,\r\n chapter: Chapter,\r\n verse?: Verse\r\n ): IterableIterator<FootnoteReference> {\r\n const style = node.getAttribute('style');\r\n if (style === 'f') {\r\n const verseReferenceRegex = /^[0-9]{1,3}:[0-9]{1,3}/;\r\n\r\n let text = '';\r\n for (let child of children(nodes, node)) {\r\n if (child.nodeType === NodeType.Text) {\r\n text += child.textContent || '';\r\n }\r\n }\r\n\r\n text = text.trim();\r\n if (verseReferenceRegex.test(text)) {\r\n text = text.replace(verseReferenceRegex, '').trim();\r\n }\r\n\r\n const note: Footnote = {\r\n noteId: this._noteCounter++,\r\n caller: node.getAttribute('caller') || null,\r\n text,\r\n reference: {\r\n chapter: chapter.number,\r\n verse: verse?.number ?? 0,\r\n },\r\n };\r\n\r\n chapter.footnotes.push(note);\r\n\r\n yield {\r\n noteId: note.noteId,\r\n };\r\n } else {\r\n for (let _ of children(nodes, node)) {\r\n // iterate through all the children\r\n // so that we don't end up with duplicates\r\n }\r\n }\r\n }\r\n\r\n *iterateChar(\r\n nodes: RewindableIterator<Node>,\r\n node: Element\r\n ): IterableIterator<string | Text> {\r\n const style = node.getAttribute('style');\r\n let text = '';\r\n\r\n for (let char of children(nodes, node)) {\r\n if (char.nodeType === NodeType.Text) {\r\n text += char.textContent || '';\r\n }\r\n }\r\n\r\n if (style === 'wj') {\r\n yield {\r\n text,\r\n wordsOfJesus: true,\r\n };\r\n } else {\r\n yield text;\r\n }\r\n\r\n // if (!parentChar(node) && !parentNote(node)) {\r\n // yield *iterateCharContent(node);\r\n // }\r\n }\r\n}\r\n\r\n// Taken from https://github.com/gracious-tech/fetch/blob/1576cc4eafb32bf347a09332094cf17c2231c90c/converters/usx-to-json/src/elements.ts#L16\r\nconst ignoredParaStyles = new Set([\r\n // <para> Identification [exclude all] - Running headings & table of contents\r\n 'ide', // See https://github.com/schierlm/BibleMultiConverter/issues/67\r\n 'rem', // Remarks (valid in schema though missed in docs)\r\n 'h',\r\n 'h1',\r\n 'h2',\r\n 'h3',\r\n 'h4',\r\n 'toc1',\r\n 'toc2',\r\n 'toc3',\r\n 'toca1',\r\n 'toca2',\r\n 'toca3',\r\n\r\n /* <para> Introductions [exclude all] - Introductionary (non-biblical) content\r\n Which might be helpful in a printed book, but intro material in apps is usually bad UX,\r\n and users that really care can research a translations methodology themselves\r\n */\r\n 'imt',\r\n 'imt1',\r\n 'imt2',\r\n 'imt3',\r\n 'imt4',\r\n 'is',\r\n 'is1',\r\n 'is2',\r\n 'is3',\r\n 'is4',\r\n 'ip',\r\n 'ipi',\r\n 'im',\r\n 'imi',\r\n 'ipq',\r\n 'imq',\r\n 'ipr',\r\n 'iq',\r\n 'iq1',\r\n 'iq2',\r\n 'iq3',\r\n 'iq4',\r\n 'ib',\r\n 'ili',\r\n 'ili1',\r\n 'ili2',\r\n 'ili3',\r\n 'ili4',\r\n 'iot',\r\n 'io',\r\n 'io1',\r\n 'io2',\r\n 'io3',\r\n 'io4',\r\n 'iex',\r\n 'imte',\r\n 'ie',\r\n\r\n /* <para> Headings [exclude some] - Exclude book & chapter headings but keep section headings\r\n Not excluded: ms# | mr | s# | sr | d | sp | sd#\r\n */\r\n 'mt',\r\n 'mt1',\r\n 'mt2',\r\n 'mt3',\r\n 'mt4',\r\n 'mte',\r\n 'mte1',\r\n 'mte2',\r\n 'mte3',\r\n 'mte4',\r\n 'cl',\r\n 'cd', // Non-biblical chapter summary, more than heading\r\n 'r', // Parallels to be provided by external data\r\n]);\r\n\r\nfunction* iterateCharContent(char: Element): IterableIterator<string | Text> {\r\n const style = char.getAttribute('style');\r\n const text = trimText(char.textContent || '');\r\n if (style === 'wj') {\r\n yield {\r\n text,\r\n wordsOfJesus: true,\r\n };\r\n } else {\r\n yield text;\r\n }\r\n}\r\n\r\nfunction trimText(text: string): string {\r\n return text.replace(/\\s+/g, ' ');\r\n}\r\n\r\nfunction trimContent<T extends string | unknown>(content: T[]): T[] {\r\n for (let i = 0; i < content.length; i++) {\r\n const value = content[i];\r\n if (typeof value === 'string') {\r\n content[i] = trimText(value as string).trim() as T;\r\n if (content[i] === '') {\r\n content.splice(i, 1);\r\n i--;\r\n continue;\r\n }\r\n } else if (isVerseText(value)) {\r\n value.text = trimText(value.text).trim();\r\n if (value.text === '') {\r\n content.splice(i, 1);\r\n i--;\r\n continue;\r\n }\r\n }\r\n }\r\n return content;\r\n}\r\n\r\nfunction addOrJoin(array: (string | unknown)[], value: string | unknown) {\r\n if (array.length === 0) {\r\n array.push(value);\r\n } else {\r\n const last = array[array.length - 1];\r\n if (typeof last === 'string' && typeof value === 'string') {\r\n array[array.length - 1] = last + value;\r\n } else if (\r\n isVerseText(last) &&\r\n isVerseText(value) &&\r\n hasSameFormatting(last, value)\r\n ) {\r\n last.text += value.text;\r\n } else {\r\n array.push(value);\r\n }\r\n }\r\n}\r\n\r\nfunction isVerseText(value: unknown): value is Text {\r\n return typeof value === 'object' && value !== null && 'text' in value;\r\n}\r\n\r\nfunction hasSameFormatting(a: Text, b: Text): boolean {\r\n return a.poem === b.poem && a.wordsOfJesus === b.wordsOfJesus;\r\n}\r\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\r\n Chapter,\r\n ChapterContent,\r\n ChapterWord,\r\n Footnote,\r\n FootnoteReference,\r\n ParseTree,\r\n Verse,\r\n Text,\r\n HebrewSubtitle,\r\n InlineLineBreak,\r\n InlineHeading,\r\n ParseMessage,\r\n} from './types.js';\r\nimport {\r\n iterateAll,\r\n children,\r\n RewindableIterator,\r\n isParent,\r\n} from './iterators.js';\r\nimport {\r\n AnnotatedContent,\r\n WordAnnotations,\r\n WordRange,\r\n addChapterWords,\r\n collapseWhitespaceMap,\r\n isAnnotatedContent,\r\n readWordAnnotations,\r\n remapChapterWords,\r\n removeChapterWordsForContent,\r\n trimWordRange,\r\n} from './words.js';\r\nimport { KNOWN_SKIPPED_VERSES } from '../utils.js';\r\n\r\nenum NodeType {\r\n Text = 3,\r\n}\r\n\r\n/**\r\n * The version of the parser.\r\n * Used to determine whether input files need to be re-parsed.\r\n */\r\nexport const PARSER_VERSION = 4;\r\n\r\n/**\r\n * Defines a class that is able to parse USX content.\r\n */\r\nexport class USXParser {\r\n private _domParser: DOMParser;\r\n private _noteCounter: number = 0;\r\n private _messages: ParseMessage[] = [];\r\n private _lastVerse: Verse | null = null;\r\n private _currentChapter: Chapter | null = null;\r\n private _bookId: string | null = null;\r\n\r\n constructor(domParser: DOMParser) {\r\n this._domParser = domParser;\r\n }\r\n\r\n /**\r\n * Parses the specified USX content.\r\n *\r\n * @param usx The USX content to parse.\r\n * @returns The parse tree that was generated.\r\n */\r\n public parse(usx: string): ParseTree {\r\n this._noteCounter = 0;\r\n this._messages = [];\r\n this._lastVerse = null;\r\n this._currentChapter = null;\r\n this._bookId = null;\r\n const parser = this._domParser;\r\n const doc = parser.parseFromString(usx, 'application/xml');\r\n const usxElement = doc.documentElement;\r\n\r\n let root: ParseTree = {\r\n type: 'root',\r\n content: [],\r\n };\r\n\r\n const bookElement = usxElement.querySelector('book[code]');\r\n\r\n if (!bookElement) {\r\n throw new Error('The USX content does not contain a book element.');\r\n }\r\n\r\n const bookCode = bookElement.getAttribute('code') || '';\r\n\r\n if (!bookCode) {\r\n throw new Error(\r\n 'The book element does not contain a code attribute.'\r\n );\r\n }\r\n\r\n this._bookId = root.id = bookCode;\r\n\r\n const header = usxElement.querySelector('para[style=\"h\"]');\r\n if (header) {\r\n root.header = header.textContent || '';\r\n }\r\n\r\n const titles = usxElement.querySelectorAll(\r\n 'para[style=\"mt1\"], para[style=\"mt2\"], para[style=\"mt3\"]'\r\n );\r\n // const title2 = usxElement.querySelector('para[style=\"mt2\"]');\r\n // const title3 = usxElement.querySelector('para[style=\"mt3\"]');\r\n\r\n if (titles.length > 0) {\r\n root.title = [...titles]\r\n .map((t) => t.textContent)\r\n .filter((t) => t)\r\n .join(' ');\r\n }\r\n\r\n for (let content of this.iterateRootContent(usxElement)) {\r\n root.content.push(content);\r\n }\r\n\r\n if (this._messages.length > 0) {\r\n root.parseMessages = this._messages.slice();\r\n }\r\n\r\n return root;\r\n }\r\n\r\n *iterateRootContent(\r\n usxElement: Element\r\n ): Generator<ParseTree['content'][0]> {\r\n const iterator = iterateAll(usxElement);\r\n while (true) {\r\n const { done, value: child } = iterator.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (!(child instanceof Element)) {\r\n continue;\r\n }\r\n\r\n if (child.nodeName === 'chapter') {\r\n if (child.hasAttribute('eid')) {\r\n continue;\r\n }\r\n\r\n const chapter: Chapter = {\r\n type: 'chapter',\r\n number: parseInt(child.getAttribute('number') || '0', 10),\r\n content: [],\r\n footnotes: [],\r\n };\r\n this._currentChapter = chapter;\r\n\r\n for (let content of this.iterateChapterContent(\r\n chapter,\r\n iterator\r\n )) {\r\n chapter.content.push(content);\r\n }\r\n\r\n yield chapter;\r\n } else if (child.nodeName === 'para') {\r\n const style = child.getAttribute('style');\r\n if (\r\n style === 's1' ||\r\n style === 's2' ||\r\n style === 's3' ||\r\n style === 's4'\r\n ) {\r\n yield {\r\n type: 'heading',\r\n content: child.textContent ? [child.textContent] : [],\r\n };\r\n }\r\n }\r\n }\r\n }\r\n\r\n *iterateChapterContent(\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): IterableIterator<ChapterContent> {\r\n while (true) {\r\n const { done, value: element } = nodes.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (!(element instanceof Element)) {\r\n continue;\r\n }\r\n\r\n if (element.nodeName === 'chapter') {\r\n break;\r\n } else if (element.nodeName === 'para') {\r\n const style = element.getAttribute('style');\r\n if (\r\n style === 's1' ||\r\n style === 's2' ||\r\n style === 's3' ||\r\n style === 's4'\r\n ) {\r\n yield {\r\n type: 'heading',\r\n content: element.textContent\r\n ? [element.textContent]\r\n : [],\r\n };\r\n } else if (style === 'b') {\r\n yield {\r\n type: 'line_break',\r\n };\r\n } else if (style === 'd') {\r\n yield* this.parseHebrewSubtitle(element, chapter, nodes);\r\n }\r\n } else if (element.nodeName === 'verse') {\r\n if (element.hasAttribute('eid')) {\r\n continue;\r\n }\r\n\r\n yield this.parseVerse(element, chapter, nodes);\r\n }\r\n }\r\n }\r\n\r\n *iterateVerseContent(\r\n chapter: Chapter,\r\n verse: Verse,\r\n nodes: RewindableIterator<Node>,\r\n previousVerse?: Verse | null\r\n ): IterableIterator<\r\n | string\r\n | FootnoteReference\r\n | Text\r\n | InlineLineBreak\r\n | AnnotatedContent<string | Text>\r\n > {\r\n let lastParent: Element | null = null;\r\n while (true) {\r\n const { done, value: node } = nodes.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (node.nodeName === 'verse') {\r\n if (!(node instanceof Element) || !node.hasAttribute('eid')) {\r\n nodes.rewind(1);\r\n }\r\n break;\r\n }\r\n\r\n const parent = node.parentElement!;\r\n let poem: number | null = null;\r\n let descriptive: boolean | null = null;\r\n\r\n if (parent.nodeName === 'para') {\r\n const style = parent.getAttribute('style');\r\n if (\r\n style === 'q1' ||\r\n style === 'q2' ||\r\n style === 'q3' ||\r\n style === 'q4'\r\n ) {\r\n poem =\r\n style === 'q1'\r\n ? 1\r\n : style === 'q2'\r\n ? 2\r\n : style === 'q3'\r\n ? 3\r\n : 4;\r\n\r\n // Send explicit line breaks\r\n // if we are in a new paragraph but the previous paragraph had the same poem style\r\n if (parent.previousElementSibling?.nodeName === 'para') {\r\n const previousStyle =\r\n parent.previousElementSibling?.getAttribute(\r\n 'style'\r\n );\r\n if (previousStyle === style && lastParent !== parent) {\r\n lastParent = parent;\r\n\r\n const firstChild = parent.firstElementChild;\r\n const startsWithVerse =\r\n firstChild?.nodeName === 'verse' &&\r\n !firstChild.hasAttribute('eid') &&\r\n parseInt(\r\n firstChild.getAttribute('number') || '0',\r\n 10\r\n ) === verse.number;\r\n\r\n if (\r\n startsWithVerse &&\r\n previousVerse &&\r\n previousVerse.number !== verse.number\r\n ) {\r\n addOrJoin(previousVerse.content, {\r\n lineBreak: true,\r\n });\r\n } else {\r\n yield {\r\n lineBreak: true,\r\n };\r\n }\r\n }\r\n }\r\n } else if (style === 'd') {\r\n descriptive = true;\r\n }\r\n }\r\n\r\n for (let value of this.iterateNodeTextContent(\r\n nodes,\r\n node,\r\n chapter,\r\n verse\r\n )) {\r\n // Word annotations travel alongside the content that they apply\r\n // to. Unwrap them so that the content is formatted exactly the\r\n // same as content that has no annotations, then re-attach them.\r\n const words = isAnnotatedContent(value) ? value.words : null;\r\n const content = isAnnotatedContent(value)\r\n ? (value.annotatedContent as string | Text)\r\n : value;\r\n\r\n let result:\r\n | string\r\n | InlineLineBreak\r\n | InlineHeading\r\n | FootnoteReference\r\n | Text = content;\r\n\r\n if (poem !== null || descriptive !== null) {\r\n if (typeof content === 'string') {\r\n let text: Text = {\r\n text: content,\r\n };\r\n\r\n if (poem !== null) {\r\n text.poem = poem;\r\n }\r\n\r\n if (descriptive !== null) {\r\n text.descriptive = true;\r\n }\r\n\r\n result = text;\r\n } else {\r\n let text:\r\n | InlineLineBreak\r\n | InlineHeading\r\n | FootnoteReference\r\n | Text = {\r\n ...content,\r\n };\r\n\r\n if ('text' in text) {\r\n if (poem !== null) {\r\n text.poem = poem;\r\n }\r\n\r\n if (descriptive !== null) {\r\n text.descriptive = true;\r\n }\r\n }\r\n result = text;\r\n }\r\n }\r\n\r\n if (words) {\r\n yield {\r\n annotatedContent: result as string | Text,\r\n words,\r\n };\r\n } else {\r\n yield result;\r\n }\r\n }\r\n }\r\n }\r\n\r\n parseVerse(\r\n element: Element,\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): Verse {\r\n const verse: Verse = {\r\n type: 'verse',\r\n number: parseInt(element.getAttribute('number') || '0', 10),\r\n content: [],\r\n };\r\n\r\n if (this._currentChapter && this._lastVerse) {\r\n if (this._currentChapter.number === chapter.number) {\r\n // We're parsing the same chapter as the last one\r\n const delta = verse.number - this._lastVerse.number;\r\n if (delta > 1) {\r\n // Delta is greater than 1, so we might have missed some verses\r\n for (\r\n let v = this._lastVerse.number + 1;\r\n v < verse.number;\r\n v++\r\n ) {\r\n let isExpected = false;\r\n if (this._bookId) {\r\n const missingVerse = `${this._bookId} ${chapter.number}:${v}`;\r\n if (KNOWN_SKIPPED_VERSES.has(missingVerse)) {\r\n isExpected = true;\r\n }\r\n }\r\n\r\n if (!isExpected) {\r\n this._messages.push({\r\n type: 'warning',\r\n message: `Verse ${this._bookId ?? '(null)'} ${chapter.number}:${v} is missing.`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n const previousVerse =\r\n this._currentChapter?.number === chapter.number\r\n ? this._lastVerse\r\n : null;\r\n\r\n const words: ChapterWord[] = [];\r\n\r\n for (let content of this.iterateVerseContent(\r\n chapter,\r\n verse,\r\n nodes,\r\n previousVerse\r\n )) {\r\n if (isAnnotatedContent(content)) {\r\n addOrJoin(\r\n verse.content,\r\n content.annotatedContent,\r\n content.words,\r\n words\r\n );\r\n } else {\r\n addOrJoin(verse.content, content);\r\n }\r\n }\r\n\r\n trimContent(verse.content, words);\r\n addChapterWords(chapter, verse.number, words);\r\n this._lastVerse = verse;\r\n return verse;\r\n }\r\n\r\n *parseHebrewSubtitle(\r\n para: Element,\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): IterableIterator<HebrewSubtitle | Verse> {\r\n const subtitle: HebrewSubtitle = {\r\n type: 'hebrew_subtitle',\r\n content: [],\r\n };\r\n\r\n for (let content of this.iterateHebrewSubtitleContent(\r\n para,\r\n chapter,\r\n nodes\r\n )) {\r\n if (typeof content === 'object' && 'number' in content) {\r\n yield content;\r\n continue;\r\n }\r\n\r\n // Hebrew subtitles aren't verses, so there is nowhere to key word\r\n // annotations by. Keep the content and drop the annotations.\r\n addOrJoin(\r\n subtitle.content,\r\n isAnnotatedContent(content) ? content.annotatedContent : content\r\n );\r\n }\r\n\r\n trimContent(subtitle.content);\r\n if (subtitle.content.length > 0) {\r\n yield subtitle;\r\n }\r\n }\r\n\r\n *iterateHebrewSubtitleContent(\r\n element: Element,\r\n chapter: Chapter,\r\n nodes: RewindableIterator<Node>\r\n ): IterableIterator<\r\n | Verse\r\n | string\r\n | Text\r\n | FootnoteReference\r\n | InlineLineBreak\r\n | AnnotatedContent<string | Text>\r\n > {\r\n while (true) {\r\n const { done, value: node } = nodes.next();\r\n if (done) {\r\n break;\r\n }\r\n\r\n if (!isParent(node, element)) {\r\n nodes.rewind(1);\r\n break;\r\n }\r\n\r\n if (node instanceof Element && node.nodeName === 'verse') {\r\n yield this.parseVerse(node, chapter, nodes);\r\n } else {\r\n yield* this.iterateNodeTextContent(nodes, node, chapter);\r\n }\r\n }\r\n }\r\n\r\n *iterateNodeTextContent(\r\n nodes: RewindableIterator<Node>,\r\n node: Node,\r\n chapter: Chapter,\r\n verse?: Verse\r\n ): IterableIterator<\r\n | string\r\n | Text\r\n | FootnoteReference\r\n | InlineLineBreak\r\n | AnnotatedContent<string | Text>\r\n > {\r\n if (node instanceof Element && node.nodeName === 'note') {\r\n yield* this.iterateNote(nodes, node, chapter, verse);\r\n } else if (node instanceof Element && node.nodeName === 'char') {\r\n yield* this.iterateChar(nodes, node);\r\n } else if (\r\n node instanceof Element &&\r\n node.nodeName === 'para' &&\r\n node.getAttribute('style') === 'b'\r\n ) {\r\n for (let _ of children(nodes, node)) {\r\n // iterate through all the children to prevent iterating over them multiple times\r\n }\r\n yield {\r\n lineBreak: true,\r\n };\r\n } else if (node.nodeType === NodeType.Text) {\r\n yield node.textContent || '';\r\n }\r\n }\r\n\r\n *iterateCharContent(char: Element): IterableIterator<string | Text> {\r\n const style = char.getAttribute('style');\r\n const text = trimText(char.textContent || '');\r\n if (style === 'wj') {\r\n yield {\r\n text,\r\n wordsOfJesus: true,\r\n };\r\n } else {\r\n yield text;\r\n }\r\n }\r\n\r\n *iterateNote(\r\n nodes: RewindableIterator<Node>,\r\n node: Element,\r\n chapter: Chapter,\r\n verse?: Verse\r\n ): IterableIterator<FootnoteReference> {\r\n const style = node.getAttribute('style');\r\n if (style === 'f') {\r\n const verseReferenceRegex = /^[0-9]{1,3}:[0-9]{1,3}/;\r\n\r\n let text = '';\r\n for (let child of children(nodes, node)) {\r\n if (child.nodeType === NodeType.Text) {\r\n text += child.textContent || '';\r\n }\r\n }\r\n\r\n text = text.trim();\r\n if (verseReferenceRegex.test(text)) {\r\n text = text.replace(verseReferenceRegex, '').trim();\r\n }\r\n\r\n const note: Footnote = {\r\n noteId: this._noteCounter++,\r\n caller: node.getAttribute('caller') || null,\r\n text,\r\n reference: {\r\n chapter: chapter.number,\r\n verse: verse?.number ?? 0,\r\n },\r\n };\r\n\r\n chapter.footnotes.push(note);\r\n\r\n yield {\r\n noteId: note.noteId,\r\n };\r\n } else {\r\n for (let _ of children(nodes, node)) {\r\n // iterate through all the children\r\n // so that we don't end up with duplicates\r\n }\r\n }\r\n }\r\n\r\n *iterateChar(\r\n nodes: RewindableIterator<Node>,\r\n node: Element\r\n ): IterableIterator<string | Text | AnnotatedContent<string | Text>> {\r\n const style = node.getAttribute('style');\r\n let text = '';\r\n\r\n // The text of every word element that is contained in this element,\r\n // including the element itself. Words can be nested inside other chars\r\n // (words of Jesus, in particular), so the ranges are tracked while the\r\n // text is being accumulated.\r\n const words: WordRange[] = [];\r\n let currentWord: Element | null = null;\r\n let currentAnnotations: WordAnnotations | null = null;\r\n let currentStart = 0;\r\n\r\n const endCurrentWord = () => {\r\n if (currentAnnotations) {\r\n const range = trimWordRange(text, currentStart, text.length);\r\n if (range) {\r\n words.push({\r\n ...range,\r\n annotations: currentAnnotations,\r\n });\r\n }\r\n }\r\n currentWord = null;\r\n currentAnnotations = null;\r\n };\r\n\r\n for (let char of children(nodes, node)) {\r\n if (char.nodeType !== NodeType.Text) {\r\n continue;\r\n }\r\n\r\n const word = wordElementFor(char, node);\r\n if (word !== currentWord) {\r\n endCurrentWord();\r\n currentWord = word;\r\n currentStart = text.length;\r\n currentAnnotations = word ? readWordAnnotations(word) : null;\r\n }\r\n\r\n text += char.textContent || '';\r\n }\r\n endCurrentWord();\r\n\r\n const content: string | Text =\r\n style === 'wj'\r\n ? {\r\n text,\r\n wordsOfJesus: true,\r\n }\r\n : text;\r\n\r\n if (words.length > 0) {\r\n yield {\r\n annotatedContent: content,\r\n words,\r\n };\r\n } else {\r\n yield content;\r\n }\r\n\r\n // if (!parentChar(node) && !parentNote(node)) {\r\n // yield *iterateCharContent(node);\r\n // }\r\n }\r\n}\r\n\r\n// Taken from https://github.com/gracious-tech/fetch/blob/1576cc4eafb32bf347a09332094cf17c2231c90c/converters/usx-to-json/src/elements.ts#L16\r\nconst ignoredParaStyles = new Set([\r\n // <para> Identification [exclude all] - Running headings & table of contents\r\n 'ide', // See https://github.com/schierlm/BibleMultiConverter/issues/67\r\n 'rem', // Remarks (valid in schema though missed in docs)\r\n 'h',\r\n 'h1',\r\n 'h2',\r\n 'h3',\r\n 'h4',\r\n 'toc1',\r\n 'toc2',\r\n 'toc3',\r\n 'toca1',\r\n 'toca2',\r\n 'toca3',\r\n\r\n /* <para> Introductions [exclude all] - Introductionary (non-biblical) content\r\n Which might be helpful in a printed book, but intro material in apps is usually bad UX,\r\n and users that really care can research a translations methodology themselves\r\n */\r\n 'imt',\r\n 'imt1',\r\n 'imt2',\r\n 'imt3',\r\n 'imt4',\r\n 'is',\r\n 'is1',\r\n 'is2',\r\n 'is3',\r\n 'is4',\r\n 'ip',\r\n 'ipi',\r\n 'im',\r\n 'imi',\r\n 'ipq',\r\n 'imq',\r\n 'ipr',\r\n 'iq',\r\n 'iq1',\r\n 'iq2',\r\n 'iq3',\r\n 'iq4',\r\n 'ib',\r\n 'ili',\r\n 'ili1',\r\n 'ili2',\r\n 'ili3',\r\n 'ili4',\r\n 'iot',\r\n 'io',\r\n 'io1',\r\n 'io2',\r\n 'io3',\r\n 'io4',\r\n 'iex',\r\n 'imte',\r\n 'ie',\r\n\r\n /* <para> Headings [exclude some] - Exclude book & chapter headings but keep section headings\r\n Not excluded: ms# | mr | s# | sr | d | sp | sd#\r\n */\r\n 'mt',\r\n 'mt1',\r\n 'mt2',\r\n 'mt3',\r\n 'mt4',\r\n 'mte',\r\n 'mte1',\r\n 'mte2',\r\n 'mte3',\r\n 'mte4',\r\n 'cl',\r\n 'cd', // Non-biblical chapter summary, more than heading\r\n 'r', // Parallels to be provided by external data\r\n]);\r\n\r\nfunction* iterateCharContent(char: Element): IterableIterator<string | Text> {\r\n const style = char.getAttribute('style');\r\n const text = trimText(char.textContent || '');\r\n if (style === 'wj') {\r\n yield {\r\n text,\r\n wordsOfJesus: true,\r\n };\r\n } else {\r\n yield text;\r\n }\r\n}\r\n\r\nfunction trimText(text: string): string {\r\n return text.replace(/\\s+/g, ' ');\r\n}\r\n\r\n/**\r\n * Gets the word element that the given node is contained in, or null if it\r\n * isn't contained in one. Never looks above the given root element.\r\n * @param node The node to find the word element for.\r\n * @param root The element to stop the search at.\r\n */\r\nfunction wordElementFor(node: Node, root: Element): Element | null {\r\n let element: Element | null = node.parentElement;\r\n while (element) {\r\n if (\r\n element.nodeName === 'char' &&\r\n element.getAttribute('style') === 'w'\r\n ) {\r\n return element;\r\n }\r\n if (element === root) {\r\n return null;\r\n }\r\n element = element.parentElement;\r\n }\r\n return null;\r\n}\r\n\r\nfunction trimContent<T extends string | unknown>(\r\n content: T[],\r\n words?: ChapterWord[] | null\r\n): T[] {\r\n for (let i = 0; i < content.length; i++) {\r\n const value = content[i];\r\n let text: string | null = null;\r\n\r\n if (typeof value === 'string') {\r\n const collapsed = collapseWhitespaceMap(value as string);\r\n content[i] = collapsed.text as T;\r\n text = collapsed.text;\r\n if (words) {\r\n remapChapterWords(words, i, collapsed.map);\r\n }\r\n } else if (isVerseText(value)) {\r\n const collapsed = collapseWhitespaceMap(value.text);\r\n value.text = collapsed.text;\r\n text = collapsed.text;\r\n if (words) {\r\n remapChapterWords(words, i, collapsed.map);\r\n }\r\n }\r\n\r\n if (text === '') {\r\n content.splice(i, 1);\r\n if (words) {\r\n removeChapterWordsForContent(words, i);\r\n }\r\n i--;\r\n continue;\r\n }\r\n }\r\n return content;\r\n}\r\n\r\nfunction addOrJoin(\r\n array: (string | unknown)[],\r\n value: string | unknown,\r\n ranges?: WordRange[] | null,\r\n words?: ChapterWord[] | null\r\n) {\r\n // Where the value ended up in the array, and how far into that item's text\r\n // it starts. Both are needed to anchor the value's word annotations.\r\n let contentIndex: number;\r\n let offset: number;\r\n\r\n if (array.length === 0) {\r\n contentIndex = 0;\r\n offset = 0;\r\n array.push(value);\r\n } else {\r\n const last = array[array.length - 1];\r\n if (typeof last === 'string' && typeof value === 'string') {\r\n contentIndex = array.length - 1;\r\n offset = last.length;\r\n array[array.length - 1] = last + value;\r\n } else if (\r\n isVerseText(last) &&\r\n isVerseText(value) &&\r\n hasSameFormatting(last, value)\r\n ) {\r\n contentIndex = array.length - 1;\r\n offset = last.text.length;\r\n last.text += value.text;\r\n } else {\r\n contentIndex = array.length;\r\n offset = 0;\r\n array.push(value);\r\n }\r\n }\r\n\r\n if (ranges && words) {\r\n for (let range of ranges) {\r\n words.push({\r\n contentIndex,\r\n start: offset + range.start,\r\n end: offset + range.end,\r\n ...range.annotations,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction isVerseText(value: unknown): value is Text {\r\n return typeof value === 'object' && value !== null && 'text' in value;\r\n}\r\n\r\nfunction hasSameFormatting(a: Text, b: Text): boolean {\r\n return a.poem === b.poem && a.wordsOfJesus === b.wordsOfJesus;\r\n}\r\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA,uBAKO;AACP,mBAWO;AACP,mBAAqC;AAErC,IAAK,WAAL,kBAAKA,cAAL;AACI,EAAAA,oBAAA,UAAO,KAAP;AADC,SAAAA;AAAA,GAAA;AAQE,MAAM,iBAAiB;AAKvB,MAAM,UAAU;AAAA,EACX;AAAA,EACA,eAAuB;AAAA,EACvB,YAA4B,CAAC;AAAA,EAC7B,aAA2B;AAAA,EAC3B,kBAAkC;AAAA,EAClC,UAAyB;AAAA,EAEjC,YAAY,WAAsB;AAC9B,SAAK,aAAa;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,MAAM,KAAwB;AACjC,SAAK,eAAe;AACpB,SAAK,YAAY,CAAC;AAClB,SAAK,aAAa;AAClB,SAAK,kBAAkB;AACvB,SAAK,UAAU;AACf,UAAM,SAAS,KAAK;AACpB,UAAM,MAAM,OAAO,gBAAgB,KAAK,iBAAiB;AACzD,UAAM,aAAa,IAAI;AAEvB,QAAI,OAAkB;AAAA,MAClB,MAAM;AAAA,MACN,SAAS,CAAC;AAAA,IACd;AAEA,UAAM,cAAc,WAAW,cAAc,YAAY;AAEzD,QAAI,CAAC,aAAa;AACd,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACtE;AAEA,UAAM,WAAW,YAAY,aAAa,MAAM,KAAK;AAErD,QAAI,CAAC,UAAU;AACX,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AAEA,SAAK,UAAU,KAAK,KAAK;AAEzB,UAAM,SAAS,WAAW,cAAc,iBAAiB;AACzD,QAAI,QAAQ;AACR,WAAK,SAAS,OAAO,eAAe;AAAA,IACxC;AAEA,UAAM,SAAS,WAAW;AAAA,MACtB;AAAA,IACJ;AAIA,QAAI,OAAO,SAAS,GAAG;AACnB,WAAK,QAAQ,CAAC,GAAG,MAAM,EAClB,IAAI,CAAC,MAAM,EAAE,WAAW,EACxB,OAAO,CAAC,MAAM,CAAC,EACf,KAAK,GAAG;AAAA,IACjB;AAEA,aAAS,WAAW,KAAK,mBAAmB,UAAU,GAAG;AACrD,WAAK,QAAQ,KAAK,OAAO;AAAA,IAC7B;AAEA,QAAI,KAAK,UAAU,SAAS,GAAG;AAC3B,WAAK,gBAAgB,KAAK,UAAU,MAAM;AAAA,IAC9C;AAEA,WAAO;AAAA,EACX;AAAA,EAEA,CAAC,mBACG,YACkC;AAClC,UAAM,eAAW,6BAAW,UAAU;AACtC,WAAO,MAAM;AACT,YAAM,EAAE,MAAM,OAAO,MAAM,IAAI,SAAS,KAAK;AAC7C,UAAI,MAAM;AACN;AAAA,MACJ;AAEA,UAAI,EAAE,iBAAiB,UAAU;AAC7B;AAAA,MACJ;AAEA,UAAI,MAAM,aAAa,WAAW;AAC9B,YAAI,MAAM,aAAa,KAAK,GAAG;AAC3B;AAAA,QACJ;AAEA,cAAM,UAAmB;AAAA,UACrB,MAAM;AAAA,UACN,QAAQ,SAAS,MAAM,aAAa,QAAQ,KAAK,KAAK,EAAE;AAAA,UACxD,SAAS,CAAC;AAAA,UACV,WAAW,CAAC;AAAA,QAChB;AACA,aAAK,kBAAkB;AAEvB,iBAAS,WAAW,KAAK;AAAA,UACrB;AAAA,UACA;AAAA,QACJ,GAAG;AACC,kBAAQ,QAAQ,KAAK,OAAO;AAAA,QAChC;AAEA,cAAM;AAAA,MACV,WAAW,MAAM,aAAa,QAAQ;AAClC,cAAM,QAAQ,MAAM,aAAa,OAAO;AACxC,YACI,UAAU,QACV,UAAU,QACV,UAAU,QACV,UAAU,MACZ;AACE,gBAAM;AAAA,YACF,MAAM;AAAA,YACN,SAAS,MAAM,cAAc,CAAC,MAAM,WAAW,IAAI,CAAC;AAAA,UACxD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,CAAC,sBACG,SACA,OACgC;AAChC,WAAO,MAAM;AACT,YAAM,EAAE,MAAM,OAAO,QAAQ,IAAI,MAAM,KAAK;AAC5C,UAAI,MAAM;AACN;AAAA,MACJ;AAEA,UAAI,EAAE,mBAAmB,UAAU;AAC/B;AAAA,MACJ;AAEA,UAAI,QAAQ,aAAa,WAAW;AAChC;AAAA,MACJ,WAAW,QAAQ,aAAa,QAAQ;AACpC,cAAM,QAAQ,QAAQ,aAAa,OAAO;AAC1C,YACI,UAAU,QACV,UAAU,QACV,UAAU,QACV,UAAU,MACZ;AACE,gBAAM;AAAA,YACF,MAAM;AAAA,YACN,SAAS,QAAQ,cACX,CAAC,QAAQ,WAAW,IACpB,CAAC;AAAA,UACX;AAAA,QACJ,WAAW,UAAU,KAAK;AACtB,gBAAM;AAAA,YACF,MAAM;AAAA,UACV;AAAA,QACJ,WAAW,UAAU,KAAK;AACtB,iBAAO,KAAK,oBAAoB,SAAS,SAAS,KAAK;AAAA,QAC3D;AAAA,MACJ,WAAW,QAAQ,aAAa,SAAS;AACrC,YAAI,QAAQ,aAAa,KAAK,GAAG;AAC7B;AAAA,QACJ;AAEA,cAAM,KAAK,WAAW,SAAS,SAAS,KAAK;AAAA,MACjD;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,CAAC,oBACG,SACA,OACA,OACA,eAOF;AACE,QAAI,aAA6B;AACjC,WAAO,MAAM;AACT,YAAM,EAAE,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK;AACzC,UAAI,MAAM;AACN;AAAA,MACJ;AAEA,UAAI,KAAK,aAAa,SAAS;AAC3B,YAAI,EAAE,gBAAgB,YAAY,CAAC,KAAK,aAAa,KAAK,GAAG;AACzD,gBAAM,OAAO,CAAC;AAAA,QAClB;AACA;AAAA,MACJ;AAEA,YAAM,SAAS,KAAK;AACpB,UAAI,OAAsB;AAC1B,UAAI,cAA8B;AAElC,UAAI,OAAO,aAAa,QAAQ;AAC5B,cAAM,QAAQ,OAAO,aAAa,OAAO;AACzC,YACI,UAAU,QACV,UAAU,QACV,UAAU,QACV,UAAU,MACZ;AACE,iBACI,UAAU,OACJ,IACA,UAAU,OACR,IACA,UAAU,OACR,IACA;AAId,cAAI,OAAO,wBAAwB,aAAa,QAAQ;AACpD,kBAAM,gBACF,OAAO,wBAAwB;AAAA,cAC3B;AAAA,YACJ;AACJ,gBAAI,kBAAkB,SAAS,eAAe,QAAQ;AAClD,2BAAa;AAEb,oBAAM,aAAa,OAAO;AAC1B,oBAAM,kBACF,YAAY,aAAa,WACzB,CAAC,WAAW,aAAa,KAAK,KAC9B;AAAA,gBACI,WAAW,aAAa,QAAQ,KAAK;AAAA,gBACrC;AAAA,cACJ,MAAM,MAAM;AAEhB,kBACI,mBACA,iBACA,cAAc,WAAW,MAAM,QACjC;AACE,0BAAU,cAAc,SAAS;AAAA,kBAC7B,WAAW;AAAA,gBACf,CAAC;AAAA,cACL,OAAO;AACH,sBAAM;AAAA,kBACF,WAAW;AAAA,gBACf;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,WAAW,UAAU,KAAK;AACtB,wBAAc;AAAA,QAClB;AAAA,MACJ;AAEA,eAAS,SAAS,KAAK;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ,GAAG;AAIC,cAAM,YAAQ,iCAAmB,KAAK,IAAI,MAAM,QAAQ;AACxD,cAAM,cAAU,iCAAmB,KAAK,IACjC,MAAM,mBACP;AAEN,YAAI,SAKS;AAEb,YAAI,SAAS,QAAQ,gBAAgB,MAAM;AACvC,cAAI,OAAO,YAAY,UAAU;AAC7B,gBAAI,OAAa;AAAA,cACb,MAAM;AAAA,YACV;AAEA,gBAAI,SAAS,MAAM;AACf,mBAAK,OAAO;AAAA,YAChB;AAEA,gBAAI,gBAAgB,MAAM;AACtB,mBAAK,cAAc;AAAA,YACvB;AAEA,qBAAS;AAAA,UACb,OAAO;AACH,gBAAI,OAIS;AAAA,cACT,GAAG;AAAA,YACP;AAEA,gBAAI,UAAU,MAAM;AAChB,kBAAI,SAAS,MAAM;AACf,qBAAK,OAAO;AAAA,cAChB;AAEA,kBAAI,gBAAgB,MAAM;AACtB,qBAAK,cAAc;AAAA,cACvB;AAAA,YACJ;AACA,qBAAS;AAAA,UACb;AAAA,QACJ;AAEA,YAAI,OAAO;AACP,gBAAM;AAAA,YACF,kBAAkB;AAAA,YAClB;AAAA,UACJ;AAAA,QACJ,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,WACI,SACA,SACA,OACK;AACL,UAAM,QAAe;AAAA,MACjB,MAAM;AAAA,MACN,QAAQ,SAAS,QAAQ,aAAa,QAAQ,KAAK,KAAK,EAAE;AAAA,MAC1D,SAAS,CAAC;AAAA,IACd;AAEA,QAAI,KAAK,mBAAmB,KAAK,YAAY;AACzC,UAAI,KAAK,gBAAgB,WAAW,QAAQ,QAAQ;AAEhD,cAAM,QAAQ,MAAM,SAAS,KAAK,WAAW;AAC7C,YAAI,QAAQ,GAAG;AAEX,mBACQ,IAAI,KAAK,WAAW,SAAS,GACjC,IAAI,MAAM,QACV,KACF;AACE,gBAAI,aAAa;AACjB,gBAAI,KAAK,SAAS;AACd,oBAAM,eAAe,GAAG,KAAK,OAAO,IAAI,QAAQ,MAAM,IAAI,CAAC;AAC3D,kBAAI,kCAAqB,IAAI,YAAY,GAAG;AACxC,6BAAa;AAAA,cACjB;AAAA,YACJ;AAEA,gBAAI,CAAC,YAAY;AACb,mBAAK,UAAU,KAAK;AAAA,gBAChB,MAAM;AAAA,gBACN,SAAS,SAAS,KAAK,WAAW,QAAQ,IAAI,QAAQ,MAAM,IAAI,CAAC;AAAA,cACrE,CAAC;AAAA,YACL;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AACA,UAAM,gBACF,KAAK,iBAAiB,WAAW,QAAQ,SACnC,KAAK,aACL;AAEV,UAAM,QAAuB,CAAC;AAE9B,aAAS,WAAW,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ,GAAG;AACC,cAAI,iCAAmB,OAAO,GAAG;AAC7B;AAAA,UACI,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,QACJ;AAAA,MACJ,OAAO;AACH,kBAAU,MAAM,SAAS,OAAO;AAAA,MACpC;AAAA,IACJ;AAEA,gBAAY,MAAM,SAAS,KAAK;AAChC,sCAAgB,SAAS,MAAM,QAAQ,KAAK;AAC5C,SAAK,aAAa;AAClB,WAAO;AAAA,EACX;AAAA,EAEA,CAAC,oBACG,MACA,SACA,OACwC;AACxC,UAAM,WAA2B;AAAA,MAC7B,MAAM;AAAA,MACN,SAAS,CAAC;AAAA,IACd;AAEA,aAAS,WAAW,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACJ,GAAG;AACC,UAAI,OAAO,YAAY,YAAY,YAAY,SAAS;AACpD,cAAM;AACN;AAAA,MACJ;AAIA;AAAA,QACI,SAAS;AAAA,YACT,iCAAmB,OAAO,IAAI,QAAQ,mBAAmB;AAAA,MAC7D;AAAA,IACJ;AAEA,gBAAY,SAAS,OAAO;AAC5B,QAAI,SAAS,QAAQ,SAAS,GAAG;AAC7B,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,CAAC,6BACG,SACA,SACA,OAQF;AACE,WAAO,MAAM;AACT,YAAM,EAAE,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK;AACzC,UAAI,MAAM;AACN;AAAA,MACJ;AAEA,UAAI,KAAC,2BAAS,MAAM,OAAO,GAAG;AAC1B,cAAM,OAAO,CAAC;AACd;AAAA,MACJ;AAEA,UAAI,gBAAgB,WAAW,KAAK,aAAa,SAAS;AACtD,cAAM,KAAK,WAAW,MAAM,SAAS,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO,KAAK,uBAAuB,OAAO,MAAM,OAAO;AAAA,MAC3D;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,CAAC,uBACG,OACA,MACA,SACA,OAOF;AACE,QAAI,gBAAgB,WAAW,KAAK,aAAa,QAAQ;AACrD,aAAO,KAAK,YAAY,OAAO,MAAM,SAAS,KAAK;AAAA,IACvD,WAAW,gBAAgB,WAAW,KAAK,aAAa,QAAQ;AAC5D,aAAO,KAAK,YAAY,OAAO,IAAI;AAAA,IACvC,WACI,gBAAgB,WAChB,KAAK,aAAa,UAClB,KAAK,aAAa,OAAO,MAAM,KACjC;AACE,eAAS,SAAK,2BAAS,OAAO,IAAI,GAAG;AAAA,MAErC;AACA,YAAM;AAAA,QACF,WAAW;AAAA,MACf;AAAA,IACJ,WAAW,KAAK,aAAa,cAAe;AACxC,YAAM,KAAK,eAAe;AAAA,IAC9B;AAAA,EACJ;AAAA,EAEA,CAAC,mBAAmB,MAAgD;AAChE,UAAM,QAAQ,KAAK,aAAa,OAAO;AACvC,UAAM,OAAO,SAAS,KAAK,eAAe,EAAE;AAC5C,QAAI,UAAU,MAAM;AAChB,YAAM;AAAA,QACF;AAAA,QACA,cAAc;AAAA,MAClB;AAAA,IACJ,OAAO;AACH,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,CAAC,YACG,OACA,MACA,SACA,OACmC;AACnC,UAAM,QAAQ,KAAK,aAAa,OAAO;AACvC,QAAI,UAAU,KAAK;AACf,YAAM,sBAAsB;AAE5B,UAAI,OAAO;AACX,eAAS,aAAS,2BAAS,OAAO,IAAI,GAAG;AACrC,YAAI,MAAM,aAAa,cAAe;AAClC,kBAAQ,MAAM,eAAe;AAAA,QACjC;AAAA,MACJ;AAEA,aAAO,KAAK,KAAK;AACjB,UAAI,oBAAoB,KAAK,IAAI,GAAG;AAChC,eAAO,KAAK,QAAQ,qBAAqB,EAAE,EAAE,KAAK;AAAA,MACtD;AAEA,YAAM,OAAiB;AAAA,QACnB,QAAQ,KAAK;AAAA,QACb,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAAA,QACvC;AAAA,QACA,WAAW;AAAA,UACP,SAAS,QAAQ;AAAA,UACjB,OAAO,OAAO,UAAU;AAAA,QAC5B;AAAA,MACJ;AAEA,cAAQ,UAAU,KAAK,IAAI;AAE3B,YAAM;AAAA,QACF,QAAQ,KAAK;AAAA,MACjB;AAAA,IACJ,OAAO;AACH,eAAS,SAAK,2BAAS,OAAO,IAAI,GAAG;AAAA,MAGrC;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,CAAC,YACG,OACA,MACiE;AACjE,UAAM,QAAQ,KAAK,aAAa,OAAO;AACvC,QAAI,OAAO;AAMX,UAAM,QAAqB,CAAC;AAC5B,QAAI,cAA8B;AAClC,QAAI,qBAA6C;AACjD,QAAI,eAAe;AAEnB,UAAM,iBAAiB,MAAM;AACzB,UAAI,oBAAoB;AACpB,cAAM,YAAQ,4BAAc,MAAM,cAAc,KAAK,MAAM;AAC3D,YAAI,OAAO;AACP,gBAAM,KAAK;AAAA,YACP,GAAG;AAAA,YACH,aAAa;AAAA,UACjB,CAAC;AAAA,QACL;AAAA,MACJ;AACA,oBAAc;AACd,2BAAqB;AAAA,IACzB;AAEA,aAAS,YAAQ,2BAAS,OAAO,IAAI,GAAG;AACpC,UAAI,KAAK,aAAa,cAAe;AACjC;AAAA,MACJ;AAEA,YAAM,OAAO,eAAe,MAAM,IAAI;AACtC,UAAI,SAAS,aAAa;AACtB,uBAAe;AACf,sBAAc;AACd,uBAAe,KAAK;AACpB,6BAAqB,WAAO,kCAAoB,IAAI,IAAI;AAAA,MAC5D;AAEA,cAAQ,KAAK,eAAe;AAAA,IAChC;AACA,mBAAe;AAEf,UAAM,UACF,UAAU,OACJ;AAAA,MACI;AAAA,MACA,cAAc;AAAA,IAClB,IACA;AAEV,QAAI,MAAM,SAAS,GAAG;AAClB,YAAM;AAAA,QACF,kBAAkB;AAAA,QAClB;AAAA,MACJ;AAAA,IACJ,OAAO;AACH,YAAM;AAAA,IACV;AAAA,EAKJ;AACJ;AAGA,MAAM,oBAAoB,oBAAI,IAAI;AAAA;AAAA,EAE9B;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACJ,CAAC;AAED,UAAU,mBAAmB,MAAgD;AACzE,QAAM,QAAQ,KAAK,aAAa,OAAO;AACvC,QAAM,OAAO,SAAS,KAAK,eAAe,EAAE;AAC5C,MAAI,UAAU,MAAM;AAChB,UAAM;AAAA,MACF;AAAA,MACA,cAAc;AAAA,IAClB;AAAA,EACJ,OAAO;AACH,UAAM;AAAA,EACV;AACJ;AAEA,SAAS,SAAS,MAAsB;AACpC,SAAO,KAAK,QAAQ,QAAQ,GAAG;AACnC;AAQA,SAAS,eAAe,MAAY,MAA+B;AAC/D,MAAI,UAA0B,KAAK;AACnC,SAAO,SAAS;AACZ,QACI,QAAQ,aAAa,UACrB,QAAQ,aAAa,OAAO,MAAM,KACpC;AACE,aAAO;AAAA,IACX;AACA,QAAI,YAAY,MAAM;AAClB,aAAO;AAAA,IACX;AACA,cAAU,QAAQ;AAAA,EACtB;AACA,SAAO;AACX;AAEA,SAAS,YACL,SACA,OACG;AACH,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,UAAM,QAAQ,QAAQ,CAAC;AACvB,QAAI,OAAsB;AAE1B,QAAI,OAAO,UAAU,UAAU;AAC3B,YAAM,gBAAY,oCAAsB,KAAe;AACvD,cAAQ,CAAC,IAAI,UAAU;AACvB,aAAO,UAAU;AACjB,UAAI,OAAO;AACP,4CAAkB,OAAO,GAAG,UAAU,GAAG;AAAA,MAC7C;AAAA,IACJ,WAAW,YAAY,KAAK,GAAG;AAC3B,YAAM,gBAAY,oCAAsB,MAAM,IAAI;AAClD,YAAM,OAAO,UAAU;AACvB,aAAO,UAAU;AACjB,UAAI,OAAO;AACP,4CAAkB,OAAO,GAAG,UAAU,GAAG;AAAA,MAC7C;AAAA,IACJ;AAEA,QAAI,SAAS,IAAI;AACb,cAAQ,OAAO,GAAG,CAAC;AACnB,UAAI,OAAO;AACP,uDAA6B,OAAO,CAAC;AAAA,MACzC;AACA;AACA;AAAA,IACJ;AAAA,EACJ;AACA,SAAO;AACX;AAEA,SAAS,UACL,OACA,OACA,QACA,OACF;AAGE,MAAI;AACJ,MAAI;AAEJ,MAAI,MAAM,WAAW,GAAG;AACpB,mBAAe;AACf,aAAS;AACT,UAAM,KAAK,KAAK;AAAA,EACpB,OAAO;AACH,UAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,QAAI,OAAO,SAAS,YAAY,OAAO,UAAU,UAAU;AACvD,qBAAe,MAAM,SAAS;AAC9B,eAAS,KAAK;AACd,YAAM,MAAM,SAAS,CAAC,IAAI,OAAO;AAAA,IACrC,WACI,YAAY,IAAI,KAChB,YAAY,KAAK,KACjB,kBAAkB,MAAM,KAAK,GAC/B;AACE,qBAAe,MAAM,SAAS;AAC9B,eAAS,KAAK,KAAK;AACnB,WAAK,QAAQ,MAAM;AAAA,IACvB,OAAO;AACH,qBAAe,MAAM;AACrB,eAAS;AACT,YAAM,KAAK,KAAK;AAAA,IACpB;AAAA,EACJ;AAEA,MAAI,UAAU,OAAO;AACjB,aAAS,SAAS,QAAQ;AACtB,YAAM,KAAK;AAAA,QACP;AAAA,QACA,OAAO,SAAS,MAAM;AAAA,QACtB,KAAK,SAAS,MAAM;AAAA,QACpB,GAAG,MAAM;AAAA,MACb,CAAC;AAAA,IACL;AAAA,EACJ;AACJ;AAEA,SAAS,YAAY,OAA+B;AAChD,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU;AACpE;AAEA,SAAS,kBAAkB,GAAS,GAAkB;AAClD,SAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE;AACrD;",
6
6
  "names": ["NodeType"]
7
7
  }
@@ -0,0 +1,187 @@
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 words_exports = {};
20
+ __export(words_exports, {
21
+ addChapterWords: () => addChapterWords,
22
+ collapseWhitespaceMap: () => collapseWhitespaceMap,
23
+ isAnnotatedContent: () => isAnnotatedContent,
24
+ readWordAnnotations: () => readWordAnnotations,
25
+ remapChapterWords: () => remapChapterWords,
26
+ removeChapterWordsForContent: () => removeChapterWordsForContent,
27
+ trimWordRange: () => trimWordRange
28
+ });
29
+ module.exports = __toCommonJS(words_exports);
30
+ function isAnnotatedContent(value) {
31
+ return typeof value === "object" && value !== null && "annotatedContent" in value;
32
+ }
33
+ const WHITESPACE = /\s/;
34
+ const OCCURRENCE_ATTRIBUTES = ["x-occurrence", "x-occurence"];
35
+ const OCCURRENCES_ATTRIBUTES = ["x-occurrences", "x-occurences"];
36
+ function readWordAnnotations(element) {
37
+ const annotations = {};
38
+ let hasAnnotations = false;
39
+ const strong = element.getAttribute("strong");
40
+ if (strong) {
41
+ const strongs = strong.split(",").map((s) => s.trim()).filter((s) => !!s);
42
+ if (strongs.length > 0) {
43
+ annotations.strongs = strongs;
44
+ hasAnnotations = true;
45
+ }
46
+ }
47
+ const lemma = element.getAttribute("lemma");
48
+ if (lemma) {
49
+ annotations.lemma = lemma;
50
+ hasAnnotations = true;
51
+ }
52
+ const morph = element.getAttribute("x-morph");
53
+ if (morph) {
54
+ annotations.morph = morph;
55
+ hasAnnotations = true;
56
+ }
57
+ const srcloc = element.getAttribute("srcloc");
58
+ if (srcloc) {
59
+ annotations.srcloc = srcloc;
60
+ hasAnnotations = true;
61
+ }
62
+ const occurrence = parseCount(
63
+ firstAttribute(element, OCCURRENCE_ATTRIBUTES)
64
+ );
65
+ if (occurrence !== null) {
66
+ annotations.occurrence = occurrence;
67
+ hasAnnotations = true;
68
+ }
69
+ const occurrences = parseCount(
70
+ firstAttribute(element, OCCURRENCES_ATTRIBUTES)
71
+ );
72
+ if (occurrences !== null) {
73
+ annotations.occurrences = occurrences;
74
+ hasAnnotations = true;
75
+ }
76
+ return hasAnnotations ? annotations : null;
77
+ }
78
+ function firstAttribute(element, names) {
79
+ for (let name of names) {
80
+ const value = element.getAttribute(name);
81
+ if (value) {
82
+ return value;
83
+ }
84
+ }
85
+ return null;
86
+ }
87
+ function parseCount(value) {
88
+ if (!value) {
89
+ return null;
90
+ }
91
+ const parsed = parseInt(value, 10);
92
+ return Number.isNaN(parsed) ? null : parsed;
93
+ }
94
+ function trimWordRange(text, start, end) {
95
+ let s = Math.max(0, start);
96
+ let e = Math.min(text.length, end);
97
+ while (s < e && WHITESPACE.test(text[s])) {
98
+ s++;
99
+ }
100
+ while (e > s && WHITESPACE.test(text[e - 1])) {
101
+ e--;
102
+ }
103
+ return e > s ? { start: s, end: e } : null;
104
+ }
105
+ function collapseWhitespaceMap(text) {
106
+ const map = new Array(text.length + 1);
107
+ let collapsed = "";
108
+ let i = 0;
109
+ while (i < text.length) {
110
+ if (WHITESPACE.test(text[i])) {
111
+ const position = collapsed.length;
112
+ while (i < text.length && WHITESPACE.test(text[i])) {
113
+ map[i] = position;
114
+ i++;
115
+ }
116
+ collapsed += " ";
117
+ } else {
118
+ map[i] = collapsed.length;
119
+ collapsed += text[i];
120
+ i++;
121
+ }
122
+ }
123
+ map[text.length] = collapsed.length;
124
+ const trimmed = collapsed.trim();
125
+ const offset = collapsed.length - collapsed.trimStart().length;
126
+ for (let j = 0; j < map.length; j++) {
127
+ map[j] = Math.min(Math.max(map[j] - offset, 0), trimmed.length);
128
+ }
129
+ return {
130
+ text: trimmed,
131
+ map
132
+ };
133
+ }
134
+ function remapChapterWords(words, contentIndex, map) {
135
+ for (let i = 0; i < words.length; i++) {
136
+ const word = words[i];
137
+ if (word.contentIndex !== contentIndex) {
138
+ continue;
139
+ }
140
+ const start = map[Math.min(word.start, map.length - 1)];
141
+ const end = map[Math.min(word.end, map.length - 1)];
142
+ if (end > start) {
143
+ word.start = start;
144
+ word.end = end;
145
+ } else {
146
+ words.splice(i, 1);
147
+ i--;
148
+ }
149
+ }
150
+ }
151
+ function removeChapterWordsForContent(words, contentIndex) {
152
+ for (let i = 0; i < words.length; i++) {
153
+ const word = words[i];
154
+ if (word.contentIndex === contentIndex) {
155
+ words.splice(i, 1);
156
+ i--;
157
+ } else if (word.contentIndex > contentIndex) {
158
+ word.contentIndex--;
159
+ }
160
+ }
161
+ }
162
+ function addChapterWords(chapter, verseNumber, words) {
163
+ if (words.length === 0) {
164
+ return;
165
+ }
166
+ if (!chapter.words) {
167
+ chapter.words = {};
168
+ }
169
+ const key = verseNumber.toString();
170
+ const existing = chapter.words[key];
171
+ if (existing) {
172
+ existing.push(...words);
173
+ } else {
174
+ chapter.words[key] = words;
175
+ }
176
+ }
177
+ // Annotate the CommonJS export names for ESM import in node:
178
+ 0 && (module.exports = {
179
+ addChapterWords,
180
+ collapseWhitespaceMap,
181
+ isAnnotatedContent,
182
+ readWordAnnotations,
183
+ remapChapterWords,
184
+ removeChapterWordsForContent,
185
+ trimWordRange
186
+ });
187
+ //# sourceMappingURL=words.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../parser/words.ts"],
4
+ "sourcesContent": ["import { Chapter, ChapterWord } from './types.js';\r\n\r\n/**\r\n * The annotations that a source associated with a word, without any information\r\n * about where the word is located.\r\n */\r\nexport type WordAnnotations = Omit<\r\n ChapterWord,\r\n 'contentIndex' | 'start' | 'end'\r\n>;\r\n\r\n/**\r\n * Defines an interface that represents a range of characters within a single\r\n * piece of text, along with the annotations that apply to it.\r\n */\r\nexport interface WordRange {\r\n /**\r\n * The index of the first character of the word.\r\n */\r\n start: number;\r\n\r\n /**\r\n * The index after the last character of the word.\r\n */\r\n end: number;\r\n\r\n /**\r\n * The annotations that apply to the word.\r\n */\r\n annotations: WordAnnotations;\r\n}\r\n\r\n/**\r\n * Defines an interface that pairs a piece of verse content with the word\r\n * annotations that apply to it, so that the annotations can be passed along\r\n * with the content while it is being parsed.\r\n *\r\n * The ranges are relative to the text of the content, and are never included in\r\n * the final parse tree.\r\n */\r\nexport interface AnnotatedContent<T> {\r\n /**\r\n * The content that the annotations apply to.\r\n */\r\n annotatedContent: T;\r\n\r\n /**\r\n * The ranges of the content that are annotated.\r\n */\r\n words: WordRange[];\r\n}\r\n\r\n/**\r\n * Determines whether the given value is content that has word annotations\r\n * attached to it.\r\n * @param value The value to test.\r\n */\r\nexport function isAnnotatedContent(\r\n value: unknown\r\n): value is AnnotatedContent<unknown> {\r\n return (\r\n typeof value === 'object' &&\r\n value !== null &&\r\n 'annotatedContent' in value\r\n );\r\n}\r\n\r\nconst WHITESPACE = /\\s/;\r\n\r\n/**\r\n * The attributes that a word's occurrence number can be stored in.\r\n * The misspelled variants are common in real-world files.\r\n */\r\nconst OCCURRENCE_ATTRIBUTES = ['x-occurrence', 'x-occurence'];\r\nconst OCCURRENCES_ATTRIBUTES = ['x-occurrences', 'x-occurences'];\r\n\r\n/**\r\n * Reads the word annotations that are attached to the given element.\r\n * Returns null if the element doesn't have any recognized annotations.\r\n * @param element The element to read the annotations from.\r\n */\r\nexport function readWordAnnotations(element: Element): WordAnnotations | null {\r\n const annotations: WordAnnotations = {};\r\n let hasAnnotations = false;\r\n\r\n const strong = element.getAttribute('strong');\r\n if (strong) {\r\n const strongs = strong\r\n .split(',')\r\n .map((s) => s.trim())\r\n .filter((s) => !!s);\r\n\r\n if (strongs.length > 0) {\r\n annotations.strongs = strongs;\r\n hasAnnotations = true;\r\n }\r\n }\r\n\r\n const lemma = element.getAttribute('lemma');\r\n if (lemma) {\r\n annotations.lemma = lemma;\r\n hasAnnotations = true;\r\n }\r\n\r\n const morph = element.getAttribute('x-morph');\r\n if (morph) {\r\n annotations.morph = morph;\r\n hasAnnotations = true;\r\n }\r\n\r\n const srcloc = element.getAttribute('srcloc');\r\n if (srcloc) {\r\n annotations.srcloc = srcloc;\r\n hasAnnotations = true;\r\n }\r\n\r\n const occurrence = parseCount(\r\n firstAttribute(element, OCCURRENCE_ATTRIBUTES)\r\n );\r\n if (occurrence !== null) {\r\n annotations.occurrence = occurrence;\r\n hasAnnotations = true;\r\n }\r\n\r\n const occurrences = parseCount(\r\n firstAttribute(element, OCCURRENCES_ATTRIBUTES)\r\n );\r\n if (occurrences !== null) {\r\n annotations.occurrences = occurrences;\r\n hasAnnotations = true;\r\n }\r\n\r\n return hasAnnotations ? annotations : null;\r\n}\r\n\r\nfunction firstAttribute(element: Element, names: string[]): string | null {\r\n for (let name of names) {\r\n const value = element.getAttribute(name);\r\n if (value) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseCount(value: string | null): number | null {\r\n if (!value) {\r\n return null;\r\n }\r\n const parsed = parseInt(value, 10);\r\n return Number.isNaN(parsed) ? null : parsed;\r\n}\r\n\r\n/**\r\n * Shrinks the given range so that it doesn't include any leading or trailing\r\n * whitespace. Returns null if the range only contains whitespace.\r\n * @param text The text that the range is in.\r\n * @param start The index of the first character of the range.\r\n * @param end The index after the last character of the range.\r\n */\r\nexport function trimWordRange(\r\n text: string,\r\n start: number,\r\n end: number\r\n): { start: number; end: number } | null {\r\n let s = Math.max(0, start);\r\n let e = Math.min(text.length, end);\r\n\r\n while (s < e && WHITESPACE.test(text[s])) {\r\n s++;\r\n }\r\n while (e > s && WHITESPACE.test(text[e - 1])) {\r\n e--;\r\n }\r\n\r\n return e > s ? { start: s, end: e } : null;\r\n}\r\n\r\n/**\r\n * Collapses the whitespace in the given text in the same manner that the\r\n * parsers normalize text (each run of whitespace becomes a single space, and the\r\n * result is trimmed), and returns a map from the indexes in the given text to\r\n * the indexes in the returned text.\r\n *\r\n * The map contains an entry for every index in the given text, plus one for the\r\n * index just past the end of it, so that both ends of a range can be mapped.\r\n * @param text The text to collapse.\r\n */\r\nexport function collapseWhitespaceMap(text: string): {\r\n text: string;\r\n map: number[];\r\n} {\r\n const map = new Array<number>(text.length + 1);\r\n let collapsed = '';\r\n let i = 0;\r\n\r\n while (i < text.length) {\r\n if (WHITESPACE.test(text[i])) {\r\n // Every character of a whitespace run maps to the single space that\r\n // the run collapses into.\r\n const position = collapsed.length;\r\n while (i < text.length && WHITESPACE.test(text[i])) {\r\n map[i] = position;\r\n i++;\r\n }\r\n collapsed += ' ';\r\n } else {\r\n map[i] = collapsed.length;\r\n collapsed += text[i];\r\n i++;\r\n }\r\n }\r\n map[text.length] = collapsed.length;\r\n\r\n // Trimming can only remove the single space that a leading or trailing\r\n // whitespace run was collapsed into, so the whole map shifts by the number\r\n // of characters that were removed from the front.\r\n const trimmed = collapsed.trim();\r\n const offset = collapsed.length - collapsed.trimStart().length;\r\n\r\n for (let j = 0; j < map.length; j++) {\r\n map[j] = Math.min(Math.max(map[j] - offset, 0), trimmed.length);\r\n }\r\n\r\n return {\r\n text: trimmed,\r\n map,\r\n };\r\n}\r\n\r\n/**\r\n * Moves the words that apply to the given content item to the indexes that they\r\n * have after the item's text was collapsed with collapseWhitespaceMap().\r\n * Words that no longer cover any characters are removed.\r\n * @param words The words to remap.\r\n * @param contentIndex The index of the content item that was collapsed.\r\n * @param map The index map that collapseWhitespaceMap() returned.\r\n */\r\nexport function remapChapterWords(\r\n words: ChapterWord[],\r\n contentIndex: number,\r\n map: number[]\r\n): void {\r\n for (let i = 0; i < words.length; i++) {\r\n const word = words[i];\r\n if (word.contentIndex !== contentIndex) {\r\n continue;\r\n }\r\n\r\n const start = map[Math.min(word.start, map.length - 1)];\r\n const end = map[Math.min(word.end, map.length - 1)];\r\n\r\n if (end > start) {\r\n word.start = start;\r\n word.end = end;\r\n } else {\r\n words.splice(i, 1);\r\n i--;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Removes the words that apply to the given content item, and moves the words\r\n * that apply to later items back by one to account for the item being removed.\r\n * @param words The words to update.\r\n * @param contentIndex The index of the content item that was removed.\r\n */\r\nexport function removeChapterWordsForContent(\r\n words: ChapterWord[],\r\n contentIndex: number\r\n): void {\r\n for (let i = 0; i < words.length; i++) {\r\n const word = words[i];\r\n if (word.contentIndex === contentIndex) {\r\n words.splice(i, 1);\r\n i--;\r\n } else if (word.contentIndex > contentIndex) {\r\n word.contentIndex--;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Adds the given words to the chapter for the given verse number.\r\n * Does nothing if there are no words.\r\n * @param chapter The chapter to add the words to.\r\n * @param verseNumber The number of the verse that the words are in.\r\n * @param words The words to add.\r\n */\r\nexport function addChapterWords(\r\n chapter: Chapter,\r\n verseNumber: number,\r\n words: ChapterWord[]\r\n): void {\r\n if (words.length === 0) {\r\n return;\r\n }\r\n\r\n if (!chapter.words) {\r\n chapter.words = {};\r\n }\r\n\r\n const key = verseNumber.toString();\r\n const existing = chapter.words[key];\r\n\r\n if (existing) {\r\n existing.push(...words);\r\n } else {\r\n chapter.words[key] = words;\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }