proskomma-core 0.9.10 → 0.9.13

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 (136) hide show
  1. package/.eslintrc.json +79 -0
  2. package/.gitattributes +2 -0
  3. package/docs/_config.yml +1 -0
  4. package/docs/index.md +3 -0
  5. package/docs/pk_edit_0_9.odt +0 -0
  6. package/docs/pk_edit_0_9.pdf +0 -0
  7. package/docs/proskomma_101_slideshow.odp +0 -0
  8. package/docs/proskomma_101_slideshow.pdf +0 -0
  9. package/docs/proskomma_edit_html.png +0 -0
  10. package/docs/proskomma_edit_html.svg +451 -0
  11. package/docs/proskomma_edit_reference.png +0 -0
  12. package/docs/proskomma_edit_reference.svg +349 -0
  13. package/docs/repo_logo.png +0 -0
  14. package/esm/package.json +3 -0
  15. package/esm/wrapper.mjs +5 -0
  16. package/index.cjs +6 -0
  17. package/package.json +18 -15
  18. package/src/graph/index.cjs +201 -0
  19. package/src/graph/lib/do_cv.cjs +249 -0
  20. package/src/graph/lib/dump.cjs +40 -0
  21. package/src/graph/lib/remake_blocks.cjs +57 -0
  22. package/src/graph/lib/sequence_chars.cjs +84 -0
  23. package/src/graph/lib/sort.cjs +39 -0
  24. package/src/graph/lib/tribos.cjs +97 -0
  25. package/src/graph/lib/tribos_expression.cjs +556 -0
  26. package/src/graph/lib/tribos_ohm_UNUSED.cjs +37 -0
  27. package/src/graph/lib/tribos_step.cjs +434 -0
  28. package/src/graph/mutations/add.cjs +91 -0
  29. package/src/graph/mutations/delete.cjs +61 -0
  30. package/src/graph/mutations/index.cjs +54 -0
  31. package/src/graph/mutations/rehash.cjs +17 -0
  32. package/src/graph/mutations/tags.cjs +120 -0
  33. package/src/graph/mutations/update.cjs +210 -0
  34. package/src/graph/mutations/versification.cjs +96 -0
  35. package/src/graph/queries/block.cjs +228 -0
  36. package/src/graph/queries/cIndex.cjs +87 -0
  37. package/src/graph/queries/cell.cjs +42 -0
  38. package/src/graph/queries/cv.cjs +19 -0
  39. package/src/graph/queries/cvBook.cjs +16 -0
  40. package/src/graph/queries/cvChapter.cjs +16 -0
  41. package/src/graph/queries/cvIndex.cjs +47 -0
  42. package/src/graph/queries/cvNavigation.cjs +116 -0
  43. package/src/graph/queries/cvVerseElement.cjs +84 -0
  44. package/src/graph/queries/cvVerses.cjs +14 -0
  45. package/src/graph/queries/doc_set.cjs +220 -0
  46. package/src/graph/queries/document.cjs +555 -0
  47. package/src/graph/queries/idParts.cjs +30 -0
  48. package/src/graph/queries/index.cjs +151 -0
  49. package/src/graph/queries/inputBlockSpec.cjs +17 -0
  50. package/src/graph/queries/inputItemObject.cjs +12 -0
  51. package/src/graph/queries/input_att_spec.cjs +14 -0
  52. package/src/graph/queries/input_key_matches.cjs +11 -0
  53. package/src/graph/queries/input_key_value.cjs +11 -0
  54. package/src/graph/queries/input_key_values.cjs +11 -0
  55. package/src/graph/queries/input_selector_spec.cjs +19 -0
  56. package/src/graph/queries/item.cjs +71 -0
  57. package/src/graph/queries/itemGroup.cjs +75 -0
  58. package/src/graph/queries/key_value.cjs +18 -0
  59. package/src/graph/queries/kv_entry.cjs +21 -0
  60. package/src/graph/queries/kv_sequence.cjs +151 -0
  61. package/src/graph/queries/node.cjs +44 -0
  62. package/src/graph/queries/orig.cjs +11 -0
  63. package/src/graph/queries/regex_index.cjs +18 -0
  64. package/src/graph/queries/row_equals_spec.cjs +11 -0
  65. package/src/graph/queries/row_match_spec.cjs +11 -0
  66. package/src/graph/queries/selector_spec.cjs +29 -0
  67. package/src/graph/queries/sequence.cjs +314 -0
  68. package/src/graph/queries/table_sequence.cjs +192 -0
  69. package/src/graph/queries/tree_sequence.cjs +58 -0
  70. package/src/graph/queries/verseNumber.cjs +44 -0
  71. package/src/graph/queries/verseRange.cjs +11 -0
  72. package/src/graph/queries/versification.cjs +25 -0
  73. package/src/index.cjs +583 -0
  74. package/src/model/doc_set.cjs +389 -0
  75. package/src/model/doc_set_helpers/block.cjs +232 -0
  76. package/src/model/doc_set_helpers/enum.cjs +87 -0
  77. package/src/model/doc_set_helpers/item.cjs +198 -0
  78. package/src/model/doc_set_helpers/rehash.cjs +53 -0
  79. package/src/model/doc_set_helpers/selectors.cjs +58 -0
  80. package/src/model/doc_set_helpers/serialize.cjs +22 -0
  81. package/src/model/doc_set_helpers/unsuccinctify.cjs +288 -0
  82. package/src/model/doc_set_helpers/update.cjs +290 -0
  83. package/src/model/document.cjs +369 -0
  84. package/src/model/document_helpers/blocks.cjs +135 -0
  85. package/src/model/document_helpers/chapter_verse.cjs +291 -0
  86. package/src/model/document_helpers/pre_enums.cjs +67 -0
  87. package/src/model/document_helpers/sequences.cjs +205 -0
  88. package/src/model/document_helpers/serialize_succinct.cjs +55 -0
  89. package/src/model/document_helpers/succinct_filter.cjs +102 -0
  90. package/src/model/versifications/eng_vrs.cjs +455 -0
  91. package/src/model/versifications/index.cjs +38 -0
  92. package/src/model/versifications/lxx_vrs.cjs +950 -0
  93. package/src/model/versifications/org_vrs.cjs +155 -0
  94. package/src/model/versifications/rsc_vrs.cjs +342 -0
  95. package/src/model/versifications/rso_vrs.cjs +541 -0
  96. package/src/model/versifications/vul_vrs.cjs +835 -0
  97. package/src/parser/index.cjs +506 -0
  98. package/src/parser/lexers/index.cjs +11 -0
  99. package/src/parser/lexers/lexingRegexes.cjs +45 -0
  100. package/src/parser/lexers/nodes.cjs +123 -0
  101. package/src/parser/lexers/object_for_fragment.cjs +123 -0
  102. package/src/parser/lexers/tsv.cjs +45 -0
  103. package/src/parser/lexers/usfm.cjs +17 -0
  104. package/src/parser/lexers/usx/index.cjs +7 -0
  105. package/src/parser/lexers/usx/usx_lexer.cjs +321 -0
  106. package/src/parser/lib/tokenize.cjs +37 -0
  107. package/src/parser/model/index.cjs +637 -0
  108. package/src/parser/parser_specs.cjs +781 -0
  109. package/src/pipelines/perf2x/index.cjs +7 -0
  110. package/src/pipelines/perf2x/perf2PkJsonPipeline.json +41 -0
  111. package/src/pipelines/perf2x/perf2usfmPipeline.json +65 -0
  112. package/src/transforms/calculateUsfmChapterPositions.cjs +106 -0
  113. package/src/transforms/index.cjs +9 -0
  114. package/src/transforms/perf2PkJson.cjs +534 -0
  115. package/src/transforms/perf2usfm.cjs +294 -0
  116. package/src/util/byteArray.cjs +251 -0
  117. package/src/util/canons.cjs +117 -0
  118. package/src/util/enums.cjs +41 -0
  119. package/src/util/generateId.cjs +6 -0
  120. package/src/util/graftDefs.cjs +15 -0
  121. package/src/util/index.cjs +29 -0
  122. package/src/util/inspectSuccinct.cjs +59 -0
  123. package/src/util/itemDefs.cjs +33 -0
  124. package/src/util/parserConstantDefs.cjs +30 -0
  125. package/src/util/scopeDefs.cjs +173 -0
  126. package/src/util/scriptlike/blocksSpec.cjs +192 -0
  127. package/src/util/scriptlike/dodson_lexicon.xsl +19 -0
  128. package/src/util/scriptlike/dodson_lexicon_to_entries.cjs +85 -0
  129. package/src/util/scriptlike/open_scriptures_hebrew_lexicon.xsl +28 -0
  130. package/src/util/scriptlike/open_scriptures_hebrew_lexicon_to_entries.cjs +85 -0
  131. package/src/util/succinct.cjs +159 -0
  132. package/src/util/tags.cjs +28 -0
  133. package/src/util/tokenDefs.cjs +27 -0
  134. package/src/util/versification.cjs +364 -0
  135. package/dist/index.js +0 -8
  136. package/dist/index.js.LICENSE.txt +0 -23
