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.
- package/.eslintrc.json +79 -0
- package/.gitattributes +2 -0
- package/docs/_config.yml +1 -0
- package/docs/index.md +3 -0
- package/docs/pk_edit_0_9.odt +0 -0
- package/docs/pk_edit_0_9.pdf +0 -0
- package/docs/proskomma_101_slideshow.odp +0 -0
- package/docs/proskomma_101_slideshow.pdf +0 -0
- package/docs/proskomma_edit_html.png +0 -0
- package/docs/proskomma_edit_html.svg +451 -0
- package/docs/proskomma_edit_reference.png +0 -0
- package/docs/proskomma_edit_reference.svg +349 -0
- package/docs/repo_logo.png +0 -0
- package/esm/package.json +3 -0
- package/esm/wrapper.mjs +5 -0
- package/index.cjs +6 -0
- package/package.json +18 -15
- package/src/graph/index.cjs +201 -0
- package/src/graph/lib/do_cv.cjs +249 -0
- package/src/graph/lib/dump.cjs +40 -0
- package/src/graph/lib/remake_blocks.cjs +57 -0
- package/src/graph/lib/sequence_chars.cjs +84 -0
- package/src/graph/lib/sort.cjs +39 -0
- package/src/graph/lib/tribos.cjs +97 -0
- package/src/graph/lib/tribos_expression.cjs +556 -0
- package/src/graph/lib/tribos_ohm_UNUSED.cjs +37 -0
- package/src/graph/lib/tribos_step.cjs +434 -0
- package/src/graph/mutations/add.cjs +91 -0
- package/src/graph/mutations/delete.cjs +61 -0
- package/src/graph/mutations/index.cjs +54 -0
- package/src/graph/mutations/rehash.cjs +17 -0
- package/src/graph/mutations/tags.cjs +120 -0
- package/src/graph/mutations/update.cjs +210 -0
- package/src/graph/mutations/versification.cjs +96 -0
- package/src/graph/queries/block.cjs +228 -0
- package/src/graph/queries/cIndex.cjs +87 -0
- package/src/graph/queries/cell.cjs +42 -0
- package/src/graph/queries/cv.cjs +19 -0
- package/src/graph/queries/cvBook.cjs +16 -0
- package/src/graph/queries/cvChapter.cjs +16 -0
- package/src/graph/queries/cvIndex.cjs +47 -0
- package/src/graph/queries/cvNavigation.cjs +116 -0
- package/src/graph/queries/cvVerseElement.cjs +84 -0
- package/src/graph/queries/cvVerses.cjs +14 -0
- package/src/graph/queries/doc_set.cjs +220 -0
- package/src/graph/queries/document.cjs +555 -0
- package/src/graph/queries/idParts.cjs +30 -0
- package/src/graph/queries/index.cjs +151 -0
- package/src/graph/queries/inputBlockSpec.cjs +17 -0
- package/src/graph/queries/inputItemObject.cjs +12 -0
- package/src/graph/queries/input_att_spec.cjs +14 -0
- package/src/graph/queries/input_key_matches.cjs +11 -0
- package/src/graph/queries/input_key_value.cjs +11 -0
- package/src/graph/queries/input_key_values.cjs +11 -0
- package/src/graph/queries/input_selector_spec.cjs +19 -0
- package/src/graph/queries/item.cjs +71 -0
- package/src/graph/queries/itemGroup.cjs +75 -0
- package/src/graph/queries/key_value.cjs +18 -0
- package/src/graph/queries/kv_entry.cjs +21 -0
- package/src/graph/queries/kv_sequence.cjs +151 -0
- package/src/graph/queries/node.cjs +44 -0
- package/src/graph/queries/orig.cjs +11 -0
- package/src/graph/queries/regex_index.cjs +18 -0
- package/src/graph/queries/row_equals_spec.cjs +11 -0
- package/src/graph/queries/row_match_spec.cjs +11 -0
- package/src/graph/queries/selector_spec.cjs +29 -0
- package/src/graph/queries/sequence.cjs +314 -0
- package/src/graph/queries/table_sequence.cjs +192 -0
- package/src/graph/queries/tree_sequence.cjs +58 -0
- package/src/graph/queries/verseNumber.cjs +44 -0
- package/src/graph/queries/verseRange.cjs +11 -0
- package/src/graph/queries/versification.cjs +25 -0
- package/src/index.cjs +583 -0
- package/src/model/doc_set.cjs +389 -0
- package/src/model/doc_set_helpers/block.cjs +232 -0
- package/src/model/doc_set_helpers/enum.cjs +87 -0
- package/src/model/doc_set_helpers/item.cjs +198 -0
- package/src/model/doc_set_helpers/rehash.cjs +53 -0
- package/src/model/doc_set_helpers/selectors.cjs +58 -0
- package/src/model/doc_set_helpers/serialize.cjs +22 -0
- package/src/model/doc_set_helpers/unsuccinctify.cjs +288 -0
- package/src/model/doc_set_helpers/update.cjs +290 -0
- package/src/model/document.cjs +369 -0
- package/src/model/document_helpers/blocks.cjs +135 -0
- package/src/model/document_helpers/chapter_verse.cjs +291 -0
- package/src/model/document_helpers/pre_enums.cjs +67 -0
- package/src/model/document_helpers/sequences.cjs +205 -0
- package/src/model/document_helpers/serialize_succinct.cjs +55 -0
- package/src/model/document_helpers/succinct_filter.cjs +102 -0
- package/src/model/versifications/eng_vrs.cjs +455 -0
- package/src/model/versifications/index.cjs +38 -0
- package/src/model/versifications/lxx_vrs.cjs +950 -0
- package/src/model/versifications/org_vrs.cjs +155 -0
- package/src/model/versifications/rsc_vrs.cjs +342 -0
- package/src/model/versifications/rso_vrs.cjs +541 -0
- package/src/model/versifications/vul_vrs.cjs +835 -0
- package/src/parser/index.cjs +506 -0
- package/src/parser/lexers/index.cjs +11 -0
- package/src/parser/lexers/lexingRegexes.cjs +45 -0
- package/src/parser/lexers/nodes.cjs +123 -0
- package/src/parser/lexers/object_for_fragment.cjs +123 -0
- package/src/parser/lexers/tsv.cjs +45 -0
- package/src/parser/lexers/usfm.cjs +17 -0
- package/src/parser/lexers/usx/index.cjs +7 -0
- package/src/parser/lexers/usx/usx_lexer.cjs +321 -0
- package/src/parser/lib/tokenize.cjs +37 -0
- package/src/parser/model/index.cjs +637 -0
- package/src/parser/parser_specs.cjs +781 -0
- package/src/pipelines/perf2x/index.cjs +7 -0
- package/src/pipelines/perf2x/perf2PkJsonPipeline.json +41 -0
- package/src/pipelines/perf2x/perf2usfmPipeline.json +65 -0
- package/src/transforms/calculateUsfmChapterPositions.cjs +106 -0
- package/src/transforms/index.cjs +9 -0
- package/src/transforms/perf2PkJson.cjs +534 -0
- package/src/transforms/perf2usfm.cjs +294 -0
- package/src/util/byteArray.cjs +251 -0
- package/src/util/canons.cjs +117 -0
- package/src/util/enums.cjs +41 -0
- package/src/util/generateId.cjs +6 -0
- package/src/util/graftDefs.cjs +15 -0
- package/src/util/index.cjs +29 -0
- package/src/util/inspectSuccinct.cjs +59 -0
- package/src/util/itemDefs.cjs +33 -0
- package/src/util/parserConstantDefs.cjs +30 -0
- package/src/util/scopeDefs.cjs +173 -0
- package/src/util/scriptlike/blocksSpec.cjs +192 -0
- package/src/util/scriptlike/dodson_lexicon.xsl +19 -0
- package/src/util/scriptlike/dodson_lexicon_to_entries.cjs +85 -0
- package/src/util/scriptlike/open_scriptures_hebrew_lexicon.xsl +28 -0
- package/src/util/scriptlike/open_scriptures_hebrew_lexicon_to_entries.cjs +85 -0
- package/src/util/succinct.cjs +159 -0
- package/src/util/tags.cjs +28 -0
- package/src/util/tokenDefs.cjs +27 -0
- package/src/util/versification.cjs +364 -0
- package/dist/index.js +0 -8
- package/dist/index.js.LICENSE.txt +0 -23
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const rowMatchSpecSchemaString = `
|
|
2
|
+
"""Row Match Specification"""
|
|
3
|
+
input rowMatchSpec {
|
|
4
|
+
"""The position of the column in which to search a match"""
|
|
5
|
+
colN: Int!
|
|
6
|
+
"""The regex to match"""
|
|
7
|
+
matching: String!
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
module.exports = { rowMatchSpecSchemaString };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const selectorSpecSchemaString = `
|
|
2
|
+
"""Specification of a selector"""
|
|
3
|
+
type selectorSpec {
|
|
4
|
+
"""Name (ie the key)"""
|
|
5
|
+
name: String!
|
|
6
|
+
"""Data type (string or integer)"""
|
|
7
|
+
type: String!
|
|
8
|
+
"""Regex for validating string selector"""
|
|
9
|
+
regex: String
|
|
10
|
+
"""Inclusive minimum value for integer selector"""
|
|
11
|
+
min: String
|
|
12
|
+
"""Inclusive maximum value for integer selector"""
|
|
13
|
+
max: String
|
|
14
|
+
"""Enum of permitted string values"""
|
|
15
|
+
enum: [String!]
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const selectorSpecResolvers = {
|
|
20
|
+
regex: root => root.regex || null,
|
|
21
|
+
min: root => root.min || null,
|
|
22
|
+
max: root => root.max || null,
|
|
23
|
+
enum: root => root.enum || null,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
selectorSpecSchemaString,
|
|
28
|
+
selectorSpecResolvers,
|
|
29
|
+
};
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
const {
|
|
2
|
+
sequenceHasChars,
|
|
3
|
+
sequenceHasMatchingChars,
|
|
4
|
+
regexSearchTermIndexes,
|
|
5
|
+
exactSearchTermIndexes,
|
|
6
|
+
} = require('../lib/sequence_chars.cjs');
|
|
7
|
+
|
|
8
|
+
const options = {
|
|
9
|
+
tokens: false,
|
|
10
|
+
scopes: true,
|
|
11
|
+
grafts: false,
|
|
12
|
+
requiredScopes: [],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const blockHasAtts = (docSet, block, attSpecsArray, attValuesArray, requireAll) => {
|
|
16
|
+
let matched = new Set([]);
|
|
17
|
+
|
|
18
|
+
for (const item of docSet.unsuccinctifyPrunedItems(block, options, false)) {
|
|
19
|
+
const [att, attType, element, key, count, value] = item[2].split('/');
|
|
20
|
+
|
|
21
|
+
for (const [n, attSpecs] of attSpecsArray.entries()) {
|
|
22
|
+
for (const attSpec of attSpecs) {
|
|
23
|
+
if (
|
|
24
|
+
attType === attSpec.attType &&
|
|
25
|
+
element === attSpec.tagName &&
|
|
26
|
+
key === attSpec.attKey &&
|
|
27
|
+
parseInt(count) === attSpec.valueN &&
|
|
28
|
+
attValuesArray[n].includes(value)
|
|
29
|
+
) {
|
|
30
|
+
if (!requireAll) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
matched.add(n);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (matched.size === attSpecsArray.length) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const sequenceSchemaString = `
|
|
47
|
+
"""A contiguous flow of content"""
|
|
48
|
+
type Sequence {
|
|
49
|
+
"""The id of the sequence"""
|
|
50
|
+
id: String!
|
|
51
|
+
"""The type of the sequence (main, heading...)"""
|
|
52
|
+
type: String!
|
|
53
|
+
"""The number of blocks in the sequence"""
|
|
54
|
+
nBlocks: Int!
|
|
55
|
+
"""The blocks in the sequence"""
|
|
56
|
+
blocks(
|
|
57
|
+
"""Only return blocks where the list of scopes is open"""
|
|
58
|
+
withScopes: [String!]
|
|
59
|
+
"""Only return blocks whose zero-indexed position is in the list"""
|
|
60
|
+
positions: [Int!]
|
|
61
|
+
"""Only return blocks with the specified block scope (eg 'blockScope/p'"""
|
|
62
|
+
withBlockScope: String
|
|
63
|
+
"""Only return blocks that contain items within the specified chapter, verse or chapterVerse range"""
|
|
64
|
+
withScriptureCV: String
|
|
65
|
+
"""Ordered list of attribute specs whose values must match those in 'attValues'"""
|
|
66
|
+
attSpecs: [[AttSpec!]!]
|
|
67
|
+
"""Ordered list of attribute values, used in conjunction with \\'attSpecs\\'"""
|
|
68
|
+
attValues: [[String!]!]
|
|
69
|
+
"""If true, blocks where all attSpecs match will be included"""
|
|
70
|
+
allAtts: Boolean
|
|
71
|
+
"""Return blocks containing a token whose payload is an exact match to one of the specified strings"""
|
|
72
|
+
withChars: [String!]
|
|
73
|
+
"""Return blocks containing a token whose payload matches the specified regexes"""
|
|
74
|
+
withMatchingChars: [String!]
|
|
75
|
+
"""If true, blocks where all regexes match will be included"""
|
|
76
|
+
allChars: Boolean
|
|
77
|
+
): [Block!]!
|
|
78
|
+
"""The items for each block in the sequence"""
|
|
79
|
+
blocksItems: [[Item!]!]
|
|
80
|
+
"""The tokens for each block in the sequence"""
|
|
81
|
+
blocksTokens: [[Item!]!]
|
|
82
|
+
"""The text for each block in the sequence"""
|
|
83
|
+
blocksText(
|
|
84
|
+
"""If true, converts each whitespace character to a single space"""
|
|
85
|
+
normalizeSpace: Boolean
|
|
86
|
+
): [String!]
|
|
87
|
+
"""The text for the sequence"""
|
|
88
|
+
text(
|
|
89
|
+
"""If true, converts each whitespace character to a single space"""
|
|
90
|
+
normalizeSpace: Boolean
|
|
91
|
+
) : String!
|
|
92
|
+
"""Sequence content grouped by scopes or milestones"""
|
|
93
|
+
itemGroups(
|
|
94
|
+
"""Produce one itemGroup for every different match of the list of scopes"""
|
|
95
|
+
byScopes: [String!]
|
|
96
|
+
"""Start a new itemGroup whenever a milestone in the list is encountered"""
|
|
97
|
+
byMilestones: [String!]
|
|
98
|
+
) : [ItemGroup!]!
|
|
99
|
+
"""A list of the tags of this sequence"""
|
|
100
|
+
tags: [String!]!
|
|
101
|
+
"""A list of the tags of this sequence as key/value tuples"""
|
|
102
|
+
tagsKv: [KeyValue!]!
|
|
103
|
+
"""Whether or not the sequence has the specified tag"""
|
|
104
|
+
hasTag(
|
|
105
|
+
"""The specified tag"""
|
|
106
|
+
tagName: String!
|
|
107
|
+
): Boolean!
|
|
108
|
+
"""A list of wordLike token strings in a main sequence"""
|
|
109
|
+
wordLikes(
|
|
110
|
+
"""Whether to coerce the strings (toLower|toUpper|none)"""
|
|
111
|
+
coerceCase: String
|
|
112
|
+
) : [String!]!
|
|
113
|
+
"""Returns true if a main sequence contains the specified tokens"""
|
|
114
|
+
hasChars(
|
|
115
|
+
"""Token strings to be matched exactly"""
|
|
116
|
+
chars: [String!]
|
|
117
|
+
"""If true all tokens must match"""
|
|
118
|
+
allChars: Boolean
|
|
119
|
+
): Boolean!
|
|
120
|
+
"""Returns true if a main sequence contains a match for specified regexes"""
|
|
121
|
+
hasMatchingChars(
|
|
122
|
+
"""Regexes to be matched"""
|
|
123
|
+
chars: [String!]
|
|
124
|
+
"""If true all regexes must match"""
|
|
125
|
+
allChars: Boolean
|
|
126
|
+
): Boolean!
|
|
127
|
+
}
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
const sequenceResolvers = {
|
|
131
|
+
nBlocks: root => root.blocks.length,
|
|
132
|
+
blocks: (root, args, context) => {
|
|
133
|
+
context.docSet.maybeBuildEnumIndexes();
|
|
134
|
+
|
|
135
|
+
if (args.withScopes && args.withScriptureCV) {
|
|
136
|
+
throw new Error('Cannot specify both withScopes and withScriptureCV');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (args.attSpecs && !args.attValues) {
|
|
140
|
+
throw new Error('Cannot specify attSpecs without attValues');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!args.attSpecs && args.attValues) {
|
|
144
|
+
throw new Error('Cannot specify attValues without attSpecs');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (args.attSpecs && args.attValues && (args.attSpecs.length !== args.attValues.length)) {
|
|
148
|
+
throw new Error('attSpecs and attValues must be same length');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (args.withChars && args.withMatchingChars) {
|
|
152
|
+
throw new Error('Cannot specify both withChars and withMatchingChars');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let ret = root.blocks;
|
|
156
|
+
|
|
157
|
+
if (args.positions) {
|
|
158
|
+
ret = Array.from(ret.entries()).filter(b => args.positions.includes(b[0])).map(b => b[1]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (args.withScopes) {
|
|
162
|
+
ret = ret.filter(b => context.docSet.allScopesInBlock(b, args.withScopes));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (args.withScriptureCV) {
|
|
166
|
+
ret = context.docSet.blocksWithScriptureCV(ret, args.withScriptureCV);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (args.attSpecs) {
|
|
170
|
+
ret = ret.filter(b => blockHasAtts(context.docSet, b, args.attSpecs, args.attValues, args.allAtts || false));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (args.withBlockScope) {
|
|
174
|
+
ret = ret.filter(b => context.docSet.blockHasBlockScope(b, args.withBlockScope));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (args.withChars) {
|
|
178
|
+
if (
|
|
179
|
+
root.type === 'main' &&
|
|
180
|
+
!sequenceHasChars(context.docSet, root, args.withChars, args.allChars)
|
|
181
|
+
) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let charsIndexesArray = exactSearchTermIndexes(context.docSet, args.withChars, args.allChars);
|
|
186
|
+
|
|
187
|
+
for (const charsIndexes of charsIndexesArray) {
|
|
188
|
+
ret = ret.filter(b => context.docSet.blockHasChars(b, charsIndexes));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (args.withMatchingChars) {
|
|
193
|
+
if (
|
|
194
|
+
root.type === 'main' &&
|
|
195
|
+
!sequenceHasMatchingChars(context.docSet, root, args.withMatchingChars, args.allChars)
|
|
196
|
+
) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let charsIndexesArray = regexSearchTermIndexes(context.docSet, args.withMatchingChars, args.allChars);
|
|
201
|
+
|
|
202
|
+
for (const charsIndexes of charsIndexesArray) {
|
|
203
|
+
ret = ret.filter(b => context.docSet.blockHasChars(b, charsIndexes));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return ret;
|
|
207
|
+
},
|
|
208
|
+
blocksItems: (root, args, context) =>
|
|
209
|
+
root.blocks.map(b => context.docSet.unsuccinctifyItems(b.c, {}, null)),
|
|
210
|
+
blocksTokens: (root, args, context) =>
|
|
211
|
+
root.blocks.map(b => context.docSet.unsuccinctifyItems(b.c, { tokens: true }, null)),
|
|
212
|
+
blocksText: (root, args, context) =>
|
|
213
|
+
root.blocks.map(
|
|
214
|
+
b => {
|
|
215
|
+
let ret = context.docSet
|
|
216
|
+
.unsuccinctifyItems(b.c, { tokens: true }, null)
|
|
217
|
+
.map(t => t[2])
|
|
218
|
+
.join('');
|
|
219
|
+
|
|
220
|
+
if (args.normalizeSpace) {
|
|
221
|
+
ret = ret.replace(/[ \t\n\r]+/g, ' ');
|
|
222
|
+
}
|
|
223
|
+
return ret;
|
|
224
|
+
},
|
|
225
|
+
),
|
|
226
|
+
text: (root, args, context) => {
|
|
227
|
+
let ret = root.blocks.map(b => context.docSet
|
|
228
|
+
.unsuccinctifyItems(b.c, { tokens: true }, null)
|
|
229
|
+
.map(t => t[2])
|
|
230
|
+
.join(''),
|
|
231
|
+
).join('\n');
|
|
232
|
+
|
|
233
|
+
if (args.normalizeSpace) {
|
|
234
|
+
ret = ret.replace(/[ \t\n\r]+/g, ' ');
|
|
235
|
+
}
|
|
236
|
+
return ret;
|
|
237
|
+
},
|
|
238
|
+
itemGroups: (root, args, context) => {
|
|
239
|
+
if (args.byScopes && args.byMilestones) {
|
|
240
|
+
throw new Error('Cannot specify both byScopes and byMilestones');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!args.byScopes && !args.byMilestones) {
|
|
244
|
+
throw new Error('Must specify either byScopes or byMilestones');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (args.byScopes) {
|
|
248
|
+
return context.docSet.sequenceItemsByScopes(
|
|
249
|
+
root.blocks,
|
|
250
|
+
args.byScopes,
|
|
251
|
+
);
|
|
252
|
+
} else {
|
|
253
|
+
return context.docSet.sequenceItemsByMilestones(root.blocks, args.byMilestones);
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
tags: root => Array.from(root.tags),
|
|
257
|
+
tagsKv: root => Array.from(root.tags).map(t => {
|
|
258
|
+
if (t.includes(':')) {
|
|
259
|
+
return [t.substring(0, t.indexOf(':')), t.substring(t.indexOf(':') + 1)];
|
|
260
|
+
} else {
|
|
261
|
+
return [t, ''];
|
|
262
|
+
}
|
|
263
|
+
}),
|
|
264
|
+
hasTag: (root, args) => root.tags.has(args.tagName),
|
|
265
|
+
wordLikes: (root, args, context) => {
|
|
266
|
+
if (root.type !== 'main') {
|
|
267
|
+
throw new Error(`Only available for the main sequence, not ${root.type}`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (args.coerceCase && !['toLower', 'toUpper', 'none'].includes(args.coerceCase)) {
|
|
271
|
+
throw new Error(`coerceCase, when present, must be 'toLower', 'toUpper' or 'none', not '${args.coerceCase}'`);
|
|
272
|
+
}
|
|
273
|
+
context.docSet.maybeBuildEnumIndexes();
|
|
274
|
+
let tokens = new Set();
|
|
275
|
+
let n = 0;
|
|
276
|
+
|
|
277
|
+
for (const b of root.tokensPresent) {
|
|
278
|
+
if (b) {
|
|
279
|
+
const enumOffset = context.docSet.enumIndexes['wordLike'][n];
|
|
280
|
+
let tokenString = context.docSet.enums['wordLike'].countedString(enumOffset);
|
|
281
|
+
|
|
282
|
+
if (args.coerceCase === 'toLower') {
|
|
283
|
+
tokenString = tokenString.toLowerCase();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (args.coerceCase === 'toUpper') {
|
|
287
|
+
tokenString = tokenString.toUpperCase();
|
|
288
|
+
}
|
|
289
|
+
tokens.add(tokenString);
|
|
290
|
+
}
|
|
291
|
+
n++;
|
|
292
|
+
}
|
|
293
|
+
return Array.from(tokens).sort();
|
|
294
|
+
},
|
|
295
|
+
hasChars: (root, args, context) => {
|
|
296
|
+
if (root.type !== 'main') {
|
|
297
|
+
throw new Error(`Only available for the main sequence, not ${root.type}`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return sequenceHasChars(context.docSet, root, args.chars, args.allChars || false);
|
|
301
|
+
},
|
|
302
|
+
hasMatchingChars: (root, args, context) => {
|
|
303
|
+
if (root.type !== 'main') {
|
|
304
|
+
throw new Error(`Only available for the main sequence, not ${root.type}`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return sequenceHasMatchingChars(context.docSet, root, args.chars, args.allChars);
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
module.exports = {
|
|
312
|
+
sequenceSchemaString,
|
|
313
|
+
sequenceResolvers,
|
|
314
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
const xre = require('xregexp');
|
|
2
|
+
const utils = require('../../util/index.cjs');
|
|
3
|
+
|
|
4
|
+
const tableSequenceSchemaString = `
|
|
5
|
+
"""A contiguous flow of content for a table"""
|
|
6
|
+
type tableSequence {
|
|
7
|
+
"""The id of the sequence"""
|
|
8
|
+
id: String!
|
|
9
|
+
"""The number of cells in the table sequence"""
|
|
10
|
+
nCells: Int!
|
|
11
|
+
"""The number of rows in the table sequence"""
|
|
12
|
+
nRows: Int!
|
|
13
|
+
"""The number of columns in the table sequence"""
|
|
14
|
+
nColumns: Int!
|
|
15
|
+
"""The cells in the table sequence"""
|
|
16
|
+
cells: [cell!]!
|
|
17
|
+
"""The rows in the table sequence"""
|
|
18
|
+
rows(
|
|
19
|
+
"""Only return rows whose zero-indexed position is in the list"""
|
|
20
|
+
positions: [Int!]
|
|
21
|
+
"""Only return columns whose zero-indexed position is in the list"""
|
|
22
|
+
columns: [Int!]
|
|
23
|
+
"""Only return rows whose cells match the specification"""
|
|
24
|
+
matches: [rowMatchSpec!]
|
|
25
|
+
"""'Only return rows whose cells contain one of the values in the specification"""
|
|
26
|
+
equals: [rowEqualsSpec!]
|
|
27
|
+
): [[cell!]!]!
|
|
28
|
+
"""A list of the tags of this sequence"""
|
|
29
|
+
tags: [String!]!
|
|
30
|
+
"""A list of the tags of this sequence as key/value tuples"""
|
|
31
|
+
tagsKv: [KeyValue!]!
|
|
32
|
+
"""Whether or not the sequence has the specified tag"""
|
|
33
|
+
hasTag(
|
|
34
|
+
"""The tag name"""
|
|
35
|
+
tagName: String
|
|
36
|
+
): Boolean!
|
|
37
|
+
"""A list of column headings for this tableSequence, derived from the sequence tags"""
|
|
38
|
+
headings: [String!]!
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const tableSequenceResolvers = {
|
|
43
|
+
nCells: root => root.blocks.length,
|
|
44
|
+
nRows: (root, args, context) => {
|
|
45
|
+
const rowNs = new Set([]);
|
|
46
|
+
|
|
47
|
+
for (const block of root.blocks) {
|
|
48
|
+
// eslint-disable-next-line no-unused-vars
|
|
49
|
+
const [itemLength, itemType, itemSubtype] = utils.succinct.headerBytes(block.bs, 0);
|
|
50
|
+
const bsPayload = context.docSet.unsuccinctifyScope(block.bs, itemType, itemSubtype, 0)[2];
|
|
51
|
+
rowNs.add(bsPayload.split('/')[1]);
|
|
52
|
+
}
|
|
53
|
+
return rowNs.size;
|
|
54
|
+
},
|
|
55
|
+
nColumns: (root, args, context) => {
|
|
56
|
+
const columnNs = new Set([]);
|
|
57
|
+
|
|
58
|
+
for (const block of root.blocks) {
|
|
59
|
+
for (const scope of context.docSet.unsuccinctifyScopes(block.is).map(s => s[2])) {
|
|
60
|
+
if (scope.startsWith('tTableCol')) {
|
|
61
|
+
columnNs.add(scope.split('/')[1]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return columnNs.size;
|
|
66
|
+
},
|
|
67
|
+
cells: (root, args, context) => {
|
|
68
|
+
const ret = [];
|
|
69
|
+
|
|
70
|
+
for (const block of root.blocks) {
|
|
71
|
+
ret.push([
|
|
72
|
+
context.docSet.unsuccinctifyScopes(block.bs)
|
|
73
|
+
.map(s => parseInt(s[2].split('/')[1])),
|
|
74
|
+
Array.from(new Set(
|
|
75
|
+
context.docSet.unsuccinctifyScopes(block.is)
|
|
76
|
+
.filter(s => s[2].startsWith('tTableCol'))
|
|
77
|
+
.map(s => parseInt(s[2].split('/')[1])),
|
|
78
|
+
)),
|
|
79
|
+
context.docSet.unsuccinctifyItems(block.c, {}, 0),
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
return ret;
|
|
83
|
+
},
|
|
84
|
+
rows: (root, args, context) => {
|
|
85
|
+
const rowMatches1 = (row, matchSpec) => {
|
|
86
|
+
if (row[matchSpec.colN] === undefined) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const matchCellText = row[matchSpec.colN][2]
|
|
91
|
+
.filter(i => i[0] === 'token')
|
|
92
|
+
.map(i => i[2])
|
|
93
|
+
.join('');
|
|
94
|
+
return xre.test(matchCellText, xre(matchSpec.matching));
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const rowMatches = (row, matchSpecs) => {
|
|
98
|
+
if (matchSpecs.length === 0) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (rowMatches1(row, matchSpecs[0])) {
|
|
103
|
+
return rowMatches(row, matchSpecs.slice(1));
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const rowEquals1 = (row, matchSpec) => {
|
|
109
|
+
if (row[matchSpec.colN] === undefined) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const matchCellText = row[matchSpec.colN][2]
|
|
114
|
+
.filter(i => i[0] === 'token')
|
|
115
|
+
.map(i => i[2])
|
|
116
|
+
.join('');
|
|
117
|
+
return matchSpec.values.includes(matchCellText);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const rowEquals = (row, matchSpecs) => {
|
|
121
|
+
if (matchSpecs.length === 0) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (rowEquals1(row, matchSpecs[0])) {
|
|
126
|
+
return rowEquals(row, matchSpecs.slice(1));
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
let ret = [];
|
|
132
|
+
let row = -1;
|
|
133
|
+
|
|
134
|
+
for (const block of root.blocks) {
|
|
135
|
+
const rows = context.docSet.unsuccinctifyScopes(block.bs)
|
|
136
|
+
.map(s => parseInt(s[2].split('/')[1]));
|
|
137
|
+
|
|
138
|
+
if (args.positions && !args.positions.includes(rows[0])) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (rows[0] !== row) {
|
|
143
|
+
ret.push([]);
|
|
144
|
+
row = rows[0];
|
|
145
|
+
}
|
|
146
|
+
ret[ret.length - 1].push([
|
|
147
|
+
rows,
|
|
148
|
+
Array.from(new Set(
|
|
149
|
+
context.docSet.unsuccinctifyScopes(block.is)
|
|
150
|
+
.filter(s => s[2].startsWith('tTableCol'))
|
|
151
|
+
.map(s => parseInt(s[2].split('/')[1])),
|
|
152
|
+
)),
|
|
153
|
+
context.docSet.unsuccinctifyItems(block.c, {}, 0),
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (args.matches) {
|
|
158
|
+
ret = ret.filter(row => rowMatches(row, args.matches));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (args.equals) {
|
|
162
|
+
ret = ret.filter(row => rowEquals(row, args.equals));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (args.columns) {
|
|
166
|
+
ret = ret.map(
|
|
167
|
+
row =>
|
|
168
|
+
[...row.entries()]
|
|
169
|
+
.filter(re => args.columns.includes(re[0]))
|
|
170
|
+
.map(re => re[1]));
|
|
171
|
+
}
|
|
172
|
+
return ret;
|
|
173
|
+
},
|
|
174
|
+
tags: root => Array.from(root.tags),
|
|
175
|
+
tagsKv: root => Array.from(root.tags).map(t => {
|
|
176
|
+
if (t.includes(':')) {
|
|
177
|
+
return [t.substring(0, t.indexOf(':')), t.substring(t.indexOf(':') + 1)];
|
|
178
|
+
} else {
|
|
179
|
+
return [t, ''];
|
|
180
|
+
}
|
|
181
|
+
}),
|
|
182
|
+
hasTag: (root, args) => root.tags.has(args.tagName),
|
|
183
|
+
headings: root => Array.from(root.tags)
|
|
184
|
+
.filter(t => t.startsWith('col'))
|
|
185
|
+
.sort((a, b) => parseInt(a.split(':')[0].substring(3)) - parseInt(b.split(':')[0].substring(3)))
|
|
186
|
+
.map(t => t.split(':')[1]),
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
module.exports = {
|
|
190
|
+
tableSequenceSchemaString,
|
|
191
|
+
tableSequenceResolvers,
|
|
192
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const Tribos = require('../lib/tribos.cjs');
|
|
2
|
+
|
|
3
|
+
const treeSequenceSchemaString = `
|
|
4
|
+
"""The nodes of a tree"""
|
|
5
|
+
type treeSequence {
|
|
6
|
+
"""The id of the sequence"""
|
|
7
|
+
id: String!
|
|
8
|
+
"""The number of nodes in the tree sequence"""
|
|
9
|
+
nNodes: Int!
|
|
10
|
+
"""The nodes in the tree sequence"""
|
|
11
|
+
nodes: [node!]!
|
|
12
|
+
"""The JSON result for a Tribos query, as a string"""
|
|
13
|
+
tribos(
|
|
14
|
+
"""The Tribos query string"""
|
|
15
|
+
query: String!
|
|
16
|
+
): String!
|
|
17
|
+
"""The JSON results for the Tribos queries, as an array of strings"""
|
|
18
|
+
triboi(
|
|
19
|
+
"""The Tribos query strings"""
|
|
20
|
+
queries: [String!]!
|
|
21
|
+
): [String!]!
|
|
22
|
+
"""Tribos documentation"""
|
|
23
|
+
tribosDoc: String!
|
|
24
|
+
"""A list of the tags of this sequence"""
|
|
25
|
+
tags: [String!]!
|
|
26
|
+
"""A list of the tags of this sequence as key/value tuples"""
|
|
27
|
+
tagsKv: [KeyValue!]!
|
|
28
|
+
"""Whether or not the sequence has the specified tag"""
|
|
29
|
+
hasTag(
|
|
30
|
+
"""The tag name"""
|
|
31
|
+
tagName: String
|
|
32
|
+
): Boolean!
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const treeSequenceResolvers = {
|
|
37
|
+
nNodes: root => root.blocks.length,
|
|
38
|
+
nodes: root => root.blocks,
|
|
39
|
+
tribos: (root, args, context) =>
|
|
40
|
+
new Tribos().parse(context.docSet, root.blocks, args.query),
|
|
41
|
+
triboi: (root, args, context) =>
|
|
42
|
+
args.queries.map(q => new Tribos().parse(context.docSet, root.blocks, q)),
|
|
43
|
+
tribosDoc: () => new Tribos().doc(),
|
|
44
|
+
tags: root => Array.from(root.tags),
|
|
45
|
+
tagsKv: root => Array.from(root.tags).map(t => {
|
|
46
|
+
if (t.includes(':')) {
|
|
47
|
+
return [t.substring(0, t.indexOf(':')), t.substring(t.indexOf(':') + 1)];
|
|
48
|
+
} else {
|
|
49
|
+
return [t, ''];
|
|
50
|
+
}
|
|
51
|
+
}),
|
|
52
|
+
hasTag: (root, args) => root.tags.has(args.tagName),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
module.exports = {
|
|
56
|
+
treeSequenceSchemaString,
|
|
57
|
+
treeSequenceResolvers,
|
|
58
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const utils = require('../../util/index.cjs');
|
|
2
|
+
|
|
3
|
+
const verseNumberSchemaString = `
|
|
4
|
+
"""Information about a verse number (which may be part of a verse range)"""
|
|
5
|
+
type verseNumber {
|
|
6
|
+
"""The verse number"""
|
|
7
|
+
number: Int!
|
|
8
|
+
"""The verse range to which the verse number belongs"""
|
|
9
|
+
range: String!
|
|
10
|
+
"""The reference for this verse when mapped to 'original' versification"""
|
|
11
|
+
orig: orig!
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
const verseNumberResolvers = {
|
|
16
|
+
orig: (root, args, context) => {
|
|
17
|
+
const localBook = context.doc.headers.bookCode;
|
|
18
|
+
const localChapter = context.cvIndex[0];
|
|
19
|
+
const localVerse = root.number;
|
|
20
|
+
const mainSequence = context.doc.sequences[context.doc.mainId];
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
mainSequence.verseMapping &&
|
|
24
|
+
'forward' in mainSequence.verseMapping &&
|
|
25
|
+
`${localChapter}` in mainSequence.verseMapping.forward
|
|
26
|
+
) {
|
|
27
|
+
const mapping = utils.versification.mapVerse(mainSequence.verseMapping.forward[`${localChapter}`], localBook, localChapter, localVerse);
|
|
28
|
+
return ({
|
|
29
|
+
book: mapping[0],
|
|
30
|
+
cvs: mapping[1],
|
|
31
|
+
});
|
|
32
|
+
} else {
|
|
33
|
+
return ({
|
|
34
|
+
book: localBook,
|
|
35
|
+
cvs: [[localChapter, localVerse]],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
verseNumberSchemaString,
|
|
43
|
+
verseNumberResolvers,
|
|
44
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const verseRangeSchemaString = `
|
|
2
|
+
"""Information about a verse range (which may only cover one verse)"""
|
|
3
|
+
type verseRange {
|
|
4
|
+
"""The range, as it would be printed in a Bible"""
|
|
5
|
+
range: String!
|
|
6
|
+
"""A list of verse numbers for this range"""
|
|
7
|
+
numbers: [Int!]!
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
module.exports = { verseRangeSchemaString };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const versificationSchemaString = `
|
|
2
|
+
"""Information about a standard versification scheme"""
|
|
3
|
+
type versification {
|
|
4
|
+
"""id, derived from the Paratext vrs filename"""
|
|
5
|
+
id: String!
|
|
6
|
+
"""A string of the original vrs file"""
|
|
7
|
+
vrs: String!
|
|
8
|
+
"""Chapter/verse information for each book"""
|
|
9
|
+
cvBooks: [cvBook!]!
|
|
10
|
+
"""Chapter/verse information for one book"""
|
|
11
|
+
cvBook(
|
|
12
|
+
"""The bookCode"""
|
|
13
|
+
bookCode: String!
|
|
14
|
+
): cvBook!
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const versificationResolvers = {
|
|
19
|
+
id: root => root[0],
|
|
20
|
+
vrs: root => root[1].raw,
|
|
21
|
+
cvBooks: root => Object.entries(root[1].cv),
|
|
22
|
+
cvBook: (root, args) => Object.entries(root[1].cv).filter(b => b[0] === args.bookCode)[0],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports = { versificationSchemaString, versificationResolvers };
|