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,87 @@
1
+ const { dumpItems } = require('../lib/dump.cjs');
2
+
3
+ const cIndexSchemaString = `
4
+ """A chapter index entry"""
5
+ type cIndex {
6
+ """The chapter number"""
7
+ chapter: Int!
8
+ """The zero-indexed number of the block where the chapter starts"""
9
+ startBlock: Int
10
+ """The zero-indexed number of the block where the chapter ends"""
11
+ endBlock: Int
12
+ """The zero-indexed position of the item where the chapter starts"""
13
+ startItem: Int
14
+ """The zero-indexed position of the item where the chapter ends"""
15
+ endItem: Int
16
+ """The value of nextToken at the beginning of the chapter"""
17
+ nextToken: Int
18
+ """A list of items for this chapter"""
19
+ items(
20
+ """If true, adds scope and nextToken information to each token"""
21
+ includeContext: Boolean
22
+ ): [Item]!
23
+ """The items as a string in a compact eyeballable format"""
24
+ dumpItems: String
25
+ """A list of tokens for this chapter"""
26
+ tokens(
27
+ """If true, adds scope and nextToken information to each token"""
28
+ includeContext: Boolean
29
+ """Return tokens whose payload is an exact match to one of the specified strings"""
30
+ withChars: [String!]
31
+ """Return tokens with one of the specified subTypes"""
32
+ withSubTypes: [String!]
33
+ ): [Item]!
34
+ """The text of the chapter as a single string"""
35
+ text(
36
+ """If true, converts each whitespace character to a single space"""
37
+ normalizeSpace: Boolean
38
+ ): String!
39
+ }
40
+ `;
41
+
42
+ const cIndexResolvers = {
43
+ chapter: root => root[0],
44
+ startBlock: root => root[1].startBlock,
45
+ endBlock: root => root[1].endBlock,
46
+ startItem: root => root[1].startItem,
47
+ endItem: root => root[1].endItem,
48
+ nextToken: root => root[1].nextToken,
49
+ items: (root, args, context) =>
50
+ context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root[1], args.includeContext)
51
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ']].concat(b)), []),
52
+ dumpItems: (root, args, context) => {
53
+ const items = context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root[1], false);
54
+
55
+ if (items.length > 0) {
56
+ return dumpItems(items.reduce((a, b) => a.concat([['token', 'lineSpace', ' ', null]].concat(b))));
57
+ } else {
58
+ return '';
59
+ }
60
+ },
61
+ tokens: (root, args, context) =>
62
+ context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root[1], args.includeContext)
63
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ']].concat(b)), [])
64
+ .filter(
65
+ i => i[0] === 'token' &&
66
+ (!args.withChars || args.withChars.includes(i[2])) &&
67
+ (!args.withSubTypes || args.withSubTypes.includes(i[1])),
68
+ ),
69
+ text: (root, args, context) => {
70
+ let ret = context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root[1])
71
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ']].concat(b)), [])
72
+ .filter(i => i[0] === 'token')
73
+ .map(t => t[1] === 'lineSpace' ? ' ' : t[2])
74
+ .join('')
75
+ .trim();
76
+
77
+ if (args.normalizeSpace) {
78
+ ret = ret.replace(/[ \t\n\r]+/g, ' ');
79
+ }
80
+ return ret;
81
+ },
82
+ };
83
+
84
+ module.exports = {
85
+ cIndexSchemaString,
86
+ cIndexResolvers,
87
+ };
@@ -0,0 +1,42 @@
1
+ const cellSchemaString = `
2
+ """A table cell"""
3
+ type cell {
4
+ """The row numbers"""
5
+ rows: [Int!]!
6
+ """The column numbers"""
7
+ columns: [Int!]!
8
+ """A list of items from the c (content) field of the cell"""
9
+ items: [Item!]!
10
+ """A list of tokens from the c (content) field of the cell"""
11
+ tokens: [Item!]!
12
+ """The text of the cell as a single string"""
13
+ text(
14
+ """If true, converts each whitespace character to a single space"""
15
+ normalizeSpace: Boolean
16
+ ): String!
17
+ }
18
+ `;
19
+
20
+ const cellResolvers = {
21
+ rows: root => root[0],
22
+ columns: root => root[1],
23
+ items: root => root[2],
24
+ tokens: root => root[2].filter(i => i[0] === 'token'),
25
+ text: (root, args) => {
26
+ let ret = root[2]
27
+ .filter(i => i[0] === 'token')
28
+ .map(t => t[2])
29
+ .join('')
30
+ .trim();
31
+
32
+ if (args.normalizeSpace) {
33
+ ret = ret.replace(/[ \t\n\r]+/g, ' ');
34
+ }
35
+ return ret;
36
+ },
37
+ };
38
+
39
+ module.exports = {
40
+ cellSchemaString,
41
+ cellResolvers,
42
+ };
@@ -0,0 +1,19 @@
1
+ const cvSchemaString = `
2
+ """A chapter-verse reference"""
3
+ type cv {
4
+ """The chapter number"""
5
+ chapter: Int
6
+ """The verse number"""
7
+ verse: Int
8
+ }
9
+ `;
10
+
11
+ const cvResolvers = {
12
+ chapter: root => root[0],
13
+ verse: root => root[1],
14
+ };
15
+
16
+ module.exports = {
17
+ cvSchemaString,
18
+ cvResolvers,
19
+ };
@@ -0,0 +1,16 @@
1
+ const cvBookSchemaString = `
2
+ """Chapter/verse information for a book"""
3
+ type cvBook {
4
+ """The bookCode"""
5
+ bookCode: String!
6
+ """The chapter records"""
7
+ chapters: [cvChapter!]!
8
+ }
9
+ `;
10
+
11
+ const cvBookResolvers = {
12
+ bookCode: root => root[0],
13
+ chapters: root => Object.entries(root[1]),
14
+ }
15
+
16
+ module.exports = { cvBookSchemaString, cvBookResolvers };
@@ -0,0 +1,16 @@
1
+ const cvChapterSchemaString = `
2
+ """Information for a chapter"""
3
+ type cvChapter {
4
+ """The chapter"""
5
+ chapter: Int!
6
+ """The maximum verse number"""
7
+ maxVerse: Int!
8
+ }
9
+ `;
10
+
11
+ const cvChapterResolvers = {
12
+ chapter: root => parseInt(root[0]),
13
+ maxVerse: root => parseInt(root[1]),
14
+ };
15
+
16
+ module.exports = { cvChapterSchemaString, cvChapterResolvers };
@@ -0,0 +1,47 @@
1
+ const cvIndexSchemaString = `
2
+ """A chapterVerse index entry"""
3
+ type cvIndex {
4
+ """The chapter number"""
5
+ chapter: Int!
6
+ """Information about the verses in the chapter"""
7
+ verses: [cvVerses]
8
+ """A list of verse number and range information, organized by verse number"""
9
+ verseNumbers: [verseNumber!]
10
+ """A list of verse number and range information, organized by verse range"""
11
+ verseRanges: [verseRange!]
12
+ }
13
+ `;
14
+
15
+ const cvIndexResolvers = {
16
+ chapter: root => root[0],
17
+ verses: root => root[1],
18
+ verseNumbers: (root, args, context) => {
19
+ context.cvIndex = root;
20
+ return [...root[1].entries()]
21
+ .filter(v => v[1].length > 0)
22
+ .map(v => ({
23
+ number: v[0],
24
+ range: v[1][v[1].length - 1].verses,
25
+ }));
26
+ },
27
+ verseRanges: root => {
28
+ const ret = [];
29
+
30
+ for (const [vn, vo] of [...root[1].entries()].filter(v => v[1].length > 0)) {
31
+ if (ret.length === 0 || ret[ret.length - 1].range !== vo[vo.length - 1].verses) {
32
+ ret.push({
33
+ range: vo[vo.length - 1].verses,
34
+ numbers: [vn],
35
+ });
36
+ } else {
37
+ ret[ret.length - 1].numbers.push(vn);
38
+ }
39
+ }
40
+ return ret;
41
+ },
42
+ };
43
+
44
+ module.exports = {
45
+ cvIndexSchemaString,
46
+ cvIndexResolvers,
47
+ };
@@ -0,0 +1,116 @@
1
+ const nv = (root, newVerseRange) => {
2
+ const chapterN = parseInt(root[0]);
3
+ const verseN = parseInt(root[1]);
4
+
5
+ if (root[3].length <= verseN || root[3][verseN].length === 0) {
6
+ return null;
7
+ }
8
+
9
+ let ret = null;
10
+ let nc = chapterN;
11
+ let nv = verseN;
12
+ let index = root[3];
13
+ let startVerseRange = index[verseN][0].verses;
14
+ let onNextChapter = false;
15
+
16
+ while (!ret) {
17
+ nv += 1;
18
+
19
+ if (nv >= index.length) {
20
+ if (onNextChapter || !root[4]) {
21
+ break;
22
+ }
23
+ nv = -1;
24
+ nc += 1;
25
+ index = root[4];
26
+ onNextChapter = true;
27
+ } else if (
28
+ index[nv].length > 0 &&
29
+ (!newVerseRange || onNextChapter || index[nv][0].verses !== startVerseRange)
30
+ ) {
31
+ ret = [nc, nv];
32
+ }
33
+ }
34
+ return ret;
35
+ };
36
+
37
+ const pv = (root, newVerseRange) => {
38
+ const chapterN = parseInt(root[0]);
39
+ const verseN = parseInt(root[1]);
40
+
41
+ if (root[3].length <= verseN || root[3][verseN].length === 0) {
42
+ return null;
43
+ }
44
+
45
+ let ret = null;
46
+ let nc = chapterN;
47
+ let nv = verseN;
48
+ let index = root[3];
49
+ let startVerseRange = index[verseN][0].verses;
50
+ let onPreviousChapter = false;
51
+
52
+ while (!ret) {
53
+ nv -= 1;
54
+
55
+ if (nv < 0) {
56
+ if (onPreviousChapter || !root[2]) {
57
+ break;
58
+ }
59
+ nv = root[2].length;
60
+ nc -= 1;
61
+ index = root[2];
62
+ onPreviousChapter = true;
63
+ } else if (
64
+ index[nv].length > 0 &&
65
+ (!newVerseRange || onPreviousChapter || index[nv][0].verses !== startVerseRange)
66
+ ) {
67
+ ret = [nc, nv];
68
+ }
69
+ }
70
+ return ret;
71
+ };
72
+
73
+ const cvNavigationSchemaString = `
74
+ """Various answers to 'previous' and 'next' with respect to a verse"""
75
+ type cvNavigation {
76
+ """The verse number for the next verse"""
77
+ nextVerse: cv
78
+ """The verse number for the previous verse"""
79
+ previousVerse: cv
80
+ """The verse number for the next verse range"""
81
+ nextVerseRangeVerse: cv
82
+ """The verse number for the previous verse range"""
83
+ previousVerseRangeVerse: cv
84
+ """The next chapter number (as a string)"""
85
+ nextChapter: String
86
+ """The previous chapter number (as a string)"""
87
+ previousChapter: String
88
+ }
89
+ `;
90
+
91
+ // root is [ < 0 chapter >, < 1 verse >, < 2 previousChapterIndex >, < 3 thisChapterIndex >, < 4 nextChapterIndex > ]
92
+ const cvNavigationResolvers = {
93
+ nextVerse: root => nv(root, false),
94
+ previousVerse: root => pv(root, false),
95
+ nextVerseRangeVerse: root => nv(root, true),
96
+ previousVerseRangeVerse: root => pv(root, true),
97
+ nextChapter: root => {
98
+ if (root[3].length > 0 && root[4].length > 0) {
99
+ return (parseInt(root[0]) + 1).toString();
100
+ } else {
101
+ return null;
102
+ }
103
+ },
104
+ previousChapter: root => {
105
+ if (root[2].length > 0 && root[3].length > 0) {
106
+ return (parseInt(root[0]) - 1).toString();
107
+ } else {
108
+ return null;
109
+ }
110
+ },
111
+ };
112
+
113
+ module.exports = {
114
+ cvNavigationSchemaString,
115
+ cvNavigationResolvers,
116
+ };
@@ -0,0 +1,84 @@
1
+ const { dumpItems } = require('../lib/dump.cjs');
2
+
3
+ const cvVerseElementSchemaString = `
4
+ """"""
5
+ type cvVerseElement {
6
+ """The zero-indexed number of the block where the verse starts"""
7
+ startBlock: Int
8
+ """The zero-indexed number of the block where the verse ends"""
9
+ endBlock: Int
10
+ """The zero-indexed position of the item where the verse starts"""
11
+ startItem: Int
12
+ """The zero-indexed position of the item where the verse ends"""
13
+ endItem: Int
14
+ """The value of nextToken at the beginning of the verse"""
15
+ nextToken: Int
16
+ """The verse range for this verse as it would be printed in a Bible"""
17
+ verseRange: String
18
+ """A list of items for this verse"""
19
+ items(
20
+ """If true, adds scope and nextToken information to each token"""
21
+ includeContext: Boolean
22
+ ): [Item]!
23
+ """The items as a string in a compact eyeballable format"""
24
+ dumpItems: String
25
+ """A list of tokens for this verse"""
26
+ tokens(
27
+ """If true, adds scope and nextToken information to each token"""
28
+ includeContext: Boolean
29
+ """Return tokens whose payload is an exact match to one of the specified strings"""
30
+ withChars: [String!]
31
+ """Return tokens with one of the specified subTypes"""
32
+ withSubTypes: [String!]
33
+ ): [Item]!
34
+ """The text of the verse as a single string"""
35
+ text(
36
+ """If true, converts each whitespace character to a single space"""
37
+ normalizeSpace: Boolean
38
+ ): String!
39
+ }
40
+ `;
41
+
42
+ const cvVerseElementResolvers = {
43
+ startBlock: root => root.startBlock,
44
+ endBlock: root => root.endBlock,
45
+ startItem: root => root.startItem,
46
+ endItem: root => root.endItem,
47
+ nextToken: root => root.nextToken,
48
+ verseRange: root => root.verses,
49
+ items: (root, args, context) =>
50
+ context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root, args.includeContext)
51
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ', null]].concat(b))),
52
+ dumpItems: (root, args, context) =>
53
+ dumpItems(
54
+ context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root, args.includeContext)
55
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ', null]].concat(b))),
56
+ ),
57
+ tokens: (root, args, context) =>
58
+ context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root, args.includeContext)
59
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ', null]].concat(b)))
60
+ .filter(
61
+ i =>
62
+ i[0] === 'token' &&
63
+ (!args.withChars || args.withChars.includes(i[2])) &&
64
+ (!args.withSubTypes || args.withSubTypes.includes(i[1])),
65
+ ),
66
+ text: (root, args, context) => {
67
+ let ret = context.docSet.itemsByIndex(context.doc.sequences[context.doc.mainId], root)
68
+ .reduce((a, b) => a.concat([['token', 'lineSpace', ' ', null]].concat(b)))
69
+ .filter(i => i[0] === 'token')
70
+ .map(t => t[1] === 'lineSpace' ? ' ' : t[2])
71
+ .join('')
72
+ .trim();
73
+
74
+ if (args.normalizeSpace) {
75
+ ret = ret.replace(/[ \t\n\r]+/g, ' ');
76
+ }
77
+ return ret;
78
+ },
79
+ };
80
+
81
+ module.exports = {
82
+ cvVerseElementSchemaString,
83
+ cvVerseElementResolvers,
84
+ };
@@ -0,0 +1,14 @@
1
+ const cvVersesSchemaString = `
2
+ """Information about a verse in the chapter, which may be split into several pieces"""
3
+ type cvVerses {
4
+ """The pieces of verse"""
5
+ verse: [cvVerseElement]
6
+ }
7
+ `;
8
+
9
+ const cvVersesResolvers = { verse: root => root };
10
+
11
+ module.exports = {
12
+ cvVersesSchemaString,
13
+ cvVersesResolvers,
14
+ };
@@ -0,0 +1,220 @@
1
+ const utils = require('../../util/index.cjs');
2
+
3
+ const { bookCodeCompareFunctions } = require('../lib/sort.cjs');
4
+
5
+ const {
6
+ sequenceHasChars,
7
+ sequenceHasMatchingChars,
8
+ } = require('../lib/sequence_chars.cjs');
9
+
10
+ const docSetSchemaString = `
11
+ """A collection of documents that share the same set of selector values"""
12
+ type DocSet {
13
+ """The id of the docSet, which is formed by concatenating the docSet's selector values"""
14
+ id: String!
15
+ """The selectors of the docSet"""
16
+ selectors: [KeyValue!]!
17
+ """A selector for this docSet"""
18
+ selector(
19
+ """The id of the selector"""
20
+ id: String!
21
+ ): String!
22
+ """A list of the tags of this docSet"""
23
+ tags: [String!]!
24
+ """A list of the tags of this docSet as key/value tuples"""
25
+ tagsKv: [KeyValue!]!
26
+ """Whether or not the docSet has the specified tag"""
27
+ hasTag(
28
+ """The tag"""
29
+ tagName: String!
30
+ ): Boolean!
31
+ """The documents in the docSet"""
32
+ documents(
33
+ """A whitelist of ids of documents to include"""
34
+ ids: [String!]
35
+ """A whitelist of ids of documents to include"""
36
+ withChars: [String!]
37
+ """Return documents whose main sequence contains a token whose payload is an exact match to one of the specified strings"""
38
+ withMatchingChars: [String!]
39
+ """If true, documents where all search terms match will be included"""
40
+ allChars: Boolean
41
+ """Only return documents where the list of scopes is used"""
42
+ withScopes: [String!]
43
+ """If true, documents where all scopes are found will be included"""
44
+ allScopes: Boolean
45
+ """Only return documents with the specified header key/values"""
46
+ withHeaderValues: [InputKeyValue!]
47
+ """Only return documents with all the specified tags"""
48
+ withTags: [String!]
49
+ """Only return documents with none of the specified tags"""
50
+ withoutTags: [String!]
51
+ """Sort returned documents by the designated method (currently ${Object.keys(bookCodeCompareFunctions).join(', ')})\`"""
52
+ sortedBy: String
53
+ ): [Document!]!
54
+ """The number of documents in the docSet"""
55
+ nDocuments: Int!
56
+ """A document in the docSet, if present"""
57
+ document(
58
+ """The book code of the required document"""
59
+ bookCode: String!
60
+ ): Document
61
+ """Whether the docSet has versification information loaded"""
62
+ hasMapping: Boolean!
63
+ """The internal index number corresponding to a string in a given docSet enum"""
64
+ enumIndexForString(
65
+ """The enum to be searched"""
66
+ enumType: String!
67
+ """The string to match"""
68
+ searchString: String!
69
+ ): Int!
70
+ """Information about internal indexes matching the case-insensitive regex in a given docSet enum"""
71
+ enumRegexIndexesForString(
72
+ """The enum to be searched"""
73
+ enumType: String!
74
+ """The regex to match"""
75
+ searchRegex: String!
76
+ ): [regexIndex!]!
77
+ """A list of wordLike token strings in the docSet"""
78
+ wordLikes(
79
+ """Whether to coerce the strings (toLower|toUpper|none)"""
80
+ coerceCase: String
81
+ ): [String!]!
82
+ """A list of unique characters in the docSet"""
83
+ uniqueChars: [String!]!
84
+ """A string containing the unique characters in the docSet"""
85
+ uniqueCharsString: String!
86
+ }
87
+ `;
88
+
89
+ const docSetResolvers = {
90
+ selectors: (root) => Object.entries(root.selectors),
91
+ selector: (root, args) => root.selectors[args.id],
92
+ tags: root => Array.from(root.tags),
93
+ tagsKv: root => Array.from(root.tags).map(t => {
94
+ if (t.includes(':')) {
95
+ return [t.substring(0, t.indexOf(':')), t.substring(t.indexOf(':') + 1)];
96
+ } else {
97
+ return [t, ''];
98
+ }
99
+ }),
100
+ hasTag: (root, args) => root.tags.has(args.tagName),
101
+ documents: (root, args, context) => {
102
+ const headerValuesMatch = (docHeaders, requiredHeaders) => {
103
+ for (const requiredHeader of requiredHeaders || []) {
104
+ if (!(requiredHeader.key in docHeaders) || docHeaders[requiredHeader.key] !== requiredHeader.value) {
105
+ return false;
106
+ }
107
+ }
108
+ return true;
109
+ };
110
+
111
+ if (args.withChars && args.withMatchingChars) {
112
+ throw new Error('Cannot specify both withChars and withMatchingChars');
113
+ }
114
+
115
+ context.docSet = root;
116
+ let ret = root.documents();
117
+
118
+ if (args.ids) {
119
+ ret = ret.filter(d => args.ids.includes(d.id));
120
+ }
121
+
122
+ if (args.withChars) {
123
+ ret = ret.filter(d => sequenceHasChars(root, d.sequences[d.mainId], args.withChars, args.allChars));
124
+ }
125
+
126
+ if (args.withMatchingChars) {
127
+ ret = ret.filter(d => sequenceHasMatchingChars(root, d.sequences[d.mainId], args.withMatchingChars, args.allChars));
128
+ }
129
+
130
+ if (args.withScopes) {
131
+ const allSequenceScopes = doc => new Set(
132
+ doc.sequences[doc.mainId].blocks
133
+ .map(b => context.docSet.unsuccinctifyBlockScopeLabelsSet(b))
134
+ .map(s => Array.from(s))
135
+ .reduce((a, b) => a.concat(b)),
136
+ );
137
+
138
+ ret = ret.filter(
139
+ d => {
140
+ const docScopes = allSequenceScopes(d);
141
+ const minHits = args.allScopes ? args.withScopes.length : 1;
142
+ return args.withScopes.filter(s => docScopes.has(s)).length >= minHits;
143
+ },
144
+ );
145
+ }
146
+
147
+ if (args.withHeaderValues) {
148
+ ret = ret.filter(d => headerValuesMatch(d.headers, args.withHeaderValues));
149
+ }
150
+
151
+ if (args.withTags) {
152
+ ret = ret.filter(d => args.withTags.filter(t => d.tags.has(t)).length === args.withTags.length);
153
+ }
154
+
155
+ if (args.withoutTags) {
156
+ ret = ret.filter(d => args.withoutTags.filter(t => d.tags.has(t)).length === 0);
157
+ }
158
+
159
+ if (args.sortedBy) {
160
+ if (!(args.sortedBy in bookCodeCompareFunctions)) {
161
+ throw new Error(`sortedBy value must be one of [${Object.keys(bookCodeCompareFunctions)}], not ${args.sortedBy}`);
162
+ }
163
+ ret.sort(bookCodeCompareFunctions[args.sortedBy]);
164
+ }
165
+
166
+ return ret;
167
+ },
168
+ nDocuments: (root, args, context) => {
169
+ context.docSet = root;
170
+ return root.documents().length;
171
+ },
172
+ document: (root, args) => root.documentWithBook(args.bookCode),
173
+ hasMapping: root => root.tags.has('hasMapping'),
174
+ enumIndexForString: (root, args) =>
175
+ utils.enums.enumStringIndex(root.enums[args.enumType], args.searchString),
176
+ enumRegexIndexesForString: (root, args) =>
177
+ utils.enums.enumRegexIndexTuples(root.enums[args.enumType], args.searchRegex),
178
+ wordLikes: (root, args) => {
179
+ if (args.coerceCase && !['toLower', 'toUpper', 'none'].includes(args.coerceCase)) {
180
+ throw new Error(`coerceCase, when present, must be 'toLower', 'toUpper' or 'none', not '${args.coerceCase}'`);
181
+ }
182
+
183
+ let tokens = utils.succinct.unpackEnum(root.enums.wordLike);
184
+
185
+ if (args.coerceCase === 'toLower') {
186
+ tokens = tokens.map(t => t.toLowerCase());
187
+ }
188
+
189
+ if (args.coerceCase === 'toUpper') {
190
+ tokens = tokens.map(t => t.toUpperCase());
191
+ }
192
+ return Array.from(new Set(tokens));
193
+ },
194
+ uniqueChars: root => {
195
+ const retSet = new Set([]);
196
+
197
+ for (const token of [...utils.succinct.unpackEnum(root.enums.wordLike), ...utils.succinct.unpackEnum(root.enums.notWordLike)]) {
198
+ for (const char of token.split('')) {
199
+ retSet.add(char);
200
+ }
201
+ }
202
+ return Array.from(retSet).sort();
203
+ },
204
+ uniqueCharsString: root => {
205
+ const retSet = new Set([]);
206
+
207
+ for (const token of [...utils.succinct.unpackEnum(root.enums.wordLike), ...utils.succinct.unpackEnum(root.enums.notWordLike)]) {
208
+ for (const char of token.split('')) {
209
+ retSet.add(char);
210
+ }
211
+ }
212
+ return Array.from(retSet).sort().join('');
213
+ },
214
+ };
215
+
216
+ module.exports = {
217
+ docSetSchemaString,
218
+ docSetResolvers,
219
+ };
220
+