@helloao/tools 0.0.1
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 -0
- package/generation/api.d.ts +203 -0
- package/generation/api.js +153 -0
- package/generation/api.spec.d.ts +2 -0
- package/generation/api.spec.js +463 -0
- package/generation/audio.d.ts +20 -0
- package/generation/audio.js +60 -0
- package/generation/audio.spec.d.ts +2 -0
- package/generation/audio.spec.js +36 -0
- package/generation/book-order.d.ts +15 -0
- package/generation/book-order.js +494 -0
- package/generation/book-order.spec.d.ts +2 -0
- package/generation/book-order.spec.js +8 -0
- package/generation/common-types.d.ts +327 -0
- package/generation/common-types.js +2 -0
- package/generation/dataset.d.ts +34 -0
- package/generation/dataset.js +106 -0
- package/generation/index.d.ts +7 -0
- package/generation/index.js +38 -0
- package/index.d.ts +5 -0
- package/index.js +32 -0
- package/package.json +27 -0
- package/parser/codex-parser.d.ts +97 -0
- package/parser/codex-parser.js +160 -0
- package/parser/codex-parser.spec.d.ts +2 -0
- package/parser/codex-parser.spec.js +645 -0
- package/parser/index.d.ts +7 -0
- package/parser/index.js +35 -0
- package/parser/iterators.d.ts +89 -0
- package/parser/iterators.js +222 -0
- package/parser/iterators.spec.d.ts +2 -0
- package/parser/iterators.spec.js +174 -0
- package/parser/types.d.ts +144 -0
- package/parser/types.js +2 -0
- package/parser/usfm-parser.d.ts +135 -0
- package/parser/usfm-parser.js +840 -0
- package/parser/usfm-parser.spec.d.ts +2 -0
- package/parser/usfm-parser.spec.js +1593 -0
- package/parser/usx-parser.d.ts +33 -0
- package/parser/usx-parser.js +425 -0
- package/parser/usx-parser.spec.d.ts +2 -0
- package/parser/usx-parser.spec.js +1260 -0
- package/typings/types.d.ts +14 -0
- package/utils.d.ts +29 -0
- package/utils.js +73 -0
- package/utils.spec.d.ts +2 -0
- package/utils.spec.js +42 -0
|
@@ -0,0 +1,1593 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const usfm_parser_1 = require("./usfm-parser");
|
|
7
|
+
const hash_js_1 = __importDefault(require("hash.js"));
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
describe('UsfmTokenizer', () => {
|
|
11
|
+
let tokenizer;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tokenizer = new usfm_parser_1.UsfmTokenizer();
|
|
14
|
+
});
|
|
15
|
+
describe('tokenize()', () => {
|
|
16
|
+
describe('markers', () => {
|
|
17
|
+
it('should be able to parse single character markers', () => {
|
|
18
|
+
const tokens = tokenizer.tokenize(`\\a`);
|
|
19
|
+
expect(tokens).toEqual([
|
|
20
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 2), 'marker'),
|
|
21
|
+
]);
|
|
22
|
+
});
|
|
23
|
+
it('should be able to parse multiple character markers', () => {
|
|
24
|
+
const tokens = tokenizer.tokenize(`\\abc`);
|
|
25
|
+
expect(tokens).toEqual([
|
|
26
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 4), 'marker'),
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
it('should be able to parse markers with numbers', () => {
|
|
30
|
+
const tokens = tokenizer.tokenize(`\\abc123`);
|
|
31
|
+
expect(tokens).toEqual([
|
|
32
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 7), 'marker'),
|
|
33
|
+
]);
|
|
34
|
+
});
|
|
35
|
+
it('should be able to parse end markers', () => {
|
|
36
|
+
const tokens = tokenizer.tokenize(`\\abc*`);
|
|
37
|
+
expect(tokens).toEqual([
|
|
38
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 5), 'marker'),
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
it('should be able to parse end markers with numbers', () => {
|
|
42
|
+
const tokens = tokenizer.tokenize(`\\abc123*`);
|
|
43
|
+
expect(tokens).toEqual([
|
|
44
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 8), 'marker'),
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
it('should not throw an error if the marker does not have a command', () => {
|
|
48
|
+
const tokens = tokenizer.tokenize(`\\`);
|
|
49
|
+
expect(tokens).toEqual([
|
|
50
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 1), 'marker')
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
it('should not throw an error if the marker has a number but not a command', () => {
|
|
54
|
+
const tokens = tokenizer.tokenize(`\\1`);
|
|
55
|
+
expect(tokens).toEqual([
|
|
56
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 2), 'marker')
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
it('should be able to parse end markers that have text after them', () => {
|
|
60
|
+
const tokens = tokenizer.tokenize(`\\abc*z`);
|
|
61
|
+
expect(tokens).toEqual([
|
|
62
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 5), 'marker'),
|
|
63
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(5, 6), 'word'),
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
it('should be able to parse end markers that have text before them', () => {
|
|
67
|
+
const tokens = tokenizer.tokenize(`z\\abc*`);
|
|
68
|
+
expect(tokens).toEqual([
|
|
69
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 1), 'word'),
|
|
70
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(1, 6), 'marker'),
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
it('should be able to parse markers that have a space after them', () => {
|
|
74
|
+
const tokens = tokenizer.tokenize(`\\abc z`);
|
|
75
|
+
expect(tokens).toEqual([
|
|
76
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 4), 'marker'),
|
|
77
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(4, 5), 'whitespace'),
|
|
78
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(5, 6), 'word'),
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
it('should be able to parse markers that have a tab after them', () => {
|
|
82
|
+
const tokens = tokenizer.tokenize(`\\abc\tz`);
|
|
83
|
+
expect(tokens).toEqual([
|
|
84
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 4), 'marker'),
|
|
85
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(4, 5), 'whitespace'),
|
|
86
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(5, 6), 'word'),
|
|
87
|
+
]);
|
|
88
|
+
});
|
|
89
|
+
it('should be able to parse markers that have a newline after them', () => {
|
|
90
|
+
const tokens = tokenizer.tokenize(`\\abc\nz`);
|
|
91
|
+
expect(tokens).toEqual([
|
|
92
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 4), 'marker'),
|
|
93
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(4, 5), 'whitespace'),
|
|
94
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(5, 6), 'word'),
|
|
95
|
+
]);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('words', () => {
|
|
99
|
+
it('should be able to parse characters into words', () => {
|
|
100
|
+
const tokens = tokenizer.tokenize(`abc`);
|
|
101
|
+
expect(tokens).toEqual([
|
|
102
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 3), 'word'),
|
|
103
|
+
]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('whitespace', () => {
|
|
107
|
+
it('should be able to parse space into whitespace', () => {
|
|
108
|
+
const tokens = tokenizer.tokenize(` `);
|
|
109
|
+
expect(tokens).toEqual([
|
|
110
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 1), 'whitespace'),
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
it('should be able to parse newlines into whitespace', () => {
|
|
114
|
+
const tokens = tokenizer.tokenize(`\n`);
|
|
115
|
+
expect(tokens).toEqual([
|
|
116
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 1), 'whitespace'),
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
it('should be able to parse carriage returns into whitespace', () => {
|
|
120
|
+
const tokens = tokenizer.tokenize(`\r`);
|
|
121
|
+
expect(tokens).toEqual([
|
|
122
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 1), 'whitespace'),
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
it('should be able to parse tabs into whitespace', () => {
|
|
126
|
+
const tokens = tokenizer.tokenize(`\t`);
|
|
127
|
+
expect(tokens).toEqual([
|
|
128
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 1), 'whitespace'),
|
|
129
|
+
]);
|
|
130
|
+
});
|
|
131
|
+
it('should be able to parse multiple whitespace into whitespace', () => {
|
|
132
|
+
const tokens = tokenizer.tokenize(`\t \r\n`);
|
|
133
|
+
expect(tokens).toEqual([
|
|
134
|
+
(0, usfm_parser_1.t)((0, usfm_parser_1.loc)(0, 4), 'whitespace'),
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('UsfmParser', () => {
|
|
141
|
+
let parser;
|
|
142
|
+
beforeEach(() => {
|
|
143
|
+
parser = new usfm_parser_1.UsfmParser();
|
|
144
|
+
});
|
|
145
|
+
describe('tokenize()', () => {
|
|
146
|
+
it('should be able to tokenize single character markers', () => {
|
|
147
|
+
const tokens = parser.tokenize(`\\a`);
|
|
148
|
+
expect(tokens).toEqual([
|
|
149
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 2), '\\a', null, 'start')
|
|
150
|
+
]);
|
|
151
|
+
});
|
|
152
|
+
it('should be able to tokenize multiple character markers', () => {
|
|
153
|
+
const tokens = parser.tokenize(`\\abc`);
|
|
154
|
+
expect(tokens).toEqual([
|
|
155
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 4), '\\abc', null, 'start')
|
|
156
|
+
]);
|
|
157
|
+
});
|
|
158
|
+
it('should be able to parse markers with numbers', () => {
|
|
159
|
+
const tokens = parser.tokenize(`\\abc123`);
|
|
160
|
+
expect(tokens).toEqual([
|
|
161
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 7), '\\abc', 123, 'start'),
|
|
162
|
+
]);
|
|
163
|
+
});
|
|
164
|
+
it('should be able to parse end markers', () => {
|
|
165
|
+
const tokens = parser.tokenize(`\\abc*`);
|
|
166
|
+
expect(tokens).toEqual([
|
|
167
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 5), '\\abc', null, 'end'),
|
|
168
|
+
]);
|
|
169
|
+
});
|
|
170
|
+
it('should be able to parse end markers with numbers', () => {
|
|
171
|
+
const tokens = parser.tokenize(`\\abc123*`);
|
|
172
|
+
expect(tokens).toEqual([
|
|
173
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 8), '\\abc', 123, 'end'),
|
|
174
|
+
]);
|
|
175
|
+
});
|
|
176
|
+
it('should throw an error if the marker does not have a command', () => {
|
|
177
|
+
expect(() => {
|
|
178
|
+
parser.tokenize(`\\`);
|
|
179
|
+
}).toThrowError();
|
|
180
|
+
});
|
|
181
|
+
it('should throw an error if the marker has a number but not a command', () => {
|
|
182
|
+
expect(() => {
|
|
183
|
+
parser.tokenize(`\\1`);
|
|
184
|
+
}).toThrowError();
|
|
185
|
+
});
|
|
186
|
+
it('should be able to parse end markers that have text after them', () => {
|
|
187
|
+
const tokens = parser.tokenize(`\\abc*z`);
|
|
188
|
+
expect(tokens).toEqual([
|
|
189
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 5), '\\abc', null, 'end'),
|
|
190
|
+
(0, usfm_parser_1.word)((0, usfm_parser_1.loc)(5, 6), 'z'),
|
|
191
|
+
]);
|
|
192
|
+
});
|
|
193
|
+
it('should be able to parse end markers that have text before them', () => {
|
|
194
|
+
const tokens = parser.tokenize(`z\\abc*`);
|
|
195
|
+
expect(tokens).toEqual([
|
|
196
|
+
(0, usfm_parser_1.word)((0, usfm_parser_1.loc)(0, 1), 'z'),
|
|
197
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(1, 6), '\\abc', null, 'end'),
|
|
198
|
+
]);
|
|
199
|
+
});
|
|
200
|
+
it('should be able to parse markers that have a space after them', () => {
|
|
201
|
+
const tokens = parser.tokenize(`\\abc z`);
|
|
202
|
+
expect(tokens).toEqual([
|
|
203
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 4), '\\abc'),
|
|
204
|
+
(0, usfm_parser_1.whitespace)((0, usfm_parser_1.loc)(4, 5), ' '),
|
|
205
|
+
(0, usfm_parser_1.word)((0, usfm_parser_1.loc)(5, 6), 'z'),
|
|
206
|
+
]);
|
|
207
|
+
});
|
|
208
|
+
it('should be able to parse markers that have a tab after them', () => {
|
|
209
|
+
const tokens = parser.tokenize(`\\abc\tz`);
|
|
210
|
+
expect(tokens).toEqual([
|
|
211
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 4), '\\abc'),
|
|
212
|
+
(0, usfm_parser_1.whitespace)((0, usfm_parser_1.loc)(4, 5), '\t'),
|
|
213
|
+
(0, usfm_parser_1.word)((0, usfm_parser_1.loc)(5, 6), 'z'),
|
|
214
|
+
]);
|
|
215
|
+
});
|
|
216
|
+
it('should be able to parse markers that have a newline after them', () => {
|
|
217
|
+
const tokens = parser.tokenize(`\\abc\nz`);
|
|
218
|
+
expect(tokens).toEqual([
|
|
219
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 4), '\\abc'),
|
|
220
|
+
(0, usfm_parser_1.whitespace)((0, usfm_parser_1.loc)(4, 5), '\n'),
|
|
221
|
+
(0, usfm_parser_1.word)((0, usfm_parser_1.loc)(5, 6), 'z'),
|
|
222
|
+
]);
|
|
223
|
+
});
|
|
224
|
+
it('should be able to parse ending markers that dont have a command', async () => {
|
|
225
|
+
const tokens = parser.tokenize(`\\w hello\\*`);
|
|
226
|
+
expect(tokens).toEqual([
|
|
227
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(0, 2), '\\w'),
|
|
228
|
+
(0, usfm_parser_1.whitespace)((0, usfm_parser_1.loc)(2, 3), ' '),
|
|
229
|
+
(0, usfm_parser_1.word)((0, usfm_parser_1.loc)(3, 8), 'hello'),
|
|
230
|
+
(0, usfm_parser_1.marker)((0, usfm_parser_1.loc)(8, 10), '\\w', null, 'end'),
|
|
231
|
+
]);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
describe('parse()', () => {
|
|
235
|
+
it('should produce a list of chapters', () => {
|
|
236
|
+
const tree = parser.parse(`\\c 1
|
|
237
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
238
|
+
\\v 2 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.
|
|
239
|
+
\\c 2
|
|
240
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
241
|
+
`);
|
|
242
|
+
expect(tree).toEqual({
|
|
243
|
+
type: 'root',
|
|
244
|
+
content: [
|
|
245
|
+
{
|
|
246
|
+
type: 'chapter',
|
|
247
|
+
number: 1,
|
|
248
|
+
content: [
|
|
249
|
+
{
|
|
250
|
+
type: 'verse',
|
|
251
|
+
number: 1,
|
|
252
|
+
content: [
|
|
253
|
+
'In the beginning God created the heavens and the earth.'
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
type: 'verse',
|
|
258
|
+
number: 2,
|
|
259
|
+
content: [
|
|
260
|
+
'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.'
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
footnotes: [],
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
type: 'chapter',
|
|
268
|
+
number: 2,
|
|
269
|
+
content: [
|
|
270
|
+
{
|
|
271
|
+
type: 'verse',
|
|
272
|
+
number: 1,
|
|
273
|
+
content: [
|
|
274
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
footnotes: [],
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
it('should infer the first verse of a chapter', () => {
|
|
284
|
+
const tree = parser.parse(`\\c 1
|
|
285
|
+
\\s1 The Two Paths
|
|
286
|
+
\\q1 Blessed is the man
|
|
287
|
+
\\q2 who does not walk in the counsel of the wicked,
|
|
288
|
+
\\q1 or set foot on the path of sinners,
|
|
289
|
+
\\q2 or sit in the seat of mockers.
|
|
290
|
+
\\q1
|
|
291
|
+
\\v 2 But his delight is in the Law of the LORD,
|
|
292
|
+
\\q2 and on His law he meditates day and night.
|
|
293
|
+
\\q1
|
|
294
|
+
\\c 2
|
|
295
|
+
\\q1 Why do the nations rage
|
|
296
|
+
\\q2 and the peoples plot in vain?
|
|
297
|
+
\\q1
|
|
298
|
+
`);
|
|
299
|
+
expect(tree).toEqual({
|
|
300
|
+
type: 'root',
|
|
301
|
+
content: [
|
|
302
|
+
{
|
|
303
|
+
type: 'chapter',
|
|
304
|
+
number: 1,
|
|
305
|
+
content: [
|
|
306
|
+
{
|
|
307
|
+
type: 'heading',
|
|
308
|
+
content: [
|
|
309
|
+
'The Two Paths'
|
|
310
|
+
]
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
type: 'verse',
|
|
314
|
+
number: 1,
|
|
315
|
+
content: [
|
|
316
|
+
{ text: 'Blessed is the man', poem: 1 },
|
|
317
|
+
{ text: 'who does not walk in the counsel of the wicked,', poem: 2 },
|
|
318
|
+
{ text: 'or set foot on the path of sinners,', poem: 1 },
|
|
319
|
+
{ text: 'or sit in the seat of mockers.', poem: 2 }
|
|
320
|
+
]
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
type: 'verse',
|
|
324
|
+
number: 2,
|
|
325
|
+
content: [
|
|
326
|
+
{ text: 'But his delight is in the Law of the LORD,', poem: 1 },
|
|
327
|
+
{ text: 'and on His law he meditates day and night.', poem: 2 }
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
],
|
|
331
|
+
footnotes: [],
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
type: 'chapter',
|
|
335
|
+
number: 2,
|
|
336
|
+
content: [
|
|
337
|
+
{
|
|
338
|
+
type: 'verse',
|
|
339
|
+
number: 1,
|
|
340
|
+
content: [
|
|
341
|
+
{ text: 'Why do the nations rage', poem: 1 },
|
|
342
|
+
{ text: 'and the peoples plot in vain?', poem: 2 }
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
footnotes: [],
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
it('should parse the intro to a book correctly', () => {
|
|
352
|
+
const tree = parser.parse(`\\id GEN - Berean Study Bible
|
|
353
|
+
\\h Genesis
|
|
354
|
+
\\toc1 Genesis
|
|
355
|
+
\\mt1 Genesis
|
|
356
|
+
\\c 1
|
|
357
|
+
\\s1 The Creation
|
|
358
|
+
\\r (John 1:1–5; Hebrews 11:1–3)
|
|
359
|
+
\\b
|
|
360
|
+
\\m
|
|
361
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
362
|
+
`);
|
|
363
|
+
expect(tree).toEqual({
|
|
364
|
+
type: 'root',
|
|
365
|
+
title: 'Genesis',
|
|
366
|
+
header: 'Genesis',
|
|
367
|
+
id: 'GEN',
|
|
368
|
+
content: [
|
|
369
|
+
{
|
|
370
|
+
type: 'chapter',
|
|
371
|
+
number: 1,
|
|
372
|
+
content: [
|
|
373
|
+
{
|
|
374
|
+
type: 'heading',
|
|
375
|
+
content: ['The Creation']
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
type: 'line_break',
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
type: 'verse',
|
|
382
|
+
number: 1,
|
|
383
|
+
content: [
|
|
384
|
+
'In the beginning God created the heavens and the earth.'
|
|
385
|
+
]
|
|
386
|
+
},
|
|
387
|
+
],
|
|
388
|
+
footnotes: [],
|
|
389
|
+
},
|
|
390
|
+
]
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
it('should be able to parse titles that are formatted with a +', () => {
|
|
394
|
+
const tree = parser.parse(`\\id GEN - Berean Study Bible
|
|
395
|
+
\\h Genesis
|
|
396
|
+
\\+toc1 Genesis
|
|
397
|
+
\\+mt1 Genesis
|
|
398
|
+
\\c 1
|
|
399
|
+
\\s1 The Creation
|
|
400
|
+
\\r (John 1:1–5; Hebrews 11:1–3)
|
|
401
|
+
\\b
|
|
402
|
+
\\m
|
|
403
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
404
|
+
`);
|
|
405
|
+
expect(tree).toEqual({
|
|
406
|
+
type: 'root',
|
|
407
|
+
title: 'Genesis',
|
|
408
|
+
header: 'Genesis',
|
|
409
|
+
id: 'GEN',
|
|
410
|
+
content: [
|
|
411
|
+
{
|
|
412
|
+
type: 'chapter',
|
|
413
|
+
number: 1,
|
|
414
|
+
content: [
|
|
415
|
+
{
|
|
416
|
+
type: 'heading',
|
|
417
|
+
content: ['The Creation']
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
type: 'line_break',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
type: 'verse',
|
|
424
|
+
number: 1,
|
|
425
|
+
content: [
|
|
426
|
+
'In the beginning God created the heavens and the earth.'
|
|
427
|
+
]
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
footnotes: [],
|
|
431
|
+
},
|
|
432
|
+
]
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
it('should support line breaks', () => {
|
|
436
|
+
const tree = parser.parse(`\\c 1
|
|
437
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
438
|
+
\\b
|
|
439
|
+
\\v 2 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.
|
|
440
|
+
\\b
|
|
441
|
+
\\c 2
|
|
442
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
443
|
+
`);
|
|
444
|
+
expect(tree).toEqual({
|
|
445
|
+
type: 'root',
|
|
446
|
+
content: [
|
|
447
|
+
{
|
|
448
|
+
type: 'chapter',
|
|
449
|
+
number: 1,
|
|
450
|
+
content: [
|
|
451
|
+
{
|
|
452
|
+
type: 'verse',
|
|
453
|
+
number: 1,
|
|
454
|
+
content: [
|
|
455
|
+
'In the beginning God created the heavens and the earth.'
|
|
456
|
+
]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
type: 'line_break'
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
type: 'verse',
|
|
463
|
+
number: 2,
|
|
464
|
+
content: [
|
|
465
|
+
'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.'
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
type: 'line_break'
|
|
470
|
+
},
|
|
471
|
+
],
|
|
472
|
+
footnotes: [],
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
type: 'chapter',
|
|
476
|
+
number: 2,
|
|
477
|
+
content: [
|
|
478
|
+
{
|
|
479
|
+
type: 'verse',
|
|
480
|
+
number: 1,
|
|
481
|
+
content: [
|
|
482
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
483
|
+
]
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
footnotes: [],
|
|
487
|
+
}
|
|
488
|
+
]
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
it('should support verses that are on the same line as another verse', () => {
|
|
492
|
+
const tree = parser.parse(`\\c 24
|
|
493
|
+
\\v 18 وَالثَّالِثَةُ وَالْعِشْرُونَ لِدَلايَا، وَالرَّابِعَةُ وَالْعِشْرُونَ لِمَعَزْيَا.
|
|
494
|
+
\\v 19 هَذَا كَانَ تَرْتِيبَ خَدَمَاتِهِمِ الَّتِي كُلِّفُوا بِها عِنْدَ دُخُولِهِمْ إِلَى بَيْتِ الرَّبِّ بِمُقْتَضَى الْمَرَاسِيمِ الَّتِي حَدَّدَهَا لَهُمْ جَدُّهُمُ الأَكْبَرُ هرُونُ، تَمَاماً كَمَا أَمَرَهُ الرَّبُّ إِلَهُ إِسْرَائِيلَ. \\s1 بقية اللاويين \\p \\v 20 أَمَّا بَقِيَّةُ أَبْنَاءِ لاوِي فَهُمْ: مِنْ ذُرِّيَّةِ عَمْرَامَ: شُوبَائِيلُ، وَمِنْ أَبْنَاءِ شُوبَائِيلَ يَحَدْيَا.
|
|
495
|
+
\\b
|
|
496
|
+
\\v 21 وَمِنْ ذُرِّيَّةِ رَحَبْيَا: الْبِكْرُ يَشِّيَّا.
|
|
497
|
+
`);
|
|
498
|
+
expect(tree).toEqual({
|
|
499
|
+
type: 'root',
|
|
500
|
+
content: [
|
|
501
|
+
{
|
|
502
|
+
type: 'chapter',
|
|
503
|
+
number: 24,
|
|
504
|
+
content: [
|
|
505
|
+
{
|
|
506
|
+
type: 'verse',
|
|
507
|
+
number: 18,
|
|
508
|
+
content: [
|
|
509
|
+
'وَالثَّالِثَةُ وَالْعِشْرُونَ لِدَلايَا، وَالرَّابِعَةُ وَالْعِشْرُونَ لِمَعَزْيَا.'
|
|
510
|
+
]
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
type: 'verse',
|
|
514
|
+
number: 19,
|
|
515
|
+
content: [
|
|
516
|
+
'هَذَا كَانَ تَرْتِيبَ خَدَمَاتِهِمِ الَّتِي كُلِّفُوا بِها عِنْدَ دُخُولِهِمْ إِلَى بَيْتِ الرَّبِّ بِمُقْتَضَى الْمَرَاسِيمِ الَّتِي حَدَّدَهَا لَهُمْ جَدُّهُمُ الأَكْبَرُ هرُونُ، تَمَاماً كَمَا أَمَرَهُ الرَّبُّ إِلَهُ إِسْرَائِيلَ.'
|
|
517
|
+
]
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
type: 'line_break',
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
type: 'heading',
|
|
524
|
+
content: [
|
|
525
|
+
'بقية اللاويين'
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
type: 'verse',
|
|
530
|
+
number: 20,
|
|
531
|
+
content: [
|
|
532
|
+
'أَمَّا بَقِيَّةُ أَبْنَاءِ لاوِي فَهُمْ: مِنْ ذُرِّيَّةِ عَمْرَامَ: شُوبَائِيلُ، وَمِنْ أَبْنَاءِ شُوبَائِيلَ يَحَدْيَا.'
|
|
533
|
+
]
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
type: 'line_break'
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
type: 'verse',
|
|
540
|
+
number: 21,
|
|
541
|
+
content: [
|
|
542
|
+
'وَمِنْ ذُرِّيَّةِ رَحَبْيَا: الْبِكْرُ يَشِّيَّا.'
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
],
|
|
546
|
+
footnotes: [],
|
|
547
|
+
},
|
|
548
|
+
]
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
it('should ignore verses that have no number indicator', () => {
|
|
552
|
+
const tree = parser.parse(`\\c 1
|
|
553
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
554
|
+
\\v
|
|
555
|
+
\\v 2 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.
|
|
556
|
+
`);
|
|
557
|
+
expect(tree).toEqual({
|
|
558
|
+
type: 'root',
|
|
559
|
+
content: [
|
|
560
|
+
{
|
|
561
|
+
type: 'chapter',
|
|
562
|
+
number: 1,
|
|
563
|
+
content: [
|
|
564
|
+
{
|
|
565
|
+
type: 'verse',
|
|
566
|
+
number: 1,
|
|
567
|
+
content: [
|
|
568
|
+
'In the beginning God created the heavens and the earth.'
|
|
569
|
+
]
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
type: 'verse',
|
|
573
|
+
number: 2,
|
|
574
|
+
content: [
|
|
575
|
+
'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.'
|
|
576
|
+
]
|
|
577
|
+
},
|
|
578
|
+
],
|
|
579
|
+
footnotes: [],
|
|
580
|
+
},
|
|
581
|
+
]
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
it('should treat paragraphs like line breaks', () => {
|
|
585
|
+
const tree = parser.parse(`\\c 1
|
|
586
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
587
|
+
\\p
|
|
588
|
+
\\v 2 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.
|
|
589
|
+
\\p
|
|
590
|
+
\\c 2
|
|
591
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
592
|
+
`);
|
|
593
|
+
expect(tree).toEqual({
|
|
594
|
+
type: 'root',
|
|
595
|
+
content: [
|
|
596
|
+
{
|
|
597
|
+
type: 'chapter',
|
|
598
|
+
number: 1,
|
|
599
|
+
content: [
|
|
600
|
+
{
|
|
601
|
+
type: 'verse',
|
|
602
|
+
number: 1,
|
|
603
|
+
content: [
|
|
604
|
+
'In the beginning God created the heavens and the earth.'
|
|
605
|
+
]
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
type: 'line_break'
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
type: 'verse',
|
|
612
|
+
number: 2,
|
|
613
|
+
content: [
|
|
614
|
+
'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.'
|
|
615
|
+
]
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
type: 'line_break'
|
|
619
|
+
},
|
|
620
|
+
],
|
|
621
|
+
footnotes: [],
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
type: 'chapter',
|
|
625
|
+
number: 2,
|
|
626
|
+
content: [
|
|
627
|
+
{
|
|
628
|
+
type: 'verse',
|
|
629
|
+
number: 1,
|
|
630
|
+
content: [
|
|
631
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
632
|
+
]
|
|
633
|
+
},
|
|
634
|
+
],
|
|
635
|
+
footnotes: [],
|
|
636
|
+
}
|
|
637
|
+
]
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
it('should support ID tags', () => {
|
|
641
|
+
const tree = parser.parse(`
|
|
642
|
+
\\id GEN - Berean Study Bible
|
|
643
|
+
\\c 1
|
|
644
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
645
|
+
\\v 2 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.
|
|
646
|
+
\\c 2
|
|
647
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
648
|
+
`);
|
|
649
|
+
expect(tree).toEqual({
|
|
650
|
+
type: 'root',
|
|
651
|
+
id: 'GEN',
|
|
652
|
+
content: [
|
|
653
|
+
{
|
|
654
|
+
type: 'chapter',
|
|
655
|
+
number: 1,
|
|
656
|
+
content: [
|
|
657
|
+
{
|
|
658
|
+
type: 'verse',
|
|
659
|
+
number: 1,
|
|
660
|
+
content: [
|
|
661
|
+
'In the beginning God created the heavens and the earth.'
|
|
662
|
+
]
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
type: 'verse',
|
|
666
|
+
number: 2,
|
|
667
|
+
content: [
|
|
668
|
+
'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.'
|
|
669
|
+
]
|
|
670
|
+
}
|
|
671
|
+
],
|
|
672
|
+
footnotes: [],
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
type: 'chapter',
|
|
676
|
+
number: 2,
|
|
677
|
+
content: [
|
|
678
|
+
{
|
|
679
|
+
type: 'verse',
|
|
680
|
+
number: 1,
|
|
681
|
+
content: [
|
|
682
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
683
|
+
]
|
|
684
|
+
},
|
|
685
|
+
],
|
|
686
|
+
footnotes: [],
|
|
687
|
+
}
|
|
688
|
+
]
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
it('should support major title headings', () => {
|
|
692
|
+
const tree = parser.parse(`
|
|
693
|
+
\\mt1 The
|
|
694
|
+
\\mt2 Title
|
|
695
|
+
\\mt3 of the Book
|
|
696
|
+
\\c 1
|
|
697
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
698
|
+
\\v 2 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.
|
|
699
|
+
\\c 2
|
|
700
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
701
|
+
`);
|
|
702
|
+
expect(tree).toEqual({
|
|
703
|
+
type: 'root',
|
|
704
|
+
title: 'The Title of the Book',
|
|
705
|
+
content: [
|
|
706
|
+
{
|
|
707
|
+
type: 'chapter',
|
|
708
|
+
number: 1,
|
|
709
|
+
content: [
|
|
710
|
+
{
|
|
711
|
+
type: 'verse',
|
|
712
|
+
number: 1,
|
|
713
|
+
content: [
|
|
714
|
+
'In the beginning God created the heavens and the earth.'
|
|
715
|
+
]
|
|
716
|
+
},
|
|
717
|
+
{
|
|
718
|
+
type: 'verse',
|
|
719
|
+
number: 2,
|
|
720
|
+
content: [
|
|
721
|
+
'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.'
|
|
722
|
+
]
|
|
723
|
+
}
|
|
724
|
+
],
|
|
725
|
+
footnotes: [],
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
type: 'chapter',
|
|
729
|
+
number: 2,
|
|
730
|
+
content: [
|
|
731
|
+
{
|
|
732
|
+
type: 'verse',
|
|
733
|
+
number: 1,
|
|
734
|
+
content: [
|
|
735
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
736
|
+
]
|
|
737
|
+
},
|
|
738
|
+
],
|
|
739
|
+
footnotes: [],
|
|
740
|
+
}
|
|
741
|
+
]
|
|
742
|
+
});
|
|
743
|
+
});
|
|
744
|
+
it('should support header text', () => {
|
|
745
|
+
const tree = parser.parse(`
|
|
746
|
+
\\h Genesis
|
|
747
|
+
\\c 1
|
|
748
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
749
|
+
\\v 2 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.
|
|
750
|
+
\\c 2
|
|
751
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
752
|
+
`);
|
|
753
|
+
expect(tree).toEqual({
|
|
754
|
+
type: 'root',
|
|
755
|
+
header: 'Genesis',
|
|
756
|
+
content: [
|
|
757
|
+
{
|
|
758
|
+
type: 'chapter',
|
|
759
|
+
number: 1,
|
|
760
|
+
content: [
|
|
761
|
+
{
|
|
762
|
+
type: 'verse',
|
|
763
|
+
number: 1,
|
|
764
|
+
content: [
|
|
765
|
+
'In the beginning God created the heavens and the earth.'
|
|
766
|
+
]
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
type: 'verse',
|
|
770
|
+
number: 2,
|
|
771
|
+
content: [
|
|
772
|
+
'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.'
|
|
773
|
+
]
|
|
774
|
+
}
|
|
775
|
+
],
|
|
776
|
+
footnotes: [],
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
type: 'chapter',
|
|
780
|
+
number: 2,
|
|
781
|
+
content: [
|
|
782
|
+
{
|
|
783
|
+
type: 'verse',
|
|
784
|
+
number: 1,
|
|
785
|
+
content: [
|
|
786
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
787
|
+
]
|
|
788
|
+
},
|
|
789
|
+
],
|
|
790
|
+
footnotes: [],
|
|
791
|
+
}
|
|
792
|
+
]
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
it('should support section headings in chapters', () => {
|
|
796
|
+
const tree = parser.parse(`\\c 1
|
|
797
|
+
\\s1 The Creation
|
|
798
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
799
|
+
\\v 2 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.
|
|
800
|
+
\\c 2
|
|
801
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
802
|
+
`);
|
|
803
|
+
expect(tree).toEqual({
|
|
804
|
+
type: 'root',
|
|
805
|
+
content: [
|
|
806
|
+
{
|
|
807
|
+
type: 'chapter',
|
|
808
|
+
number: 1,
|
|
809
|
+
content: [
|
|
810
|
+
{
|
|
811
|
+
type: 'heading',
|
|
812
|
+
content: [
|
|
813
|
+
'The Creation'
|
|
814
|
+
]
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
type: 'verse',
|
|
818
|
+
number: 1,
|
|
819
|
+
content: [
|
|
820
|
+
'In the beginning God created the heavens and the earth.'
|
|
821
|
+
]
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
type: 'verse',
|
|
825
|
+
number: 2,
|
|
826
|
+
content: [
|
|
827
|
+
'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.'
|
|
828
|
+
]
|
|
829
|
+
}
|
|
830
|
+
],
|
|
831
|
+
footnotes: [],
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
type: 'chapter',
|
|
835
|
+
number: 2,
|
|
836
|
+
content: [
|
|
837
|
+
{
|
|
838
|
+
type: 'verse',
|
|
839
|
+
number: 1,
|
|
840
|
+
content: [
|
|
841
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
842
|
+
]
|
|
843
|
+
},
|
|
844
|
+
],
|
|
845
|
+
footnotes: [],
|
|
846
|
+
}
|
|
847
|
+
]
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
it('should support section headings outside of chapters', () => {
|
|
851
|
+
const tree = parser.parse(`\\s1 The Creation
|
|
852
|
+
`);
|
|
853
|
+
expect(tree).toEqual({
|
|
854
|
+
type: 'root',
|
|
855
|
+
content: [
|
|
856
|
+
{
|
|
857
|
+
type: 'heading',
|
|
858
|
+
content: [
|
|
859
|
+
'The Creation'
|
|
860
|
+
],
|
|
861
|
+
}
|
|
862
|
+
]
|
|
863
|
+
});
|
|
864
|
+
});
|
|
865
|
+
it('should support footnotes', () => {
|
|
866
|
+
const tree = parser.parse(`\\c 1
|
|
867
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
868
|
+
\\v 2 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.
|
|
869
|
+
\\v 3 And God said, “Let there be light,” \\f + \\fr 1:3 \\ft Cited in 2 Corinthians 4:6\\f* and there was light.
|
|
870
|
+
\\c 2
|
|
871
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
872
|
+
`);
|
|
873
|
+
expect(tree).toEqual({
|
|
874
|
+
type: 'root',
|
|
875
|
+
content: [
|
|
876
|
+
{
|
|
877
|
+
type: 'chapter',
|
|
878
|
+
number: 1,
|
|
879
|
+
content: [
|
|
880
|
+
{
|
|
881
|
+
type: 'verse',
|
|
882
|
+
number: 1,
|
|
883
|
+
content: [
|
|
884
|
+
'In the beginning God created the heavens and the earth.'
|
|
885
|
+
]
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
type: 'verse',
|
|
889
|
+
number: 2,
|
|
890
|
+
content: [
|
|
891
|
+
'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.'
|
|
892
|
+
]
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
type: 'verse',
|
|
896
|
+
number: 3,
|
|
897
|
+
content: [
|
|
898
|
+
'And God said, “Let there be light,”',
|
|
899
|
+
{
|
|
900
|
+
noteId: 0
|
|
901
|
+
},
|
|
902
|
+
'and there was light.'
|
|
903
|
+
]
|
|
904
|
+
}
|
|
905
|
+
],
|
|
906
|
+
footnotes: [
|
|
907
|
+
{
|
|
908
|
+
noteId: 0,
|
|
909
|
+
text: 'Cited in 2 Corinthians 4:6',
|
|
910
|
+
caller: '+',
|
|
911
|
+
reference: {
|
|
912
|
+
chapter: 1,
|
|
913
|
+
verse: 3
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
]
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
type: 'chapter',
|
|
920
|
+
number: 2,
|
|
921
|
+
content: [
|
|
922
|
+
{
|
|
923
|
+
type: 'verse',
|
|
924
|
+
number: 1,
|
|
925
|
+
content: [
|
|
926
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
927
|
+
]
|
|
928
|
+
},
|
|
929
|
+
],
|
|
930
|
+
footnotes: []
|
|
931
|
+
}
|
|
932
|
+
]
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
it('should support custom footnote callers', () => {
|
|
936
|
+
const tree = parser.parse(`\\c 1
|
|
937
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
938
|
+
\\v 2 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.
|
|
939
|
+
\\v 3 And God said, “Let there be light,” \\f a \\fr 1:3 \\ft Cited in 2 Corinthians 4:6\\f* and there was light.
|
|
940
|
+
\\c 2
|
|
941
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
942
|
+
`);
|
|
943
|
+
expect(tree).toEqual({
|
|
944
|
+
type: 'root',
|
|
945
|
+
content: [
|
|
946
|
+
{
|
|
947
|
+
type: 'chapter',
|
|
948
|
+
number: 1,
|
|
949
|
+
content: [
|
|
950
|
+
{
|
|
951
|
+
type: 'verse',
|
|
952
|
+
number: 1,
|
|
953
|
+
content: [
|
|
954
|
+
'In the beginning God created the heavens and the earth.'
|
|
955
|
+
]
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
type: 'verse',
|
|
959
|
+
number: 2,
|
|
960
|
+
content: [
|
|
961
|
+
'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.'
|
|
962
|
+
]
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
type: 'verse',
|
|
966
|
+
number: 3,
|
|
967
|
+
content: [
|
|
968
|
+
'And God said, “Let there be light,”',
|
|
969
|
+
{
|
|
970
|
+
noteId: 0
|
|
971
|
+
},
|
|
972
|
+
'and there was light.'
|
|
973
|
+
]
|
|
974
|
+
}
|
|
975
|
+
],
|
|
976
|
+
footnotes: [
|
|
977
|
+
{
|
|
978
|
+
noteId: 0,
|
|
979
|
+
text: 'Cited in 2 Corinthians 4:6',
|
|
980
|
+
caller: 'a',
|
|
981
|
+
reference: {
|
|
982
|
+
chapter: 1,
|
|
983
|
+
verse: 3
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
type: 'chapter',
|
|
990
|
+
number: 2,
|
|
991
|
+
content: [
|
|
992
|
+
{
|
|
993
|
+
type: 'verse',
|
|
994
|
+
number: 1,
|
|
995
|
+
content: [
|
|
996
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
997
|
+
]
|
|
998
|
+
},
|
|
999
|
+
],
|
|
1000
|
+
footnotes: []
|
|
1001
|
+
}
|
|
1002
|
+
]
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
it('should ignore introduction paragraphs', () => {
|
|
1006
|
+
const tree = parser.parse(`
|
|
1007
|
+
\\ip The Holy Bible is translated into many languages, and being translated into many more, so that everyone may have an opportunity to hear the Good News about Jesus Christ.\\f + \\fr 1:0 \\ft “Christ” means “Anointed One”.\\f*
|
|
1008
|
+
`);
|
|
1009
|
+
expect(tree).toEqual({
|
|
1010
|
+
type: 'root',
|
|
1011
|
+
content: [
|
|
1012
|
+
// {
|
|
1013
|
+
// type: 'intro_paragraph',
|
|
1014
|
+
// content: [
|
|
1015
|
+
// 'The Holy Bible is translated into many languages, and being translated into many more, so that everyone may have an opportunity to hear the Good News about Jesus Christ.'
|
|
1016
|
+
// ]
|
|
1017
|
+
// }
|
|
1018
|
+
]
|
|
1019
|
+
});
|
|
1020
|
+
});
|
|
1021
|
+
it('should support references', () => {
|
|
1022
|
+
const tree = parser.parse(`\\c 1
|
|
1023
|
+
\\r (John 1:1–5; Hebrews 11:1–3)
|
|
1024
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
1025
|
+
\\v 2 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.
|
|
1026
|
+
\\c 2
|
|
1027
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
1028
|
+
`);
|
|
1029
|
+
expect(tree).toEqual({
|
|
1030
|
+
type: 'root',
|
|
1031
|
+
content: [
|
|
1032
|
+
{
|
|
1033
|
+
type: 'chapter',
|
|
1034
|
+
number: 1,
|
|
1035
|
+
content: [
|
|
1036
|
+
{
|
|
1037
|
+
type: 'verse',
|
|
1038
|
+
number: 1,
|
|
1039
|
+
content: [
|
|
1040
|
+
'In the beginning God created the heavens and the earth.'
|
|
1041
|
+
]
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
type: 'verse',
|
|
1045
|
+
number: 2,
|
|
1046
|
+
content: [
|
|
1047
|
+
'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.'
|
|
1048
|
+
]
|
|
1049
|
+
}
|
|
1050
|
+
],
|
|
1051
|
+
footnotes: [],
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
type: 'chapter',
|
|
1055
|
+
number: 2,
|
|
1056
|
+
content: [
|
|
1057
|
+
{
|
|
1058
|
+
type: 'verse',
|
|
1059
|
+
number: 1,
|
|
1060
|
+
content: [
|
|
1061
|
+
'Thus the heavens and the earth were completed in all their vast array.'
|
|
1062
|
+
]
|
|
1063
|
+
},
|
|
1064
|
+
],
|
|
1065
|
+
footnotes: [],
|
|
1066
|
+
}
|
|
1067
|
+
]
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
it('should support parsing descriptive titles', () => {
|
|
1071
|
+
const tree = parser.parse(`\\c 6
|
|
1072
|
+
\\s1 Do Not Rebuke Me in Your Anger
|
|
1073
|
+
\\r (Psalm 38:1–22)
|
|
1074
|
+
\\b
|
|
1075
|
+
\\d For the choirmaster. With stringed instruments, according to Sheminith.\\f + \\fr 6:1 \\ft Sheminith is probably a musical term; here and in 1 Chronicles 15:21 and Psalm 12:1.\\f* A Psalm of David.
|
|
1076
|
+
\\b
|
|
1077
|
+
\\q1
|
|
1078
|
+
\\v 1 O LORD, do not rebuke me in Your anger
|
|
1079
|
+
\\q2 or discipline me in Your wrath.
|
|
1080
|
+
\\q1
|
|
1081
|
+
`);
|
|
1082
|
+
expect(tree).toEqual({
|
|
1083
|
+
type: 'root',
|
|
1084
|
+
content: [
|
|
1085
|
+
{
|
|
1086
|
+
type: 'chapter',
|
|
1087
|
+
number: 6,
|
|
1088
|
+
content: [
|
|
1089
|
+
{
|
|
1090
|
+
type: 'heading',
|
|
1091
|
+
content: [
|
|
1092
|
+
'Do Not Rebuke Me in Your Anger'
|
|
1093
|
+
]
|
|
1094
|
+
},
|
|
1095
|
+
{
|
|
1096
|
+
type: 'line_break',
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
type: 'hebrew_subtitle',
|
|
1100
|
+
content: [
|
|
1101
|
+
'For the choirmaster. With stringed instruments, according to Sheminith.',
|
|
1102
|
+
{ noteId: 0 },
|
|
1103
|
+
'A Psalm of David.'
|
|
1104
|
+
]
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
type: 'line_break',
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
type: 'verse',
|
|
1111
|
+
number: 1,
|
|
1112
|
+
content: [
|
|
1113
|
+
{ text: 'O LORD, do not rebuke me in Your anger', poem: 1 },
|
|
1114
|
+
{ text: 'or discipline me in Your wrath.', poem: 2 },
|
|
1115
|
+
]
|
|
1116
|
+
},
|
|
1117
|
+
],
|
|
1118
|
+
footnotes: [
|
|
1119
|
+
{
|
|
1120
|
+
noteId: 0,
|
|
1121
|
+
text: 'Sheminith is probably a musical term; here and in 1 Chronicles 15:21 and Psalm 12:1.',
|
|
1122
|
+
caller: '+',
|
|
1123
|
+
reference: {
|
|
1124
|
+
chapter: 6,
|
|
1125
|
+
verse: 1
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
],
|
|
1129
|
+
},
|
|
1130
|
+
]
|
|
1131
|
+
});
|
|
1132
|
+
});
|
|
1133
|
+
it('should ignore word level attributes', () => {
|
|
1134
|
+
const tree = parser.parse(`\\c 1
|
|
1135
|
+
\\v 1 \\w In|strong="H0430"\\w* \\w the|strong="H0853"\\w* \\w beginning|strong="H7225"\\w*, \\w God|strong="H0430"\\w* \\w created|strong="H1254"\\w* \\w the|strong="H0853"\\w* \\w heavens|strong="H8064"\\w* \\w and|strong="H0430"\\w* \\w the|strong="H0853"\\w* \\w earth|strong="H0776"\\w*.
|
|
1136
|
+
`);
|
|
1137
|
+
expect(tree).toEqual({
|
|
1138
|
+
type: 'root',
|
|
1139
|
+
content: [
|
|
1140
|
+
{
|
|
1141
|
+
type: 'chapter',
|
|
1142
|
+
number: 1,
|
|
1143
|
+
content: [
|
|
1144
|
+
{
|
|
1145
|
+
type: 'verse',
|
|
1146
|
+
number: 1,
|
|
1147
|
+
content: [
|
|
1148
|
+
'In the beginning, God created the heavens and the earth.'
|
|
1149
|
+
]
|
|
1150
|
+
},
|
|
1151
|
+
],
|
|
1152
|
+
footnotes: [],
|
|
1153
|
+
},
|
|
1154
|
+
]
|
|
1155
|
+
});
|
|
1156
|
+
});
|
|
1157
|
+
it('should ignore cross references', () => {
|
|
1158
|
+
const tree = parser.parse(`\\c 5
|
|
1159
|
+
\\p
|
|
1160
|
+
\\v 1 \\w Seeing|strong="G3708"\\w* \\w the|strong="G3588"\\w* \\w multitudes|strong="G3793"\\w*, \\w he|strong="G2532"\\w* \\w went|strong="G0305"\\w* \\w up|strong="G0305"\\w* \\w onto|strong="G1519"\\w* \\w the|strong="G3588"\\w* \\w mountain|strong="G3735"\\w*. \\w When|strong="G2532"\\w* \\w he|strong="G2532"\\w* \\w had|strong="G3588"\\w* \\w sat|strong="G2523"\\w* \\w down|strong="G2523"\\w*, \\w his|strong="G0846"\\w* \\w disciples|strong="G3101"\\w* \\w came|strong="G4334"\\w* \\w to|strong="G1519"\\w* \\w him|strong="G0846"\\w*.
|
|
1161
|
+
\\v 2 \\w He|strong="G2532"\\w* \\w opened|strong="G0455"\\w* \\w his|strong="G0846"\\w* \\w mouth|strong="G4750"\\w* \\w and|strong="G2532"\\w* \\w taught|strong="G1321"\\w* \\w them|strong="G0846"\\w*, \\w saying|strong="G3004"\\w*,
|
|
1162
|
+
\\q1
|
|
1163
|
+
\\v 3 \\wj “\\+w Blessed|strong="G3107"\\+w* \\+w are|strong="G1510"\\+w* \\+w the|strong="G3588"\\+w* \\+w poor|strong="G4434"\\+w* \\+w in|strong="G4434"\\+w* \\+w spirit|strong="G4151"\\+w*,\\wj*
|
|
1164
|
+
\\q2 \\wj \\+w for|strong="G3754"\\+w* \\+w theirs|strong="G0846"\\+w* \\+w is|strong="G1510"\\+w* \\+w the|strong="G3588"\\+w* \\+w Kingdom|strong="G0932"\\+w* \\+w of|strong="G0932"\\+w* \\+w Heaven|strong="G3772"\\+w*.\\wj*\\x + \\xo 5:3 \\xt Isaiah 57:15; 66:2\\x*
|
|
1165
|
+
`);
|
|
1166
|
+
expect(tree).toEqual({
|
|
1167
|
+
type: 'root',
|
|
1168
|
+
content: [
|
|
1169
|
+
{
|
|
1170
|
+
type: 'chapter',
|
|
1171
|
+
number: 5,
|
|
1172
|
+
content: [
|
|
1173
|
+
{
|
|
1174
|
+
type: 'line_break'
|
|
1175
|
+
},
|
|
1176
|
+
{
|
|
1177
|
+
type: 'verse',
|
|
1178
|
+
number: 1,
|
|
1179
|
+
content: [
|
|
1180
|
+
'Seeing the multitudes, he went up onto the mountain. When he had sat down, his disciples came to him.'
|
|
1181
|
+
]
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
type: 'verse',
|
|
1185
|
+
number: 2,
|
|
1186
|
+
content: [
|
|
1187
|
+
'He opened his mouth and taught them, saying,',
|
|
1188
|
+
]
|
|
1189
|
+
},
|
|
1190
|
+
{
|
|
1191
|
+
type: 'verse',
|
|
1192
|
+
number: 3,
|
|
1193
|
+
content: [
|
|
1194
|
+
{
|
|
1195
|
+
"poem": 1,
|
|
1196
|
+
"text": "“Blessed are the poor in spirit,",
|
|
1197
|
+
"wordsOfJesus": true,
|
|
1198
|
+
},
|
|
1199
|
+
{
|
|
1200
|
+
"poem": 2,
|
|
1201
|
+
"text": "for theirs is the Kingdom of Heaven.",
|
|
1202
|
+
"wordsOfJesus": true,
|
|
1203
|
+
},
|
|
1204
|
+
]
|
|
1205
|
+
},
|
|
1206
|
+
],
|
|
1207
|
+
footnotes: [],
|
|
1208
|
+
},
|
|
1209
|
+
]
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1212
|
+
it('should support the Words of Jesus', () => {
|
|
1213
|
+
const tree = parser.parse(`\\c 8
|
|
1214
|
+
\\v 10 \\w When|strong="G2532"\\w* \\w Jesus|strong="G2424"\\w* \\w heard|strong="G0191"\\w* \\w it|strong="G0191"\\w*, \\w he|strong="G2532"\\w* \\w marveled|strong="G2296"\\w* \\w and|strong="G2532"\\w* \\w said|strong="G3004"\\w* \\w to|strong="G3004"\\w* \\w those|strong="G3588"\\w* \\w who|strong="G3588"\\w* \\w followed|strong="G0190"\\w*, \\wj “Most \\+w certainly|strong="G2532"\\+w* \\+w I|strong="G0281"\\+w* \\+w tell|strong="G3004"\\+w* \\+w you|strong="G5210"\\+w*, \\+w I|strong="G0281"\\+w* \\+w haven’t|strong="G3761"\\+w* \\+w found|strong="G2147"\\+w* \\+w so|strong="G2532"\\+w* \\+w great|strong="G5118"\\+w* \\+w a|strong="G2147"\\+w* \\+w faith|strong="G4102"\\+w*, \\+w not|strong="G3761"\\+w* \\+w even|strong="G2532"\\+w* \\+w in|strong="G1722"\\+w* \\+w Israel|strong="G2474"\\+w*. \\wj*
|
|
1215
|
+
\\v 11 \\wj \\+w I|strong="G2532"\\+w* \\+w tell|strong="G3004"\\+w* \\+w you|strong="G5210"\\+w* \\+w that|strong="G3754"\\+w* \\+w many|strong="G4183"\\+w* \\+w will|strong="G4183"\\+w* \\+w come|strong="G2240"\\+w* \\+w from|strong="G0575"\\+w* \\+w the|strong="G3588"\\+w* \\+w east|strong="G0395"\\+w* \\+w and|strong="G2532"\\+w* \\+w the|strong="G3588"\\+w* \\+w west|strong="G1424"\\+w*, \\+w and|strong="G2532"\\+w* \\+w will|strong="G4183"\\+w* \\+w sit|strong="G0347"\\+w* \\+w down|strong="G0347"\\+w* \\+w with|strong="G3326"\\+w* \\+w Abraham|strong="G0011"\\+w*, \\+w Isaac|strong="G2464"\\+w*, \\+w and|strong="G2532"\\+w* \\+w Jacob|strong="G2384"\\+w* \\+w in|strong="G1722"\\+w* \\+w the|strong="G3588"\\+w* \\+w Kingdom|strong="G0932"\\+w* \\+w of|strong="G0932"\\+w* \\+w Heaven|strong="G3772"\\+w*, \\wj*
|
|
1216
|
+
\\v 12 \\wj \\+w but|strong="G1161"\\+w* \\+w the|strong="G3588"\\+w* children \\+w of|strong="G5207"\\+w* \\+w the|strong="G3588"\\+w* \\+w Kingdom|strong="G0932"\\+w* \\+w will|strong="G1510"\\+w* \\+w be|strong="G1510"\\+w* thrown \\+w out|strong="G1831"\\+w* \\+w into|strong="G1519"\\+w* \\+w the|strong="G3588"\\+w* \\+w outer|strong="G1857"\\+w* \\+w darkness|strong="G4655"\\+w*. \\+w There|strong="G1563"\\+w* \\+w will|strong="G1510"\\+w* \\+w be|strong="G1510"\\+w* \\+w weeping|strong="G2805"\\+w* \\+w and|strong="G2532"\\+w* \\+w gnashing|strong="G1030"\\+w* \\+w of|strong="G5207"\\+w* \\+w teeth|strong="G3599"\\+w*.”\\wj*
|
|
1217
|
+
\\v 13 \\w Jesus|strong="G2424"\\w* \\w said|strong="G3004"\\w* \\w to|strong="G3004"\\w* \\w the|strong="G3588"\\w* \\w centurion|strong="G1543"\\w*, \\wj “\\+w Go|strong="G5217"\\+w* \\+w your|strong="G2532"\\+w* \\+w way|strong="G1722"\\+w*. \\+w Let|strong="G1096"\\+w* \\+w it|strong="G2532"\\+w* \\+w be|strong="G1096"\\+w* \\+w done|strong="G1096"\\+w* \\+w for|strong="G1722"\\+w* \\+w you|strong="G4771"\\+w* \\+w as|strong="G5613"\\+w* \\+w you|strong="G4771"\\+w* \\+w have|strong="G2532"\\+w* \\+w believed|strong="G4100"\\+w*.”\\wj* \\w His|strong="G5613"\\w* \\w servant|strong="G3816"\\w* \\w was|strong="G2424"\\w* \\w healed|strong="G2390"\\w* \\w in|strong="G1722"\\w* \\w that|strong="G1565"\\w* \\w hour|strong="G5610"\\w*.
|
|
1218
|
+
`);
|
|
1219
|
+
expect(tree).toEqual({
|
|
1220
|
+
type: 'root',
|
|
1221
|
+
content: [
|
|
1222
|
+
{
|
|
1223
|
+
type: 'chapter',
|
|
1224
|
+
number: 8,
|
|
1225
|
+
content: [
|
|
1226
|
+
{
|
|
1227
|
+
type: 'verse',
|
|
1228
|
+
number: 10,
|
|
1229
|
+
content: [
|
|
1230
|
+
'When Jesus heard it, he marveled and said to those who followed,',
|
|
1231
|
+
{
|
|
1232
|
+
text: '“Most certainly I tell you, I haven’t found so great a faith, not even in Israel.',
|
|
1233
|
+
wordsOfJesus: true
|
|
1234
|
+
}
|
|
1235
|
+
]
|
|
1236
|
+
},
|
|
1237
|
+
{
|
|
1238
|
+
type: 'verse',
|
|
1239
|
+
number: 11,
|
|
1240
|
+
content: [
|
|
1241
|
+
{
|
|
1242
|
+
text: 'I tell you that many will come from the east and the west, and will sit down with Abraham, Isaac, and Jacob in the Kingdom of Heaven,',
|
|
1243
|
+
wordsOfJesus: true
|
|
1244
|
+
}
|
|
1245
|
+
]
|
|
1246
|
+
},
|
|
1247
|
+
{
|
|
1248
|
+
type: 'verse',
|
|
1249
|
+
number: 12,
|
|
1250
|
+
content: [
|
|
1251
|
+
{
|
|
1252
|
+
text: 'but the children of the Kingdom will be thrown out into the outer darkness. There will be weeping and gnashing of teeth.”',
|
|
1253
|
+
wordsOfJesus: true
|
|
1254
|
+
}
|
|
1255
|
+
]
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
type: 'verse',
|
|
1259
|
+
number: 13,
|
|
1260
|
+
content: [
|
|
1261
|
+
'Jesus said to the centurion,',
|
|
1262
|
+
{
|
|
1263
|
+
text: '“Go your way. Let it be done for you as you have believed.”',
|
|
1264
|
+
wordsOfJesus: true
|
|
1265
|
+
},
|
|
1266
|
+
"His servant was healed in that hour.",
|
|
1267
|
+
]
|
|
1268
|
+
}
|
|
1269
|
+
],
|
|
1270
|
+
footnotes: []
|
|
1271
|
+
},
|
|
1272
|
+
]
|
|
1273
|
+
});
|
|
1274
|
+
});
|
|
1275
|
+
it('should not place spaces between Words of Jesus', () => {
|
|
1276
|
+
const tree = parser.parse(`\\c 8
|
|
1277
|
+
\\v 11 \\wj I tell you that many will come \\wj* \\wj from the east and the west, and will sit down with Abraham, Isaac, and Jacob in the Kingdom of Heaven, \\wj*
|
|
1278
|
+
`);
|
|
1279
|
+
expect(tree).toEqual({
|
|
1280
|
+
type: 'root',
|
|
1281
|
+
content: [
|
|
1282
|
+
{
|
|
1283
|
+
type: 'chapter',
|
|
1284
|
+
number: 8,
|
|
1285
|
+
content: [
|
|
1286
|
+
{
|
|
1287
|
+
type: 'verse',
|
|
1288
|
+
number: 11,
|
|
1289
|
+
content: [
|
|
1290
|
+
{
|
|
1291
|
+
text: 'I tell you that many will come',
|
|
1292
|
+
wordsOfJesus: true
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
text: 'from the east and the west, and will sit down with Abraham, Isaac, and Jacob in the Kingdom of Heaven,',
|
|
1296
|
+
wordsOfJesus: true
|
|
1297
|
+
}
|
|
1298
|
+
]
|
|
1299
|
+
},
|
|
1300
|
+
],
|
|
1301
|
+
footnotes: []
|
|
1302
|
+
},
|
|
1303
|
+
]
|
|
1304
|
+
});
|
|
1305
|
+
});
|
|
1306
|
+
it('should handle verses that are split between headings', () => {
|
|
1307
|
+
const tree = parser.parse(`\\c 1
|
|
1308
|
+
\\v 1 This is Solomon’s Song of Songs.\\f + \\fr 1:1 \\ft Most translators add subheadings for speaker identifications such as The Bride, The Groom, and The Friends based on the gender and number of the Hebrew words.\\f*
|
|
1309
|
+
\\s2 The Bride
|
|
1310
|
+
\\b
|
|
1311
|
+
\\q1
|
|
1312
|
+
\\v 2 Let him kiss me with the kisses of his mouth!
|
|
1313
|
+
\\q2 For your love is more delightful than wine.
|
|
1314
|
+
\\q1
|
|
1315
|
+
\\v 3 The fragrance of your perfume is pleasing;
|
|
1316
|
+
\\q2 your name is like perfume poured out.
|
|
1317
|
+
\\q2 No wonder the maidens adore you.
|
|
1318
|
+
\\b
|
|
1319
|
+
\\q1
|
|
1320
|
+
\\v 4 Take me away with you—let us hurry!
|
|
1321
|
+
\\q2 May the king bring me to his chambers.
|
|
1322
|
+
\\s2 The Friends
|
|
1323
|
+
\\b
|
|
1324
|
+
\\q1 We will rejoice and delight in you;
|
|
1325
|
+
\\q2 we will praise your love more than wine.
|
|
1326
|
+
\\s2 The Bride
|
|
1327
|
+
\\b
|
|
1328
|
+
\\q1 It is only right that they adore you.
|
|
1329
|
+
`);
|
|
1330
|
+
expect(tree).toEqual({
|
|
1331
|
+
type: 'root',
|
|
1332
|
+
content: [
|
|
1333
|
+
{
|
|
1334
|
+
type: 'chapter',
|
|
1335
|
+
number: 1,
|
|
1336
|
+
content: [
|
|
1337
|
+
{
|
|
1338
|
+
type: 'verse',
|
|
1339
|
+
number: 1,
|
|
1340
|
+
content: [
|
|
1341
|
+
'This is Solomon’s Song of Songs.',
|
|
1342
|
+
{
|
|
1343
|
+
noteId: 0
|
|
1344
|
+
}
|
|
1345
|
+
]
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
type: 'heading',
|
|
1349
|
+
content: ['The Bride']
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
type: 'line_break'
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
type: 'verse',
|
|
1356
|
+
number: 2,
|
|
1357
|
+
content: [
|
|
1358
|
+
{
|
|
1359
|
+
text: 'Let him kiss me with the kisses of his mouth!',
|
|
1360
|
+
poem: 1
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
text: 'For your love is more delightful than wine.',
|
|
1364
|
+
poem: 2
|
|
1365
|
+
},
|
|
1366
|
+
]
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
type: 'verse',
|
|
1370
|
+
number: 3,
|
|
1371
|
+
content: [
|
|
1372
|
+
{
|
|
1373
|
+
text: 'The fragrance of your perfume is pleasing;',
|
|
1374
|
+
poem: 1
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
text: 'your name is like perfume poured out.',
|
|
1378
|
+
poem: 2
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
text: 'No wonder the maidens adore you.',
|
|
1382
|
+
poem: 2
|
|
1383
|
+
}
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
type: 'line_break'
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
type: 'verse',
|
|
1391
|
+
number: 4,
|
|
1392
|
+
content: [
|
|
1393
|
+
{
|
|
1394
|
+
text: 'Take me away with you—let us hurry!',
|
|
1395
|
+
poem: 1
|
|
1396
|
+
},
|
|
1397
|
+
{
|
|
1398
|
+
text: 'May the king bring me to his chambers.',
|
|
1399
|
+
poem: 2
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
heading: 'The Friends'
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
lineBreak: true
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
text: 'We will rejoice and delight in you;',
|
|
1409
|
+
poem: 1
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
text: 'we will praise your love more than wine.',
|
|
1413
|
+
poem: 2
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
heading: 'The Bride'
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
lineBreak: true
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
text: 'It is only right that they adore you.',
|
|
1423
|
+
poem: 1
|
|
1424
|
+
}
|
|
1425
|
+
]
|
|
1426
|
+
},
|
|
1427
|
+
],
|
|
1428
|
+
footnotes: [
|
|
1429
|
+
{
|
|
1430
|
+
noteId: 0,
|
|
1431
|
+
text: 'Most translators add subheadings for speaker identifications such as The Bride, The Groom, and The Friends based on the gender and number of the Hebrew words.',
|
|
1432
|
+
caller: '+',
|
|
1433
|
+
reference: {
|
|
1434
|
+
chapter: 1,
|
|
1435
|
+
verse: 1
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
]
|
|
1439
|
+
},
|
|
1440
|
+
]
|
|
1441
|
+
});
|
|
1442
|
+
});
|
|
1443
|
+
it('should ignore \\zaln-s world-level attributes', () => {
|
|
1444
|
+
const tree = parser.parse(`\\c 1
|
|
1445
|
+
\\v 1 \\zaln-s | x-strong="H0430" x-lemma="אֱלֹהִים" x-morph="He,Ncmsc" x-tw="rc://*/tw/dict/bible/kt/god"\\*\\w Test|x-occurence="1"\\w* \\zaln-e\\*
|
|
1446
|
+
\\v 2 Hello
|
|
1447
|
+
`);
|
|
1448
|
+
expect(tree).toEqual({
|
|
1449
|
+
type: 'root',
|
|
1450
|
+
content: [
|
|
1451
|
+
{
|
|
1452
|
+
type: 'chapter',
|
|
1453
|
+
number: 1,
|
|
1454
|
+
content: [
|
|
1455
|
+
{
|
|
1456
|
+
type: 'verse',
|
|
1457
|
+
number: 1,
|
|
1458
|
+
content: [
|
|
1459
|
+
'Test',
|
|
1460
|
+
]
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
type: 'verse',
|
|
1464
|
+
number: 2,
|
|
1465
|
+
content: [
|
|
1466
|
+
'Hello'
|
|
1467
|
+
]
|
|
1468
|
+
},
|
|
1469
|
+
],
|
|
1470
|
+
footnotes: []
|
|
1471
|
+
},
|
|
1472
|
+
]
|
|
1473
|
+
});
|
|
1474
|
+
});
|
|
1475
|
+
describe('Bible', () => {
|
|
1476
|
+
const cases = [
|
|
1477
|
+
['bsb/01GENBSB.usfm', 50],
|
|
1478
|
+
['bsb/02EXOBSB.usfm', 40],
|
|
1479
|
+
['bsb/03LEVBSB.usfm', 27],
|
|
1480
|
+
['bsb/04NUMBSB.usfm', 36],
|
|
1481
|
+
['bsb/05DEUBSB.usfm', 34],
|
|
1482
|
+
['bsb/06JOSBSB.usfm', 24],
|
|
1483
|
+
['bsb/07JDGBSB.usfm', 21],
|
|
1484
|
+
['bsb/08RUTBSB.usfm', 4],
|
|
1485
|
+
['bsb/091SABSB.usfm', 31],
|
|
1486
|
+
['bsb/102SABSB.usfm', 24],
|
|
1487
|
+
['bsb/111KIBSB.usfm', 22],
|
|
1488
|
+
['bsb/122KIBSB.usfm', 25],
|
|
1489
|
+
['bsb/131CHBSB.usfm', 29],
|
|
1490
|
+
['bsb/142CHBSB.usfm', 36],
|
|
1491
|
+
['bsb/15EZRBSB.usfm', 10],
|
|
1492
|
+
['bsb/16NEHBSB.usfm', 13],
|
|
1493
|
+
['bsb/17ESTBSB.usfm', 10],
|
|
1494
|
+
['bsb/18JOBBSB.usfm', 42],
|
|
1495
|
+
['bsb/19PSABSB.usfm', 150],
|
|
1496
|
+
['bsb/41MATBSB.usfm', 28],
|
|
1497
|
+
['engwebp/02-GENengwebp.usfm', 50],
|
|
1498
|
+
['engwebp/03-EXOengwebp.usfm', 40],
|
|
1499
|
+
['engwebp/70-MATengwebp.usfm', 28],
|
|
1500
|
+
['arbnav/02-GENarbnav.usfm', 50],
|
|
1501
|
+
['arbnav/70-MATarbnav.usfm', 28],
|
|
1502
|
+
['hinirv/usfm/gen.usfm', 50],
|
|
1503
|
+
['hinirv/usfm/mat.usfm', 28],
|
|
1504
|
+
['grcbre/usfm/gen.usfm', 50],
|
|
1505
|
+
['grctcg/usfm/mat.usfm', 28],
|
|
1506
|
+
['hbomas/usfm/gen.usfm', 50],
|
|
1507
|
+
];
|
|
1508
|
+
it.each(cases)('should consistently parse %s', async (file, expectedChapters) => {
|
|
1509
|
+
const filePath = (0, path_1.resolve)(__dirname, '..', '..', '..', 'bible', file);
|
|
1510
|
+
const data = await (0, promises_1.readFile)(filePath, { encoding: 'utf-8' });
|
|
1511
|
+
const parsed = parser.parse(data);
|
|
1512
|
+
const numChapters = parsed.content.filter(c => c.type === 'chapter').length;
|
|
1513
|
+
expect(numChapters).toBe(expectedChapters);
|
|
1514
|
+
const json = JSON.stringify(parsed);
|
|
1515
|
+
const result = JSON.parse(json);
|
|
1516
|
+
expect(result).toEqual(parsed);
|
|
1517
|
+
const parsedHash = hash_js_1.default.sha256().update(json).digest('hex');
|
|
1518
|
+
expect(parsedHash).toMatchSnapshot();
|
|
1519
|
+
});
|
|
1520
|
+
it('should consistently parse matthew in the BSB', async () => {
|
|
1521
|
+
const filePath = (0, path_1.resolve)(__dirname, '..', '..', '..', 'bible', 'bsb/41MATBSB.usfm');
|
|
1522
|
+
const data = await (0, promises_1.readFile)(filePath, { encoding: 'utf-8' });
|
|
1523
|
+
const parsed = parser.parse(data);
|
|
1524
|
+
const numChapters = parsed.content.filter(c => c.type === 'chapter').length;
|
|
1525
|
+
expect(numChapters).toBe(28);
|
|
1526
|
+
const json = JSON.stringify(parsed);
|
|
1527
|
+
const result = JSON.parse(json);
|
|
1528
|
+
expect(result).toEqual(parsed);
|
|
1529
|
+
expect(parsed).toMatchSnapshot();
|
|
1530
|
+
});
|
|
1531
|
+
});
|
|
1532
|
+
});
|
|
1533
|
+
describe('renderMarkdown()', () => {
|
|
1534
|
+
it('should create basic markdown from a parse tree', () => {
|
|
1535
|
+
const tree = parser.parse(`
|
|
1536
|
+
\\h Genesis
|
|
1537
|
+
\\c 1
|
|
1538
|
+
\\v 1 In the beginning God created the heavens and the earth.
|
|
1539
|
+
\\v 2 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.
|
|
1540
|
+
\\v 3 And God said, “Let there be light,” \\f + \\fr 1:3 \\ft Cited in 2 Corinthians 4:6\\f* and there was light.
|
|
1541
|
+
\\c 2
|
|
1542
|
+
\\v 1 Thus the heavens and the earth were completed in all their vast array.
|
|
1543
|
+
`);
|
|
1544
|
+
const md = parser.renderMarkdown(tree);
|
|
1545
|
+
expect(md).toMatchSnapshot();
|
|
1546
|
+
});
|
|
1547
|
+
});
|
|
1548
|
+
});
|
|
1549
|
+
describe('isDigit()', () => {
|
|
1550
|
+
it('should retrun true for all the ascii digits', () => {
|
|
1551
|
+
for (let d = 0; d < 10; d++) {
|
|
1552
|
+
let digit = d.toString();
|
|
1553
|
+
expect((0, usfm_parser_1.isDigit)(digit)).toBe(true);
|
|
1554
|
+
}
|
|
1555
|
+
});
|
|
1556
|
+
it('should return true for all digit code points in a string', () => {
|
|
1557
|
+
let str = '0123456789';
|
|
1558
|
+
for (let d of str) {
|
|
1559
|
+
expect((0, usfm_parser_1.isDigit)(d)).toBe(true);
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
it('should return false for non digits', () => {
|
|
1563
|
+
let str = 'abcdefghijkflmnopqrstuvwxyz';
|
|
1564
|
+
for (let c of str) {
|
|
1565
|
+
expect((0, usfm_parser_1.isDigit)(c)).toBe(false);
|
|
1566
|
+
}
|
|
1567
|
+
});
|
|
1568
|
+
it('should return false for strings longer than length 1', () => {
|
|
1569
|
+
let strings = [
|
|
1570
|
+
'0a',
|
|
1571
|
+
'0b',
|
|
1572
|
+
'9a',
|
|
1573
|
+
'9b',
|
|
1574
|
+
];
|
|
1575
|
+
for (let str of strings) {
|
|
1576
|
+
expect((0, usfm_parser_1.isDigit)(str)).toBe(false);
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
});
|
|
1580
|
+
describe('isWhitespace()', () => {
|
|
1581
|
+
it('should return true for common whitespace characters', () => {
|
|
1582
|
+
let chars = [' ', '\n', '\t', '\r'];
|
|
1583
|
+
for (let char of chars) {
|
|
1584
|
+
expect((0, usfm_parser_1.isWhitespace)(char)).toBe(true);
|
|
1585
|
+
}
|
|
1586
|
+
});
|
|
1587
|
+
it('should return false for non-whitespace characters', () => {
|
|
1588
|
+
let str = 'abcdefghijkflmnopqrstuvwxyz0123456789';
|
|
1589
|
+
for (let c of str) {
|
|
1590
|
+
expect((0, usfm_parser_1.isWhitespace)(c)).toBe(false);
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
});
|