proskomma-core 0.9.7 → 0.9.12

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 (300) hide show
  1. package/.eslintrc.json +79 -0
  2. package/.gitattributes +2 -0
  3. package/babel.config.js +18 -0
  4. package/docs/_config.yml +1 -0
  5. package/docs/index.md +3 -0
  6. package/docs/pk_edit_0_9.odt +0 -0
  7. package/docs/pk_edit_0_9.pdf +0 -0
  8. package/docs/proskomma_101_slideshow.odp +0 -0
  9. package/docs/proskomma_101_slideshow.pdf +0 -0
  10. package/docs/proskomma_edit_html.png +0 -0
  11. package/docs/proskomma_edit_html.svg +451 -0
  12. package/docs/proskomma_edit_reference.png +0 -0
  13. package/docs/proskomma_edit_reference.svg +349 -0
  14. package/docs/repo_logo.png +0 -0
  15. package/esm/package.json +3 -0
  16. package/esm/wrapper.mjs +5 -0
  17. package/index.js +6 -0
  18. package/package.json +19 -17
  19. package/src/graph/index.cjs +201 -0
  20. package/src/graph/lib/do_cv.cjs +249 -0
  21. package/src/graph/lib/dump.cjs +40 -0
  22. package/src/graph/lib/remake_blocks.cjs +57 -0
  23. package/src/graph/lib/sequence_chars.cjs +84 -0
  24. package/src/graph/lib/sort.cjs +39 -0
  25. package/src/graph/lib/tribos.cjs +97 -0
  26. package/src/graph/lib/tribos_expression.cjs +556 -0
  27. package/src/graph/lib/tribos_ohm_UNUSED.cjs +37 -0
  28. package/src/graph/lib/tribos_step.cjs +434 -0
  29. package/src/graph/mutations/add.cjs +91 -0
  30. package/src/graph/mutations/delete.cjs +61 -0
  31. package/src/graph/mutations/index.cjs +54 -0
  32. package/src/graph/mutations/rehash.cjs +17 -0
  33. package/src/graph/mutations/tags.cjs +120 -0
  34. package/src/graph/mutations/update.cjs +210 -0
  35. package/src/graph/mutations/versification.cjs +96 -0
  36. package/src/graph/queries/block.cjs +228 -0
  37. package/src/graph/queries/cIndex.cjs +87 -0
  38. package/src/graph/queries/cell.cjs +42 -0
  39. package/src/graph/queries/cv.cjs +19 -0
  40. package/src/graph/queries/cvBook.cjs +16 -0
  41. package/src/graph/queries/cvChapter.cjs +16 -0
  42. package/src/graph/queries/cvIndex.cjs +47 -0
  43. package/src/graph/queries/cvNavigation.cjs +116 -0
  44. package/src/graph/queries/cvVerseElement.cjs +84 -0
  45. package/src/graph/queries/cvVerses.cjs +14 -0
  46. package/src/graph/queries/doc_set.cjs +220 -0
  47. package/src/graph/queries/document.cjs +555 -0
  48. package/src/graph/queries/idParts.cjs +30 -0
  49. package/src/graph/queries/index.cjs +151 -0
  50. package/src/graph/queries/inputBlockSpec.cjs +17 -0
  51. package/src/graph/queries/inputItemObject.cjs +12 -0
  52. package/src/graph/queries/input_att_spec.cjs +14 -0
  53. package/src/graph/queries/input_key_matches.cjs +11 -0
  54. package/src/graph/queries/input_key_value.cjs +11 -0
  55. package/src/graph/queries/input_key_values.cjs +11 -0
  56. package/src/graph/queries/input_selector_spec.cjs +19 -0
  57. package/src/graph/queries/item.cjs +71 -0
  58. package/src/graph/queries/itemGroup.cjs +75 -0
  59. package/src/graph/queries/key_value.cjs +18 -0
  60. package/src/graph/queries/kv_entry.cjs +21 -0
  61. package/src/graph/queries/kv_sequence.cjs +151 -0
  62. package/src/graph/queries/node.cjs +44 -0
  63. package/src/graph/queries/orig.cjs +11 -0
  64. package/src/graph/queries/regex_index.cjs +18 -0
  65. package/src/graph/queries/row_equals_spec.cjs +11 -0
  66. package/src/graph/queries/row_match_spec.cjs +11 -0
  67. package/src/graph/queries/selector_spec.cjs +29 -0
  68. package/src/graph/queries/sequence.cjs +314 -0
  69. package/src/graph/queries/table_sequence.cjs +192 -0
  70. package/src/graph/queries/tree_sequence.cjs +58 -0
  71. package/src/graph/queries/verseNumber.cjs +44 -0
  72. package/src/graph/queries/verseRange.cjs +11 -0
  73. package/src/graph/queries/versification.cjs +25 -0
  74. package/src/index.cjs +583 -0
  75. package/src/model/doc_set.cjs +389 -0
  76. package/src/model/doc_set_helpers/block.cjs +232 -0
  77. package/src/model/doc_set_helpers/enum.cjs +87 -0
  78. package/src/model/doc_set_helpers/item.cjs +198 -0
  79. package/src/model/doc_set_helpers/rehash.cjs +53 -0
  80. package/src/model/doc_set_helpers/selectors.cjs +58 -0
  81. package/src/model/doc_set_helpers/serialize.cjs +22 -0
  82. package/src/model/doc_set_helpers/unsuccinctify.cjs +288 -0
  83. package/src/model/doc_set_helpers/update.cjs +290 -0
  84. package/src/model/document.cjs +369 -0
  85. package/src/model/document_helpers/blocks.cjs +135 -0
  86. package/src/model/document_helpers/chapter_verse.cjs +291 -0
  87. package/src/model/document_helpers/pre_enums.cjs +67 -0
  88. package/src/model/document_helpers/sequences.cjs +205 -0
  89. package/src/model/document_helpers/serialize_succinct.cjs +55 -0
  90. package/src/model/document_helpers/succinct_filter.cjs +102 -0
  91. package/src/model/versifications/eng_vrs.cjs +455 -0
  92. package/src/model/versifications/index.cjs +38 -0
  93. package/src/model/versifications/lxx_vrs.cjs +950 -0
  94. package/src/model/versifications/org_vrs.cjs +155 -0
  95. package/src/model/versifications/rsc_vrs.cjs +342 -0
  96. package/src/model/versifications/rso_vrs.cjs +541 -0
  97. package/src/model/versifications/vul_vrs.cjs +835 -0
  98. package/src/parser/index.cjs +506 -0
  99. package/src/parser/lexers/index.cjs +11 -0
  100. package/src/parser/lexers/lexingRegexes.cjs +45 -0
  101. package/src/parser/lexers/nodes.cjs +123 -0
  102. package/src/parser/lexers/object_for_fragment.cjs +123 -0
  103. package/src/parser/lexers/tsv.cjs +45 -0
  104. package/src/parser/lexers/usfm.cjs +17 -0
  105. package/src/parser/lexers/usx/index.cjs +7 -0
  106. package/src/parser/lexers/usx/usx_lexer.cjs +321 -0
  107. package/src/parser/lib/tokenize.cjs +37 -0
  108. package/src/parser/model/index.cjs +637 -0
  109. package/src/parser/parser_specs.cjs +781 -0
  110. package/src/pipelines/perf2x/index.cjs +7 -0
  111. package/src/pipelines/perf2x/perf2PkJsonPipeline.json +41 -0
  112. package/src/pipelines/perf2x/perf2usfmPipeline.json +65 -0
  113. package/src/transforms/calculateUsfmChapterPositions.cjs +106 -0
  114. package/src/transforms/index.cjs +9 -0
  115. package/src/transforms/perf2PkJson.cjs +534 -0
  116. package/src/transforms/perf2usfm.cjs +294 -0
  117. package/src/util/byteArray.cjs +251 -0
  118. package/src/util/canons.cjs +117 -0
  119. package/src/util/enums.cjs +41 -0
  120. package/src/util/generateId.cjs +6 -0
  121. package/src/util/graftDefs.cjs +15 -0
  122. package/src/util/index.cjs +29 -0
  123. package/src/util/inspectSuccinct.cjs +59 -0
  124. package/src/util/itemDefs.cjs +33 -0
  125. package/src/util/parserConstantDefs.cjs +30 -0
  126. package/src/util/scopeDefs.cjs +173 -0
  127. package/src/util/scriptlike/blocksSpec.cjs +192 -0
  128. package/src/util/scriptlike/dodson_lexicon.xsl +19 -0
  129. package/src/util/scriptlike/dodson_lexicon_to_entries.cjs +85 -0
  130. package/src/util/scriptlike/open_scriptures_hebrew_lexicon.xsl +28 -0
  131. package/src/util/scriptlike/open_scriptures_hebrew_lexicon_to_entries.cjs +85 -0
  132. package/src/util/succinct.cjs +159 -0
  133. package/src/util/tags.cjs +28 -0
  134. package/src/util/tokenDefs.cjs +27 -0
  135. package/src/util/versification.cjs +364 -0
  136. package/test/code/main/bad.cjs +79 -0
  137. package/test/code/main/basics.cjs +534 -0
  138. package/test/code/main/block.cjs +586 -0
  139. package/test/code/main/block_scope_numbers.cjs +31 -0
  140. package/test/code/main/blocks_with_atts.cjs +150 -0
  141. package/test/code/main/blocks_with_cv.cjs +250 -0
  142. package/test/code/main/break.cjs +73 -0
  143. package/test/code/main/checksum.cjs +36 -0
  144. package/test/code/main/cl_global.cjs +35 -0
  145. package/test/code/main/class_for_fragment.cjs +18 -0
  146. package/test/code/main/clean_usfm.cjs +46 -0
  147. package/test/code/main/cp_vp.cjs +158 -0
  148. package/test/code/main/custom.cjs +124 -0
  149. package/test/code/main/cv.cjs +249 -0
  150. package/test/code/main/cvMatching.cjs +155 -0
  151. package/test/code/main/cv_indexes.cjs +189 -0
  152. package/test/code/main/cv_navigation.cjs +124 -0
  153. package/test/code/main/document.cjs +382 -0
  154. package/test/code/main/empty_blocks.cjs +71 -0
  155. package/test/code/main/entries.cjs +402 -0
  156. package/test/code/main/export_lexing_regexes.cjs +19 -0
  157. package/test/code/main/fig.cjs +67 -0
  158. package/test/code/main/filter.cjs +222 -0
  159. package/test/code/main/glossary.cjs +36 -0
  160. package/test/code/main/graft_headings.cjs +36 -0
  161. package/test/code/main/graft_introduction.cjs +96 -0
  162. package/test/code/main/graft_note.cjs +104 -0
  163. package/test/code/main/graft_rems.cjs +34 -0
  164. package/test/code/main/graft_sidebars.cjs +62 -0
  165. package/test/code/main/graft_title.cjs +36 -0
  166. package/test/code/main/hello.cjs +105 -0
  167. package/test/code/main/import_document.cjs +22 -0
  168. package/test/code/main/import_usfm_int.cjs +48 -0
  169. package/test/code/main/item_groups.cjs +133 -0
  170. package/test/code/main/items_with_cv.cjs +311 -0
  171. package/test/code/main/milestone_attributes.cjs +163 -0
  172. package/test/code/main/mixed_sequence_documents.cjs +137 -0
  173. package/test/code/main/mixed_sequences.cjs +217 -0
  174. package/test/code/main/modify_sequence.cjs +29 -0
  175. package/test/code/main/multiple_chapters.cjs +58 -0
  176. package/test/code/main/multiple_content.cjs +105 -0
  177. package/test/code/main/mutate_add.cjs +180 -0
  178. package/test/code/main/mutate_delete.cjs +236 -0
  179. package/test/code/main/mutate_rehash.cjs +68 -0
  180. package/test/code/main/mutate_tags.cjs +90 -0
  181. package/test/code/main/mutate_update.cjs +538 -0
  182. package/test/code/main/selectors.cjs +289 -0
  183. package/test/code/main/sequence.cjs +361 -0
  184. package/test/code/main/serialize.cjs +104 -0
  185. package/test/code/main/spans.cjs +51 -0
  186. package/test/code/main/split_long_tokens.cjs +30 -0
  187. package/test/code/main/standard_vrs.cjs +76 -0
  188. package/test/code/main/subclass.cjs +25 -0
  189. package/test/code/main/table.cjs +119 -0
  190. package/test/code/main/tags.cjs +248 -0
  191. package/test/code/main/token_alignment.cjs +84 -0
  192. package/test/code/main/trees.cjs +211 -0
  193. package/test/code/main/tribos.cjs +865 -0
  194. package/test/code/main/tsv.cjs +385 -0
  195. package/test/code/main/usx_ref.cjs +65 -0
  196. package/test/code/main/verse_mapping.cjs +252 -0
  197. package/test/code/main/verse_range.cjs +31 -0
  198. package/test/code/main/word_likes.cjs +41 -0
  199. package/test/code/utils/byte_array.cjs +271 -0
  200. package/test/code/utils/canons.cjs +20 -0
  201. package/test/code/utils/generate_id.cjs +17 -0
  202. package/test/code/utils/graft_defs.cjs +16 -0
  203. package/test/code/utils/inspect.cjs +130 -0
  204. package/test/code/utils/items.cjs +56 -0
  205. package/test/code/utils/push_succinct.cjs +69 -0
  206. package/test/code/utils/scope_defs.cjs +79 -0
  207. package/test/code/utils/serialize.cjs +28 -0
  208. package/test/code/utils/splice.cjs +67 -0
  209. package/test/code/utils/tags.cjs +69 -0
  210. package/test/code/utils/versification.cjs +249 -0
  211. package/test/lib/load.js +110 -0
  212. package/test/skipped_code/diff.js +53 -0
  213. package/test/test_data/inputBlockSpec/dodson.json +1654 -0
  214. package/test/test_data/inputBlockSpec/kv.json +326 -0
  215. package/test/test_data/inputBlockSpec/mk1.json +1019 -0
  216. package/test/test_data/inputBlockSpec/table.json +170 -0
  217. package/test/test_data/tree/genealogy.json +55 -0
  218. package/test/test_data/tree/jude.json +15965 -0
  219. package/test/test_data/tsv/en_tn_66-JUD.tsv +75 -0
  220. package/test/test_data/tsv/twl_JUD.tsv +144 -0
  221. package/test/test_data/usfm/1pe_webbe.usfm +13 -0
  222. package/test/test_data/usfm/66-JUD-ust.usfm +1089 -0
  223. package/test/test_data/usfm/78-GALspavbl.usfm +10 -0
  224. package/test/test_data/usfm/add_test.usfm +15 -0
  225. package/test/test_data/usfm/backslash.usfm +4 -0
  226. package/test/test_data/usfm/cl.usfm +14 -0
  227. package/test/test_data/usfm/cp_vp.usfm +8 -0
  228. package/test/test_data/usfm/custom.usfm +13 -0
  229. package/test/test_data/usfm/en_ust_oba.usfm +875 -0
  230. package/test/test_data/usfm/en_ust_psa_1.usfm +20 -0
  231. package/test/test_data/usfm/fig.usfm +3 -0
  232. package/test/test_data/usfm/filter.usfm +7 -0
  233. package/test/test_data/usfm/footnote.usfm +11 -0
  234. package/test/test_data/usfm/frt.usfm +4 -0
  235. package/test/test_data/usfm/headings.usfm +7 -0
  236. package/test/test_data/usfm/hello.usfm +8 -0
  237. package/test/test_data/usfm/int.usfm +7 -0
  238. package/test/test_data/usfm/milestone_attributes.usfm +7 -0
  239. package/test/test_data/usfm/milestone_attributes_default.usfm +7 -0
  240. package/test/test_data/usfm/no_break_space.usfm +4 -0
  241. package/test/test_data/usfm/no_mt.usfm +6 -0
  242. package/test/test_data/usfm/rems.usfm +6 -0
  243. package/test/test_data/usfm/section_intros.usfm +26 -0
  244. package/test/test_data/usfm/sidebars.usfm +25 -0
  245. package/test/test_data/usfm/slash_in_att.usfm +6 -0
  246. package/test/test_data/usfm/soft_line_break.usfm +4 -0
  247. package/test/test_data/usfm/spans.usfm +5 -0
  248. package/test/test_data/usfm/split_long_tokens.usfm +6 -0
  249. package/test/test_data/usfm/table.usfm +18 -0
  250. package/test/test_data/usfm/table_at_end.usfm +11 -0
  251. package/test/test_data/usfm/table_in_intro.usfm +22 -0
  252. package/test/test_data/usfm/table_no_end_cells.usfm +18 -0
  253. package/test/test_data/usfm/tit_kitchen_sink.usfm +73 -0
  254. package/test/test_data/usfm/titus_template.usfm +58 -0
  255. package/test/test_data/usfm/ugnt_3jn.usfm +265 -0
  256. package/test/test_data/usfm/ult_3jn.usfm +335 -0
  257. package/test/test_data/usfm/unknown.usfm +5 -0
  258. package/test/test_data/usfm/ust_psa.usfm +29 -0
  259. package/test/test_data/usfm/ust_psa_verse_ranges.usfm +24 -0
  260. package/test/test_data/usfm/ust_psa_with_ts.usfm +29 -0
  261. package/test/test_data/usfm/verse_breaks_in_blocks.usfm +20 -0
  262. package/test/test_data/usfm/verse_range.usfm +7 -0
  263. package/test/test_data/usfm/web_ecc.usfm +391 -0
  264. package/test/test_data/usfm/web_psa51.usfm +71 -0
  265. package/test/test_data/usfm/whitespace.usfm +12 -0
  266. package/test/test_data/usfm/xref.usfm +11 -0
  267. package/test/test_data/usx/bad_element.usx +2 -0
  268. package/test/test_data/usx/cp_vp.usx +12 -0
  269. package/test/test_data/usx/diff1.usx +59 -0
  270. package/test/test_data/usx/diff2.usx +74 -0
  271. package/test/test_data/usx/douay_rheims_ecc.usx +58 -0
  272. package/test/test_data/usx/douay_rheims_psa.usx +5366 -0
  273. package/test/test_data/usx/douay_rheims_psa_40_60.usx +666 -0
  274. package/test/test_data/usx/douay_rheims_rut.usx +26 -0
  275. package/test/test_data/usx/esg3.usx +47 -0
  276. package/test/test_data/usx/fig.usx +6 -0
  277. package/test/test_data/usx/milestone_attributes.usx +11 -0
  278. package/test/test_data/usx/not_nfc18_glo.usx +9 -0
  279. package/test/test_data/usx/not_nfc18_phm.usx +24 -0
  280. package/test/test_data/usx/opt_break.usx +10 -0
  281. package/test/test_data/usx/sidebars.usx +29 -0
  282. package/test/test_data/usx/table.usx +23 -0
  283. package/test/test_data/usx/web_psa.usx +8489 -0
  284. package/test/test_data/usx/web_psa150.usx +33 -0
  285. package/test/test_data/usx/web_psa_40_60.usx +1079 -0
  286. package/test/test_data/usx/web_rut.usx +95 -0
  287. package/test/test_data/usx/web_rut_1.usx +17 -0
  288. package/test/test_data/utils/douay_rheims.vrs +520 -0
  289. package/test/test_data/utils/douay_rheims_PSA.usx +5366 -0
  290. package/test/test_data/utils/serialize_example.json +91 -0
  291. package/test/test_data/utils/truncated_versification.vrs +29 -0
  292. package/test/test_data/utils/web_rut_items.json +2977 -0
  293. package/test/test_data/utils/webbe.vrs +395 -0
  294. package/test/test_data/utils/webbe_PSA.usx +8489 -0
  295. package/test/test_data/vrs/douay_rheims.vrs +520 -0
  296. package/test/test_data/vrs/truncated_versification.vrs +27 -0
  297. package/test/test_data/vrs/webbe.vrs +397 -0
  298. package/webpack.prod.js +50 -0
  299. package/dist/index.js +0 -8
  300. package/dist/index.js.LICENSE.txt +0 -23
