@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
@@ -10,9 +10,18 @@ import {
10
10
  TranslationSchema,
11
11
  TranslationBookSchema,
12
12
  TranslationBookChapterSchema,
13
- CommentarySchema
13
+ ChapterWordSchema,
14
+ CommentarySchema,
15
+ SimpleChapterDataSchema,
16
+ SimpleChapterWordSchema,
17
+ SimpleCommentaryChapterDataSchema,
18
+ SimpleTranslationBookChapterSchema
14
19
  } from "./common-types.js";
15
- import "zod-openapi";
20
+ import {
21
+ simplifyChapter,
22
+ simplifyCommentaryChapter
23
+ } from "./simple.js";
24
+ import { BookIdSchema } from "../utils.js";
16
25
  export const ApiAvailableTranslationsSchema = z.object({
17
26
  /**
18
27
  * The list of translations.
@@ -170,6 +179,15 @@ export const ApiTranslationSchema = TranslationSchema.extend({
170
179
  */
171
180
  completeTranslationApiLink: z.string().optional().meta({
172
181
  description: "The API link for downloading the complete translation as a single JSON file. Relative to the API origin. Undefined if complete translation files are not available."
182
+ }),
183
+ /**
184
+ * The API link for downloading the complete translation as a single JSON file,
185
+ * using the simplified chapter format.
186
+ *
187
+ * Undefined if complete translation files are not available.
188
+ */
189
+ simpleCompleteTranslationApiLink: z.string().optional().meta({
190
+ description: "The API link for downloading the complete translation as a single JSON file, using the simplified chapter format. Relative to the API origin. Undefined if complete translation files are not available."
173
191
  })
174
192
  }).meta({
175
193
  id: "ApiTranslation",
@@ -192,6 +210,28 @@ export const ApiTranslationCompleteSchema = z.object({
192
210
  id: "ApiTranslationComplete",
193
211
  description: "Defines the complete translation download data. Maps to the /api/:translationId/complete.json endpoint."
194
212
  });
213
+ export const TranslationCompleteChapterSchema = TranslationBookChapterSchema.extend({
214
+ /**
215
+ * The number of verses that the chapter contains.
216
+ */
217
+ numberOfVerses: z.number().meta({
218
+ description: "The number of verses that the chapter contains."
219
+ })
220
+ }).meta({
221
+ id: "TranslationCompleteChapter",
222
+ description: "A chapter in the complete translation download."
223
+ });
224
+ export const SimpleTranslationCompleteChapterSchema = SimpleTranslationBookChapterSchema.extend({
225
+ /**
226
+ * The number of verses that the chapter contains.
227
+ */
228
+ numberOfVerses: z.number().meta({
229
+ description: "The number of verses that the chapter contains."
230
+ })
231
+ }).meta({
232
+ id: "SimpleTranslationCompleteChapter",
233
+ description: "A chapter in the complete translation download, using the simplified chapter format."
234
+ });
195
235
  export const ApiTranslationCompleteBookSchema = TranslationBookSchema.extend({
196
236
  /**
197
237
  * The number of chapters in the book.
@@ -208,13 +248,41 @@ export const ApiTranslationCompleteBookSchema = TranslationBookSchema.extend({
208
248
  /**
209
249
  * The complete list of chapters with all content.
210
250
  */
211
- chapters: z.array(TranslationBookChapterSchema).meta({
251
+ chapters: z.array(TranslationCompleteChapterSchema).meta({
212
252
  description: "The complete list of chapters with all content."
213
253
  })
214
254
  }).meta({
215
255
  id: "ApiTranslationCompleteBook",
216
256
  description: "A book in the complete translation download."
217
257
  });
258
+ export const ApiSimpleTranslationCompleteSchema = z.object({
259
+ /**
260
+ * The translation metadata.
261
+ */
262
+ translation: z.lazy(() => ApiTranslationSchema).meta({
263
+ description: "The translation metadata."
264
+ }),
265
+ /**
266
+ * The complete list of books with all their chapters.
267
+ */
268
+ books: z.array(z.lazy(() => ApiSimpleTranslationCompleteBookSchema)).meta({
269
+ description: "The complete list of books with all their chapters."
270
+ })
271
+ }).meta({
272
+ id: "ApiSimpleTranslationComplete",
273
+ description: "Defines the complete translation download data, using the simplified chapter format. Maps to the /api/:translationId/complete.simple.json endpoint."
274
+ });
275
+ export const ApiSimpleTranslationCompleteBookSchema = ApiTranslationCompleteBookSchema.extend({
276
+ /**
277
+ * The complete list of chapters with all content.
278
+ */
279
+ chapters: z.array(SimpleTranslationCompleteChapterSchema).meta({
280
+ description: "The complete list of chapters with all content."
281
+ })
282
+ }).meta({
283
+ id: "ApiSimpleTranslationCompleteBook",
284
+ description: "A book in the complete translation download, using the simplified chapter format."
285
+ });
218
286
  export const ApiCommentarySchema = CommentarySchema.extend({
219
287
  /**
220
288
  * The API link for the list of available books for this translation.
@@ -367,6 +435,42 @@ export const ApiCommentaryProfileSchema = CommentaryProfileSchema.extend({
367
435
  id: "ApiCommentaryProfile",
368
436
  description: "Defines an interface that contains information about a profile."
369
437
  });
438
+ export const TranslationChapterReferenceSchema = z.object({
439
+ translationId: z.string().meta({
440
+ description: "The ID of the translation that the chapter reference is for."
441
+ }),
442
+ book: BookIdSchema,
443
+ chapter: z.int().positive().meta({
444
+ description: "The chapter number of the chapter reference."
445
+ })
446
+ }).meta({
447
+ id: "TranslationChapterReference",
448
+ description: "Defines a reference to a chapter in a translation."
449
+ });
450
+ export const CommentaryChapterReferenceSchema = z.object({
451
+ commentaryId: z.string().meta({
452
+ description: "The ID of the commentary that the chapter reference is for."
453
+ }),
454
+ book: BookIdSchema,
455
+ chapter: z.int().positive().meta({
456
+ description: "The chapter number of the chapter reference."
457
+ })
458
+ }).meta({
459
+ id: "CommentaryChapterReference",
460
+ description: "Defines a reference to a chapter in a commentary."
461
+ });
462
+ export const DatasetChapterReferenceSchema = z.object({
463
+ datasetId: z.string().meta({
464
+ description: "The ID of the dataset that the chapter reference is for."
465
+ }),
466
+ book: BookIdSchema,
467
+ chapter: z.int().positive().meta({
468
+ description: "The chapter number of the chapter reference."
469
+ })
470
+ }).meta({
471
+ id: "DatasetChapterReference",
472
+ description: "Defines a reference to a chapter in a dataset."
473
+ });
370
474
  export const ApiTranslationBookSchema = TranslationBookSchema.extend({
371
475
  /**
372
476
  * The number of the first chapter in the book.
@@ -380,6 +484,10 @@ export const ApiTranslationBookSchema = TranslationBookSchema.extend({
380
484
  firstChapterApiLink: z.string().meta({
381
485
  description: "The link to the first chapter of the book."
382
486
  }),
487
+ /**
488
+ * The reference for the first chapter in the book.
489
+ */
490
+ firstChapterReference: TranslationChapterReferenceSchema,
383
491
  /**
384
492
  * The number of the last chapter in the book.
385
493
  */
@@ -392,6 +500,10 @@ export const ApiTranslationBookSchema = TranslationBookSchema.extend({
392
500
  lastChapterApiLink: z.string().meta({
393
501
  description: "The link to the last chapter of the book."
394
502
  }),
503
+ /**
504
+ * The reference for the last chapter in the book.
505
+ */
506
+ lastChapterReference: TranslationChapterReferenceSchema,
395
507
  /**
396
508
  * The number of chapters that the book contains.
397
509
  */
@@ -425,6 +537,12 @@ export const ApiCommentaryBookSchema = CommentaryBookSchema.extend({
425
537
  firstChapterApiLink: z.string().nullable().meta({
426
538
  description: "The link to the first chapter of the book. Null if the comentary book has no chapters."
427
539
  }),
540
+ /**
541
+ * The reference for the first chapter in the book.
542
+ */
543
+ firstChapterReference: CommentaryChapterReferenceSchema.nullable().meta({
544
+ description: "The reference for the first chapter in the book. Null if the comentary book has no chapters."
545
+ }),
428
546
  /**
429
547
  * The number of the last chapter in the book.
430
548
  *
@@ -441,6 +559,12 @@ export const ApiCommentaryBookSchema = CommentaryBookSchema.extend({
441
559
  lastChapterApiLink: z.string().nullable().meta({
442
560
  description: "The link to the last chapter of the book. Null if the comentary book has no chapters."
443
561
  }),
562
+ /**
563
+ * The reference for the last chapter in the book.
564
+ */
565
+ lastChapterReference: CommentaryChapterReferenceSchema.nullable().meta({
566
+ description: "The reference for the last chapter in the book. Null if the comentary book has no chapters."
567
+ }),
444
568
  /**
445
569
  * The number of chapters that the book contains.
446
570
  */
@@ -470,6 +594,10 @@ export const ApiDatasetBookSchema = DatasetBookSchema.extend({
470
594
  firstChapterApiLink: z.string().meta({
471
595
  description: "The link to the first chapter of the book."
472
596
  }),
597
+ /**
598
+ * The reference for the first chapter in the book.
599
+ */
600
+ firstChapterReference: DatasetChapterReferenceSchema,
473
601
  /**
474
602
  * The number of the last chapter in the book.
475
603
  */
@@ -482,6 +610,10 @@ export const ApiDatasetBookSchema = DatasetBookSchema.extend({
482
610
  lastChapterApiLink: z.string().meta({
483
611
  description: "The link to the last chapter of the book."
484
612
  }),
613
+ /**
614
+ * The reference for the last chapter in the book.
615
+ */
616
+ lastChapterReference: DatasetChapterReferenceSchema,
485
617
  /**
486
618
  * The number of chapters that the book contains.
487
619
  */
@@ -504,7 +636,10 @@ export const ApiDatasetBookSchema = DatasetBookSchema.extend({
504
636
  id: "ApiDatasetBook",
505
637
  description: "Defines a schema that contains information about a book in a dataset."
506
638
  });
507
- export const ApiTranslationBookChapterSchema = TranslationBookChapterSchema.extend({
639
+ const ApiTranslationBookChapterBaseSchema = TranslationBookChapterSchema.omit({
640
+ thisChapterWords: true
641
+ });
642
+ export const ApiTranslationBookChapterSchema = ApiTranslationBookChapterBaseSchema.extend({
508
643
  /**
509
644
  * The translation information for the book chapter.
510
645
  */
@@ -523,6 +658,10 @@ export const ApiTranslationBookChapterSchema = TranslationBookChapterSchema.exte
523
658
  thisChapterLink: z.string().meta({
524
659
  description: "The API link for this chapter. Relative to the API origin."
525
660
  }),
661
+ /**
662
+ * The reference for this chapter.
663
+ */
664
+ thisChapterReference: TranslationChapterReferenceSchema,
526
665
  /**
527
666
  * The link to the next chapter.
528
667
  * Null if this is the last chapter in the translation.
@@ -530,6 +669,15 @@ export const ApiTranslationBookChapterSchema = TranslationBookChapterSchema.exte
530
669
  nextChapterApiLink: z.string().nullable().meta({
531
670
  description: "The API link to the next chapter. Relative to the API origin. Null if this is the last chapter in the translation."
532
671
  }),
672
+ /**
673
+ * The reference for the next chapter.
674
+ * Null if this is the last chapter in the translation.
675
+ */
676
+ nextChapterReference: TranslationChapterReferenceSchema.nullable().meta(
677
+ {
678
+ description: "The reference for the next chapter. Null if this is the last chapter in the translation."
679
+ }
680
+ ),
533
681
  /**
534
682
  * The links to the audio versions for the next chapter.
535
683
  * Null if this is the last chapter in the translation.
@@ -537,6 +685,26 @@ export const ApiTranslationBookChapterSchema = TranslationBookChapterSchema.exte
537
685
  nextChapterAudioLinks: z.record(z.string(), z.string()).nullable().meta({
538
686
  description: "The links to the audio versions for the next chapter. Relative to the API origin. Null if this is the last chapter in the translation."
539
687
  }),
688
+ /**
689
+ * The links to the audio timings for different audio versions for the chapter.
690
+ */
691
+ thisChapterAudioTimings: z.record(z.string(), z.string()).meta({
692
+ description: "The links to the audio timings for different audio versions for the chapter. Relative to the API origin."
693
+ }),
694
+ /**
695
+ * The links to the audio timings for different audio versions for the next chapter.
696
+ * Null if this is the last chapter in the translation.
697
+ */
698
+ nextChapterAudioTimings: z.record(z.string(), z.string()).nullable().meta({
699
+ description: "The links to the audio timings for different audio versions for the next chapter. Relative to the API origin. Null if this is the last chapter in the translation."
700
+ }),
701
+ /**
702
+ * The links to the audio timings for different audio versions for the previous chapter.
703
+ * Null if this is the first chapter in the translation.
704
+ */
705
+ previousChapterAudioTimings: z.record(z.string(), z.string()).nullable().meta({
706
+ description: "The links to the audio timings for different audio versions for the previous chapter. Relative to the API origin. Null if this is the first chapter in the translation."
707
+ }),
540
708
  /**
541
709
  * The link to the previous chapter.
542
710
  * Null if this is the first chapter in the translation.
@@ -544,6 +712,13 @@ export const ApiTranslationBookChapterSchema = TranslationBookChapterSchema.exte
544
712
  previousChapterApiLink: z.string().nullable().meta({
545
713
  description: "The API link to the previous chapter. Relative to the API origin. Null if this is the first chapter in the translation."
546
714
  }),
715
+ /**
716
+ * The reference for the previous chapter.
717
+ * Null if this is the first chapter in the translation.
718
+ */
719
+ previousChapterReference: TranslationChapterReferenceSchema.nullable().meta({
720
+ description: "The reference for the previous chapter. Null if this is the first chapter in the translation."
721
+ }),
547
722
  /**
548
723
  * The links to the audio versions for the previous chapter.
549
724
  * Null if this is the first chapter in the translation.
@@ -551,16 +726,66 @@ export const ApiTranslationBookChapterSchema = TranslationBookChapterSchema.exte
551
726
  previousChapterAudioLinks: z.record(z.string(), z.string()).nullable().meta({
552
727
  description: "The links to the audio versions for the previous chapter. Relative to the API origin. Null if this is the first chapter in the translation."
553
728
  }),
729
+ /**
730
+ * The link to the word-level annotations for the chapter.
731
+ * Omitted if the chapter doesn't have any word-level annotations.
732
+ */
733
+ thisChapterWordsLink: z.string().optional().meta({
734
+ description: "The link to the word-level annotations for this chapter. Relative to the API origin. Omitted if the chapter doesn't have any word-level annotations."
735
+ }),
736
+ /**
737
+ * The link to the word-level annotations for the next chapter.
738
+ * Omitted if this is the last chapter in the translation, or if the next
739
+ * chapter doesn't have any word-level annotations.
740
+ */
741
+ nextChapterWordsLink: z.string().optional().meta({
742
+ description: "The link to the word-level annotations for the next chapter. Relative to the API origin. Omitted if this is the last chapter in the translation, or if the next chapter doesn't have any word-level annotations."
743
+ }),
744
+ /**
745
+ * The link to the word-level annotations for the previous chapter.
746
+ * Omitted if this is the first chapter in the translation, or if the
747
+ * previous chapter doesn't have any word-level annotations.
748
+ */
749
+ previousChapterWordsLink: z.string().optional().meta({
750
+ description: "The link to the word-level annotations for the previous chapter. Relative to the API origin. Omitted if this is the first chapter in the translation, or if the previous chapter doesn't have any word-level annotations."
751
+ }),
554
752
  /**
555
753
  * The number of verses that the chapter contains.
556
754
  */
557
755
  numberOfVerses: z.number().meta({
558
756
  description: "The number of verses that the chapter contains."
757
+ }),
758
+ /**
759
+ * The link to the simplified version of this chapter.
760
+ * Omitted if simplified chapters were not generated.
761
+ */
762
+ simpleChapterApiLink: z.string().optional().meta({
763
+ description: "The API link to the simplified version of this chapter. Relative to the API origin. Omitted if simplified chapters are not available."
559
764
  })
560
765
  }).meta({
561
766
  id: "ApiTranslationBookChapter",
562
767
  description: "Defines an interface that contains information about a book chapter in a translation."
563
768
  });
769
+ export const ApiSimpleTranslationBookChapterSchema = ApiTranslationBookChapterSchema.omit({
770
+ chapter: true,
771
+ simpleChapterApiLink: true
772
+ }).extend({
773
+ /**
774
+ * The simplified information for the chapter.
775
+ */
776
+ chapter: z.lazy(() => SimpleChapterDataSchema).meta({
777
+ description: "The simplified information for the chapter. Each verse contains a single text string, and the footnotes and formatting are represented by offsets into that string."
778
+ }),
779
+ /**
780
+ * The link to the regular version of this chapter.
781
+ */
782
+ fullChapterApiLink: z.string().meta({
783
+ description: "The API link to the regular (non-simplified) version of this chapter. Relative to the API origin."
784
+ })
785
+ }).meta({
786
+ id: "ApiSimpleTranslationBookChapter",
787
+ description: "Defines an interface that contains information about a book chapter in a translation, using the simplified chapter format."
788
+ });
564
789
  export const ApiCommentaryBookChapterSchema = CommentaryBookChapterSchema.extend({
565
790
  /**
566
791
  * The commentary information for the book chapter.
@@ -580,6 +805,7 @@ export const ApiCommentaryBookChapterSchema = CommentaryBookChapterSchema.extend
580
805
  thisChapterLink: z.string().meta({
581
806
  description: "The API link for this chapter. Relative to the API origin."
582
807
  }),
808
+ thisChapterReference: CommentaryChapterReferenceSchema,
583
809
  /**
584
810
  * The link to the next chapter.
585
811
  * Null if this is the last chapter in the translation.
@@ -587,6 +813,9 @@ export const ApiCommentaryBookChapterSchema = CommentaryBookChapterSchema.extend
587
813
  nextChapterApiLink: z.string().nullable().meta({
588
814
  description: "The API link to the next chapter. Relative to the API origin. Null if this is the last chapter in the commentary."
589
815
  }),
816
+ nextChapterReference: CommentaryChapterReferenceSchema.nullable().meta({
817
+ description: "The reference for the next chapter. Null if this is the last chapter in the commentary."
818
+ }),
590
819
  /**
591
820
  * The link to the previous chapter.
592
821
  * Null if this is the first chapter in the translation.
@@ -594,16 +823,46 @@ export const ApiCommentaryBookChapterSchema = CommentaryBookChapterSchema.extend
594
823
  previousChapterApiLink: z.string().nullable().meta({
595
824
  description: "The API link to the previous chapter. Relative to the API origin. Null if this is the first chapter in the commentary."
596
825
  }),
826
+ previousChapterReference: CommentaryChapterReferenceSchema.nullable().meta({
827
+ description: "The reference for the previous chapter. Null if this is the first chapter in the commentary."
828
+ }),
597
829
  /**
598
830
  * The number of verses that the chapter contains.
599
831
  */
600
832
  numberOfVerses: z.number().meta({
601
833
  description: "The number of verses that the chapter contains."
834
+ }),
835
+ /**
836
+ * The link to the simplified version of this chapter.
837
+ * Omitted if simplified chapters were not generated.
838
+ */
839
+ simpleChapterApiLink: z.string().optional().meta({
840
+ description: "The API link to the simplified version of this chapter. Relative to the API origin. Omitted if simplified chapters are not available."
602
841
  })
603
842
  }).meta({
604
843
  id: "ApiCommentaryBookChapter",
605
844
  description: "Defines a schema that contains information about a book chapter in a commentary."
606
845
  });
846
+ export const ApiSimpleCommentaryBookChapterSchema = ApiCommentaryBookChapterSchema.omit({
847
+ chapter: true,
848
+ simpleChapterApiLink: true
849
+ }).extend({
850
+ /**
851
+ * The simplified information for the chapter.
852
+ */
853
+ chapter: z.lazy(() => SimpleCommentaryChapterDataSchema).meta({
854
+ description: "The simplified information for the chapter. Each verse contains a single text string, and the footnotes and formatting are represented by offsets into that string."
855
+ }),
856
+ /**
857
+ * The link to the regular version of this chapter.
858
+ */
859
+ fullChapterApiLink: z.string().meta({
860
+ description: "The API link to the regular (non-simplified) version of this chapter. Relative to the API origin."
861
+ })
862
+ }).meta({
863
+ id: "ApiSimpleCommentaryBookChapter",
864
+ description: "Defines a schema that contains information about a book chapter in a commentary, using the simplified chapter format."
865
+ });
607
866
  export const ApiDatasetBookChapterSchema = DatasetBookChapterSchema.extend({
608
867
  /**
609
868
  * The dataset information for the book chapter.
@@ -623,6 +882,7 @@ export const ApiDatasetBookChapterSchema = DatasetBookChapterSchema.extend({
623
882
  thisChapterLink: z.string().meta({
624
883
  description: "The API link for this chapter. Relative to the API origin."
625
884
  }),
885
+ thisChapterReference: DatasetChapterReferenceSchema,
626
886
  /**
627
887
  * The link to the next chapter.
628
888
  * Null if this is the last chapter in the translation.
@@ -630,6 +890,9 @@ export const ApiDatasetBookChapterSchema = DatasetBookChapterSchema.extend({
630
890
  nextChapterApiLink: z.string().nullable().meta({
631
891
  description: "The API link to the next chapter. Relative to the API origin. Null if this is the last chapter in the dataset."
632
892
  }),
893
+ nextChapterReference: DatasetChapterReferenceSchema.nullable().meta({
894
+ description: "The reference for the next chapter. Null if this is the last chapter in the dataset."
895
+ }),
633
896
  /**
634
897
  * The link to the previous chapter.
635
898
  * Null if this is the first chapter in the translation.
@@ -637,6 +900,9 @@ export const ApiDatasetBookChapterSchema = DatasetBookChapterSchema.extend({
637
900
  previousChapterApiLink: z.string().nullable().meta({
638
901
  description: "The API link to the previous chapter. Relative to the API origin. Null if this is the first chapter in the dataset."
639
902
  }),
903
+ previousChapterReference: DatasetChapterReferenceSchema.nullable().meta({
904
+ description: "The reference for the previous chapter. Null if this is the first chapter in the dataset."
905
+ }),
640
906
  /**
641
907
  * The number of verses that the chapter contains.
642
908
  */
@@ -673,6 +939,169 @@ export const ApiTranslationBookChapterAudioSchema = z.object({
673
939
  description: "The original URL of the audio."
674
940
  })
675
941
  });
942
+ export const ApiTranslationBookChapterAudioTimingsSchema = z.object({
943
+ /**
944
+ * The ID of the translation.
945
+ */
946
+ translationId: z.string().meta({
947
+ description: "The ID of the translation."
948
+ }),
949
+ /**
950
+ * The ID of the book.
951
+ */
952
+ bookId: z.string().meta({
953
+ description: "The ID of the book."
954
+ }),
955
+ /**
956
+ * The number of the chapter.
957
+ */
958
+ chapterNumber: z.number().meta({
959
+ description: "The number of the chapter."
960
+ }),
961
+ /**
962
+ * The reader for the chapter.
963
+ */
964
+ reader: z.string().meta({
965
+ description: "The reader for the chapter."
966
+ }),
967
+ /**
968
+ * The link to the audio for these timings.
969
+ */
970
+ audioLink: z.string().meta({
971
+ description: "The link to the audio for these timings."
972
+ }),
973
+ /**
974
+ * The link to the information for this chapter.
975
+ */
976
+ thisChapterLink: z.string().meta({
977
+ description: "The link to the information for this chapter."
978
+ }),
979
+ /**
980
+ * The link to the information for the next chapter.
981
+ * Null if this is the last chapter in the translation.
982
+ */
983
+ nextChapterLink: z.string().nullable().meta({
984
+ description: "The link to the information for the next chapter. Null if this is the last chapter in the translation."
985
+ }),
986
+ /**
987
+ * The link to the information for the previous chapter.
988
+ * Null if this is the first chapter in the translation.
989
+ */
990
+ previousChapterLink: z.string().nullable().meta({
991
+ description: "The link to the information for the previous chapter. Null if this is the first chapter in the translation."
992
+ }),
993
+ /**
994
+ * The link to this audio timings file.
995
+ */
996
+ thisChapterAudioTimingsLink: z.string().meta({
997
+ description: "The link to this audio timings file."
998
+ }),
999
+ /**
1000
+ * The link to the timings for the next chapter.
1001
+ * Null if this is the last chapter in the translation.
1002
+ */
1003
+ nextChapterAudioTimingsLink: z.string().nullable().meta({
1004
+ description: "The link to the timings for the next chapter. Null if this is the last chapter in the translation."
1005
+ }),
1006
+ /**
1007
+ * The link to the timings for the previous chapter.
1008
+ * Null if this is the first chapter in the translation.
1009
+ */
1010
+ previousChapterAudioTimingsLink: z.string().nullable().meta({
1011
+ description: "The link to the timings for the previous chapter. Null if this is the first chapter in the translation."
1012
+ }),
1013
+ /**
1014
+ * The times in seconds at which each verse starts, in order.
1015
+ */
1016
+ verses: z.array(z.number()).meta({
1017
+ description: "The times in seconds at which each verse starts, in order. The first number (index 0) is the time in the recording at which the first verse starts."
1018
+ })
1019
+ }).meta({
1020
+ id: "ApiTranslationBookChapterAudioTimings",
1021
+ description: "Defines an interface that contains the audio timings for a book chapter, for a specific reader."
1022
+ });
1023
+ export const ApiTranslationBookChapterWordsSchema = z.object({
1024
+ /**
1025
+ * The ID of the translation.
1026
+ */
1027
+ translationId: z.string().meta({
1028
+ description: "The ID of the translation."
1029
+ }),
1030
+ /**
1031
+ * The ID of the book.
1032
+ */
1033
+ bookId: z.string().meta({
1034
+ description: "The ID of the book."
1035
+ }),
1036
+ /**
1037
+ * The number of the chapter.
1038
+ */
1039
+ chapterNumber: z.number().meta({
1040
+ description: "The number of the chapter."
1041
+ }),
1042
+ /**
1043
+ * The link to the information for this chapter.
1044
+ */
1045
+ thisChapterLink: z.string().meta({
1046
+ description: "The link to the information for this chapter."
1047
+ }),
1048
+ /**
1049
+ * The link to the information for the next chapter.
1050
+ * Null if this is the last chapter in the translation.
1051
+ */
1052
+ nextChapterLink: z.string().nullable().meta({
1053
+ description: "The link to the information for the next chapter. Null if this is the last chapter in the translation."
1054
+ }),
1055
+ /**
1056
+ * The link to the information for the previous chapter.
1057
+ * Null if this is the first chapter in the translation.
1058
+ */
1059
+ previousChapterLink: z.string().nullable().meta({
1060
+ description: "The link to the information for the previous chapter. Null if this is the first chapter in the translation."
1061
+ }),
1062
+ /**
1063
+ * The link to this words file.
1064
+ */
1065
+ thisChapterWordsLink: z.string().meta({
1066
+ description: "The link to this words file."
1067
+ }),
1068
+ /**
1069
+ * The link to the words for the next chapter.
1070
+ * Null if this is the last chapter in the translation, or if the next chapter
1071
+ * doesn't have any word-level annotations.
1072
+ */
1073
+ nextChapterWordsLink: z.string().nullable().meta({
1074
+ description: "The link to the words for the next chapter. Null if this is the last chapter in the translation, or if the next chapter doesn't have any word-level annotations."
1075
+ }),
1076
+ /**
1077
+ * The link to the words for the previous chapter.
1078
+ * Null if this is the first chapter in the translation, or if the previous
1079
+ * chapter doesn't have any word-level annotations.
1080
+ */
1081
+ previousChapterWordsLink: z.string().nullable().meta({
1082
+ description: "The link to the words for the previous chapter. Null if this is the first chapter in the translation, or if the previous chapter doesn't have any word-level annotations."
1083
+ }),
1084
+ /**
1085
+ * The annotated words for each verse in the chapter.
1086
+ */
1087
+ verses: z.record(z.string(), z.array(z.lazy(() => ChapterWordSchema))).meta({
1088
+ description: "The annotated words for each verse in the chapter, keyed by verse number. Each list is in the order that the words occur in the verse."
1089
+ })
1090
+ }).meta({
1091
+ id: "ApiTranslationBookChapterWords",
1092
+ description: "Defines an interface that contains the word-level annotations for a book chapter."
1093
+ });
1094
+ export const ApiSimpleTranslationBookChapterWordsSchema = ApiTranslationBookChapterWordsSchema.extend({
1095
+ /**
1096
+ * The annotated words for each verse in the chapter.
1097
+ */
1098
+ verses: z.record(z.string(), z.array(z.lazy(() => SimpleChapterWordSchema))).meta({
1099
+ description: "The annotated words for each verse in the chapter, keyed by verse number. Each list is in the order that the words occur in the verse. The offsets are into the text of the simplified verse."
1100
+ })
1101
+ }).meta({
1102
+ id: "ApiSimpleTranslationBookChapterWords",
1103
+ description: "Defines an interface that contains the word-level annotations for a book chapter, with their offsets remapped onto the text of each simplified verse."
1104
+ });
676
1105
  export const ApiCommentaryProfileContentSchema = z.object({
677
1106
  /**
678
1107
  * The commentary information for the profile.
@@ -696,6 +1125,7 @@ export const ApiCommentaryProfileContentSchema = z.object({
696
1125
  export function generateApiForDataset(dataset, options = {}) {
697
1126
  const { useCommonName, pathPrefix } = options;
698
1127
  const apiPathPrefix = pathPrefix ? pathPrefix : "";
1128
+ const generateSimpleChapterFiles = !!options.generateSimpleChapterFiles;
699
1129
  let api = {
700
1130
  availableTranslations: {
701
1131
  translations: []
@@ -703,7 +1133,10 @@ export function generateApiForDataset(dataset, options = {}) {
703
1133
  translationBooks: [],
704
1134
  translationBookChapters: [],
705
1135
  translationBookChapterAudio: [],
1136
+ translationBookChapterAudioTimings: [],
1137
+ translationBookChapterWords: [],
706
1138
  translationComplete: [],
1139
+ simpleTranslationComplete: [],
707
1140
  availableCommentaries: {
708
1141
  commentaries: []
709
1142
  },
@@ -713,6 +1146,11 @@ export function generateApiForDataset(dataset, options = {}) {
713
1146
  commentaryProfileContents: [],
714
1147
  pathPrefix: apiPathPrefix
715
1148
  };
1149
+ if (generateSimpleChapterFiles) {
1150
+ api.simpleTranslationBookChapters = [];
1151
+ api.simpleTranslationBookChapterWords = [];
1152
+ api.simpleCommentaryBookChapters = [];
1153
+ }
716
1154
  const getNativeName = options.getNativeName;
717
1155
  const getEnglishName = options.getEnglishName;
718
1156
  for (let { books, ...translation } of dataset.translations) {
@@ -733,6 +1171,11 @@ export function generateApiForDataset(dataset, options = {}) {
733
1171
  apiPathPrefix
734
1172
  ),
735
1173
  completeTranslationApiLink: options.generateCompleteTranslationFiles ? completeTranslationApiLink(translation.id, apiPathPrefix) : void 0,
1174
+ simpleCompleteTranslationApiLink: options.generateCompleteTranslationFiles ? completeTranslationApiLink(
1175
+ translation.id,
1176
+ apiPathPrefix,
1177
+ SIMPLE_JSON_EXTENSION
1178
+ ) : void 0,
736
1179
  numberOfBooks,
737
1180
  totalNumberOfChapters: 0,
738
1181
  totalNumberOfVerses: 0,
@@ -747,6 +1190,9 @@ export function generateApiForDataset(dataset, options = {}) {
747
1190
  books: []
748
1191
  };
749
1192
  let translationChapters = [];
1193
+ let pendingAudioTimings = [];
1194
+ let rawAudioTimingsByChapter = /* @__PURE__ */ new Map();
1195
+ let rawWordsByChapter = /* @__PURE__ */ new Map();
750
1196
  for (let { chapters, ...book } of books) {
751
1197
  const firstChapterNumber = chapters[0]?.chapter.number;
752
1198
  const lastChapterNumber = chapters[chapters.length - 1]?.chapter.number;
@@ -760,6 +1206,11 @@ export function generateApiForDataset(dataset, options = {}) {
760
1206
  "json",
761
1207
  apiPathPrefix
762
1208
  ),
1209
+ firstChapterReference: {
1210
+ translationId: translation.id,
1211
+ book: book.id,
1212
+ chapter: firstChapterNumber
1213
+ },
763
1214
  lastChapterNumber,
764
1215
  lastChapterApiLink: bookChapterApiLink(
765
1216
  translation.id,
@@ -768,11 +1219,22 @@ export function generateApiForDataset(dataset, options = {}) {
768
1219
  "json",
769
1220
  apiPathPrefix
770
1221
  ),
1222
+ lastChapterReference: {
1223
+ translationId: translation.id,
1224
+ book: book.id,
1225
+ chapter: lastChapterNumber
1226
+ },
771
1227
  numberOfChapters: chapters.length,
772
1228
  totalNumberOfVerses: 0
773
1229
  };
774
- for (let { chapter, thisChapterAudioLinks } of chapters) {
1230
+ for (let {
1231
+ chapter,
1232
+ thisChapterAudioLinks,
1233
+ thisChapterAudioTimings,
1234
+ thisChapterWords
1235
+ } of chapters) {
775
1236
  const audio = {};
1237
+ const audioTimings = {};
776
1238
  const apiBookChapter = {
777
1239
  translation: apiTranslation,
778
1240
  book: apiBook,
@@ -784,12 +1246,29 @@ export function generateApiForDataset(dataset, options = {}) {
784
1246
  "json",
785
1247
  apiPathPrefix
786
1248
  ),
1249
+ thisChapterReference: {
1250
+ translationId: translation.id,
1251
+ book: book.id,
1252
+ chapter: chapter.number
1253
+ },
787
1254
  thisChapterAudioLinks: audio,
788
1255
  nextChapterApiLink: null,
1256
+ nextChapterReference: null,
789
1257
  nextChapterAudioLinks: null,
790
1258
  previousChapterApiLink: null,
1259
+ previousChapterReference: null,
791
1260
  previousChapterAudioLinks: null,
792
- numberOfVerses: 0
1261
+ thisChapterAudioTimings: audioTimings,
1262
+ nextChapterAudioTimings: null,
1263
+ previousChapterAudioTimings: null,
1264
+ numberOfVerses: 0,
1265
+ simpleChapterApiLink: generateSimpleChapterFiles ? bookChapterApiLink(
1266
+ translation.id,
1267
+ getBookLink(book),
1268
+ chapter.number,
1269
+ SIMPLE_JSON_EXTENSION,
1270
+ apiPathPrefix
1271
+ ) : void 0
793
1272
  };
794
1273
  for (let reader in thisChapterAudioLinks) {
795
1274
  if (options.generateAudioFiles) {
@@ -810,6 +1289,34 @@ export function generateApiForDataset(dataset, options = {}) {
810
1289
  audio[reader] = thisChapterAudioLinks[reader];
811
1290
  }
812
1291
  }
1292
+ rawAudioTimingsByChapter.set(
1293
+ apiBookChapter,
1294
+ thisChapterAudioTimings
1295
+ );
1296
+ if (thisChapterWords) {
1297
+ apiBookChapter.thisChapterWordsLink = bookChapterWordsApiLink(
1298
+ translation.id,
1299
+ getBookLink(book),
1300
+ chapter.number,
1301
+ apiPathPrefix
1302
+ );
1303
+ rawWordsByChapter.set(apiBookChapter, thisChapterWords);
1304
+ }
1305
+ for (let reader in thisChapterAudioTimings) {
1306
+ const verses = thisChapterAudioTimings[reader];
1307
+ audioTimings[reader] = bookChapterAudioTimingsApiLink(
1308
+ translation.id,
1309
+ getBookLink(book),
1310
+ chapter.number,
1311
+ reader,
1312
+ apiPathPrefix
1313
+ );
1314
+ pendingAudioTimings.push({
1315
+ reader,
1316
+ verses,
1317
+ apiBookChapter
1318
+ });
1319
+ }
813
1320
  for (let c of chapter.content) {
814
1321
  if (c.type === "verse") {
815
1322
  apiBookChapter.numberOfVerses++;
@@ -835,54 +1342,226 @@ export function generateApiForDataset(dataset, options = {}) {
835
1342
  }
836
1343
  }
837
1344
  for (let i = 0; i < translationChapters.length; i++) {
1345
+ const currentChapter = translationChapters[i];
838
1346
  if (i > 0) {
839
- translationChapters[i].previousChapterApiLink = bookChapterApiLink(
1347
+ const previousChapter = translationChapters[i - 1];
1348
+ currentChapter.previousChapterApiLink = bookChapterApiLink(
840
1349
  translation.id,
841
- getBookLink(translationChapters[i - 1].book),
842
- translationChapters[i - 1].chapter.number,
1350
+ getBookLink(previousChapter.book),
1351
+ previousChapter.chapter.number,
843
1352
  "json",
844
1353
  apiPathPrefix
845
1354
  );
846
- translationChapters[i].previousChapterAudioLinks = translationChapters[i - 1].thisChapterAudioLinks;
1355
+ currentChapter.previousChapterReference = {
1356
+ translationId: translation.id,
1357
+ book: previousChapter.book.id,
1358
+ chapter: previousChapter.chapter.number
1359
+ };
1360
+ currentChapter.previousChapterAudioLinks = previousChapter.thisChapterAudioLinks;
1361
+ currentChapter.previousChapterAudioTimings = previousChapter.thisChapterAudioTimings;
1362
+ if (previousChapter.thisChapterWordsLink) {
1363
+ currentChapter.previousChapterWordsLink = previousChapter.thisChapterWordsLink;
1364
+ }
847
1365
  }
848
1366
  if (i < translationChapters.length - 1) {
849
- translationChapters[i].nextChapterApiLink = bookChapterApiLink(
1367
+ const nextChapter = translationChapters[i + 1];
1368
+ currentChapter.nextChapterApiLink = bookChapterApiLink(
850
1369
  translation.id,
851
- getBookLink(translationChapters[i + 1].book),
852
- translationChapters[i + 1].chapter.number,
1370
+ getBookLink(nextChapter.book),
1371
+ nextChapter.chapter.number,
853
1372
  "json",
854
1373
  apiPathPrefix
855
1374
  );
856
- translationChapters[i].nextChapterAudioLinks = translationChapters[i + 1].thisChapterAudioLinks;
1375
+ currentChapter.nextChapterReference = {
1376
+ translationId: translation.id,
1377
+ book: nextChapter.book.id,
1378
+ chapter: nextChapter.chapter.number
1379
+ };
1380
+ currentChapter.nextChapterAudioLinks = nextChapter.thisChapterAudioLinks;
1381
+ currentChapter.nextChapterAudioTimings = nextChapter.thisChapterAudioTimings;
1382
+ if (nextChapter.thisChapterWordsLink) {
1383
+ currentChapter.nextChapterWordsLink = nextChapter.thisChapterWordsLink;
1384
+ }
1385
+ }
1386
+ }
1387
+ const simplifiedChapters = /* @__PURE__ */ new Map();
1388
+ if (generateSimpleChapterFiles || options.generateCompleteTranslationFiles) {
1389
+ for (let chapter of translationChapters) {
1390
+ simplifiedChapters.set(
1391
+ chapter,
1392
+ simplifyChapter(
1393
+ chapter.chapter,
1394
+ rawWordsByChapter.get(chapter)
1395
+ )
1396
+ );
857
1397
  }
858
1398
  }
1399
+ if (api.simpleTranslationBookChapters) {
1400
+ let hasSimpleWords2 = function(chapter) {
1401
+ const words = simplifiedChapters.get(chapter)?.words;
1402
+ return !!words && Object.keys(words).length > 0;
1403
+ };
1404
+ var hasSimpleWords = hasSimpleWords2;
1405
+ const simpleChapterLink = (chapter) => bookChapterApiLink(
1406
+ translation.id,
1407
+ getBookLink(chapter.book),
1408
+ chapter.chapter.number,
1409
+ SIMPLE_JSON_EXTENSION,
1410
+ apiPathPrefix
1411
+ );
1412
+ const simpleWordsLink = (chapter) => hasSimpleWords2(chapter) ? bookChapterWordsApiLink(
1413
+ translation.id,
1414
+ getBookLink(chapter.book),
1415
+ chapter.chapter.number,
1416
+ apiPathPrefix,
1417
+ SIMPLE_JSON_EXTENSION
1418
+ ) : void 0;
1419
+ for (let i = 0; i < translationChapters.length; i++) {
1420
+ const currentChapter = translationChapters[i];
1421
+ const {
1422
+ chapter,
1423
+ simpleChapterApiLink,
1424
+ thisChapterWordsLink,
1425
+ nextChapterWordsLink,
1426
+ previousChapterWordsLink,
1427
+ ...rest
1428
+ } = currentChapter;
1429
+ const previousChapter = translationChapters[i - 1];
1430
+ const nextChapter = translationChapters[i + 1];
1431
+ const simplified = simplifiedChapters.get(currentChapter);
1432
+ const simpleChapter = {
1433
+ ...rest,
1434
+ chapter: simplified.chapter,
1435
+ thisChapterLink: simpleChapterLink(currentChapter),
1436
+ fullChapterApiLink: rest.thisChapterLink,
1437
+ previousChapterApiLink: previousChapter ? simpleChapterLink(previousChapter) : null,
1438
+ nextChapterApiLink: nextChapter ? simpleChapterLink(nextChapter) : null
1439
+ };
1440
+ const thisWordsLink = simpleWordsLink(currentChapter);
1441
+ if (thisWordsLink) {
1442
+ simpleChapter.thisChapterWordsLink = thisWordsLink;
1443
+ api.simpleTranslationBookChapterWords?.push({
1444
+ translationId: translation.id,
1445
+ bookId: currentChapter.book.id,
1446
+ chapterNumber: currentChapter.chapter.number,
1447
+ thisChapterLink: simpleChapter.thisChapterLink,
1448
+ nextChapterLink: simpleChapter.nextChapterApiLink,
1449
+ previousChapterLink: simpleChapter.previousChapterApiLink,
1450
+ thisChapterWordsLink: thisWordsLink,
1451
+ nextChapterWordsLink: nextChapter ? simpleWordsLink(nextChapter) ?? null : null,
1452
+ previousChapterWordsLink: previousChapter ? simpleWordsLink(previousChapter) ?? null : null,
1453
+ verses: simplified.words
1454
+ });
1455
+ }
1456
+ const nextWordsLink = nextChapter ? simpleWordsLink(nextChapter) : void 0;
1457
+ if (nextWordsLink) {
1458
+ simpleChapter.nextChapterWordsLink = nextWordsLink;
1459
+ }
1460
+ const previousWordsLink = previousChapter ? simpleWordsLink(previousChapter) : void 0;
1461
+ if (previousWordsLink) {
1462
+ simpleChapter.previousChapterWordsLink = previousWordsLink;
1463
+ }
1464
+ api.simpleTranslationBookChapters.push(simpleChapter);
1465
+ }
1466
+ }
1467
+ for (let { reader, verses, apiBookChapter } of pendingAudioTimings) {
1468
+ api.translationBookChapterAudioTimings.push({
1469
+ translationId: translation.id,
1470
+ bookId: apiBookChapter.book.id,
1471
+ chapterNumber: apiBookChapter.chapter.number,
1472
+ reader,
1473
+ audioLink: apiBookChapter.thisChapterAudioLinks[reader] ?? "",
1474
+ thisChapterLink: apiBookChapter.thisChapterLink,
1475
+ nextChapterLink: apiBookChapter.nextChapterApiLink,
1476
+ previousChapterLink: apiBookChapter.previousChapterApiLink,
1477
+ thisChapterAudioTimingsLink: apiBookChapter.thisChapterAudioTimings[reader],
1478
+ nextChapterAudioTimingsLink: apiBookChapter.nextChapterAudioTimings?.[reader] ?? null,
1479
+ previousChapterAudioTimingsLink: apiBookChapter.previousChapterAudioTimings?.[reader] ?? null,
1480
+ verses
1481
+ });
1482
+ }
1483
+ for (let apiBookChapter of translationChapters) {
1484
+ const words = rawWordsByChapter.get(apiBookChapter);
1485
+ if (!words || !apiBookChapter.thisChapterWordsLink) {
1486
+ continue;
1487
+ }
1488
+ api.translationBookChapterWords.push({
1489
+ translationId: translation.id,
1490
+ bookId: apiBookChapter.book.id,
1491
+ chapterNumber: apiBookChapter.chapter.number,
1492
+ thisChapterLink: apiBookChapter.thisChapterLink,
1493
+ nextChapterLink: apiBookChapter.nextChapterApiLink,
1494
+ previousChapterLink: apiBookChapter.previousChapterApiLink,
1495
+ thisChapterWordsLink: apiBookChapter.thisChapterWordsLink,
1496
+ nextChapterWordsLink: apiBookChapter.nextChapterWordsLink ?? null,
1497
+ previousChapterWordsLink: apiBookChapter.previousChapterWordsLink ?? null,
1498
+ verses: words
1499
+ });
1500
+ }
859
1501
  api.availableTranslations.translations.push(apiTranslation);
860
1502
  api.translationBooks.push(translationBooks);
861
1503
  if (options.generateCompleteTranslationFiles) {
1504
+ const completeBooks = translationBooks.books.map((book) => ({
1505
+ book,
1506
+ chapters: translationChapters.filter(
1507
+ (ch) => ch.book.id === book.id
1508
+ )
1509
+ }));
1510
+ const completeBook = (book, chapters) => ({
1511
+ id: book.id,
1512
+ name: book.name,
1513
+ commonName: book.commonName,
1514
+ title: book.title,
1515
+ order: book.order,
1516
+ numberOfChapters: book.numberOfChapters,
1517
+ totalNumberOfVerses: book.totalNumberOfVerses,
1518
+ isApocryphal: book.isApocryphal,
1519
+ chapters
1520
+ });
1521
+ const completeChapter = (chapter) => ({
1522
+ numberOfVerses: chapter.numberOfVerses,
1523
+ thisChapterAudioLinks: chapter.thisChapterAudioLinks,
1524
+ // The complete files contain the raw audio timings rather than links
1525
+ // to them, since the point is to have everything in one file.
1526
+ thisChapterAudioTimings: rawAudioTimingsByChapter.get(chapter) ?? {}
1527
+ });
862
1528
  const completeTranslation = {
863
1529
  translation: apiTranslation,
864
- books: translationBooks.books.map((book) => {
865
- const bookChapters = translationChapters.filter(
866
- (ch) => ch.book.id === book.id
867
- );
868
- return {
869
- id: book.id,
870
- name: book.name,
871
- commonName: book.commonName,
872
- title: book.title,
873
- order: book.order,
874
- numberOfChapters: book.numberOfChapters,
875
- totalNumberOfVerses: book.totalNumberOfVerses,
876
- isApocryphal: book.isApocryphal,
877
- chapters: bookChapters.map((ch) => ({
878
- numberOfVerses: ch.numberOfVerses,
879
- thisChapterAudioLinks: ch.thisChapterAudioLinks,
880
- chapter: ch.chapter
881
- }))
882
- };
883
- })
1530
+ books: completeBooks.map(
1531
+ ({ book, chapters }) => completeBook(
1532
+ book,
1533
+ chapters.map((ch) => {
1534
+ const words = rawWordsByChapter.get(ch);
1535
+ return {
1536
+ ...completeChapter(ch),
1537
+ // The complete files also contain the word annotations
1538
+ // themselves rather than links to them.
1539
+ ...words ? { thisChapterWords: words } : {},
1540
+ chapter: ch.chapter
1541
+ };
1542
+ })
1543
+ )
1544
+ )
884
1545
  };
885
1546
  api.translationComplete.push(completeTranslation);
1547
+ const simpleCompleteTranslation = {
1548
+ translation: apiTranslation,
1549
+ books: completeBooks.map(
1550
+ ({ book, chapters }) => completeBook(
1551
+ book,
1552
+ chapters.map((ch) => {
1553
+ const simplified = simplifiedChapters.get(ch);
1554
+ const hasWords = Object.keys(simplified.words).length > 0;
1555
+ return {
1556
+ ...completeChapter(ch),
1557
+ ...hasWords ? { thisChapterWords: simplified.words } : {},
1558
+ chapter: simplified.chapter
1559
+ };
1560
+ })
1561
+ )
1562
+ )
1563
+ };
1564
+ api.simpleTranslationComplete.push(simpleCompleteTranslation);
886
1565
  }
887
1566
  }
888
1567
  for (let { books, profiles, ...commentary } of dataset.commentaries) {
@@ -927,6 +1606,11 @@ export function generateApiForDataset(dataset, options = {}) {
927
1606
  "json",
928
1607
  apiPathPrefix
929
1608
  ) : null,
1609
+ firstChapterReference: firstChapterNumber ? {
1610
+ commentaryId: commentary.id,
1611
+ book: book.id,
1612
+ chapter: firstChapterNumber
1613
+ } : null,
930
1614
  lastChapterNumber,
931
1615
  lastChapterApiLink: lastChapterNumber ? bookCommentaryChapterApiLink(
932
1616
  commentary.id,
@@ -935,6 +1619,11 @@ export function generateApiForDataset(dataset, options = {}) {
935
1619
  "json",
936
1620
  apiPathPrefix
937
1621
  ) : null,
1622
+ lastChapterReference: lastChapterNumber ? {
1623
+ commentaryId: commentary.id,
1624
+ book: book.id,
1625
+ chapter: lastChapterNumber
1626
+ } : null,
938
1627
  numberOfChapters: chapters.length,
939
1628
  totalNumberOfVerses: 0
940
1629
  };
@@ -950,9 +1639,23 @@ export function generateApiForDataset(dataset, options = {}) {
950
1639
  "json",
951
1640
  apiPathPrefix
952
1641
  ),
1642
+ thisChapterReference: {
1643
+ commentaryId: commentary.id,
1644
+ book: book.id,
1645
+ chapter: chapter.number
1646
+ },
953
1647
  nextChapterApiLink: null,
1648
+ nextChapterReference: null,
954
1649
  previousChapterApiLink: null,
955
- numberOfVerses: 0
1650
+ previousChapterReference: null,
1651
+ numberOfVerses: 0,
1652
+ simpleChapterApiLink: generateSimpleChapterFiles ? bookCommentaryChapterApiLink(
1653
+ commentary.id,
1654
+ getBookLink(book),
1655
+ chapter.number,
1656
+ SIMPLE_JSON_EXTENSION,
1657
+ apiPathPrefix
1658
+ ) : void 0
956
1659
  };
957
1660
  for (let c of chapter.content) {
958
1661
  if (c.type === "verse") {
@@ -1006,6 +1709,11 @@ export function generateApiForDataset(dataset, options = {}) {
1006
1709
  "json",
1007
1710
  apiPathPrefix
1008
1711
  );
1712
+ commentaryChapters[i].previousChapterReference = {
1713
+ commentaryId: commentary.id,
1714
+ book: commentaryChapters[i - 1].book.id,
1715
+ chapter: commentaryChapters[i - 1].chapter.number
1716
+ };
1009
1717
  }
1010
1718
  if (i < commentaryChapters.length - 1) {
1011
1719
  commentaryChapters[i].nextChapterApiLink = bookCommentaryChapterApiLink(
@@ -1015,6 +1723,33 @@ export function generateApiForDataset(dataset, options = {}) {
1015
1723
  "json",
1016
1724
  apiPathPrefix
1017
1725
  );
1726
+ commentaryChapters[i].nextChapterReference = {
1727
+ commentaryId: commentary.id,
1728
+ book: commentaryChapters[i + 1].book.id,
1729
+ chapter: commentaryChapters[i + 1].chapter.number
1730
+ };
1731
+ }
1732
+ }
1733
+ if (api.simpleCommentaryBookChapters) {
1734
+ const simpleChapterLink = (chapter) => bookCommentaryChapterApiLink(
1735
+ commentary.id,
1736
+ getBookLink(chapter.book),
1737
+ chapter.chapter.number,
1738
+ SIMPLE_JSON_EXTENSION,
1739
+ apiPathPrefix
1740
+ );
1741
+ for (let i = 0; i < commentaryChapters.length; i++) {
1742
+ const { chapter, simpleChapterApiLink, ...currentChapter } = commentaryChapters[i];
1743
+ const previousChapter = commentaryChapters[i - 1];
1744
+ const nextChapter = commentaryChapters[i + 1];
1745
+ api.simpleCommentaryBookChapters.push({
1746
+ ...currentChapter,
1747
+ chapter: simplifyCommentaryChapter(chapter),
1748
+ thisChapterLink: simpleChapterLink(commentaryChapters[i]),
1749
+ fullChapterApiLink: currentChapter.thisChapterLink,
1750
+ previousChapterApiLink: previousChapter ? simpleChapterLink(previousChapter) : null,
1751
+ nextChapterApiLink: nextChapter ? simpleChapterLink(nextChapter) : null
1752
+ });
1018
1753
  }
1019
1754
  }
1020
1755
  api.availableCommentaries.commentaries.push(apiCommentary);
@@ -1054,6 +1789,11 @@ export function generateApiForDataset(dataset, options = {}) {
1054
1789
  "json",
1055
1790
  apiPathPrefix
1056
1791
  ),
1792
+ firstChapterReference: {
1793
+ datasetId: datasetInfo.id,
1794
+ book: book.id,
1795
+ chapter: firstChapterNumber
1796
+ },
1057
1797
  lastChapterNumber,
1058
1798
  lastChapterApiLink: bookDatasetChapterApiLink(
1059
1799
  datasetInfo.id,
@@ -1062,6 +1802,11 @@ export function generateApiForDataset(dataset, options = {}) {
1062
1802
  "json",
1063
1803
  apiPathPrefix
1064
1804
  ),
1805
+ lastChapterReference: {
1806
+ datasetId: datasetInfo.id,
1807
+ book: book.id,
1808
+ chapter: lastChapterNumber
1809
+ },
1065
1810
  numberOfChapters: chapters.length,
1066
1811
  totalNumberOfVerses: 0,
1067
1812
  totalNumberOfReferences: 0
@@ -1078,8 +1823,15 @@ export function generateApiForDataset(dataset, options = {}) {
1078
1823
  "json",
1079
1824
  apiPathPrefix
1080
1825
  ),
1826
+ thisChapterReference: {
1827
+ datasetId: datasetInfo.id,
1828
+ book: book.id,
1829
+ chapter: chapter.number
1830
+ },
1081
1831
  nextChapterApiLink: null,
1832
+ nextChapterReference: null,
1082
1833
  previousChapterApiLink: null,
1834
+ previousChapterReference: null,
1083
1835
  numberOfVerses: chapter.content.length,
1084
1836
  numberOfReferences: 0
1085
1837
  };
@@ -1108,6 +1860,11 @@ export function generateApiForDataset(dataset, options = {}) {
1108
1860
  "json",
1109
1861
  apiPathPrefix
1110
1862
  );
1863
+ datasetChapters[i].previousChapterReference = {
1864
+ datasetId: datasetInfo.id,
1865
+ book: datasetChapters[i - 1].book.id,
1866
+ chapter: datasetChapters[i - 1].chapter.number
1867
+ };
1111
1868
  }
1112
1869
  if (i < datasetChapters.length - 1) {
1113
1870
  datasetChapters[i].nextChapterApiLink = bookDatasetChapterApiLink(
@@ -1117,6 +1874,11 @@ export function generateApiForDataset(dataset, options = {}) {
1117
1874
  "json",
1118
1875
  apiPathPrefix
1119
1876
  );
1877
+ datasetChapters[i].nextChapterReference = {
1878
+ datasetId: datasetInfo.id,
1879
+ book: datasetChapters[i + 1].book.id,
1880
+ chapter: datasetChapters[i + 1].chapter.number
1881
+ };
1120
1882
  }
1121
1883
  }
1122
1884
  if (!api.availableDatasets) {
@@ -1155,9 +1917,21 @@ export function generateFilesForApi(api) {
1155
1917
  for (let bookChapter of api.translationBookChapters) {
1156
1918
  files.push(jsonFile(bookChapter.thisChapterLink, bookChapter));
1157
1919
  }
1920
+ for (let bookChapter of api.simpleTranslationBookChapters ?? []) {
1921
+ files.push(jsonFile(bookChapter.thisChapterLink, bookChapter));
1922
+ }
1158
1923
  for (let audio of api.translationBookChapterAudio) {
1159
1924
  files.push(downloadedFile(audio.link, audio.originalUrl));
1160
1925
  }
1926
+ for (let timings of api.translationBookChapterAudioTimings) {
1927
+ files.push(jsonFile(timings.thisChapterAudioTimingsLink, timings));
1928
+ }
1929
+ for (let words of api.translationBookChapterWords) {
1930
+ files.push(jsonFile(words.thisChapterWordsLink, words));
1931
+ }
1932
+ for (let words of api.simpleTranslationBookChapterWords ?? []) {
1933
+ files.push(jsonFile(words.thisChapterWordsLink, words));
1934
+ }
1161
1935
  for (let complete of api.translationComplete) {
1162
1936
  if (complete.translation.completeTranslationApiLink) {
1163
1937
  files.push(
@@ -1168,6 +1942,16 @@ export function generateFilesForApi(api) {
1168
1942
  );
1169
1943
  }
1170
1944
  }
1945
+ for (let complete of api.simpleTranslationComplete) {
1946
+ if (complete.translation.simpleCompleteTranslationApiLink) {
1947
+ files.push(
1948
+ jsonFile(
1949
+ complete.translation.simpleCompleteTranslationApiLink,
1950
+ complete
1951
+ )
1952
+ );
1953
+ }
1954
+ }
1171
1955
  files.push(
1172
1956
  jsonFile(
1173
1957
  `${api.pathPrefix}/api/available_commentaries.json`,
@@ -1199,6 +1983,9 @@ export function generateFilesForApi(api) {
1199
1983
  for (let bookChapter of api.commentaryBookChapters) {
1200
1984
  files.push(jsonFile(bookChapter.thisChapterLink, bookChapter));
1201
1985
  }
1986
+ for (let bookChapter of api.simpleCommentaryBookChapters ?? []) {
1987
+ files.push(jsonFile(bookChapter.thisChapterLink, bookChapter));
1988
+ }
1202
1989
  if (api.availableDatasets) {
1203
1990
  files.push(
1204
1991
  jsonFile(
@@ -1234,8 +2021,8 @@ export async function* generateOutputFilesFromDatasets(datasets, options) {
1234
2021
  export function listOfBooksApiLink(translationId, prefix = "") {
1235
2022
  return `${prefix}/api/${translationId}/books.json`;
1236
2023
  }
1237
- export function completeTranslationApiLink(translationId, prefix = "") {
1238
- return `${prefix}/api/${translationId}/complete.json`;
2024
+ export function completeTranslationApiLink(translationId, prefix = "", extension = "json") {
2025
+ return `${prefix}/api/${translationId}/complete.${extension}`;
1239
2026
  }
1240
2027
  export function listOfCommentaryBooksApiLink(commentaryId, prefix = "") {
1241
2028
  return `${prefix}/api/c/${commentaryId}/books.json`;
@@ -1243,6 +2030,7 @@ export function listOfCommentaryBooksApiLink(commentaryId, prefix = "") {
1243
2030
  export function listOfDatasetBooksApiLink(datasetId, prefix = "") {
1244
2031
  return `${prefix}/api/d/${datasetId}/books.json`;
1245
2032
  }
2033
+ export const SIMPLE_JSON_EXTENSION = "simple.json";
1246
2034
  export function bookChapterApiLink(translationId, commonName, chapterNumber, extension, prefix = "") {
1247
2035
  return `${prefix}/api/${translationId}/${replaceSpacesWithUnderscores(
1248
2036
  commonName
@@ -1258,6 +2046,16 @@ export function bookChapterAudioApiLink(translationId, bookId, chapterNumber, re
1258
2046
  bookId
1259
2047
  )}/${chapterNumber}.${reader}.mp3`;
1260
2048
  }
2049
+ export function bookChapterAudioTimingsApiLink(translationId, bookId, chapterNumber, reader, prefix = "") {
2050
+ return `${prefix}/api/${translationId}/${replaceSpacesWithUnderscores(
2051
+ bookId
2052
+ )}/${chapterNumber}.${reader}.audioTimings.json`;
2053
+ }
2054
+ export function bookChapterWordsApiLink(translationId, bookId, chapterNumber, prefix = "", extension = "json") {
2055
+ return `${prefix}/api/${translationId}/${replaceSpacesWithUnderscores(
2056
+ bookId
2057
+ )}/${chapterNumber}.words.${extension}`;
2058
+ }
1261
2059
  export function bookDatasetChapterApiLink(translationId, commonName, chapterNumber, extension, prefix = "") {
1262
2060
  return `${prefix}/api/d/${translationId}/${replaceSpacesWithUnderscores(
1263
2061
  commonName