1 | const {
|
2 | XM_TERM_TAG_DEFAULT_GRAPH,
|
3 | XM_TERM_TAG_NODE_NAMED,
|
4 | XM_TERM_TAG_NODE_BLANK,
|
5 | XM_TERM_TAG_LITERAL_SIMPLE,
|
6 | XM_TERM_TAG_LITERAL_LANGUAGED,
|
7 | XM_TERM_TAG_LITERAL_DATATYPED,
|
8 | XM_TERM_TAG_NODE,
|
9 | XM_TERM_TAG_LITERAL,
|
10 | XM_TERM_TAG_ANY,
|
11 | } = require('./constants.js');
|
12 |
|
13 | const X_RANK_PROPERTY_ACCESS = 1;
|
14 | const X_RANK_STRING_EQUALS = 3;
|
15 | const X_RANK_STRING_INDEX_OF = 3.5;
|
16 | const X_RANK_STRING_ENDS_WITH = 5;
|
17 | const X_RANK_CONCISE_STRING_EQUALS = 6;
|
18 | const X_RANK_CONCISE_PREFIXES_STRING_EQUALS = 6.5;
|
19 | const X_RANK_CONCISE_STRING_INDEX_OF = 7;
|
20 | const X_RANK_CONCISE_PREFIXES_STRING_INDEX_OF = 7.5;
|
21 | const X_RANK_REGEX = 11;
|
22 | const X_RANK_CONCISE_REGEX = 12;
|
23 | const X_RANK_TERM_COMPARE = 5.5;
|
24 |
|
25 | const F_SORT_GEN_RANK = (g_a, g_b) => g_a.rank - g_b.rank;
|
26 |
|
27 | const F_REDUCE_DECAY = (x_total, x_rank) => x_total + (x_rank / 2);
|
28 |
|
29 | const R_PLAIN_REGEX = /^(\^?)((?:\\.|[^.[\]{}?*+$()|])*)(\$?)$/;
|
30 |
|
31 | const RT_TEXT_PREFIX = /^[^~>_^@"*?]/;
|
32 |
|
33 | const H_TEST_RANGE = {
|
34 | [XM_TERM_TAG_DEFAULT_GRAPH]: {
|
35 | rank: X_RANK_PROPERTY_ACCESS,
|
36 |
|
37 | gen: sj => `${sj}.isDefaultGraph`,
|
38 | },
|
39 |
|
40 | [XM_TERM_TAG_NODE]: {
|
41 | rank: X_RANK_PROPERTY_ACCESS + (X_RANK_PROPERTY_ACCESS / 2),
|
42 |
|
43 | gen(sj) {
|
44 | return `(${sj}.isNamedNode || ${sj}.isBlankNode)`;
|
45 | },
|
46 | },
|
47 |
|
48 | [XM_TERM_TAG_LITERAL]: {
|
49 | rank: X_RANK_PROPERTY_ACCESS,
|
50 |
|
51 | gen(sj) {
|
52 | return `${sj}.isLiteral`;
|
53 | },
|
54 | },
|
55 |
|
56 | [XM_TERM_TAG_NODE_NAMED]: {
|
57 | rank: X_RANK_PROPERTY_ACCESS,
|
58 |
|
59 | gen(sj) {
|
60 | return `${sj}.isNamedNode`;
|
61 | },
|
62 | },
|
63 |
|
64 | [XM_TERM_TAG_NODE_BLANK]: {
|
65 | rank: X_RANK_PROPERTY_ACCESS,
|
66 |
|
67 | gen(sj) {
|
68 | return `${sj}.isBlankNode`;
|
69 | },
|
70 | },
|
71 |
|
72 | [XM_TERM_TAG_LITERAL_SIMPLE]: {
|
73 | rank: X_RANK_PROPERTY_ACCESS,
|
74 |
|
75 | gen(sj) {
|
76 | return `${sj}.isSimple`;
|
77 | },
|
78 | },
|
79 |
|
80 | [XM_TERM_TAG_LITERAL_LANGUAGED]: {
|
81 | rank: X_RANK_PROPERTY_ACCESS,
|
82 |
|
83 | gen(sj) {
|
84 | return `${sj}.isLanguaged`;
|
85 | },
|
86 | },
|
87 |
|
88 | [XM_TERM_TAG_LITERAL_DATATYPED]: {
|
89 | rank: X_RANK_PROPERTY_ACCESS,
|
90 |
|
91 | gen(sj) {
|
92 | return `${sj}.isDatatyped`;
|
93 | },
|
94 | },
|
95 | };
|
96 |
|
97 |
|
98 | function compile_tags(xm_tags) {
|
99 |
|
100 | if(xm_tags && XM_TERM_TAG_ANY !== xm_tags) {
|
101 |
|
102 | if(xm_tags in H_TEST_RANGE) {
|
103 | return H_TEST_RANGE[xm_tags];
|
104 | }
|
105 |
|
106 | else {
|
107 | let a_selectors = [];
|
108 |
|
109 |
|
110 | for(let [sm_test, g_select] of Object.entries(H_TEST_RANGE)) {
|
111 | let xm_test = +sm_test;
|
112 |
|
113 |
|
114 | if(xm_test === (xm_test & xm_tags)) {
|
115 |
|
116 | xm_tags &= ~xm_test;
|
117 |
|
118 |
|
119 | a_selectors.push(g_select);
|
120 |
|
121 |
|
122 | if(!xm_tags) break;
|
123 | }
|
124 | }
|
125 |
|
126 |
|
127 | if(xm_tags) {
|
128 | console.assert(`case not covered: ${xm_tags}`);
|
129 | }
|
130 |
|
131 |
|
132 | return {
|
133 | rank: a_selectors.map(g => g.rank).reduce(F_REDUCE_DECAY, 0),
|
134 |
|
135 | gen(sj_target) {
|
136 | return '('+a_selectors.map(g => g.gen(sj_target)).join(' && ')+')';
|
137 | },
|
138 | };
|
139 | }
|
140 | }
|
141 | }
|
142 |
|
143 |
|
144 | const pretag = (g, sj_target) => g.tags? compile_tags(g.tags).gen(sj_target)+' && ': '';
|
145 |
|
146 | const wrap = (s, b) => b? `(${s})`: s;
|
147 |
|
148 | const escape_str = s => s.replace(/'/g, '\\\'').replace(/\r\n\v\f/g, '');
|
149 |
|
150 | const track_prefix = (si_var_iri, si_prefix, s_suffix) => ({
|
151 | declare: `let ${si_var_iri} = null;`,
|
152 |
|
153 |
|
154 | prefix: {
|
155 | [escape_str(si_prefix)]: `${si_var_iri} = p_iri+'${escape_str(s_suffix)}';`,
|
156 | },
|
157 | });
|
158 |
|
159 | const H_COMPILERS = {
|
160 | and(a_items) {
|
161 | let a_compiled = a_items.map(g => this.compile(g));
|
162 |
|
163 |
|
164 | let b_tight_tags = false;
|
165 |
|
166 |
|
167 | if(a_compiled.slice(1).every(g => g === a_compiled[0].tags)) {
|
168 |
|
169 | a_compiled.push(compile_tags(a_compiled[0].tags));
|
170 | }
|
171 |
|
172 | else {
|
173 |
|
174 | b_tight_tags = true;
|
175 | }
|
176 |
|
177 |
|
178 | a_compiled.sort(F_SORT_GEN_RANK);
|
179 |
|
180 | return {
|
181 | rank: a_compiled.reduce(F_REDUCE_DECAY, 0),
|
182 |
|
183 | test(g_quad) {
|
184 | for(let g_compiled of a_compiled) {
|
185 | if(!g_compiled.test(g_quad)) return false;
|
186 | }
|
187 |
|
188 | return true;
|
189 | },
|
190 |
|
191 | gen(sj_target) {
|
192 | let f_map_gen = b_tight_tags
|
193 | ? (k, i) => a_compiled[i].auto(sj_target)
|
194 | : k => k.gen(sj_target);
|
195 |
|
196 | return wrap(a_compiled.map(f_map_gen).join(' && '), a_compiled.length > 1);
|
197 | },
|
198 | };
|
199 | },
|
200 |
|
201 | or(a_items) {
|
202 | let a_compiled = a_items.map(g => this.compile(g)).sort(F_SORT_GEN_RANK);
|
203 |
|
204 | return {
|
205 | rank: a_compiled.reduce(F_REDUCE_DECAY, 0),
|
206 |
|
207 | test(g_quad) {
|
208 | for(let g_compiled of a_compiled) {
|
209 | if(g_compiled.test(g_quad)) return true;
|
210 | }
|
211 |
|
212 | return false;
|
213 | },
|
214 |
|
215 | gen(sj_target) {
|
216 | return wrap(a_compiled.map(k => k.auto(sj_target)).join(' || '), a_compiled.length > 1);
|
217 | },
|
218 | };
|
219 | },
|
220 |
|
221 | not(g_not) {
|
222 | let k_not = this.compile(g_not);
|
223 |
|
224 | return {
|
225 | rank: k_not.rank,
|
226 |
|
227 | test(g_quad) {
|
228 | return !k_not.test(g_quad);
|
229 | },
|
230 |
|
231 | gen(sj_target) {
|
232 | return `!(${pretag(k_not, sj_target)}${k_not.gen(sj_target)})`;
|
233 | },
|
234 | };
|
235 | },
|
236 |
|
237 | range(g_range) {
|
238 | let {
|
239 | term: g_term,
|
240 | tags: xm_tags,
|
241 | } = g_range;
|
242 |
|
243 |
|
244 | let k_term = g_term? this.compile(g_range.term): null;
|
245 |
|
246 |
|
247 | let fsj_tag = null;
|
248 |
|
249 |
|
250 | if(k_term && k_term.tags) {
|
251 | xm_tags |= k_term.tags;
|
252 | }
|
253 |
|
254 |
|
255 | if(xm_tags && XM_TERM_TAG_ANY !== xm_tags) {
|
256 |
|
257 | if(xm_tags in H_TEST_RANGE) {
|
258 | fsj_tag = H_TEST_RANGE[xm_tags];
|
259 | }
|
260 |
|
261 | else {
|
262 | let a_selectors = [];
|
263 |
|
264 |
|
265 | for(let [sm_test, fsj_select] of Object.entries(H_TEST_RANGE)) {
|
266 | let xm_test = +sm_test;
|
267 |
|
268 |
|
269 | if(xm_test === (xm_test & xm_tags)) {
|
270 |
|
271 | xm_tags &= ~xm_test;
|
272 |
|
273 |
|
274 | a_selectors.push(fsj_select);
|
275 |
|
276 |
|
277 | if(!xm_tags) break;
|
278 | }
|
279 | }
|
280 |
|
281 |
|
282 | if(xm_tags) {
|
283 | console.assert(`case not covered: ${xm_tags}`);
|
284 | }
|
285 |
|
286 |
|
287 | fsj_tag = sj_target => a_selectors.map(fsj => fsj(sj_target)).join(' && ');
|
288 | }
|
289 | }
|
290 |
|
291 |
|
292 | if(fsj_tag && k_term) {
|
293 | return {
|
294 | rank: X_RANK_PROPERTY_ACCESS,
|
295 |
|
296 | gen(sj_target) {
|
297 | return `${fsj_tag(sj_target)} && ${k_term.gen(sj_target)}`;
|
298 | },
|
299 | };
|
300 | }
|
301 | else {
|
302 | debugger;
|
303 | }
|
304 | },
|
305 |
|
306 | iri(p_iri) {
|
307 | return {
|
308 | tags: XM_TERM_TAG_NODE_NAMED,
|
309 |
|
310 | rank: X_RANK_STRING_EQUALS,
|
311 |
|
312 | gen(sj_target) {
|
313 | return `'${escape_str(p_iri)}' === ${sj_target}.value`;
|
314 | },
|
315 | };
|
316 | },
|
317 |
|
318 | pname(g_pname) {
|
319 | let {
|
320 | prefix: si_prefix,
|
321 | local: s_suffix,
|
322 | } = g_pname;
|
323 |
|
324 | let si_var_iri = this.acquire('p_iri');
|
325 |
|
326 | return {
|
327 | tags: XM_TERM_TAG_NODE_NAMED,
|
328 |
|
329 | rank: X_RANK_STRING_EQUALS,
|
330 |
|
331 | hooks() {
|
332 | return track_prefix(si_var_iri, si_prefix, s_suffix);
|
333 | },
|
334 |
|
335 | gen(sj_target) {
|
336 | return `${si_var_iri} === ${sj_target}.value`;
|
337 | },
|
338 | };
|
339 | },
|
340 |
|
341 | language(s_lang) {
|
342 | return {
|
343 |
|
344 |
|
345 |
|
346 |
|
347 | rank: X_RANK_STRING_EQUALS,
|
348 |
|
349 | gen(sj_target) {
|
350 | return `'${escape_str(s_lang).toLowerCase()}' === ${sj_target}.language`;
|
351 | },
|
352 | };
|
353 | },
|
354 |
|
355 | datatype(g_datatype) {
|
356 | let k_datatype = this.compile(g_datatype);
|
357 |
|
358 | return {
|
359 | tags: XM_TERM_TAG_LITERAL_DATATYPED,
|
360 |
|
361 | rank: X_RANK_PROPERTY_ACCESS,
|
362 |
|
363 | gen(sj_target) {
|
364 | return k_datatype.toString( `${sj_target}.datatype`);
|
365 | },
|
366 | };
|
367 | },
|
368 |
|
369 | literal(g_literal) {
|
370 | let {
|
371 | contents: s_contents,
|
372 | post: g_post,
|
373 | } = g_literal;
|
374 |
|
375 | let f_contents = sj_target => `'${escape_str(s_contents)}' === ${sj_target}.value`;
|
376 |
|
377 | if(g_post) {
|
378 | let k_post = this.compile(g_post);
|
379 |
|
380 | return {
|
381 | tags: k_post.tags,
|
382 |
|
383 | rank: [X_RANK_STRING_EQUALS, k_post.rank].reduce(F_REDUCE_DECAY, 0),
|
384 |
|
385 | gen(sj_target) {
|
386 | return `${f_contents(sj_target)} && ${k_post.gen(sj_target)}`;
|
387 | },
|
388 | };
|
389 | }
|
390 | else {
|
391 | return {
|
392 | tags: XM_TERM_TAG_LITERAL_SIMPLE,
|
393 |
|
394 | rank: X_RANK_STRING_EQUALS,
|
395 |
|
396 | gen(sj_contents) {
|
397 | return f_contents(sj_contents);
|
398 | },
|
399 | };
|
400 | }
|
401 | },
|
402 |
|
403 | default_graph() {
|
404 | return {
|
405 | tags: XM_TERM_TAG_DEFAULT_GRAPH,
|
406 |
|
407 | rank: 0,
|
408 |
|
409 | gen: () => 'true',
|
410 | };
|
411 | },
|
412 |
|
413 | anon() {
|
414 | return {
|
415 | tags: XM_TERM_TAG_NODE_BLANK,
|
416 |
|
417 | rank: 0,
|
418 |
|
419 | gen: () => 'true',
|
420 | };
|
421 | },
|
422 |
|
423 | bnode(s_label) {
|
424 | if(s_label) {
|
425 | return {
|
426 | tags: XM_TERM_TAG_NODE_BLANK,
|
427 |
|
428 | rank: X_RANK_STRING_EQUALS,
|
429 |
|
430 | gen(sj_target) {
|
431 | return `'${escape_str(s_label)}' === ${sj_target}.value`;
|
432 | },
|
433 | };
|
434 | }
|
435 | else {
|
436 | return {
|
437 | tags: XM_TERM_TAG_NODE_BLANK,
|
438 |
|
439 | rank: 0,
|
440 |
|
441 | gen: () => 'true',
|
442 | };
|
443 | }
|
444 | },
|
445 |
|
446 | regex(g_regex) {
|
447 | let r_pattern = g_regex.pattern;
|
448 | let s_source = r_pattern.source;
|
449 |
|
450 |
|
451 | if(g_regex.concise) {
|
452 | let m_plain = R_PLAIN_REGEX.exec(s_source);
|
453 |
|
454 |
|
455 | if(m_plain && r_pattern.flags.indexOf('i') < 0) {
|
456 | let [, s_anchor_start, s_text, s_anchor_end] = m_plain;
|
457 |
|
458 |
|
459 | if(s_anchor_start) {
|
460 |
|
461 | switch(s_text[0]) {
|
462 |
|
463 | case '@':
|
464 | case '^': {
|
465 | let b_datatype = '^' === s_text[0];
|
466 | let b_prefixed_datatype = b_datatype && '>' !== s_text[1];
|
467 | let sj_prefixes = b_prefixed_datatype? 'h_prefixes': '';
|
468 |
|
469 | let xm_tags = b_datatype? XM_TERM_TAG_LITERAL_DATATYPED: XM_TERM_TAG_LITERAL_LANGUAGED;
|
470 |
|
471 |
|
472 | if(s_anchor_end) {
|
473 | return {
|
474 | tags: xm_tags,
|
475 |
|
476 | prefixes: !!sj_prefixes,
|
477 |
|
478 | ...(b_prefixed_datatype
|
479 | ? {
|
480 | rank: X_RANK_CONCISE_PREFIXES_STRING_EQUALS,
|
481 | }
|
482 | : {
|
483 | rank: X_RANK_CONCISE_STRING_EQUALS,
|
484 | }),
|
485 |
|
486 | gen(sj_target) {
|
487 | return `'${escape_str(s_text)}' === ${sj_target}.concise(${sj_prefixes})`;
|
488 | },
|
489 | };
|
490 | }
|
491 |
|
492 | else {
|
493 |
|
494 | let i_contents = s_text.indexOf('"');
|
495 | if(i_contents >= 0) {
|
496 | let s_contents = s_text.slice(i_contents);
|
497 |
|
498 |
|
499 | if(s_contents) {
|
500 | return {
|
501 | tags: xm_tags,
|
502 |
|
503 | prefixes: !!sj_prefixes,
|
504 |
|
505 | rank: b_prefixed_datatype? X_RANK_CONCISE_PREFIXES_STRING_INDEX_OF: X_RANK_CONCISE_STRING_INDEX_OF,
|
506 |
|
507 | gen(sj_target) {
|
508 | return `0 === ${sj_target}.concise(${sj_prefixes}).indexOf('${escape_str(s_text)}')`;
|
509 | },
|
510 | };
|
511 | }
|
512 |
|
513 | else if(b_datatype) {
|
514 | return {
|
515 | tags: xm_tags,
|
516 |
|
517 | prefixes: !!sj_prefixes,
|
518 |
|
519 | rank: b_prefixed_datatype? X_RANK_CONCISE_PREFIXES_STRING_EQUALS: X_RANK_CONCISE_STRING_EQUALS,
|
520 |
|
521 | gen(sj_target) {
|
522 | return `'${escape_str(s_text.slice(1))}' === ${sj_target}.datatype.concise(${sj_prefixes})`;
|
523 | },
|
524 | };
|
525 | }
|
526 |
|
527 | else {
|
528 | return {
|
529 | tags: xm_tags,
|
530 |
|
531 | rank: X_RANK_CONCISE_STRING_INDEX_OF,
|
532 |
|
533 | gen(sj_target) {
|
534 | return `'${escape_str(s_text.slice(1))}' === ${sj_target}.language`;
|
535 | },
|
536 | };
|
537 | }
|
538 | }
|
539 |
|
540 | else if(b_datatype) {
|
541 | return {
|
542 | tags: xm_tags,
|
543 |
|
544 | prefixes: !!sj_prefixes,
|
545 |
|
546 | rank: b_prefixed_datatype? X_RANK_CONCISE_PREFIXES_STRING_INDEX_OF: X_RANK_CONCISE_STRING_INDEX_OF,
|
547 |
|
548 | gen(sj_target) {
|
549 | return `0 === ${sj_target}.datatype.concise(${sj_prefixes}).indexOf('${escape_str(s_text)}')`;
|
550 | },
|
551 | };
|
552 | }
|
553 |
|
554 | else {
|
555 | return {
|
556 | tags: xm_tags,
|
557 |
|
558 | rank: X_RANK_STRING_INDEX_OF,
|
559 |
|
560 | gen(sj_target) {
|
561 | return `0 === ${sj_target}.language.indexOf('${escape_str(s_text.slice(1))}')`;
|
562 | },
|
563 | };
|
564 | }
|
565 | }
|
566 | }
|
567 |
|
568 |
|
569 | case '"': {
|
570 | let s_contents = s_text.slice(1);
|
571 |
|
572 |
|
573 | if(s_anchor_end) {
|
574 | return {
|
575 | tags: XM_TERM_TAG_LITERAL_SIMPLE,
|
576 |
|
577 | rank: X_RANK_STRING_EQUALS,
|
578 |
|
579 | gen(sj_target) {
|
580 | return `'${s_contents}' === ${sj_target}.value`;
|
581 | },
|
582 | };
|
583 | }
|
584 |
|
585 | else {
|
586 | return {
|
587 | tags: XM_TERM_TAG_LITERAL_SIMPLE,
|
588 |
|
589 | rank: X_RANK_STRING_INDEX_OF,
|
590 |
|
591 | gen(sj_target) {
|
592 | return `0 === ${sj_target}.value.indexOf('${s_contents}')`;
|
593 | },
|
594 | };
|
595 | }
|
596 | }
|
597 |
|
598 |
|
599 | case '>': {
|
600 | let p_iri = s_text.slice(1);
|
601 |
|
602 |
|
603 | if(s_anchor_end) {
|
604 | return {
|
605 | tags: XM_TERM_TAG_LITERAL_SIMPLE,
|
606 |
|
607 | rank: X_RANK_STRING_EQUALS,
|
608 |
|
609 | gen(sj_target) {
|
610 | return `'${p_iri}' === ${sj_target}.value`;
|
611 | },
|
612 | };
|
613 | }
|
614 |
|
615 | else {
|
616 | return {
|
617 | tags: XM_TERM_TAG_LITERAL_SIMPLE,
|
618 |
|
619 | rank: X_RANK_STRING_INDEX_OF,
|
620 |
|
621 | gen(sj_target) {
|
622 | return `0 === ${sj_target}.value.indexOf('${p_iri}')`;
|
623 | },
|
624 | };
|
625 | }
|
626 | }
|
627 |
|
628 |
|
629 | default: {
|
630 | let i_colon = s_text.indexOf(':');
|
631 | let si_prefix = s_text.slice(0, i_colon);
|
632 | let s_suffix = s_text.slice(i_colon+1);
|
633 |
|
634 | let si_var_iri = this.acquire('p_iri');
|
635 |
|
636 |
|
637 | if(s_anchor_end) {
|
638 |
|
639 | return {
|
640 | tags: XM_TERM_TAG_NODE_NAMED,
|
641 |
|
642 | rank: X_RANK_STRING_EQUALS,
|
643 |
|
644 | hooks() {
|
645 | return track_prefix(si_var_iri, si_prefix, s_suffix);
|
646 | },
|
647 |
|
648 | gen(sj_target) {
|
649 | return `${si_var_iri} === ${sj_target}.value`;
|
650 | },
|
651 | };
|
652 | }
|
653 |
|
654 | else {
|
655 |
|
656 | return {
|
657 | tags: XM_TERM_TAG_NODE_NAMED,
|
658 |
|
659 | rank: X_RANK_STRING_INDEX_OF,
|
660 |
|
661 | hooks() {
|
662 | return track_prefix(si_var_iri, si_prefix, s_suffix);
|
663 | },
|
664 |
|
665 | gen(sj_target) {
|
666 | return `0 === ${sj_target}.value.indexOf(${si_var_iri})`;
|
667 | },
|
668 | };
|
669 | }
|
670 | }
|
671 | }
|
672 | }
|
673 |
|
674 | else if(s_anchor_end) {
|
675 |
|
676 | return {
|
677 | rank: X_RANK_STRING_ENDS_WITH,
|
678 |
|
679 | gen(sj_target) {
|
680 | return `${sj_target}.concise().endsWith('${escape_str(s_text)}')`;
|
681 | },
|
682 | };
|
683 | }
|
684 |
|
685 | else {
|
686 |
|
687 | return {
|
688 | rank: X_RANK_STRING_INDEX_OF,
|
689 |
|
690 | gen(sj_target) {
|
691 | return `${sj_target}.concise().indexOf('${escape_str(s_text)}') > -1`;
|
692 | },
|
693 | };
|
694 | }
|
695 | }
|
696 |
|
697 | else {
|
698 | let si_var_regex = this.acquire('rt_term');
|
699 |
|
700 | return {
|
701 | rank: X_RANK_CONCISE_REGEX,
|
702 |
|
703 | prefixes: true,
|
704 |
|
705 | hooks() {
|
706 | return {
|
707 | declare: `let ${si_var_regex} = /${s_source}/${r_pattern.flags};`,
|
708 | };
|
709 | },
|
710 |
|
711 | gen(sj_target) {
|
712 | return `${si_var_regex}.test(${sj_target}.concise(h_prefixes))`;
|
713 | },
|
714 | };
|
715 | }
|
716 | }
|
717 |
|
718 | else {
|
719 | let si_var_regex = this.acquire('rt_term');
|
720 |
|
721 | return {
|
722 | rank: X_RANK_REGEX,
|
723 |
|
724 | hooks() {
|
725 | return {
|
726 | declare: `let ${si_var_regex} = /${s_source}/${r_pattern.flags};`,
|
727 | };
|
728 | },
|
729 |
|
730 | gen(sj_target) {
|
731 | return `${si_var_regex}.test(${sj_target}.value)`;
|
732 | },
|
733 | };
|
734 | }
|
735 | },
|
736 |
|
737 | ref(s_ref) {
|
738 | this._as_destructures.add(s_ref);
|
739 |
|
740 | return {
|
741 | rank: X_RANK_TERM_COMPARE,
|
742 |
|
743 | gen(sj_target) {
|
744 | return `${sj_target}.equals(kt_${s_ref})`;
|
745 | },
|
746 | };
|
747 | },
|
748 | };
|
749 |
|
750 |
|
751 | class Context {
|
752 | constructor() {
|
753 | this._c_vars =0;
|
754 | this._s_declare = '';
|
755 | this._h_prefix_handlers = {};
|
756 | this._b_capture_prefixes = false;
|
757 | this._as_destructures = new Set();
|
758 | this._a_refs = [];
|
759 | this._c_patterns = 0;
|
760 | }
|
761 |
|
762 | start_pattern() {
|
763 | this._a_refs.push({});
|
764 | this._c_patterns += 1;
|
765 | }
|
766 |
|
767 | acquire(s_var) {
|
768 | return `${s_var}_${this._c_vars++}`;
|
769 | }
|
770 |
|
771 | push_hook(g_hook) {
|
772 | if(g_hook.declare) {
|
773 | this._s_declare += g_hook.declare;
|
774 | }
|
775 |
|
776 | if(g_hook.prefix) {
|
777 | let h_handlers = this._h_prefix_handlers;
|
778 |
|
779 | let h_prefix = g_hook.prefix;
|
780 | for(let si_prefix in h_prefix) {
|
781 | (h_handlers[si_prefix] = h_handlers[si_prefix] || [])
|
782 | .push(h_prefix[si_prefix]);
|
783 | }
|
784 | }
|
785 | }
|
786 |
|
787 | get destructures() {
|
788 | return this._as_destructures;
|
789 | }
|
790 |
|
791 | get declarations() {
|
792 | return this._s_declare;
|
793 | }
|
794 |
|
795 | get prefix_handlers() {
|
796 | return this._h_prefix_handlers;
|
797 | }
|
798 |
|
799 | get capture_prefixes() {
|
800 | return this._b_capture_prefixes;
|
801 | }
|
802 |
|
803 | compile(g_src) {
|
804 | let {
|
805 | type: s_type,
|
806 | value: w_value,
|
807 | } = g_src;
|
808 |
|
809 | if(!(s_type in H_COMPILERS)) {
|
810 | console.assert(`syntax object type ${s_type} not mapped`);
|
811 | }
|
812 |
|
813 | let g_compiled = H_COMPILERS[s_type].call(this, w_value);
|
814 |
|
815 |
|
816 | if(g_compiled.hooks) {
|
817 | this.push_hook(g_compiled.hooks());
|
818 | }
|
819 |
|
820 |
|
821 | if(g_compiled.prefixes) {
|
822 | this._b_capture_prefixes = true;
|
823 | }
|
824 |
|
825 | g_compiled.auto = (sj_target) => {
|
826 | let sj_compiled = g_compiled.gen(sj_target);
|
827 |
|
828 | if(g_compiled.tags) {
|
829 | let sj_pretag = pretag(g_compiled, sj_target);
|
830 |
|
831 | return wrap(sj_pretag+sj_compiled, sj_pretag);
|
832 | }
|
833 | else {
|
834 | return sj_compiled;
|
835 | }
|
836 | };
|
837 |
|
838 | return g_compiled;
|
839 | }
|
840 | }
|
841 |
|
842 |
|
843 | class Pattern {
|
844 | constructor(k_context, g_source) {
|
845 | let x_rank = 0;
|
846 | let c_decay = 0;
|
847 |
|
848 | let a_conditions = this._a_conditions = [];
|
849 | let a_destructures = this._a_destructures = [];
|
850 | this._g_graph = null;
|
851 |
|
852 | k_context._c_patterns += 1;
|
853 |
|
854 | if(g_source.graph) {
|
855 | let g_compiled = k_context.compile(g_source.graph);
|
856 |
|
857 | x_rank += g_compiled.rank / (Math.pow(2, c_decay++));
|
858 |
|
859 | let b_default_graph = XM_TERM_TAG_DEFAULT_GRAPH === g_compiled.tags;
|
860 |
|
861 | if(b_default_graph) {
|
862 | this._g_graph = {
|
863 | compiled: g_compiled,
|
864 | condition: g_compiled.auto( `kt_graph`),
|
865 | variable: 'b_default_graph',
|
866 | default: true,
|
867 | };
|
868 |
|
869 | a_conditions.push('b_default_graph');
|
870 | }
|
871 | else {
|
872 | let si_var_graph = k_context.acquire('b_graph_pass');
|
873 |
|
874 | this._g_graph = {
|
875 | compiled: g_compiled,
|
876 | condition: g_compiled.auto( `kt_graph`),
|
877 | variable: b_default_graph? 'b_default_graph': si_var_graph,
|
878 | default: b_default_graph,
|
879 | };
|
880 |
|
881 | a_conditions.push(si_var_graph);
|
882 | }
|
883 | }
|
884 |
|
885 | if(g_source.object) {
|
886 | let g_compiled = k_context.compile(g_source.object);
|
887 |
|
888 | x_rank += g_compiled.rank / (Math.pow(2, c_decay++));
|
889 |
|
890 | a_conditions.push(g_compiled.auto( `kt_object`));
|
891 |
|
892 | a_destructures.push('object');
|
893 | }
|
894 |
|
895 | if(g_source.subject) {
|
896 | let g_compiled = k_context.compile(g_source.subject);
|
897 |
|
898 | x_rank += g_compiled.rank / (Math.pow(2, c_decay++));
|
899 |
|
900 | a_conditions.push(g_compiled.auto( `kt_subject`));
|
901 |
|
902 | a_destructures.push('subject');
|
903 | }
|
904 |
|
905 | if(g_source.predicate) {
|
906 | let g_compiled = k_context.compile(g_source.predicate);
|
907 |
|
908 | x_rank += g_compiled.rank / (Math.pow(2, c_decay++));
|
909 |
|
910 | a_conditions.push(g_compiled.auto( `kt_predicate`));
|
911 |
|
912 | a_destructures.push('predicate');
|
913 | }
|
914 |
|
915 | this._x_rank = x_rank;
|
916 | }
|
917 |
|
918 | get destructures() {
|
919 | return this._a_destructures;
|
920 | }
|
921 |
|
922 | get graph() {
|
923 | return this._g_graph;
|
924 | }
|
925 |
|
926 | get rank() {
|
927 | return this._x_rank;
|
928 | }
|
929 |
|
930 | get conditions() {
|
931 | return this._a_conditions.join('\n\t && ');
|
932 | }
|
933 | }
|
934 |
|
935 | const gobble = (s_text) => {
|
936 | let m_indent = /^(?:\s*\n)+([ \t]*)/.exec(s_text);
|
937 | if(m_indent) {
|
938 | let r_indent = new RegExp('\\n'+m_indent[1], 'g');
|
939 | return s_text.trim().replace(r_indent, '\n');
|
940 | }
|
941 | else {
|
942 | return s_text;
|
943 | }
|
944 | };
|
945 |
|
946 | function prepare(a_sources) {
|
947 | let k_context = new Context();
|
948 |
|
949 | let a_patterns = a_sources
|
950 | .map(g_source => new Pattern(k_context, g_source))
|
951 | .sort(F_SORT_GEN_RANK);
|
952 |
|
953 | let sj_init = '';
|
954 | let sj_events = '';
|
955 |
|
956 | let a_graphs = [];
|
957 |
|
958 |
|
959 | for(let k_pattern of a_patterns) {
|
960 |
|
961 | if(k_pattern.graph) {
|
962 | a_graphs.push(k_pattern.graph);
|
963 | }
|
964 |
|
965 |
|
966 | if(k_pattern.declarations) {
|
967 | sj_init += k_pattern.declarations;
|
968 | }
|
969 | }
|
970 |
|
971 |
|
972 | {
|
973 | let s_branches = '';
|
974 |
|
975 |
|
976 | let h_prefix_cases = k_context.prefix_handlers;
|
977 | for(let si_prefix in h_prefix_cases) {
|
978 | s_branches += `
|
979 | case '${si_prefix}': {
|
980 | ${h_prefix_cases[si_prefix].join('\n')}
|
981 | break;
|
982 | }
|
983 | `;
|
984 | }
|
985 |
|
986 | if(s_branches || k_context.capture_prefixes) {
|
987 | sj_init += `let h_prefixes = {};\n`;
|
988 |
|
989 | sj_events += `
|
990 | ds_reader.on('prefix', (si_prefix, p_iri) => {
|
991 | ${k_context.capture_prefixes? /* syntax: js */ `h_prefixes[si_prefix] = p_iri;`: ''}
|
992 |
|
993 | switch(si_prefix) {
|
994 | ${s_branches}
|
995 | }
|
996 | });
|
997 | `;
|
998 | }
|
999 | }
|
1000 |
|
1001 |
|
1002 | if(a_graphs.length) {
|
1003 |
|
1004 | let a_graphs_nond = [];
|
1005 |
|
1006 |
|
1007 | let b_default_graph = false;
|
1008 | {
|
1009 |
|
1010 | for(let g_graph of a_graphs) {
|
1011 | if(g_graph.default) {
|
1012 | b_default_graph = true;
|
1013 | }
|
1014 | else {
|
1015 | a_graphs_nond.push(g_graph);
|
1016 | }
|
1017 | }
|
1018 |
|
1019 |
|
1020 | if(b_default_graph) {
|
1021 | sj_init += `let b_default_graph = true;\n`;
|
1022 | }
|
1023 | }
|
1024 |
|
1025 | sj_init += `const KT_DEFAULT_GRAPH = factory.defaultGraph();\n`;
|
1026 | sj_init += a_graphs_nond.map(g => `let ${g.variable}_init = (kt_graph => (${g.condition}))(KT_DEFAULT_GRAPH);\n`);
|
1027 | sj_init += a_graphs_nond.map(g => `let ${g.variable} = ${g.variable}_init;\n`);
|
1028 |
|
1029 | sj_events = `
|
1030 | ds_reader.on('enter', (kt_graph) => {
|
1031 | ${a_graphs_nond.map(g => /* syntax: js */ `
|
1032 | if(${g.condition}) {
|
1033 | ${g.variable} = true;
|
1034 | ${b_default_graph? /* syntax: js */ `b_default_graph = false;`: ''}
|
1035 | }
|
1036 | `)}
|
1037 |
|
1038 | ${b_default_graph
|
1039 | ? /* syntax: js */ `
|
1040 | if(kt_graph.isDefaultGraph) {
|
1041 | b_default_graph = true;
|
1042 | }
|
1043 | `
|
1044 | : ''}
|
1045 | });
|
1046 |
|
1047 | ds_reader.on('exit', (kt_graph) => {
|
1048 | ${a_graphs_nond.map(g => /* syntax: js */ `
|
1049 | ${g.variable} = ${g.variable}_init;
|
1050 | `)}
|
1051 |
|
1052 | ${b_default_graph
|
1053 | ? /* syntax: js */ `
|
1054 | if(!kt_graph.isDefaultGraph) {
|
1055 | b_default_graph = false;
|
1056 | }
|
1057 | `
|
1058 | : ''}
|
1059 | });
|
1060 | `;
|
1061 | }
|
1062 |
|
1063 |
|
1064 | let sj_destructures = Array.from(
|
1065 | a_patterns.reduce((as_out, k) => new Set([...as_out, ...k.destructures]), k_context.destructures),
|
1066 | ).map(s => `let kt_${s} = g_quad.${s};`).join('\n');
|
1067 |
|
1068 | let sj_filter = gobble( `
|
1069 | ${k_context.declarations}
|
1070 | ${sj_init}
|
1071 |
|
1072 | let ds_filter = new stream.Transform.QuadsToOther({
|
1073 | objectMode: true,
|
1074 |
|
1075 | transform(g_quad, s_encoding, fke_transform) {
|
1076 | ${sj_destructures}
|
1077 | let b_cond = ${a_patterns.map(k => wrap(k.conditions, a_patterns.length > 1)).join('\n\t ||')};
|
1078 |
|
1079 | // condition passed
|
1080 | if(b_cond) {
|
1081 | this.push(g_quad);
|
1082 | }
|
1083 |
|
1084 | // done with quad
|
1085 | fke_transform();
|
1086 | },
|
1087 | });
|
1088 |
|
1089 | ds_filter.on('pipe', (ds_reader) => {
|
1090 | ${sj_events}
|
1091 | });
|
1092 |
|
1093 | return ds_filter;
|
1094 | `);
|
1095 |
|
1096 | return sj_filter;
|
1097 | }
|
1098 |
|
1099 | module.exports = {
|
1100 | prepare,
|
1101 | };
|