@nymphjs/query-parser 1.0.0-beta.122 → 1.0.0-beta.124

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.
@@ -158,14 +158,14 @@ function selectorsParser({
158
158
  });
159
159
 
160
160
  if (options) {
161
- const limitRegex = /(?: |^)limit:(\d+)(?= |$)/;
161
+ const limitRegex = /(?:\s|^)limit:(\d+)(?=\s|$)/;
162
162
  const limitMatch = curQuery.match(limitRegex);
163
163
  if (limitMatch) {
164
164
  options.limit = Number(limitMatch[1]);
165
165
  }
166
166
  curQuery = curQuery.replace(limitRegex, '');
167
167
 
168
- const offsetRegex = /(?: |^)offset:(\d+)(?= |$)/;
168
+ const offsetRegex = /(?:\s|^)offset:(\d+)(?=\s|$)/;
169
169
  const offsetMatch = curQuery.match(offsetRegex);
170
170
  if (offsetMatch) {
171
171
  options.offset = Number(offsetMatch[1]);
@@ -175,14 +175,14 @@ function selectorsParser({
175
175
  // JavaScript variable names are ridiculously infeasable to check
176
176
  // thoroughly, so this is a "best attempt".
177
177
  const sortRegex =
178
- /(?: |^)sort:(-|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)(?= |$)/;
178
+ /(?:\s|^)sort:(-|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)(?=\s|$)/;
179
179
  const sortMatch = curQuery.match(sortRegex);
180
180
  if (sortMatch) {
181
181
  options.sort = sortMatch[1] === '-' ? null : sortMatch[1];
182
182
  }
183
183
  curQuery = curQuery.replace(sortRegex, '');
184
184
 
185
- const reverseRegex = /(?: |^)reverse:(true|false|1|0)(?= |$)/;
185
+ const reverseRegex = /(?:\s|^)reverse:(true|false|1|0)(?=\s|$)/;
186
186
  const reverseMatch = curQuery.match(reverseRegex);
187
187
  if (reverseMatch) {
188
188
  options.reverse = reverseMatch[1] === 'true' || reverseMatch[1] === '1';
@@ -233,8 +233,98 @@ function selectorParser({
233
233
  }): string {
234
234
  let curQuery = query;
235
235
 
236
- // eg. prop(some search string) or prop!(some search string)
237
- const searchRegex = /(?: |^)([^\s=\[\]<>{}]+?)!?\([^\)]+\)(?= |$)/g;
236
+ // This one needs to happen first, because it has entire queries in it.
237
+ // eg. user<{User name="Hunter"}> or -user<{User name="Hunter"}>
238
+ const qrefRegex =
239
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)<\{(\w+)(?=\s)/;
240
+ // This is used to bypass badly formatted things that match the above regex.
241
+ let offsetIndex = 0;
242
+ let qrefMatch = curQuery.match(qrefRegex);
243
+ while (qrefMatch) {
244
+ let endIndex = (qrefMatch.index ?? 0) + offsetIndex + qrefMatch[0].length;
245
+ let curOpen = 1;
246
+ while (curOpen) {
247
+ const indexOfNextOpen = curQuery.indexOf('<{', endIndex);
248
+ const indexOfNextClose = curQuery.slice(endIndex).search(/(?<!\\)\}>/);
249
+
250
+ if (indexOfNextClose < 0) {
251
+ endIndex = curQuery.length;
252
+ break;
253
+ }
254
+
255
+ if (
256
+ indexOfNextOpen > -1 &&
257
+ indexOfNextOpen < endIndex + indexOfNextClose
258
+ ) {
259
+ endIndex = indexOfNextOpen + 2;
260
+ curOpen++;
261
+ } else {
262
+ endIndex += indexOfNextClose + 2;
263
+ curOpen--;
264
+ }
265
+ }
266
+
267
+ if (!('qref' in selector)) {
268
+ selector.qref = [];
269
+ }
270
+ if (!('!qref' in selector)) {
271
+ selector['!qref'] = [];
272
+ }
273
+
274
+ const match = curQuery.slice(
275
+ (qrefMatch.index ?? 0) + offsetIndex,
276
+ endIndex,
277
+ );
278
+ try {
279
+ let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
280
+ value = unQuoteCurlies(value.slice(1, -1));
281
+ let [className, qrefQuery] = splitn(value, ' ', 2);
282
+ const EntityClass = qrefMap[className].class;
283
+ if (EntityClass == null) {
284
+ throw new Error();
285
+ }
286
+ const qref = queryParser({
287
+ query: qrefQuery,
288
+ entityClass: EntityClass,
289
+ defaultFields: qrefMap[className].defaultFields,
290
+ qrefMap,
291
+ bareHandler,
292
+ });
293
+ if (name.startsWith('-')) {
294
+ (selector['!qref'] as [string, any][]).push([name.slice(1), qref]);
295
+ } else {
296
+ (selector.qref as [string, any][]).push([name, qref]);
297
+ }
298
+ } catch (e: any) {
299
+ offsetIndex = endIndex;
300
+ qrefMatch = curQuery.slice(offsetIndex).match(qrefRegex);
301
+
302
+ if (!selector.qref?.length) {
303
+ delete selector.qref;
304
+ }
305
+ if (!selector['!qref']?.length) {
306
+ delete selector['!qref'];
307
+ }
308
+
309
+ continue;
310
+ }
311
+ if (!selector.qref?.length) {
312
+ delete selector.qref;
313
+ }
314
+ if (!selector['!qref']?.length) {
315
+ delete selector['!qref'];
316
+ }
317
+
318
+ curQuery =
319
+ curQuery.slice(0, (qrefMatch.index ?? 0) + offsetIndex) +
320
+ ' ' +
321
+ curQuery.slice(endIndex);
322
+ qrefMatch = curQuery.slice(offsetIndex).match(qrefRegex);
323
+ }
324
+
325
+ // eg. prop(some search string) or -prop(some search string)
326
+ const searchRegex =
327
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)\([^\)]+\)(?=\s|\)|\}>|$)/g;
238
328
  const searchMatch = curQuery.match(searchRegex);
