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,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
|
+
|