@helloao/tools 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +97 -97
- package/generation/api.d.ts +32 -3
- package/generation/api.js +42 -16
- package/generation/api.spec.js +193 -0
- package/package.json +1 -1
- package/parser/iterators.spec.js +45 -45
- package/parser/usfm-parser.spec.js +171 -171
- package/parser/usx-parser.spec.js +487 -487
- package/typings/types.d.ts +13 -13
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2022 AO Lab
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 AO Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
## Hello AO Tools
|
|
2
|
-
|
|
3
|
-
Tools for the [Free Use Bible API](https://bible.helloao.org).
|
|
4
|
-
|
|
5
|
-
### Features
|
|
6
|
-
|
|
7
|
-
- Parse [USFM](https://ubsicap.github.io/usfm/), [USX](https://ubsicap.github.io/usx/), and Codex (JSON) files and understand some basic structure.
|
|
8
|
-
- Generate JSON from USFM, USX, and other formats.
|
|
9
|
-
|
|
10
|
-
### Installation
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
$ npm install @helloao/tools
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### Usage
|
|
17
|
-
|
|
18
|
-
#### Parse a USX File
|
|
19
|
-
```typescript
|
|
20
|
-
import { parser } from '@helloao/tools';
|
|
21
|
-
// Used to parse XML
|
|
22
|
-
const parser = new DOMParser();
|
|
23
|
-
const usx = new parser.USXParser(parser);
|
|
24
|
-
const parseTree = usx.parse('YOUR USX');
|
|
25
|
-
console.log(parseTree);
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
#### Generate the API Files for a translation
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import { parser, generation } from '@helloao/tools';
|
|
32
|
-
|
|
33
|
-
// Used to parse XML
|
|
34
|
-
const domParser = new DOMParser();
|
|
35
|
-
|
|
36
|
-
// Each input file needs some metadata about the translation that it is associated with
|
|
37
|
-
const translation: generation.ParseTreeMetadata = {
|
|
38
|
-
translation: {
|
|
39
|
-
|
|
40
|
-
// The ID of the translation
|
|
41
|
-
// this should be unique for the translation
|
|
42
|
-
id: 'my translation id',
|
|
43
|
-
|
|
44
|
-
// The name of the translation in the translation's language
|
|
45
|
-
name: 'my translation name',
|
|
46
|
-
|
|
47
|
-
// The name of the translation in English
|
|
48
|
-
englishName: 'my translation name',
|
|
49
|
-
|
|
50
|
-
// The website that hosts information about the translation
|
|
51
|
-
website: 'translation website',
|
|
52
|
-
|
|
53
|
-
// The URL that hosts information about the license that the
|
|
54
|
-
// translation is shared under
|
|
55
|
-
licenseUrl: 'translation license',
|
|
56
|
-
|
|
57
|
-
// The ISO 639 letter language tag that the translation is primarily in.
|
|
58
|
-
language: 'eng',
|
|
59
|
-
|
|
60
|
-
// The direction that the text is written in.
|
|
61
|
-
// "ltr" means "left to right" and "rtl" means "right to left"
|
|
62
|
-
direction: 'ltr',
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// The list of files that should be processed.
|
|
67
|
-
const files: generation.InputFile[] = [
|
|
68
|
-
{
|
|
69
|
-
// the metadata about the translation for this file
|
|
70
|
-
metadata: translation,
|
|
71
|
-
|
|
72
|
-
// The content contained in the file
|
|
73
|
-
content: 'YOUR USX',
|
|
74
|
-
|
|
75
|
-
// The type of the file.
|
|
76
|
-
// One of "usx", "usfm", and "json"
|
|
77
|
-
fileType: 'usx'
|
|
78
|
-
}
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
// Generate a dataset from the files
|
|
82
|
-
// Datasets organize all the files and their content
|
|
83
|
-
// by translation, book, chapter, and verse
|
|
84
|
-
const dataset = generation.dataset.generateDataset(files,
|
|
85
|
-
|
|
86
|
-
// Generate an API representation from the files
|
|
87
|
-
// This adds links between chapters and additional metadata.
|
|
88
|
-
const api = generation.api.generateApiForDataset(dataset);
|
|
89
|
-
|
|
90
|
-
// Generate output files from the API representation.
|
|
91
|
-
// This will give us a list of files and file paths that represent
|
|
92
|
-
// the entire API.
|
|
93
|
-
const outputFiles = generation.api.generateFilesForApi(api);
|
|
94
|
-
|
|
95
|
-
for (let file of outputFiles) {
|
|
96
|
-
console.log(file.path, file.content);
|
|
97
|
-
}
|
|
1
|
+
## Hello AO Tools
|
|
2
|
+
|
|
3
|
+
Tools for the [Free Use Bible API](https://bible.helloao.org).
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Parse [USFM](https://ubsicap.github.io/usfm/), [USX](https://ubsicap.github.io/usx/), and Codex (JSON) files and understand some basic structure.
|
|
8
|
+
- Generate JSON from USFM, USX, and other formats.
|
|
9
|
+
|
|
10
|
+
### Installation
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
$ npm install @helloao/tools
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Usage
|
|
17
|
+
|
|
18
|
+
#### Parse a USX File
|
|
19
|
+
```typescript
|
|
20
|
+
import { parser } from '@helloao/tools';
|
|
21
|
+
// Used to parse XML
|
|
22
|
+
const parser = new DOMParser();
|
|
23
|
+
const usx = new parser.USXParser(parser);
|
|
24
|
+
const parseTree = usx.parse('YOUR USX');
|
|
25
|
+
console.log(parseTree);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
#### Generate the API Files for a translation
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { parser, generation } from '@helloao/tools';
|
|
32
|
+
|
|
33
|
+
// Used to parse XML
|
|
34
|
+
const domParser = new DOMParser();
|
|
35
|
+
|
|
36
|
+
// Each input file needs some metadata about the translation that it is associated with
|
|
37
|
+
const translation: generation.ParseTreeMetadata = {
|
|
38
|
+
translation: {
|
|
39
|
+
|
|
40
|
+
// The ID of the translation
|
|
41
|
+
// this should be unique for the translation
|
|
42
|
+
id: 'my translation id',
|
|
43
|
+
|
|
44
|
+
// The name of the translation in the translation's language
|
|
45
|
+
name: 'my translation name',
|
|
46
|
+
|
|
47
|
+
// The name of the translation in English
|
|
48
|
+
englishName: 'my translation name',
|
|
49
|
+
|
|
50
|
+
// The website that hosts information about the translation
|
|
51
|
+
website: 'translation website',
|
|
52
|
+
|
|
53
|
+
// The URL that hosts information about the license that the
|
|
54
|
+
// translation is shared under
|
|
55
|
+
licenseUrl: 'translation license',
|
|
56
|
+
|
|
57
|
+
// The ISO 639 letter language tag that the translation is primarily in.
|
|
58
|
+
language: 'eng',
|
|
59
|
+
|
|
60
|
+
// The direction that the text is written in.
|
|
61
|
+
// "ltr" means "left to right" and "rtl" means "right to left"
|
|
62
|
+
direction: 'ltr',
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// The list of files that should be processed.
|
|
67
|
+
const files: generation.InputFile[] = [
|
|
68
|
+
{
|
|
69
|
+
// the metadata about the translation for this file
|
|
70
|
+
metadata: translation,
|
|
71
|
+
|
|
72
|
+
// The content contained in the file
|
|
73
|
+
content: 'YOUR USX',
|
|
74
|
+
|
|
75
|
+
// The type of the file.
|
|
76
|
+
// One of "usx", "usfm", and "json"
|
|
77
|
+
fileType: 'usx'
|
|
78
|
+
}
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// Generate a dataset from the files
|
|
82
|
+
// Datasets organize all the files and their content
|
|
83
|
+
// by translation, book, chapter, and verse
|
|
84
|
+
const dataset = generation.dataset.generateDataset(files, domParser);
|
|
85
|
+
|
|
86
|
+
// Generate an API representation from the files
|
|
87
|
+
// This adds links between chapters and additional metadata.
|
|
88
|
+
const api = generation.api.generateApiForDataset(dataset);
|
|
89
|
+
|
|
90
|
+
// Generate output files from the API representation.
|
|
91
|
+
// This will give us a list of files and file paths that represent
|
|
92
|
+
// the entire API.
|
|
93
|
+
const outputFiles = generation.api.generateFilesForApi(api);
|
|
94
|
+
|
|
95
|
+
for (let file of outputFiles) {
|
|
96
|
+
console.log(file.path, file.content);
|
|
97
|
+
}
|
|
98
98
|
```
|
package/generation/api.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ export interface ApiOutput {
|
|
|
27
27
|
* - /api/:translationId/:bookId/:chapterNumber.:reader.mp3
|
|
28
28
|
*/
|
|
29
29
|
translationBookChapterAudio: ApiTranslationBookChapterAudio[];
|
|
30
|
+
/**
|
|
31
|
+
* The path prefix that the API should use.
|
|
32
|
+
*/
|
|
33
|
+
pathPrefix: string;
|
|
30
34
|
}
|
|
31
35
|
/**
|
|
32
36
|
* The list of available translations.
|
|
@@ -168,6 +172,9 @@ export interface ApiTranslationBookChapterAudio {
|
|
|
168
172
|
*/
|
|
169
173
|
originalUrl: string;
|
|
170
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* The options for generating the API.
|
|
177
|
+
*/
|
|
171
178
|
export interface GenerateApiOptions {
|
|
172
179
|
/**
|
|
173
180
|
* Whether to use the common name for the book chapter API link. If false, then book IDs are used.
|
|
@@ -182,6 +189,10 @@ export interface GenerateApiOptions {
|
|
|
182
189
|
* Defaults to false.
|
|
183
190
|
*/
|
|
184
191
|
generateAudioFiles?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* The prefix that should be added to paths that are generated.
|
|
194
|
+
*/
|
|
195
|
+
pathPrefix?: string;
|
|
185
196
|
}
|
|
186
197
|
/**
|
|
187
198
|
* Generates the API output for the given dataset.
|
|
@@ -194,9 +205,27 @@ export declare function generateApiForDataset(dataset: DatasetOutput, options?:
|
|
|
194
205
|
* @param api The API that the files should be generated for.
|
|
195
206
|
*/
|
|
196
207
|
export declare function generateFilesForApi(api: ApiOutput): OutputFile[];
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
208
|
+
/**
|
|
209
|
+
* Generates the output files for the given datasets.
|
|
210
|
+
* @param datasets The datasets to generate the output files for.
|
|
211
|
+
* @param options The options for generating the API files.
|
|
212
|
+
*/
|
|
213
|
+
export declare function generateOutputFilesFromDatasets(datasets: AsyncIterable<DatasetOutput>, options?: GenerateApiOptions): AsyncGenerator<OutputFile[]>;
|
|
214
|
+
/**
|
|
215
|
+
* Gets the API Link for the list of books endpoint for a translation.
|
|
216
|
+
* @param translationId The ID of the translation.
|
|
217
|
+
* @returns
|
|
218
|
+
*/
|
|
219
|
+
export declare function listOfBooksApiLink(translationId: string, prefix?: string): string;
|
|
220
|
+
/**
|
|
221
|
+
* Getes the API link for a book chapter.
|
|
222
|
+
* @param translationId The ID of the translation.
|
|
223
|
+
* @param commonName The name of the book.
|
|
224
|
+
* @param chapterNumber The number of the book.
|
|
225
|
+
* @param extension The extension of the file.
|
|
226
|
+
*/
|
|
227
|
+
export declare function bookChapterApiLink(translationId: string, commonName: string, chapterNumber: number, extension: string, prefix?: string): string;
|
|
228
|
+
export declare function bookChapterAudioApiLink(translationId: string, bookId: string, chapterNumber: number, reader: string, prefix?: string): string;
|
|
200
229
|
export declare function jsonFile(path: string, content: any, mergable?: boolean): OutputFile;
|
|
201
230
|
export declare function downloadedFile(path: string, url: string): OutputFile;
|
|
202
231
|
export declare function replaceSpacesWithUnderscores(str: string): string;
|
package/generation/api.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateApiForDataset = generateApiForDataset;
|
|
4
4
|
exports.generateFilesForApi = generateFilesForApi;
|
|
5
|
+
exports.generateOutputFilesFromDatasets = generateOutputFilesFromDatasets;
|
|
5
6
|
exports.listOfBooksApiLink = listOfBooksApiLink;
|
|
6
7
|
exports.bookChapterApiLink = bookChapterApiLink;
|
|
7
8
|
exports.bookChapterAudioApiLink = bookChapterAudioApiLink;
|
|
@@ -15,7 +16,8 @@ const all_iso_language_codes_1 = require("all-iso-language-codes");
|
|
|
15
16
|
* @param options The options for generating the API.
|
|
16
17
|
*/
|
|
17
18
|
function generateApiForDataset(dataset, options = {}) {
|
|
18
|
-
const { useCommonName } = options;
|
|
19
|
+
const { useCommonName, pathPrefix } = options;
|
|
20
|
+
const apiPathPrefix = pathPrefix ? pathPrefix : '';
|
|
19
21
|
let api = {
|
|
20
22
|
availableTranslations: {
|
|
21
23
|
translations: [],
|
|
@@ -23,12 +25,13 @@ function generateApiForDataset(dataset, options = {}) {
|
|
|
23
25
|
translationBooks: [],
|
|
24
26
|
translationBookChapters: [],
|
|
25
27
|
translationBookChapterAudio: [],
|
|
28
|
+
pathPrefix: apiPathPrefix
|
|
26
29
|
};
|
|
27
30
|
for (let { books, ...translation } of dataset.translations) {
|
|
28
31
|
const apiTranslation = {
|
|
29
32
|
...translation,
|
|
30
33
|
availableFormats: ['json'],
|
|
31
|
-
listOfBooksApiLink: listOfBooksApiLink(translation.id),
|
|
34
|
+
listOfBooksApiLink: listOfBooksApiLink(translation.id, apiPathPrefix),
|
|
32
35
|
numberOfBooks: books.length,
|
|
33
36
|
totalNumberOfChapters: 0,
|
|
34
37
|
totalNumberOfVerses: 0,
|
|
@@ -43,8 +46,8 @@ function generateApiForDataset(dataset, options = {}) {
|
|
|
43
46
|
for (let { chapters, ...book } of books) {
|
|
44
47
|
const apiBook = {
|
|
45
48
|
...book,
|
|
46
|
-
firstChapterApiLink: bookChapterApiLink(translation.id, getBookLink(book), 1, 'json'),
|
|
47
|
-
lastChapterApiLink: bookChapterApiLink(translation.id, getBookLink(book), chapters.length, 'json'),
|
|
49
|
+
firstChapterApiLink: bookChapterApiLink(translation.id, getBookLink(book), 1, 'json', apiPathPrefix),
|
|
50
|
+
lastChapterApiLink: bookChapterApiLink(translation.id, getBookLink(book), chapters.length, 'json', apiPathPrefix),
|
|
48
51
|
numberOfChapters: chapters.length,
|
|
49
52
|
totalNumberOfVerses: 0,
|
|
50
53
|
};
|
|
@@ -54,7 +57,7 @@ function generateApiForDataset(dataset, options = {}) {
|
|
|
54
57
|
translation: apiTranslation,
|
|
55
58
|
book: apiBook,
|
|
56
59
|
chapter: chapter,
|
|
57
|
-
thisChapterLink: bookChapterApiLink(translation.id, getBookLink(book), chapter.number, 'json'),
|
|
60
|
+
thisChapterLink: bookChapterApiLink(translation.id, getBookLink(book), chapter.number, 'json', apiPathPrefix),
|
|
58
61
|
thisChapterAudioLinks: audio,
|
|
59
62
|
nextChapterApiLink: null,
|
|
60
63
|
nextChapterAudioLinks: null,
|
|
@@ -66,7 +69,7 @@ function generateApiForDataset(dataset, options = {}) {
|
|
|
66
69
|
if (options.generateAudioFiles) {
|
|
67
70
|
const apiAudio = {
|
|
68
71
|
chapter: apiBookChapter,
|
|
69
|
-
link: bookChapterAudioApiLink(translation.id, getBookLink(book), chapter.number, reader),
|
|
72
|
+
link: bookChapterAudioApiLink(translation.id, getBookLink(book), chapter.number, reader, apiPathPrefix),
|
|
70
73
|
originalUrl: thisChapterAudioLinks[reader],
|
|
71
74
|
};
|
|
72
75
|
audio[reader] = apiAudio.link;
|
|
@@ -91,11 +94,11 @@ function generateApiForDataset(dataset, options = {}) {
|
|
|
91
94
|
}
|
|
92
95
|
for (let i = 0; i < translationChapters.length; i++) {
|
|
93
96
|
if (i > 0) {
|
|
94
|
-
translationChapters[i].previousChapterApiLink = bookChapterApiLink(translation.id, getBookLink(translationChapters[i - 1].book), translationChapters[i - 1].chapter.number, 'json');
|
|
97
|
+
translationChapters[i].previousChapterApiLink = bookChapterApiLink(translation.id, getBookLink(translationChapters[i - 1].book), translationChapters[i - 1].chapter.number, 'json', apiPathPrefix);
|
|
95
98
|
translationChapters[i].previousChapterAudioLinks = translationChapters[i - 1].thisChapterAudioLinks;
|
|
96
99
|
}
|
|
97
100
|
if (i < translationChapters.length - 1) {
|
|
98
|
-
translationChapters[i].nextChapterApiLink = bookChapterApiLink(translation.id, getBookLink(translationChapters[i + 1].book), translationChapters[i + 1].chapter.number, 'json');
|
|
101
|
+
translationChapters[i].nextChapterApiLink = bookChapterApiLink(translation.id, getBookLink(translationChapters[i + 1].book), translationChapters[i + 1].chapter.number, 'json', apiPathPrefix);
|
|
99
102
|
translationChapters[i].nextChapterAudioLinks = translationChapters[i + 1].thisChapterAudioLinks;
|
|
100
103
|
}
|
|
101
104
|
}
|
|
@@ -113,7 +116,7 @@ function generateApiForDataset(dataset, options = {}) {
|
|
|
113
116
|
*/
|
|
114
117
|
function generateFilesForApi(api) {
|
|
115
118
|
let files = [];
|
|
116
|
-
files.push(jsonFile(
|
|
119
|
+
files.push(jsonFile(`${api.pathPrefix}/api/available_translations.json`, api.availableTranslations, true));
|
|
117
120
|
for (let translationBooks of api.translationBooks) {
|
|
118
121
|
files.push(jsonFile(translationBooks.translation.listOfBooksApiLink, translationBooks));
|
|
119
122
|
}
|
|
@@ -125,15 +128,38 @@ function generateFilesForApi(api) {
|
|
|
125
128
|
}
|
|
126
129
|
return files;
|
|
127
130
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Generates the output files for the given datasets.
|
|
133
|
+
* @param datasets The datasets to generate the output files for.
|
|
134
|
+
* @param options The options for generating the API files.
|
|
135
|
+
*/
|
|
136
|
+
async function* generateOutputFilesFromDatasets(datasets, options) {
|
|
137
|
+
for await (let dataset of datasets) {
|
|
138
|
+
const api = generateApiForDataset(dataset, options);
|
|
139
|
+
const files = generateFilesForApi(api);
|
|
140
|
+
yield files;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Gets the API Link for the list of books endpoint for a translation.
|
|
145
|
+
* @param translationId The ID of the translation.
|
|
146
|
+
* @returns
|
|
147
|
+
*/
|
|
148
|
+
function listOfBooksApiLink(translationId, prefix = '') {
|
|
149
|
+
return `${prefix}/api/${translationId}/books.json`;
|
|
131
150
|
}
|
|
132
|
-
|
|
133
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Getes the API link for a book chapter.
|
|
153
|
+
* @param translationId The ID of the translation.
|
|
154
|
+
* @param commonName The name of the book.
|
|
155
|
+
* @param chapterNumber The number of the book.
|
|
156
|
+
* @param extension The extension of the file.
|
|
157
|
+
*/
|
|
158
|
+
function bookChapterApiLink(translationId, commonName, chapterNumber, extension, prefix = '') {
|
|
159
|
+
return `${prefix}/api/${translationId}/${replaceSpacesWithUnderscores(commonName)}/${chapterNumber}.${extension}`;
|
|
134
160
|
}
|
|
135
|
-
function bookChapterAudioApiLink(translationId, bookId, chapterNumber, reader) {
|
|
136
|
-
return
|
|
161
|
+
function bookChapterAudioApiLink(translationId, bookId, chapterNumber, reader, prefix = '') {
|
|
162
|
+
return `${prefix}/api/${translationId}/${replaceSpacesWithUnderscores(bookId)}/${chapterNumber}.${reader}.mp3`;
|
|
137
163
|
}
|
|
138
164
|
function jsonFile(path, content, mergable) {
|
|
139
165
|
return {
|
package/generation/api.spec.js
CHANGED
|
@@ -215,6 +215,199 @@ describe('generateApiForDataset()', () => {
|
|
|
215
215
|
// ]
|
|
216
216
|
// });
|
|
217
217
|
});
|
|
218
|
+
it('should use the given path prefix', () => {
|
|
219
|
+
let translation1 = {
|
|
220
|
+
id: 'bsb',
|
|
221
|
+
name: 'Berean Standard Bible',
|
|
222
|
+
englishName: 'Berean Standard Bible',
|
|
223
|
+
shortName: 'BSB',
|
|
224
|
+
language: 'eng',
|
|
225
|
+
direction: 'ltr',
|
|
226
|
+
licenseUrl: 'https://berean.bible/terms.htm',
|
|
227
|
+
website: 'https://berean.bible'
|
|
228
|
+
};
|
|
229
|
+
let inputFiles = [
|
|
230
|
+
{
|
|
231
|
+
fileType: 'usfm',
|
|
232
|
+
metadata: {
|
|
233
|
+
translation: translation1
|
|
234
|
+
},
|
|
235
|
+
content: firstXLines(_01GENBSB_usfm_1.default, 13)
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
fileType: 'usfm',
|
|
239
|
+
metadata: {
|
|
240
|
+
translation: translation1
|
|
241
|
+
},
|
|
242
|
+
content: firstXLines(_02EXOBSB_usfm_1.default, 14)
|
|
243
|
+
}
|
|
244
|
+
];
|
|
245
|
+
const dataset = (0, dataset_1.generateDataset)(inputFiles, new linkedom_1.DOMParser());
|
|
246
|
+
const generated = (0, api_1.generateApiForDataset)(dataset, {
|
|
247
|
+
pathPrefix: '/hello'
|
|
248
|
+
});
|
|
249
|
+
const files = (0, api_1.generateFilesForApi)(generated);
|
|
250
|
+
const tree = fileTree(files);
|
|
251
|
+
const expectedTranslation = {
|
|
252
|
+
id: 'bsb',
|
|
253
|
+
name: 'Berean Standard Bible',
|
|
254
|
+
englishName: 'Berean Standard Bible',
|
|
255
|
+
shortName: 'BSB',
|
|
256
|
+
language: 'eng',
|
|
257
|
+
textDirection: 'ltr',
|
|
258
|
+
licenseUrl: 'https://berean.bible/terms.htm',
|
|
259
|
+
website: 'https://berean.bible',
|
|
260
|
+
availableFormats: [
|
|
261
|
+
'json'
|
|
262
|
+
],
|
|
263
|
+
listOfBooksApiLink: '/hello/api/bsb/books.json',
|
|
264
|
+
numberOfBooks: 2,
|
|
265
|
+
totalNumberOfChapters: 2,
|
|
266
|
+
totalNumberOfVerses: 4,
|
|
267
|
+
languageName: 'English',
|
|
268
|
+
languageEnglishName: 'English',
|
|
269
|
+
};
|
|
270
|
+
expect(tree).toEqual({
|
|
271
|
+
'/hello/api/available_translations.json': {
|
|
272
|
+
translations: [
|
|
273
|
+
expectedTranslation
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
'/hello/api/bsb/books.json': {
|
|
277
|
+
translation: expectedTranslation,
|
|
278
|
+
books: [
|
|
279
|
+
{
|
|
280
|
+
id: 'GEN',
|
|
281
|
+
name: 'Genesis',
|
|
282
|
+
commonName: 'Genesis',
|
|
283
|
+
title: 'Genesis',
|
|
284
|
+
order: 1,
|
|
285
|
+
numberOfChapters: 1,
|
|
286
|
+
totalNumberOfVerses: 2,
|
|
287
|
+
firstChapterApiLink: '/hello/api/bsb/GEN/1.json',
|
|
288
|
+
lastChapterApiLink: '/hello/api/bsb/GEN/1.json',
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
id: 'EXO',
|
|
292
|
+
name: 'Exodus',
|
|
293
|
+
commonName: 'Exodus',
|
|
294
|
+
title: 'Exodus',
|
|
295
|
+
order: 2,
|
|
296
|
+
numberOfChapters: 1,
|
|
297
|
+
totalNumberOfVerses: 2,
|
|
298
|
+
firstChapterApiLink: '/hello/api/bsb/EXO/1.json',
|
|
299
|
+
lastChapterApiLink: '/hello/api/bsb/EXO/1.json',
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
},
|
|
303
|
+
'/hello/api/bsb/GEN/1.json': {
|
|
304
|
+
translation: expectedTranslation,
|
|
305
|
+
book: {
|
|
306
|
+
id: 'GEN',
|
|
307
|
+
name: 'Genesis',
|
|
308
|
+
commonName: 'Genesis',
|
|
309
|
+
title: 'Genesis',
|
|
310
|
+
order: 1,
|
|
311
|
+
numberOfChapters: 1,
|
|
312
|
+
totalNumberOfVerses: 2,
|
|
313
|
+
firstChapterApiLink: '/hello/api/bsb/GEN/1.json',
|
|
314
|
+
lastChapterApiLink: '/hello/api/bsb/GEN/1.json'
|
|
315
|
+
},
|
|
316
|
+
thisChapterLink: '/hello/api/bsb/GEN/1.json',
|
|
317
|
+
thisChapterAudioLinks: {},
|
|
318
|
+
nextChapterApiLink: '/hello/api/bsb/EXO/1.json',
|
|
319
|
+
nextChapterAudioLinks: {},
|
|
320
|
+
previousChapterApiLink: null,
|
|
321
|
+
previousChapterAudioLinks: null,
|
|
322
|
+
numberOfVerses: 2,
|
|
323
|
+
chapter: {
|
|
324
|
+
number: 1,
|
|
325
|
+
content: [
|
|
326
|
+
{
|
|
327
|
+
type: 'heading',
|
|
328
|
+
content: [
|
|
329
|
+
'The Creation'
|
|
330
|
+
]
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
type: 'line_break'
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
type: 'verse',
|
|
337
|
+
number: 1,
|
|
338
|
+
content: [
|
|
339
|
+
'In the beginning God created the heavens and the earth.'
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
type: 'line_break'
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
type: 'verse',
|
|
347
|
+
number: 2,
|
|
348
|
+
content: [
|
|
349
|
+
'Now the earth was formless and void, and darkness was over the surface of the deep. And the Spirit of God was hovering over the surface of the waters.'
|
|
350
|
+
],
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
footnotes: []
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
'/hello/api/bsb/EXO/1.json': {
|
|
357
|
+
translation: expectedTranslation,
|
|
358
|
+
book: {
|
|
359
|
+
id: 'EXO',
|
|
360
|
+
name: 'Exodus',
|
|
361
|
+
commonName: 'Exodus',
|
|
362
|
+
title: 'Exodus',
|
|
363
|
+
order: 2,
|
|
364
|
+
numberOfChapters: 1,
|
|
365
|
+
totalNumberOfVerses: 2,
|
|
366
|
+
firstChapterApiLink: '/hello/api/bsb/EXO/1.json',
|
|
367
|
+
lastChapterApiLink: '/hello/api/bsb/EXO/1.json'
|
|
368
|
+
},
|
|
369
|
+
thisChapterLink: '/hello/api/bsb/EXO/1.json',
|
|
370
|
+
thisChapterAudioLinks: {},
|
|
371
|
+
nextChapterApiLink: null,
|
|
372
|
+
nextChapterAudioLinks: null,
|
|
373
|
+
previousChapterApiLink: '/hello/api/bsb/GEN/1.json',
|
|
374
|
+
previousChapterAudioLinks: {},
|
|
375
|
+
numberOfVerses: 2,
|
|
376
|
+
chapter: {
|
|
377
|
+
number: 1,
|
|
378
|
+
content: [
|
|
379
|
+
{
|
|
380
|
+
type: 'heading',
|
|
381
|
+
content: [
|
|
382
|
+
'The Israelites Multiply in Egypt'
|
|
383
|
+
]
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
type: 'line_break'
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
type: 'verse',
|
|
390
|
+
number: 1,
|
|
391
|
+
content: [
|
|
392
|
+
'These are the names of the sons of Israel who went to Egypt with Jacob, each with his family:'
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
type: 'line_break'
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
type: 'verse',
|
|
400
|
+
number: 2,
|
|
401
|
+
content: [
|
|
402
|
+
'Reuben, Simeon, Levi, and Judah;'
|
|
403
|
+
],
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
footnotes: []
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
});
|
|
218
411
|
it('should use underscores for spaces in the book name', () => {
|
|
219
412
|
let translation1 = {
|
|
220
413
|
id: 'bsb',
|