239
329
  if (searchMatch) {
240
330
  selector.search = [];
@@ -242,8 +332,8 @@ function selectorParser({
242
332
  for (let match of searchMatch) {
243
333
  try {
244
334
  let [name, value] = splitn(match.trim().slice(0, -1), '(', 2);
245
- if (name.endsWith('!')) {
246
- selector['!search'].push([name.slice(0, -1), value]);
335
+ if (name.startsWith('-')) {
336
+ selector['!search'].push([name.slice(1), value]);
247
337
  } else {
248
338
  selector.search.push([name, value]);
249
339
  }
@@ -260,48 +350,44 @@ function selectorParser({
260
350
  }
261
351
  curQuery = curQuery.replace(searchRegex, '');
262
352
 
263
- // eg. user<{User name="Hunter"}> or user!<{User name="Hunter"}>
264
- const qrefRegex = /(?: |^)([^\s=\[\]<>{}]+?)!?<\{(\w+) (.*?[^\\])\}>(?= |$)/g;
265
- const qrefMatch = curQuery.match(qrefRegex);
266
- if (qrefMatch) {
267
- selector.qref = [];
268
- selector['!qref'] = [];
269
- for (let match of qrefMatch) {
353
+ // eg. name:Marty or name:"Marty McFly" or -name:'Marty McFly'
354
+ const searchColonRegex =
355
+ /(?:\s|^)(?!(limit|offset|sort|reverse):)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?):("[^"]*?"|'[^']*?'|[^\s]+)(?=\s|\)|\}>|$)/g;
356
+ const searchColonMatch = curQuery.match(searchColonRegex);
357
+ if (searchColonMatch) {
358
+ if (!('search' in selector)) {
359
+ selector.search = [];
360
+ }
361
+ if (!('!search' in selector)) {
362
+ selector['!search'] = [];
363
+ }
364
+ for (let match of searchColonMatch) {
270
365
  try {
271
- let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
272
- value = unQuoteCurlies(value.slice(1, -1));
273
- let [className, qrefQuery] = splitn(value, ' ', 2);
274
- const EntityClass = qrefMap[className].class;
275
- if (EntityClass == null) {
276
- continue;
277
- }
278
- const qref = queryParser({
279
- query: qrefQuery,
280
- entityClass: EntityClass,
281
- defaultFields: qrefMap[className].defaultFields,
282
- qrefMap,
283
- bareHandler,
284
- });
285
- if (name.endsWith('!')) {
286
- selector['!qref'].push([name.slice(0, -1), qref]);
366
+ let [name, value] = splitn(match.trim(), ':', 2);
367
+ if (name.startsWith('-')) {
368
+ (selector['!search'] as [string, string][]).push([
369
+ name.slice(1),
370
+ value,
371
+ ]);
287
372
  } else {
288
- selector.qref.push([name, qref]);
373
+ (selector.search as [string, string][]).push([name, value]);
289
374
  }
290
375
  } catch (e: any) {
291
376
  continue;
292
377
  }
293
378
  }
294
- if (!selector.qref.length) {
295
- delete selector.qref;
379
+ if (selector.search == null || !selector.search.length) {
380
+ delete selector.search;
296
381
  }
297
- if (!selector['!qref'].length) {
298
- delete selector['!qref'];
382
+ if (selector['!search'] == null || !selector['!search'].length) {
383
+ delete selector['!search'];
299
384
  }
300
385
  }
301
- curQuery = curQuery.replace(qrefRegex, '');
386
+ curQuery = curQuery.replace(searchColonRegex, '');
302
387
 
303
388
  // eg. someArray=[1,2] or someObject={"prop":"some value"}
304
- const equalJsonRegex = /(?: |^)([^\s=\[\]<>{}]+?)!?=(\{|\[)/g;
389
+ const equalJsonRegex =
390
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)=(\{|\[)/g;
305
391
  const equalJsonMatch = [...curQuery.matchAll(equalJsonRegex)];
306
392
  if (equalJsonMatch) {
307
393
  if (!('equal' in selector)) {
@@ -318,9 +404,9 @@ function selectorParser({
318
404
  let nextEndToken = curQuery.indexOf(opener === '{' ? '}' : ']', start);
319
405
  while (nextEndToken !== -1) {
320
406
  try {
321
- if (name.endsWith('!')) {
407
+ if (name.startsWith('-')) {
322
408
  (selector['!equal'] as [string, any][]).unshift([
323
- name.slice(0, -1),
409
+ name.slice(1),
324
410
  JSON.parse(curQuery.substring(start, nextEndToken + 1)),
325
411
  ]);
326
412
  } else {
@@ -352,7 +438,7 @@ function selectorParser({
352
438
 
353
439
  // eg. name=Marty or name="Marty McFly" or enabled=true
354
440
  const equalRegex =
355
- /(?: |^)([^\s=\[\]<>{}]+?)!?=(""|".*?[^\\]"|[^ ]+)(?= |$)/g;
441
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)=(""|".*?[^\\]"|[^\s]+)(?=\s|\)|\}>|$)/g;
356
442
  const equalMatch = curQuery.match(equalRegex);
357
443
  if (equalMatch) {
358
444
  if (!('equal' in selector)) {
@@ -365,18 +451,18 @@ function selectorParser({
365
451
  try {
366
452
  let [name, value] = splitn(match.trim(), '=', 2);
367
453
  try {
368
- if (name.endsWith('!')) {
454
+ if (name.startsWith('-')) {
369
455
  (selector['!equal'] as [string, any][]).push([
370
- name.slice(0, -1),
456
+ name.slice(1),
371
457
  JSON.parse(value),
372
458
  ]);
373
459
  } else {
374
460
  (selector.equal as [string, any][]).push([name, JSON.parse(value)]);
375
461
  }
376
462
  } catch (e: any) {
377
- if (name.endsWith('!')) {
463
+ if (name.startsWith('-')) {
378
464
  (selector['!equal'] as [string, any][]).push([
379
- name.slice(0, -1),
465
+ name.slice(1),
380
466
  unQuoteString(value),
381
467
  ]);
382
468
  } else {
@@ -399,8 +485,9 @@ function selectorParser({
399
485
  }
400
486
  curQuery = curQuery.replace(equalRegex, '');
401
487
 
402
- // eg. user<{790274347f9b3a018c2cedee}> or user!<{790274347f9b3a018c2cedee}>
403
- const refRegex = /(?: |^)([^\s=\[\]<>{}]+?)!?<\{([0-9a-f]{24})\}>(?= |$)/g;
488
+ // eg. user<{790274347f9b3a018c2cedee}> or -user<{790274347f9b3a018c2cedee}>
489
+ const refRegex =
490
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)<\{([0-9a-f]{24})\}>(?=\s|\)|\}>|$)/g;
404
491
  const refMatch = curQuery.match(refRegex);
405
492
  if (refMatch) {
406
493
  selector.ref = [];
@@ -408,8 +495,8 @@ function selectorParser({
408
495
  for (let match of refMatch) {
409
496
  try {
410
497
  let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
411
- if (name.endsWith('!')) {
412
- selector['!ref'].push([name.slice(0, -1), value.slice(1, -1)]);
498
+ if (name.startsWith('-')) {
499
+ selector['!ref'].push([name.slice(1), value.slice(1, -1)]);
413
500
  } else {
414
501
  selector.ref.push([name, value.slice(1, -1)]);
415
502
  }
@@ -426,9 +513,9 @@ function selectorParser({
426
513
  }
427
514
  curQuery = curQuery.replace(refRegex, '');
428
515
 
429
- // eg. someArrayOfNumbers<10> or someObject!<"some string">
516
+ // eg. someArrayOfNumbers<10> or -someObject<"some string">
430
517
  const containRegex =
431
- /(?: |^)([^\s=\[\]<>{}]+?)!?(<(?:[^"][^>]*?|".*?[^\\]"))>(?= |$)/g;
518
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)(<(?:[^"][^>]*?|".*?[^\\]"))>(?=\s|\)|\}>|$)/g;
432
519
  const containMatch = curQuery.match(containRegex);
433
520
  if (containMatch) {
434
521
  selector.contain = [];
@@ -437,20 +524,17 @@ function selectorParser({
437
524
  try {
438
525
  let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
439
526
  try {
440
- if (name.endsWith('!')) {
527
+ if (name.startsWith('-')) {
441
528
  selector['!contain'].push([
442
- name.slice(0, -1),
529
+ name.slice(1),
443
530
  JSON.parse(unQuoteString(value)),
444
531
  ]);
445
532
  } else {
446
533
  selector.contain.push([name, JSON.parse(unQuoteString(value))]);
447
534
  }
448
535
  } catch (e: any) {
449
- if (name.endsWith('!')) {
450
- selector['!contain'].push([
451
- name.slice(0, -1),
452
- unQuoteString(value),
453
- ]);
536
+ if (name.startsWith('-')) {
537
+ selector['!contain'].push([name.slice(1), unQuoteString(value)]);
454
538
  } else {
455
539
  selector.contain.push([name, unQuoteString(value)]);
456
540
  }
@@ -468,9 +552,9 @@ function selectorParser({
468
552
  }
469
553
  curQuery = curQuery.replace(containRegex, '');
470
554
 
471
- // eg. name~/Hunter/ or name!~/hunter/i
555
+ // eg. name~/Hunter/ or -name~/hunter/i
472
556
  const posixRegex =
473
- /(?: |^)([^\s=\[\]<>{}]+?)!?~(\/\/|\/.*?[^\\]\/)i?(?= |$)/g;
557
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)~(\/\/|\/.*?[^\\]\/)i?(?=\s|\)|\}>|$)/g;
474
558
  const posixMatch = curQuery.match(posixRegex);
475
559
  if (posixMatch) {
476
560
  selector.match = [];
@@ -480,15 +564,15 @@ function selectorParser({
480
564
  for (let match of posixMatch) {
481
565
  try {
482
566
  let [name, value] = splitn(match.trim(), '~', 2);
483
- if (name.endsWith('!')) {
567
+ if (name.startsWith('-')) {
484
568
  if (value.endsWith('i')) {
485
569
  selector['!imatch'].push([
486
- name.slice(0, -1),
570
+ name.slice(1),
487
571
  value.replace(/^\/|\/i$/g, ''),
488
572
  ]);
489
573
  } else {
490
574
  selector['!match'].push([
491
- name.slice(0, -1),
575
+ name.slice(1),
492
576
  value.replace(/^\/|\/$/g, ''),
493
577
  ]);
494
578
  }
@@ -518,9 +602,9 @@ function selectorParser({
518
602
  }
519
603
  curQuery = curQuery.replace(posixRegex, '');
520
604
 
521
- // eg. name~Hunter or name!~"hunter"i
605
+ // eg. name~Hunter or -name~"hunter"i
522
606
  const likeRegex =
523
- /(?: |^)([^\s=\[\]<>{}]+?)!?~(""i?|".*?[^\\]"i?|[^ ]+)(?= |$)/g;
607
+ /(?:\s|^)-?([^-\s=\[\]<>{}()][^\s=\[\]<>{}()]*?)~(""i?|".*?[^\\]"i?|[^\s]+)(?=\s|\)|\}>|$)/g;
524
608
  const likeMatch = curQuery.match(likeRegex);
525
609
  if (likeMatch) {
526
610
  selector.like = [];
@@ -530,14 +614,14 @@ function selectorParser({
530
614
  for (let match of likeMatch) {
531
615
  try {
532
616
  let [name, value] = splitn(match.trim(), '~', 2);
533
- if (name.endsWith('!')) {
617
+ if (name.startsWith('-')) {
534
618
  if (value.endsWith('"i')) {
535
619
  selector['!ilike'].push([
536
- name.slice(0, -1),
620
+ name.slice(1),
537
621
  unQuoteString(value.slice(0, -1)),
538
622
  ]);
539
623
  } else {
540
- selector['!like'].push([name.slice(0, -1), unQuoteString(value)]);
624
+ selector['!like'].push([name.slice(1), unQuoteString(value)]);
541
625
  }
542
626
  } else {
543
627
  if (value.endsWith('"i')) {
@@ -565,16 +649,16 @@ function selectorParser({
565
649
  }
566
650
  curQuery = curQuery.replace(likeRegex, '');
567
651
 
568
- // eg. {790274347f9b3a018c2cedee} or {!790274347f9b3a018c2cedee}
569
- const guidRegex = /(?: |^)\{!?([0-9a-f]{24})\}(?= |$)/g;
652
+ // eg. {790274347f9b3a018c2cedee} or -{790274347f9b3a018c2cedee}
653
+ const guidRegex = /(?:\s|^)-?\{([0-9a-f]{24})\}(?=\s|\)|\}>|$)/g;
570
654
  const guidMatch = curQuery.match(guidRegex);
571
655
  if (guidMatch) {
572
656
  selector.guid = [];
573
657
  selector['!guid'] = [];
574
658
  for (let match of guidMatch) {
575
659
  try {
576
- let guid = match.trim().replace(/^\{|\}$/g, '');
577
- if (guid.startsWith('!')) {
660
+ let guid = match.trim().replace(/^(-?)\{|\}$/g, '$1');
661
+ if (guid.startsWith('-')) {
578
662
  selector['!guid'].push(guid.slice(1));
579
663
  } else {
580
664
  selector.guid.push(guid);
@@ -592,16 +676,16 @@ function selectorParser({
592
676
  }
593
677
  curQuery = curQuery.replace(guidRegex, '');
594
678
 
595
- // eg. [enabled] or [!defaultPrimaryGroup]
596
- const truthyRegex = /(?: |^)\[(!?[^\s=\[\]<>{}]+?)\](?= |$)/g;
679
+ // eg. [enabled] or -[defaultPrimaryGroup]
680
+ const truthyRegex = /(?:\s|^)-?\[([^\s=\[\]<>{}]+?)\](?=\s|\)|\}>|$)/g;
597
681
  const truthyMatch = curQuery.match(truthyRegex);
598
682
  if (truthyMatch) {
599
683
  selector.truthy = [];
600
684
  selector['!truthy'] = [];
601
685
  for (let match of truthyMatch) {
602
686
  try {
603
- let name = match.trim().replace(/^\[|\]$/g, '');
604
- if (name.startsWith('!')) {
687
+ let name = match.trim().replace(/^(-?)\[|\]$/g, '$1');
688
+ if (name.startsWith('-')) {
605
689
  selector['!truthy'].push(name.slice(1));
606
690
  } else {
607
691
  selector.truthy.push(name);
@@ -619,16 +703,16 @@ function selectorParser({
619
703
  }
620
704
  curQuery = curQuery.replace(truthyRegex, '');
621
705
 
622
- // eg. <archived> or <!archived>
623
- const tagRegex = /(?: |^)<(!?\w+)>(?= |$)/g;
706
+ // eg. <archived> or -<archived>
707
+ const tagRegex = /(?:\s|^)-?<(\w+)>(?=\s|\)|\}>|$)/g;
624
708
  const tagMatch = curQuery.match(tagRegex);
625
709
  if (tagMatch) {
626
710
  selector.tag = [];
627
711
  selector['!tag'] = [];
628
712
  for (let match of tagMatch) {
629
713
  try {
630
- let name = match.trim().replace(/^<|>$/g, '');
631
- if (name.startsWith('!')) {
714
+ let name = match.trim().replace(/^(-?)<|>$/g, '$1');
715
+ if (name.startsWith('-')) {
632
716
  selector['!tag'].push(name.slice(1));
633
717
  } else {
634
718
  selector.tag.push(name);
@@ -646,15 +730,21 @@ function selectorParser({
646
730
  }
647
731
  curQuery = curQuery.replace(tagRegex, '');
648
732
 
649
- // eg. cdate>15
650
- const gtRegex = /(?: |^)([^\s=\[\]<>{}]+?)>(-?\d+(?:\.\d+)?)(?= |$)/g;
733
+ // eg. cdate>15 or -cdate>15
734
+ const gtRegex =
735
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)>(-?\d+(?:\.\d+)?)(?=\s|\)|\}>|$)/g;
651
736
  const gtMatch = curQuery.match(gtRegex);
652
737
  if (gtMatch) {
653
738
  selector.gt = [];
739
+ selector['!gt'] = [];
654
740
  for (let match of gtMatch) {
655
741
  try {
656
742
  let [name, value] = splitn(match.trim(), '>', 2);
657
- selector.gt.push([name, Number(value)]);
743
+ if (name.startsWith('-')) {
744
+ selector['!gt'].push([name.slice(1), Number(value)]);
745
+ } else {
746
+ selector.gt.push([name, Number(value)]);
747
+ }
658
748
  } catch (e: any) {
659
749
  continue;
660
750
  }
@@ -662,24 +752,39 @@ function selectorParser({
662
752
  if (!selector.gt.length) {
663
753
  delete selector.gt;
664
754
  }
755
+ if (!selector['!gt'].length) {
756
+ delete selector['!gt'];
757
+ }
665
758
  }
666
759
  curQuery = curQuery.replace(gtRegex, '');
667
760
 
668
- // eg. cdate>yesterday or cdate>"2 days ago"
669
- const gtRelativeRegex = /(?: |^)([^\s=\[\]<>{}]+?)>(\w+|"[^"]+")(?= |$)/g;
761
+ // eg. cdate>yesterday or -cdate>"2 days ago"
762
+ const gtRelativeRegex =
763
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)>(\w+|"[^"]+")(?=\s|\)|\}>|$)/g;
670
764
  const gtRelativeMatch = curQuery.match(gtRelativeRegex);
671
765
  if (gtRelativeMatch) {
672
766
  if (selector.gt == null) {
673
767
  selector.gt = [];
674
768
  }
769
+ if (selector['!gt'] == null) {
770
+ selector['!gt'] = [];
771
+ }
675
772
  for (let match of gtRelativeMatch) {
676
773
  try {
677
774
  let [name, value] = splitn(match.trim(), '>', 2);
678
- (selector.gt as [string, null, string][]).push([
679
- name,
680
- null,
681
- value.replace(/"/g, ''),
682
- ]);
775
+ if (name.startsWith('-')) {
776
+ (selector['!gt'] as [string, null, string][]).push([
777
+ name.slice(1),
778
+ null,
779
+ value.replace(/"/g, ''),
780
+ ]);
781
+ } else {
782
+ (selector.gt as [string, null, string][]).push([
783
+ name,
784
+ null,
785
+ value.replace(/"/g, ''),
786
+ ]);
787
+ }
683
788
  } catch (e: any) {
684
789
  continue;
685
790
  }
@@ -687,18 +792,27 @@ function selectorParser({
687
792
  if (!selector.gt.length) {
688
793
  delete selector.gt;
689
794
  }
795
+ if (!selector['!gt'].length) {
796
+ delete selector['!gt'];
797
+ }
690
798
  }
691
799
  curQuery = curQuery.replace(gtRelativeRegex, '');
692
800
 
693
- // eg. cdate>=15
694
- const gteRegex = /(?: |^)([^\s=\[\]<>{}]+?)>=(-?\d+(?:\.\d+)?)(?= |$)/g;
801
+ // eg. cdate>=15 or -cdate>=15
802
+ const gteRegex =
803
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)>=(-?\d+(?:\.\d+)?)(?=\s|\)|\}>|$)/g;
695
804
  const gteMatch = curQuery.match(gteRegex);
696
805
  if (gteMatch) {
697
806
  selector.gte = [];
807
+ selector['!gte'] = [];
698
808
  for (let match of gteMatch) {
699
809
  try {
700
810
  let [name, value] = splitn(match.trim(), '>=', 2);
701
- selector.gte.push([name, Number(value)]);
811
+ if (name.startsWith('-')) {
812
+ selector['!gte'].push([name.slice(1), Number(value)]);
813
+ } else {
814
+ selector.gte.push([name, Number(value)]);
815
+ }
702
816
  } catch (e: any) {
703
817
  continue;
704
818
  }
@@ -706,24 +820,39 @@ function selectorParser({
706
820
  if (!selector.gte.length) {
707
821
  delete selector.gte;
708
822
  }
823
+ if (!selector['!gte'].length) {
824
+ delete selector['!gte'];
825
+ }
709
826
  }
710
827
  curQuery = curQuery.replace(gteRegex, '');
711
828
 
712
- // eg. cdate>=yesterday or cdate>="2 days ago"
713
- const gteRelativeRegex = /(?: |^)([^\s=\[\]<>{}]+?)>=(\w+|"[^"]+")(?= |$)/g;
829
+ // eg. cdate>=yesterday or -cdate>="2 days ago"
830
+ const gteRelativeRegex =
831
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)>=(\w+|"[^"]+")(?=\s|\)|\}>|$)/g;
714
832
  const gteRelativeMatch = curQuery.match(gteRelativeRegex);
715
833
  if (gteRelativeMatch) {
716
834
  if (selector.gte == null) {
717
835
  selector.gte = [];
718
836
  }
837
+ if (selector['!gte'] == null) {
838
+ selector['!gte'] = [];
839
+ }
719
840
  for (let match of gteRelativeMatch) {
720
841
  try {
721
842
  let [name, value] = splitn(match.trim(), '>=', 2);
722
- (selector.gte as [string, null, string][]).push([
723
- name,
724
- null,
725
- value.replace(/"/g, ''),
726
- ]);
843
+ if (name.startsWith('-')) {
844
+ (selector['!gte'] as [string, null, string][]).push([
845
+ name.slice(1),
846
+ null,
847
+ value.replace(/"/g, ''),
848
+ ]);
849
+ } else {
850
+ (selector.gte as [string, null, string][]).push([
851
+ name,
852
+ null,
853
+ value.replace(/"/g, ''),
854
+ ]);
855
+ }
727
856
  } catch (e: any) {
728
857
  continue;
729
858
  }
@@ -731,18 +860,27 @@ function selectorParser({
731
860
  if (!selector.gte.length) {
732
861
  delete selector.gte;
733
862
  }
863
+ if (!selector['!gte'].length) {
864
+ delete selector['!gte'];
865
+ }
734
866
  }
735
867
  curQuery = curQuery.replace(gteRelativeRegex, '');
736
868
 
737
- // eg. cdate<15
738
- const ltRegex = /(?: |^)([^\s=\[\]<>{}]+?)<(-?\d+(?:\.\d+)?)(?= |$)/g;
869
+ // eg. cdate<15 or -cdate<15
870
+ const ltRegex =
871
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)<(-?\d+(?:\.\d+)?)(?=\s|\)|\}>|$)/g;
739
872
  const ltMatch = curQuery.match(ltRegex);
740
873
  if (ltMatch) {
741
874
  selector.lt = [];
875
+ selector['!lt'] = [];
742
876
  for (let match of ltMatch) {
743
877
  try {
744
878
  let [name, value] = splitn(match.trim(), '<', 2);
745
- selector.lt.push([name, Number(value)]);
879
+ if (name.startsWith('-')) {
880
+ selector['!lt'].push([name.slice(1), Number(value)]);
881
+ } else {
882
+ selector.lt.push([name, Number(value)]);
883
+ }
746
884
  } catch (e: any) {
747
885
  continue;
748
886
  }
@@ -750,24 +888,39 @@ function selectorParser({
750
888
  if (!selector.lt.length) {
751
889
  delete selector.lt;
752
890
  }
891
+ if (!selector['!lt'].length) {
892
+ delete selector['!lt'];
893
+ }
753
894
  }
754
895
  curQuery = curQuery.replace(ltRegex, '');
755
896
 
756
- // eg. cdate<yesterday or cdate<"2 days ago"
757
- const ltRelativeRegex = /(?: |^)([^\s=\[\]<>{}]+?)<(\w+|"[^"]+")(?= |$)/g;
897
+ // eg. cdate<yesterday or -cdate<"2 days ago"
898
+ const ltRelativeRegex =
899
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)<(\w+|"[^"]+")(?=\s|\)|\}>|$)/g;
758
900
  const ltRelativeMatch = curQuery.match(ltRelativeRegex);
759
901
  if (ltRelativeMatch) {
760
902
  if (selector.lt == null) {
761
903
  selector.lt = [];
762
904
  }
905
+ if (selector['!lt'] == null) {
906
+ selector['!lt'] = [];
907
+ }
763
908
  for (let match of ltRelativeMatch) {
764
909
  try {
765
910
  let [name, value] = splitn(match.trim(), '<', 2);
766
- (selector.lt as [string, null, string][]).push([
767
- name,
768
- null,
769
- value.replace(/"/g, ''),
770
- ]);
911
+ if (name.startsWith('-')) {
912
+ (selector['!lt'] as [string, null, string][]).push([
913
+ name.slice(1),
914
+ null,
915
+ value.replace(/"/g, ''),
916
+ ]);
917
+ } else {
918
+ (selector.lt as [string, null, string][]).push([
919
+ name,
920
+ null,
921
+ value.replace(/"/g, ''),
922
+ ]);
923
+ }
771
924
  } catch (e: any) {
772
925
  continue;
773
926
  }
@@ -775,18 +928,27 @@ function selectorParser({
775
928
  if (!selector.lt.length) {
776
929
  delete selector.lt;
777
930
  }
931
+ if (!selector['!lt'].length) {
932
+ delete selector['!lt'];
933
+ }
778
934
  }
779
935
  curQuery = curQuery.replace(ltRelativeRegex, '');
780
936
 
781
- // eg. cdate<=15
782
- const lteRegex = /(?: |^)([^\s=\[\]<>{}]+?)<=(-?\d+(?:\.\d+)?)(?= |$)/g;
937
+ // eg. cdate<=15 or -cdate<=15
938
+ const lteRegex =
939
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)<=(-?\d+(?:\.\d+)?)(?=\s|\)|\}>|$)/g;
783
940
  const lteMatch = curQuery.match(lteRegex);
784
941
  if (lteMatch) {
785
942
  selector.lte = [];
943
+ selector['!lte'] = [];
786
944
  for (let match of lteMatch) {
787
945
  try {
788
946
  let [name, value] = splitn(match.trim(), '<=', 2);
789
- selector.lte.push([name, Number(value)]);
947
+ if (name.startsWith('-')) {
948
+ selector['!lte'].push([name.slice(1), Number(value)]);
949
+ } else {
950
+ selector.lte.push([name, Number(value)]);
951
+ }
790
952
  } catch (e: any) {
791
953
  continue;
792
954
  }
@@ -794,24 +956,39 @@ function selectorParser({
794
956
  if (!selector.lte.length) {
795
957
  delete selector.lte;
796
958
  }
959
+ if (!selector['!lte'].length) {
960
+ delete selector['!lte'];
961
+ }
797
962
  }
798
963
  curQuery = curQuery.replace(lteRegex, '');
799
964
 
800
- // eg. cdate<=yesterday or cdate<="2 days ago"
801
- const lteRelativeRegex = /(?: |^)([^\s=\[\]<>{}]+?)<=(\w+|"[^"]+")(?= |$)/g;
965
+ // eg. cdate<=yesterday or -cdate<="2 days ago"
966
+ const lteRelativeRegex =
967
+ /(?:\s|^)-?([^\s=\[\]<>{}]+?)<=(\w+|"[^"]+")(?=\s|\)|\}>|$)/g;
802
968
  const lteRelativeMatch = curQuery.match(lteRelativeRegex);
803
969
  if (lteRelativeMatch) {
804
970
  if (selector.lte == null) {
805
971
  selector.lte = [];
806
972
  }
973
+ if (selector['!lte'] == null) {
974
+ selector['!lte'] = [];
975
+ }
807
976
  for (let match of lteRelativeMatch) {
808
977
  try {
809
978
  let [name, value] = splitn(match.trim(), '<=', 2);
810
- (selector.lte as [string, null, string][]).push([
811
- name,
812
- null,
813
- value.replace(/"/g, ''),
814
- ]);
979
+ if (name.startsWith('-')) {
980
+ (selector['!lte'] as [string, null, string][]).push([
981
+ name.slice(1),
982
+ null,
983
+ value.replace(/"/g, ''),
984
+ ]);
985
+ } else {
986
+ (selector.lte as [string, null, string][]).push([
987
+ name,
988
+ null,
989
+ value.replace(/"/g, ''),
990
+ ]);
991
+ }
815
992
  } catch (e: any) {
816
993
  continue;
817
994
  }
@@ -819,6 +996,9 @@ function selectorParser({
819
996
  if (!selector.lte.length) {
820
997
  delete selector.lte;
821
998
  }
999
+ if (!selector['!lte'].length) {
1000
+ delete selector['!lte'];
1001
+ }
822
1002
  }
823
1003
  curQuery = curQuery.replace(lteRelativeRegex, '');
824
1004