@@ -0,0 +1,85 @@
1
+ const fse = require('fs-extra');
2
+ const { tokenizeString } = require('./blocksSpec.cjs');
3
+
4
+ const itemTokens = str => tokenizeString(str).map(tr => ({
5
+ type: 'token',
6
+ subType: tr[1],
7
+ payload: tr[0],
8
+ }));
9
+
10
+ const rowRecord = rowArray => ({
11
+ 'bs': {
12
+ 'type': 'scope',
13
+ 'subType': 'start',
14
+ 'payload': `kvPrimary/${rowArray[0]}`,
15
+ },
16
+ 'bg': [],
17
+ 'os': [],
18
+ 'is': [
19
+ {
20
+ 'type': 'scope',
21
+ 'subType': 'start',
22
+ 'payload': `kvSecondary/strong/${rowArray[1]}`,
23
+ },
24
+ {
25
+ 'type': 'scope',
26
+ 'subType': 'start',
27
+ 'payload': 'kvField/briefDef',
28
+ },
29
+ {
30
+ 'type': 'scope',
31
+ 'subType': 'start',
32
+ 'payload': 'kvField/fullDef',
33
+ },
34
+ ],
35
+ 'items': [
36
+ {
37
+ 'type': 'scope',
38
+ 'subType': 'start',
39
+ 'payload': `kvSecondary/strong/${rowArray[1]}`,
40
+ },
41
+ {
42
+ 'type': 'scope',
43
+ 'subType': 'start',
44
+ 'payload': 'kvField/briefDef',
45
+ },
46
+ ...itemTokens(rowArray[4].length > 0 ? rowArray[4].replace(/; $/, '') : rowArray[5]),
47
+ {
48
+ 'type': 'scope',
49
+ 'subType': 'end',
50
+ 'payload': 'kvField/briefDef',
51
+ },
52
+ {
53
+ 'type': 'scope',
54
+ 'subType': 'start',
55
+ 'payload': 'kvField/fullDef',
56
+ },
57
+ ...itemTokens(rowArray[3]),
58
+ {
59
+ 'type': 'scope',
60
+ 'subType': 'end',
61
+ 'payload': 'kvField/fullDef',
62
+ },
63
+ {
64
+ 'type': 'scope',
65
+ 'subType': 'end',
66
+ 'payload': `kvSecondary/strong/${rowArray[1]}`,
67
+ },
68
+ ],
69
+ });
70
+
71
+ const lexicon_tsv = fse.readFileSync(process.argv[2])
72
+ .toString()
73
+ .split('\n')
74
+ .map(row => row.split('\t'))
75
+ .filter(row => row.length > 1);
76
+
77
+ console.log(
78
+ JSON.stringify(
79
+ lexicon_tsv.map(
80
+ row => rowRecord(row),
81
+ ),
82
+ null,
83
+ 2,
84
+ ),
85
+ );
@@ -0,0 +1,159 @@
1
+ const tokenDefs = require('./tokenDefs.cjs');
2
+ const scopeDefs = require('./scopeDefs.cjs');
3
+ const itemDefs = require('./itemDefs.cjs');
4
+
5
+ const headerBytes = (succinct, pos) =>{
6
+ const headerByte = succinct.byte(pos);
7
+ const itemType = headerByte >> 6;
8
+ const itemLength = headerByte & 0x0000003F;
9
+ const itemSubtype = succinct.byte(pos + 1);
10
+ return [itemLength, itemType, itemSubtype];
11
+ };
12
+
13
+ const succinctTokenChars = (enums, enumIndexes, succinct, itemSubtype, pos) => {
14
+ const itemCategory = tokenDefs.tokenCategory[tokenDefs.tokenEnumLabels[itemSubtype]];
15
+ const itemIndex = enumIndexes[itemCategory][succinct.nByte(pos + 2)];
16
+ return enums[itemCategory].countedString(itemIndex);
17
+ };
18
+
19
+ const succinctScopeLabel = (enums, enumIndexes, succinct, itemSubtype, pos) => {
20
+ const scopeType = scopeDefs.scopeEnumLabels[itemSubtype];
21
+ let nScopeBits = scopeDefs.nComponentsForScope(scopeType);
22
+ let offset = 2;
23
+ let scopeBits = '';
24
+
25
+ while (nScopeBits > 1) {
26
+ const itemIndexIndex = succinct.nByte(pos + offset);
27
+ const itemIndex = enumIndexes.scopeBits[itemIndexIndex];
28
+ const scopeBitString = enums.scopeBits.countedString(itemIndex);
29
+ scopeBits += `/${scopeBitString}`;
30
+ offset += succinct.nByteLength(itemIndexIndex);
31
+ nScopeBits--;
32
+ }
33
+ return `${scopeType}${scopeBits}`;
34
+ };
35
+
36
+ const succinctGraftName = (enums, enumIndexes, itemSubtype) => {
37
+ const graftIndex = enumIndexes.graftTypes[itemSubtype];
38
+ return enums.graftTypes.countedString(graftIndex);
39
+ };
40
+
41
+ const succinctGraftSeqId = (enums, enumIndexes, succinct, pos) => {
42
+ const seqIndex = enumIndexes.ids[succinct.nByte(pos + 2)];
43
+ return enums.ids.countedString(seqIndex);
44
+ };
45
+
46
+ const enumIndexes = (enums) => {
47
+ const ret = {};
48
+
49
+ for (const [category, succinct] of Object.entries(enums)) {
50
+ ret[category] = enumIndex(category, succinct);
51
+ }
52
+ return ret;
53
+ };
54
+
55
+ const enumIndex = (category, enumSuccinct) => {
56
+ const indexSuccinct = new Uint32Array(enumSuccinct.length);
57
+ let pos = 0;
58
+ let count = 0;
59
+
60
+ while (pos < enumSuccinct.length) {
61
+ indexSuccinct[count] = pos;
62
+ const stringLength = enumSuccinct.byte(pos);
63
+ pos += (stringLength + 1);
64
+ count += 1;
65
+ }
66
+ return indexSuccinct;
67
+ };
68
+
69
+ const unpackEnum = (succinct, includeIndex) => {
70
+ if (!includeIndex) {
71
+ includeIndex = false;
72
+ }
73
+
74
+ let pos = 0;
75
+ let count = 0;
76
+ const ret = [];
77
+
78
+ while (pos < succinct.length) {
79
+ const stringLength = succinct.byte(pos);
80
+ const unpacked = succinct.countedString(pos);
81
+ ret.push(includeIndex ? [count, unpacked] : unpacked);
82
+ pos += stringLength + 1;
83
+ count++;
84
+ }
85
+ return ret;
86
+ };
87
+
88
+ const undefinedArgError = (func, field) => {
89
+ throw new Error(`Undefined or null argument '${field}' in '${func}'`);
90
+ };
91
+
92
+ const pushSuccinctTokenBytes = (bA, tokenEnumIndex, charsEnumIndex) => {
93
+ if (tokenEnumIndex === undefined || tokenEnumIndex === null) {
94
+ undefinedArgError('pushSuccinctTokenBytes', 'tokenEnumIndex');
95
+ }
96
+
97
+ if (charsEnumIndex === undefined || charsEnumIndex === null) {
98
+ undefinedArgError('pushSuccinctTokenBytes', 'charsEnumIndex');
99
+ }
100
+
101
+ const lengthPos = bA.length;
102
+ bA.pushByte(0);
103
+ bA.pushByte(tokenEnumIndex);
104
+ bA.pushNByte(charsEnumIndex);
105
+ bA.setByte(lengthPos, (bA.length - lengthPos) | itemDefs.itemEnum.token << 6);
106
+ };
107
+
108
+ const pushSuccinctGraftBytes = (bA, graftTypeEnumIndex, seqEnumIndex) => {
109
+ if (graftTypeEnumIndex === undefined || graftTypeEnumIndex === null) {
110
+ undefinedArgError('pushSuccinctGraftBytes', 'graftTypeEnumIndex');
111
+ }
112
+
113
+ if (seqEnumIndex === undefined || seqEnumIndex === null) {
114
+ undefinedArgError('pushSuccinctGraftBytes', 'seqEnumIndex');
115
+ }
116
+
117
+ const lengthPos = bA.length;
118
+ bA.pushByte(0);
119
+ bA.pushByte(graftTypeEnumIndex);
120
+ bA.pushNByte(seqEnumIndex);
121
+ bA.setByte(lengthPos, (bA.length - lengthPos) | itemDefs.itemEnum.graft << 6);
122
+ };
123
+
124
+ const pushSuccinctScopeBytes = (bA, itemTypeByte, scopeTypeByte, scopeBitBytes) => {
125
+ if (itemTypeByte === undefined || itemTypeByte === null) {
126
+ undefinedArgError('pushSuccinctScopeBytes', 'itemTypeByte');
127
+ }
128
+
129
+ if (scopeTypeByte === undefined || scopeTypeByte === null) {
130
+ undefinedArgError('pushSuccinctScopeBytes', 'scopeTypeByte');
131
+ }
132
+
133
+ if (scopeBitBytes === undefined || scopeBitBytes === null) {
134
+ undefinedArgError('pushSuccinctScopeBytes', 'scopeBitBytes');
135
+ }
136
+
137
+ const lengthPos = bA.length;
138
+ bA.pushByte(0);
139
+ bA.pushByte(scopeTypeByte);
140
+
141
+ for (const sbb of scopeBitBytes) {
142
+ bA.pushNByte(sbb);
143
+ }
144
+ bA.setByte(lengthPos, (bA.length - lengthPos) | itemTypeByte << 6);
145
+ };
146
+
147
+ module.exports = {
148
+ enumIndex,
149
+ enumIndexes,
150
+ headerBytes,
151
+ pushSuccinctTokenBytes,
152
+ pushSuccinctGraftBytes,
153
+ pushSuccinctScopeBytes,
154
+ succinctTokenChars,
155
+ succinctScopeLabel,
156
+ succinctGraftName,
157
+ succinctGraftSeqId,
158
+ unpackEnum,
159
+ };
@@ -0,0 +1,28 @@
1
+ const xre = require('xregexp');
2
+
3
+ const validateTags = tags => {
4
+ for (const tag of tags) {
5
+ validateTag(tag);
6
+ }
7
+ };
8
+
9
+ const validateTag = tag => {
10
+ if (!xre.exec(tag, /^[a-z][A-za-z0-9]*(:.+)?$/)) {
11
+ throw new Error(`Tag '${tag}' is not valid (should be [a-z][A-za-z0-9]*(:.+)?)`);
12
+ }
13
+ };
14
+
15
+ const addTag = (tags, tag) => {
16
+ validateTag(tag);
17
+ tags.add(tag);
18
+ };
19
+
20
+ const removeTag = (tags, tag) => {
21
+ validateTag(tag);
22
+ tags.delete(tag);
23
+ };
24
+
25
+ module.exports = {
26
+ validateTags, validateTag, addTag, removeTag,
27
+ };
28
+
@@ -0,0 +1,27 @@
1
+ const tokenEnum = {
2
+ wordLike: 0,
3
+ punctuation: 1,
4
+ lineSpace: 2,
5
+ eol: 3,
6
+ softLineBreak: 4,
7
+ noBreakSpace: 5,
8
+ bareSlash: 6,
9
+ unknown: 7,
10
+ };
11
+
12
+ const tokenEnumLabels = Object.entries(tokenEnum).sort((a, b) => a[1] - b[1]).map(kv => kv[0]);
13
+
14
+ const tokenCategory = {
15
+ wordLike: 'wordLike',
16
+ punctuation: 'notWordLike',
17
+ lineSpace: 'notWordLike',
18
+ eol: 'notWordLike',
19
+ softLineBreak: 'notWordLike',
20
+ noBreakSpace: 'notWordLike',
21
+ bareSlash: 'notWordLike',
22
+ unknown: 'notWordLike',
23
+ };
24
+
25
+ module.exports = {
26
+ tokenEnum, tokenEnumLabels, tokenCategory,
27
+ };
@@ -0,0 +1,364 @@
1
+ const xre = require('xregexp');
2
+
3
+ const ByteArray = require('./byteArray.cjs');
4
+
5
+ const cvMappingType = 2;
6
+ const bcvMappingType = 3;
7
+
8
+ const bookCodes = [ // From Paratext via Scripture Burrito
9
+ 'GEN',
10
+ 'EXO',
11
+ 'LEV',
12
+ 'NUM',
13
+ 'DEU',
14
+ 'JOS',
15
+ 'JDG',
16
+ 'RUT',
17
+ '1SA',
18
+ '2SA',
19
+ '1KI',
20
+ '2KI',
21
+ '1CH',
22
+ '2CH',
23
+ 'EZR',
24
+ 'NEH',
25
+ 'EST',
26
+ 'JOB',
27
+ 'PSA',
28
+ 'PRO',
29
+ 'ECC',
30
+ 'SNG',
31
+ 'ISA',
32
+ 'JER',
33
+ 'LAM',
34
+ 'EZK',
35
+ 'DAN',
36
+ 'HOS',
37
+ 'JOL',
38
+ 'AMO',
39
+ 'OBA',
40
+ 'JON',
41
+ 'MIC',
42
+ 'NAM',
43
+ 'HAB',
44
+ 'ZEP',
45
+ 'HAG',
46
+ 'ZEC',
47
+ 'MAL',
48
+ 'MAT',
49
+ 'MRK',
50
+ 'LUK',
51
+ 'JHN',
52
+ 'ACT',
53
+ 'ROM',
54
+ '1CO',
55
+ '2CO',
56
+ 'GAL',
57
+ 'EPH',
58
+ 'PHP',
59
+ 'COL',
60
+ '1TH',
61
+ '2TH',
62
+ '1TI',
63
+ '2TI',
64
+ 'TIT',
65
+ 'PHM',
66
+ 'HEB',
67
+ 'JAS',
68
+ '1PE',
69
+ '2PE',
70
+ '1JN',
71
+ '2JN',
72
+ '3JN',
73
+ 'JUD',
74
+ 'REV',
75
+ 'TOB',
76
+ 'JDT',
77
+ 'ESG',
78
+ 'WIS',
79
+ 'SIR',
80
+ 'BAR',
81
+ 'LJE',
82
+ 'S3Y',
83
+ 'SUS',
84
+ 'BEL',
85
+ '1MA',
86
+ '2MA',
87
+ '3MA',
88
+ '4MA',
89
+ '1ES',
90
+ '2ES',
91
+ 'MAN',
92
+ 'PS2',
93
+ 'ODA',
94
+ 'PSS',
95
+ 'JSA',
96
+ 'JDB',
97
+ 'TBS',
98
+ 'SST',
99
+ 'DNT',
100
+ 'BLT',
101
+ 'EZA',
102
+ '5EZ',
103
+ '6EZ',
104
+ 'DAG',
105
+ 'PS3',
106
+ '2BA',
107
+ 'LBA',
108
+ 'JUB',
109
+ 'ENO',
110
+ '1MQ',
111
+ '2MQ',
112
+ '3MQ',
113
+ 'REP',
114
+ '4BA',
115
+ 'LAO',
116
+ ];
117
+
118
+ const bookCodeIndex = () => {
119
+ const ret = {};
120
+
121
+ for (const [bookN, book] of Object.entries(bookCodes)) {
122
+ ret[book] = parseInt(bookN);
123
+ }
124
+ return ret;
125
+ };
126
+
127
+ const vrs2json = vrsString => {
128
+ const ret = {};
129
+
130
+ for (
131
+ const vrsLineBits of
132
+ vrsString
133
+ .split(/[\n\r]+/)
134
+ .map(l => l.trim())
135
+ .map(l => xre.exec(l, xre('^([A-Z1-6]{3} [0-9]+:[0-9]+(-[0-9]+)?) = ([A-Z1-6]{3} [0-9]+:[0-9]+[a-z]?(-[0-9]+)?)$')))
136
+ ) {
137
+ if (!vrsLineBits) {
138
+ continue;
139
+ }
140
+
141
+ if (!(vrsLineBits[1] in ret)) {
142
+ ret[vrsLineBits[1]] = [];
143
+ }
144
+ ret[vrsLineBits[1]].push(vrsLineBits[3]);
145
+ }
146
+ return { mappedVerses: ret };
147
+ };
148
+
149
+ const reverseVersification = vrsJson => {
150
+ // Assumes each verse is only mapped from once
151
+ const ret = {};
152
+
153
+ for (const [fromSpec, toSpecs] of Object.entries(vrsJson.mappedVerses)) {
154
+ for (const toSpec of toSpecs) {
155
+ if (toSpec in ret) {
156
+ ret[toSpec].push(fromSpec);
157
+ } else {
158
+ ret[toSpec] = [fromSpec];
159
+ }
160
+ }
161
+ }
162
+ return { reverseMappedVerses: ret };
163
+ };
164
+
165
+ const preSuccinctVerseMapping = mappingJson => {
166
+ const ret = {};
167
+
168
+ for (let [fromSpec, toSpecs] of Object.entries(mappingJson)) {
169
+ if (typeof toSpecs === 'string') {
170
+ toSpecs = [toSpecs];
171
+ }
172
+
173
+ const [fromBook, fromCVV] = fromSpec.split(' ');
174
+ const toBook = toSpecs[0].split(' ')[0];
175
+ const record = toBook === fromBook ? ['cv'] : ['bcv'];
176
+ let [fromCh, fromV] = fromCVV.split(':');
177
+ let toV = fromV;
178
+
179
+ if (fromV.includes('-')) {
180
+ const vBits = fromV.split('-');
181
+ fromV = vBits[0];
182
+ toV = vBits[1];
183
+ }
184
+ record.push([parseInt(fromV), parseInt(toV)]);
185
+ record.push([]);
186
+
187
+ for (const toCVV of toSpecs.map(ts => ts.split(' ')[1])) {
188
+ let [toCh, fromV] = toCVV.split(':');
189
+ let toV = fromV;
190
+
191
+ if (fromV.includes('-')) {
192
+ const vBits = fromV.split('-');
193
+ fromV = vBits[0];
194
+ toV = vBits[1];
195
+ }
196
+
197
+ if (record[0] === 'cv') {
198
+ record[2].push([parseInt(toCh), parseInt(fromV), parseInt(toV)]);
199
+ } else {
200
+ record[2].push([parseInt(toCh), parseInt(fromV), parseInt(toV), toBook]);
201
+ }
202
+ }
203
+
204
+ if (!(fromBook in ret)) {
205
+ ret[fromBook] = {};
206
+ }
207
+
208
+ if (!(fromCh in ret[fromBook])) {
209
+ ret[fromBook][fromCh] = [];
210
+ }
211
+ ret[fromBook][fromCh].push(record);
212
+ }
213
+ return ret;
214
+ };
215
+
216
+ const succinctifyVerseMappings = preSuccinct => {
217
+ const ret = {};
218
+ const bci = bookCodeIndex();
219
+
220
+ for (const [book, chapters] of Object.entries(preSuccinctVerseMapping(preSuccinct))) {
221
+ ret[book] = {};
222
+
223
+ for (const [chapter, mappings] of Object.entries(chapters)) {
224
+ ret[book][chapter] = succinctifyVerseMapping(mappings, bci);
225
+ }
226
+ }
227
+ return ret;
228
+ };
229
+
230
+ const succinctifyVerseMapping = (preSuccinctBC, bci) => {
231
+ const makeMappingLengthByte = (recordType, length) =>
232
+ length + (recordType * 64);
233
+
234
+ const ret = new ByteArray(64);
235
+
236
+ for (const [recordTypeStr, [fromVerseStart, fromVerseEnd], mappings] of preSuccinctBC) {
237
+ const pos = ret.length;
238
+ const recordType = recordTypeStr === 'bcv' ? bcvMappingType : cvMappingType;
239
+ ret.pushNBytes([0, fromVerseStart, fromVerseEnd]);
240
+
241
+ if (recordType === bcvMappingType) {
242
+ const bookIndex = bci[mappings[0][3]];
243
+ ret.pushNByte(bookIndex);
244
+ }
245
+ ret.pushNByte(mappings.length);
246
+
247
+ for (const [ch, fromV] of mappings) {
248
+ ret.pushNBytes([ch, fromV]);
249
+ }
250
+
251
+ const recordLength = ret.length - pos;
252
+
253
+ if (recordLength > 63) {
254
+ throw new Error(`Mapping in succinctifyVerseMapping ${JSON.stringify(mappings)} is too long (${recordLength} bytes)`);
255
+ }
256
+ ret.setByte(pos, makeMappingLengthByte(recordType, recordLength));
257
+ }
258
+ ret.trim();
259
+ return ret;
260
+ };
261
+
262
+ const mappingLengthByte = (succinct, pos) => {
263
+ const sByte = succinct.byte(pos);
264
+ return [
265
+ sByte >> 6,
266
+ sByte % 64,
267
+ ];
268
+ };
269
+
270
+ // eslint-disable-next-line no-unused-vars
271
+ const unsuccinctifyVerseMapping = (succinctBC, fromBookCode, bci) => {
272
+ const ret = [];
273
+ let pos = 0;
274
+
275
+ while (pos < succinctBC.length) {
276
+ let recordPos = pos;
277
+ const unsuccinctRecord = {};
278
+ const [recordType, recordLength] = mappingLengthByte(succinctBC, pos);
279
+ recordPos++;
280
+ unsuccinctRecord.fromVerseStart = succinctBC.nByte(recordPos);
281
+ recordPos += succinctBC.nByteLength(unsuccinctRecord.fromVerseStart);
282
+ unsuccinctRecord.fromVerseEnd = succinctBC.nByte(recordPos);
283
+ recordPos += succinctBC.nByteLength(unsuccinctRecord.fromVerseEnd);
284
+ unsuccinctRecord.bookCode = fromBookCode;
285
+
286
+ if (recordType === bcvMappingType) {
287
+ const bookIndex = succinctBC.nByte(recordPos);
288
+ unsuccinctRecord.bookCode = bookCodes[bookIndex];
289
+ recordPos += succinctBC.nByteLength(bookIndex);
290
+ }
291
+
292
+ const nMappings = succinctBC.nByte(recordPos);
293
+ recordPos += succinctBC.nByteLength(nMappings);
294
+ const mappings = [];
295
+
296
+ while (mappings.length < nMappings) {
297
+ const mapping = {};
298
+ mapping.ch = succinctBC.nByte(recordPos);
299
+ recordPos += succinctBC.nByteLength(mapping.ch);
300
+ mapping.verseStart = succinctBC.nByte(recordPos);
301
+ recordPos += succinctBC.nByteLength(mapping.verseStart);
302
+ mappings.push(mapping);
303
+ }
304
+ unsuccinctRecord.mapping = mappings;
305
+ ret.push(unsuccinctRecord);
306
+ pos += recordLength;
307
+ }
308
+ return ret;
309
+ };
310
+
311
+ const mapVerse = (succinct, b, c, v) => {
312
+ // Succinct for one chapter.
313
+ // Pass book and chapter to provide complete response in each case.
314
+ let ret = null;
315
+ let pos = 0;
316
+
317
+ while (pos < succinct.length) {
318
+ let recordPos = pos;
319
+ const [recordType, recordLength] = mappingLengthByte(succinct, pos);
320
+ recordPos++;
321
+ const fromVerseStart = succinct.nByte(recordPos);
322
+ recordPos += succinct.nByteLength(fromVerseStart);
323
+ const fromVerseEnd = succinct.nByte(recordPos);
324
+ recordPos += succinct.nByteLength(fromVerseEnd);
325
+
326
+ if (v < fromVerseStart || v > fromVerseEnd) {
327
+ pos += recordLength;
328
+ continue;
329
+ }
330
+
331
+ let bookCode = b;
332
+
333
+ if (recordType === bcvMappingType) {
334
+ const bookIndex = succinct.nByte(recordPos);
335
+ bookCode = bookCodes[bookIndex];
336
+ recordPos += succinct.nByteLength(bookIndex);
337
+ }
338
+ ret = [bookCode, []];
339
+ const nMappings = succinct.nByte(recordPos);
340
+ recordPos += succinct.nByteLength(nMappings);
341
+
342
+ while (ret[1].length < nMappings) {
343
+ const ch = succinct.nByte(recordPos);
344
+ recordPos += succinct.nByteLength(ch);
345
+ const verseStart = succinct.nByte(recordPos);
346
+ recordPos += succinct.nByteLength(verseStart);
347
+ ret[1].push([ch, (v - fromVerseStart) + verseStart]);
348
+ }
349
+ break;
350
+ }
351
+ return ret || [b, [[c, v]]];
352
+ };
353
+
354
+ module.exports = {
355
+ vrs2json,
356
+ reverseVersification,
357
+ preSuccinctVerseMapping,
358
+ bookCodes,
359
+ succinctifyVerseMapping,
360
+ succinctifyVerseMappings,
361
+ unsuccinctifyVerseMapping,
362
+ bookCodeIndex,
363
+ mapVerse,
364
+ };