@@ -0,0 +1,556 @@
1
+ const xre = require('xregexp');
2
+
3
+ const aggregateFunctions = {
4
+ equals: (docSet, node, a, b) => a === b,
5
+ notEqual: (docSet, node, a, b) => a !== b,
6
+ and: (docSet, node, ...args) => args.filter(a => !a).length === 0,
7
+ or: (docSet, node, ...args) => args.filter(a => a).length > 0,
8
+ not: (docSet, node, a) => !a,
9
+ idRef: (docSet, node) => docSet.unsuccinctifyScopes(node.bs)[0][2].split('/')[1],
10
+ parentIdRef: (docSet, node) => docSet.unsuccinctifyScopes(node.is).filter(s => s[2].startsWith('tTreeParent'))[0][2].split('/')[1],
11
+ nChildren: (docSet, node) => docSet.unsuccinctifyScopes(node.is).filter(s => s[2].startsWith('tTreeChild')).length,
12
+ contentRef: (docSet, node, label) => {
13
+ const labelIG = docSet.sequenceItemsByScopes([node], ['tTreeContent/'], false)
14
+ .filter(ig => {
15
+ const key = ig[0].filter(s => s.startsWith('tTreeContent'))[0].split('/')[1];
16
+ return key === label;
17
+ });
18
+ return labelIG[0] ?
19
+ labelIG[0][1].filter(i => i[0] === 'token').map(t => t[2]).join('') :
20
+ '';
21
+ },
22
+ hasContent: (docSet, node, label) => {
23
+ const labelIG = docSet.sequenceItemsByScopes([node], ['tTreeContent/'], false)
24
+ .filter(ig => {
25
+ const key = ig[0].filter(s => s.startsWith('tTreeContent'))[0].split('/')[1];
26
+ return key === label;
27
+ });
28
+ return labelIG.length > 0;
29
+ },
30
+ concat: (docSet, node, ...args) => args.join(''),
31
+ startsWith: (docSet, node, a, b) => a.startsWith(b),
32
+ endsWith: (docSet, node, a, b) => a.endsWith(b),
33
+ contains: (docSet, node, a, b) => a.includes(b),
34
+ matches: (docSet, node, a, b) => xre.test(a, xre(b)),
35
+ int: (docSet, node, str) => parseInt(str),
36
+ string: (docSet, node, int) => `${int}`,
37
+ left: (docSet, node, str, int) => str.substring(0, int),
38
+ right: (docSet, node, str, int) => str.substring(str.length - int),
39
+ length: (docSet, node, str) => str.length,
40
+ indexOf: (docSet, node, a, b) => a.indexOf(b),
41
+ add: (docSet, node, ...args) => args.reduce((x, y) => x + y),
42
+ mul: (docSet, node, ...args) => args.reduce((x, y) => x * y),
43
+ sub: (docSet, node, a, b) => a - b,
44
+ div: (docSet, node, a, b) => Math.floor(a / b),
45
+ mod: (docSet, node, a, b) => a % b,
46
+ gt: (docSet, node, a, b) => a > b,
47
+ lt: (docSet, node, a, b) => a < b,
48
+ ge: (docSet, node, a, b) => a >= b,
49
+ le: (docSet, node, a, b) => a <= b,
50
+ };
51
+
52
+ const parseFunctions = {
53
+ quotedString: str => str.substring(1, str.length - 1),
54
+ int: str => parseInt(str),
55
+ true: () => true,
56
+ false: () => false,
57
+ };
58
+
59
+ const splitArgs = str => {
60
+ const ret = [[]];
61
+ let pos = 0;
62
+ let nParen = 0;
63
+ let inQuote = false;
64
+
65
+ while (str && pos < str.length) {
66
+ switch (str[pos]) {
67
+ case '\\':
68
+ ret[ret.length - 1].push(str[pos]);
69
+
70
+ if (str[pos + 1] ==='\'') {
71
+ ret[ret.length - 1].push(str[pos + 1]);
72
+ pos++;
73
+ }
74
+ break;
75
+ case '\'':
76
+ ret[ret.length - 1].push(str[pos]);
77
+ inQuote = !inQuote;
78
+ break;
79
+ case '(':
80
+ if (inQuote) {
81
+ ret[ret.length - 1].push(str[pos]);
82
+ } else {
83
+ ret[ret.length - 1].push(str[pos]);
84
+ nParen++;
85
+ }
86
+ break;
87
+ case ')':
88
+ if (inQuote) {
89
+ ret[ret.length - 1].push(str[pos]);
90
+ } else {
91
+ ret[ret.length - 1].push(str[pos]);
92
+ nParen--;
93
+ }
94
+ break;
95
+ case ',':
96
+ if (!inQuote && nParen === 0) {
97
+ ret.push([]);
98
+
99
+ while (str[pos + 1] === ' ') {
100
+ pos++;
101
+ }
102
+ } else {
103
+ ret[ret.length - 1].push(str[pos]);
104
+ }
105
+ break;
106
+ default:
107
+ ret[ret.length - 1].push(str[pos]);
108
+ }
109
+ pos++;
110
+ }
111
+ return ret.map(e => e.join(''));
112
+ };
113
+
114
+ const expressions = {
115
+ expression: { oneOf: ['stringExpression', 'intExpression', 'booleanExpression'] },
116
+ booleanExpression: { oneOf: ['booleanPrimitive', 'equals', 'notEqual', 'and', 'or', 'not', 'contains', 'startsWith', 'endsWith', 'matches', 'gt', 'lt', 'ge', 'le', 'hasContent'] },
117
+ stringExpression: { oneOf: ['concat', 'left', 'right', 'string', 'idRef', 'parentIdRef', 'contentRef', 'stringPrimitive'] },
118
+ intExpression: { oneOf: ['length', 'indexOf', 'int', 'nChildren', 'intPrimitive', 'add', 'sub', 'mul', 'div', 'mod'] },
119
+ equals: {
120
+ regex: xre('^==\\((.+)\\)$'),
121
+ doc: {
122
+ operator: '==',
123
+ args: ['expression', 'expression'],
124
+ result: 'boolean',
125
+ description: 'Are the arguments strictly equal?',
126
+ },
127
+ argStructure: [['expression', [2, 2]]],
128
+ },
129
+ notEqual: {
130
+ regex: xre('^!=\\((.+)\\)$'),
131
+ doc: {
132
+ operator: '!=',
133
+ args: ['expression', 'expression'],
134
+ result: 'boolean',
135
+ description: 'Are the arguments not strictly equal?',
136
+ },
137
+ argStructure: [['expression', [2, 2]]],
138
+ },
139
+ and: {
140
+ regex: xre('^and\\((.+)\\)$'),
141
+ doc: {
142
+ operator: 'and',
143
+ args: ['boolean', 'boolean', '...'],
144
+ result: 'boolean',
145
+ description: 'Are all the arguments true?',
146
+ },
147
+ breakOn: false,
148
+ argStructure: [['booleanExpression', [2, null]]],
149
+ },
150
+ or: {
151
+ regex: xre('^or\\((.+)\\)$'),
152
+ doc: {
153
+ operator: 'or',
154
+ args: ['boolean', 'boolean'],
155
+ result: 'boolean',
156
+ description: 'Are any arguments true?',
157
+ },
158
+ breakOn: true,
159
+ argStructure: [['booleanExpression', [2, null]]],
160
+ },
161
+ concat: {
162
+ regex: xre('^concat\\((.+)\\)$'),
163
+ doc: {
164
+ operator: 'concat',
165
+ args: ['string', 'string', '...'],
166
+ result: 'string',
167
+ description: 'Concatenates string arguments',
168
+ },
169
+ argStructure: [['stringExpression', [2, null]]],
170
+ },
171
+ contentRef: {
172
+ regex: xre('^content\\((.+)\\)$'),
173
+ doc: {
174
+ operator: 'content',
175
+ args: ['string'],
176
+ result: 'string',
177
+ description: 'String value of the specified content for the node',
178
+ },
179
+ argStructure: [['stringExpression', [1, 1]]],
180
+ },
181
+ hasContent: {
182
+ regex: xre('^hasContent\\((.+)\\)$'),
183
+ doc: {
184
+ operator: 'hasContent',
185
+ args: ['string'],
186
+ result: 'boolean',
187
+ description: 'Does the node have this content?',
188
+ },
189
+ argStructure: [['stringExpression', [1, 1]]],
190
+ },
191
+ contains: {
192
+ regex: xre('^contains\\((.+)\\)$'),
193
+ doc: {
194
+ operator: 'contains',
195
+ args: ['string', 'string'],
196
+ result: 'boolean',
197
+ description: 'Does the first string contain the second string?',
198
+ },
199
+ argStructure: [['stringExpression', [2, 2]]],
200
+ },
201
+ startsWith: {
202
+ regex: xre('^startsWith\\((.+)\\)$'),
203
+ doc: {
204
+ operator: 'startsWith',
205
+ args: ['string', 'string'],
206
+ result: 'boolean',
207
+ description: 'Does the first string start with the second string?',
208
+ },
209
+ argStructure: [['stringExpression', [2, 2]]],
210
+ },
211
+ endsWith: {
212
+ regex: xre('^endsWith\\((.+)\\)$'),
213
+ doc: {
214
+ operator: 'endsWith',
215
+ args: ['string', 'string'],
216
+ result: 'boolean',
217
+ description: 'Does the first string end with the second string?',
218
+ },
219
+ argStructure: [['stringExpression', [2, 2]]],
220
+ },
221
+ matches: {
222
+ regex: xre('^matches\\((.+)\\)$'),
223
+ doc: {
224
+ operator: 'matches',
225
+ args: ['string', 'regex'],
226
+ result: 'boolean',
227
+ description: 'Does the first string match the regex in the second string?',
228
+ },
229
+ argStructure: [['stringExpression', [2, 2]]],
230
+ },
231
+ left: {
232
+ regex: xre('^left\\((.+)\\)$'),
233
+ doc: {
234
+ operator: 'left',
235
+ args: ['string', 'integer'],
236
+ result: 'string',
237
+ description: 'The first n characters of the string',
238
+ },
239
+ argStructure: [['stringExpression', [1, 1]], ['intExpression', [1, 1]]],
240
+ },
241
+ right: {
242
+ regex: xre('^right\\((.+)\\)$'),
243
+ doc: {
244
+ operator: 'right',
245
+ args: ['string', 'integer'],
246
+ result: 'string',
247
+ description: 'The last n characters of the string',
248
+ },
249
+ argStructure: [['stringExpression', [1, 1]], ['intExpression', [1, 1]]],
250
+ },
251
+ length: {
252
+ regex: xre('^length\\((.+)\\)$'),
253
+ doc: {
254
+ operator: 'length',
255
+ args: ['string'],
256
+ result: 'integer',
257
+ description: 'The number of characters in the string',
258
+ },
259
+ argStructure: [['stringExpression', [1, 1]]],
260
+ },
261
+ indexOf: {
262
+ regex: xre('^indexOf\\((.+)\\)$'),
263
+ doc: {
264
+ operator: 'indexOf',
265
+ args: ['string', 'string'],
266
+ result: 'number',
267
+ description: 'The integer position at which the second string starts in the first string',
268
+ },
269
+ argStructure: [['stringExpression', [2, 2]]],
270
+ },
271
+ not: {
272
+ regex: xre('^not\\((.+)\\)$'),
273
+ doc: {
274
+ operator: 'not',
275
+ args: ['boolean'],
276
+ result: 'boolean',
277
+ description: 'The inverse boolean value of the argument',
278
+ },
279
+ argStructure: [['booleanExpression', [1, 1]]],
280
+ },
281
+ int: {
282
+ regex: xre('^int\\((.+)\\)$'),
283
+ doc: {
284
+ operator: 'int',
285
+ args: ['string'],
286
+ result: 'integer',
287
+ description: 'The integer value of the string',
288
+ },
289
+ argStructure: [['stringExpression', [1, 1]]],
290
+ },
291
+ string: {
292
+ regex: xre('^string\\((.+)\\)$'),
293
+ doc: {
294
+ operator: 'string',
295
+ args: ['integer'],
296
+ result: 'string',
297
+ description: 'The string value of the integer',
298
+ },
299
+ argStructure: [['intExpression', [1, 1]]],
300
+ },
301
+ idRef: {
302
+ regex: xre('^id$'),
303
+ doc: {
304
+ operator: 'id',
305
+ args: [],
306
+ result: 'string',
307
+ description: 'The node ID',
308
+ },
309
+ argStructure: [],
310
+ },
311
+ parentIdRef: {
312
+ regex: xre('^parentId$'),
313
+ doc: {
314
+ operator: 'parentId',
315
+ args: [],
316
+ result: 'string',
317
+ description: 'The node\'s parent ID',
318
+ },
319
+ argStructure: [],
320
+ },
321
+ nChildren: {
322
+ regex: xre('^nChildren$'),
323
+ doc: {
324
+ operator: 'nChildren',
325
+ args: [],
326
+ result: 'int',
327
+ description: 'The number of children of the node',
328
+ },
329
+ argStructure: [],
330
+ },
331
+ add: {
332
+ regex: xre('^add\\((.+)\\)$'),
333
+ doc: {
334
+ operator: 'add',
335
+ args: ['integer', '...'],
336
+ result: 'integer',
337
+ description: 'The numeric sum of the arguments',
338
+ },
339
+ argStructure: [['intExpression', [2, null]]],
340
+ },
341
+ mul: {
342
+ regex: xre('^mul\\((.+)\\)$'),
343
+ doc: {
344
+ operator: 'mul',
345
+ args: ['integer', '...'],
346
+ result: 'integer',
347
+ description: 'The numeric product of the arguments',
348
+ },
349
+ argStructure: [['intExpression', [2, null]]],
350
+ },
351
+ sub: {
352
+ regex: xre('^sub\\((.+)\\)$'),
353
+ doc: {
354
+ operator: 'sub',
355
+ args: ['integer', 'integer'],
356
+ result: 'integer',
357
+ description: 'The first integer minus the second',
358
+ },
359
+ argStructure: [['intExpression', [2, 2]]],
360
+ },
361
+ div: {
362
+ regex: xre('^div\\((.+)\\)$'),
363
+ doc: {
364
+ operator: 'div',
365
+ args: ['integer', 'integer'],
366
+ result: 'integer',
367
+ description: 'The first integer divided by the second',
368
+ },
369
+ argStructure: [['intExpression', [2, 2]]],
370
+ },
371
+ mod: {
372
+ regex: xre('^mod\\((.+)\\)$'),
373
+ doc: {
374
+ operator: 'mod',
375
+ args: ['integer', 'integer'],
376
+ result: 'integer',
377
+ description: 'The modulus of the first integer when divided by the second',
378
+ },
379
+ argStructure: [['intExpression', [2, 2]]],
380
+ },
381
+ gt: {
382
+ regex: xre('^>\\((.+)\\)$'),
383
+ doc: {
384
+ operator: '>',
385
+ args: ['integer', 'integer'],
386
+ result: 'boolean',
387
+ description: 'Is the first integer numerically greater than the second?',
388
+ },
389
+ argStructure: [['intExpression', [2, 2]]],
390
+ },
391
+ lt: {
392
+ regex: xre('^<\\((.+)\\)$'),
393
+ doc: {
394
+ operator: '<',
395
+ args: ['integer', 'integer'],
396
+ result: 'boolean',
397
+ description: 'Is the first integer numerically less than the second?',
398
+ },
399
+ argStructure: [['intExpression', [2, 2]]],
400
+ },
401
+ ge: {
402
+ regex: xre('^>=\\((.+)\\)$'),
403
+ doc: {
404
+ operator: '>=',
405
+ args: ['integer', 'integer'],
406
+ result: 'boolean',
407
+ description: 'Is the first integer numerically greater than or equal to the second?',
408
+ },
409
+ argStructure: [['intExpression', [2, 2]]],
410
+ },
411
+ le: {
412
+ regex: xre('^<=\\((.+)\\)$'),
413
+ doc: {
414
+ operator: '<=',
415
+ args: ['integer', 'integer'],
416
+ result: 'boolean',
417
+ description: 'Is the first integer numerically less than or equal to the second?',
418
+ },
419
+ argStructure: [['intExpression', [2, 2]]],
420
+ },
421
+ stringPrimitive: {
422
+ regex: xre('^(\'([^\']|\\\\\')*\')$'),
423
+ parseFunctions: [null, 'quotedString'],
424
+ },
425
+ intPrimitive: {
426
+ regex: xre('^(-?[0-9]+)$'),
427
+ parseFunctions: [null, 'int'],
428
+ },
429
+ booleanPrimitive: {
430
+ regex: xre('^(true)|(false)$'),
431
+ parseFunctions: [null, 'true', 'false'],
432
+ },
433
+ };
434
+
435
+ const parseRegexExpression = (docSet, node, predicateString, expressionId, matches) => {
436
+ // console.log(`parseRegexExpression ${predicateString} ${expressionId} ${matches}`);
437
+ const expressionRecord = expressions[expressionId];
438
+
439
+ if (!expressionRecord) {
440
+ throw new Error(`Unknown expression ${expressionId} for predicate ${predicateString}`);
441
+ }
442
+
443
+ const nExpectedArgs = structure => [
444
+ structure.map(a => a[1][0]).reduce((a, b) => a + b),
445
+ structure.filter(a => a[1][1] === null).length > 0,
446
+ ];
447
+
448
+ if (expressionRecord.parseFunctions) {
449
+ let found = false;
450
+
451
+ for (const [n, parseFunction] of expressionRecord.parseFunctions.entries()) {
452
+ if (!parseFunction || !matches[n]) {
453
+ continue;
454
+ }
455
+ found = true;
456
+ return { data: parseFunctions[parseFunction](matches[n]) };
457
+ }
458
+
459
+ if (!found) {
460
+ return { errors: `Could not parse predicate ${predicateString}` };
461
+ }
462
+ } else {
463
+ const argRecords = splitArgs(matches[1]);
464
+ const argStructure = expressionRecord.argStructure;
465
+ const argResults = [];
466
+
467
+ if (argStructure.length > 0) {
468
+ const nExpected = nExpectedArgs(argStructure);
469
+
470
+ if (argRecords.length < nExpected[0]) {
471
+ return { errors: `Expected at least ${nExpected[0]} args for '${expressionId}', found ${argRecords.length}` };
472
+ }
473
+
474
+ if (!nExpected[1] && argRecords.length > nExpected[0]) {
475
+ return { errors: `Expected at most ${nExpected[0]} args for '${expressionId}', found ${argRecords.length}` };
476
+ }
477
+
478
+ let argRecordN = 0;
479
+ let argStructureN = 0;
480
+ let nOccs = 0;
481
+
482
+ while (argRecordN < argRecords.length) {
483
+ const argRecord = argRecords[argRecordN];
484
+ const argResult = parseExpression(docSet, node, argRecord, argStructure[argStructureN][0]);
485
+
486
+ if ('breakOn' in expressionRecord && !argRecord.errors && argResult.data === expressionRecord.breakOn) {
487
+ return argResult;
488
+ }
489
+ argResults.push(argResult);
490
+ argRecordN++;
491
+ nOccs++;
492
+
493
+ if (argStructure[argStructureN][1][1] && nOccs >= argStructure[argStructureN][1][1]) {
494
+ argStructureN++;
495
+ nOccs = 0;
496
+ }
497
+ }
498
+ }
499
+
500
+ if (argResults.filter(ar => ar.errors).length === 0) {
501
+ // console.log(expressionId);
502
+ const args = argResults.map(ar => ar.data);
503
+ const aggregated = aggregateFunctions[expressionId](docSet, node, ...args);
504
+ // console.log('aggregated', expressionId, argRecords, aggregated);
505
+ return { data: aggregated };
506
+ }
507
+ return { errors: `Could not parse arguments to ${expressionId}: ${argRecords.filter(ar => ar.errors).map(ar => ar.errors).join('; ')}` };
508
+ }
509
+ };
510
+
511
+ const parseExpression = (docSet, node, predicate, expressionId) => {
512
+ // console.log(`parseExpression ${predicate}, ${expressionId}`);
513
+ const expressionRecord = expressions[expressionId];
514
+
515
+ if (!expressionRecord) {
516
+ throw new Error(`Unknown expression ${expressionId} for predicate ${predicate}`);
517
+ }
518
+
519
+ if (expressionRecord.oneOf) {
520
+ let errors = null;
521
+
522
+ for (const option of expressionRecord.oneOf) {
523
+ const optionResult = parseExpression(docSet, node, predicate, option);
524
+
525
+ if (!optionResult.errors) {
526
+ return optionResult;
527
+ } else if (!errors || (optionResult.errors.length < errors.length)) {
528
+ errors = optionResult.errors;
529
+ }
530
+ }
531
+ return { errors: errors };
532
+ } else {
533
+ const matches = xre.exec(predicate, expressionRecord.regex);
534
+
535
+ if (matches) {
536
+ const reResult = parseRegexExpression(docSet, node, predicate, expressionId, matches);
537
+ return reResult;
538
+ } else {
539
+ return { errors: `Could not match ${predicate}` };
540
+ }
541
+ }
542
+ };
543
+
544
+ const doPredicate = (docSet, result, predicateString) => ({
545
+ data: result.data.filter(node => {
546
+ const nodeResult = parseExpression(docSet, node, predicateString, 'booleanExpression');
547
+
548
+ // console.log();
549
+ if (nodeResult.errors) {
550
+ throw new Error(`Predicate - ${nodeResult.errors}`);
551
+ }
552
+ return nodeResult.data;
553
+ }),
554
+ });
555
+
556
+ module.exports = { expressions, doPredicate };
@@ -0,0 +1,37 @@
1
+ /*
2
+ predicateExpression {
3
+ Exp
4
+ = booleanExpression
5
+
6
+ booleanExpression =
7
+ "true" |
8
+ "false" |
9
+ booleanNonPrimitive
10
+
11
+ booleanNonPrimitive =
12
+ equalsOperator |
13
+ notEqualOperator |
14
+ andOperator |
15
+ orOperator
16
+
17
+ equalsOperator = "==" "(" expressions ")"
18
+ notEqualOperator = "!=" "(" expressions ")"
19
+ andOperator = "and" "(" booleanExpressions ")"
20
+ orOperator = "or" "(" booleanExpressions ")"
21
+
22
+ expressions = expression ("," " "* expressions)*
23
+ booleanExpressions = booleanExpression ("," " "* booleanExpressions)*
24
+ stringExpressions = stringExpression ("," " "* stringExpressions)*
25
+
26
+ expression = booleanExpression | stringExpression
27
+
28
+ stringExpression = stringLiteral | stringNonPrimitive
29
+
30
+ stringNonPrimitive = concatOperator
31
+
32
+ concatOperator = "concat" "(" stringExpressions ")"
33
+
34
+ stringLiteral = "'" letter* "'"
35
+
36
+ }
37
+ */