@nymphjs/query-parser 1.0.0-beta.121 → 1.0.0-beta.123
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/CHANGELOG.md +10 -0
- package/README.md +52 -48
- package/dist/queryParser.js +285 -120
- package/dist/queryParser.js.map +1 -1
- package/dist/queryParser.test.js +402 -29
- package/dist/queryParser.test.js.map +1 -1
- package/package.json +8 -5
- package/src/queryParser.test.ts +454 -29
- package/src/queryParser.ts +300 -120
package/src/queryParser.ts
CHANGED
|
@@ -158,14 +158,14 @@ function selectorsParser({
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
if (options) {
|
|
161
|
-
const limitRegex = /(
|
|
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 = /(
|
|
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
|
-
/(
|
|
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 = /(
|
|
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
|
-
//
|
|
237
|
-
|
|
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.
|
|
246
|
-
selector['!search'].push([name.slice(
|
|
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.
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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()
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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.
|
|
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.
|
|
295
|
-
delete selector.
|
|
379
|
+
if (selector.search == null || !selector.search.length) {
|
|
380
|
+
delete selector.search;
|
|
296
381
|
}
|
|
297
|
-
if (!selector['!
|
|
298
|
-
delete selector['!
|
|
382
|
+
if (selector['!search'] == null || !selector['!search'].length) {
|
|
383
|
+
delete selector['!search'];
|
|
299
384
|
}
|
|
300
385
|
}
|
|
301
|
-
curQuery = curQuery.replace(
|
|
386
|
+
curQuery = curQuery.replace(searchColonRegex, '');
|
|
302
387
|
|
|
303
388
|
// eg. someArray=[1,2] or someObject={"prop":"some value"}
|
|
304
|
-
const equalJsonRegex =
|
|
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.
|
|
407
|
+
if (name.startsWith('-')) {
|
|
322
408
|
(selector['!equal'] as [string, any][]).unshift([
|
|
323
|
-
name.slice(
|
|
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
|
-
/(
|
|
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.
|
|
454
|
+
if (name.startsWith('-')) {
|
|
369
455
|
(selector['!equal'] as [string, any][]).push([
|
|
370
|
-
name.slice(
|
|
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.
|
|
463
|
+
if (name.startsWith('-')) {
|
|
378
464
|
(selector['!equal'] as [string, any][]).push([
|
|
379
|
-
name.slice(
|
|
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
|
|
403
|
-
const refRegex =
|
|
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.
|
|
412
|
-
selector['!ref'].push([name.slice(
|
|
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
|
|
516
|
+
// eg. someArrayOfNumbers<10> or -someObject<"some string">
|
|
430
517
|
const containRegex =
|
|
431
|
-
/(
|
|
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.
|
|
527
|
+
if (name.startsWith('-')) {
|
|
441
528
|
selector['!contain'].push([
|
|
442
|
-
name.slice(
|
|
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.
|
|
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
|
|
555
|
+
// eg. name~/Hunter/ or -name~/hunter/i
|
|
472
556
|
const posixRegex =
|
|
473
|
-
/(
|
|
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.
|
|
567
|
+
if (name.startsWith('-')) {
|
|
484
568
|
if (value.endsWith('i')) {
|
|
485
569
|
selector['!imatch'].push([
|
|
486
|
-
name.slice(
|
|
570
|
+
name.slice(1),
|
|
487
571
|
value.replace(/^\/|\/i$/g, ''),
|
|
488
572
|
]);
|
|
489
573
|
} else {
|
|
490
574
|
selector['!match'].push([
|
|
491
|
-
name.slice(
|
|
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
|
|
605
|
+
// eg. name~Hunter or -name~"hunter"i
|
|
522
606
|
const likeRegex =
|
|
523
|
-
/(
|
|
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.
|
|
617
|
+
if (name.startsWith('-')) {
|
|
534
618
|
if (value.endsWith('"i')) {
|
|
535
619
|
selector['!ilike'].push([
|
|
536
|
-
name.slice(
|
|
620
|
+
name.slice(1),
|
|
537
621
|
unQuoteString(value.slice(0, -1)),
|
|
538
622
|
]);
|
|
539
623
|
} else {
|
|
540
|
-
selector['!like'].push([name.slice(
|
|
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 {
|
|
569
|
-
const guidRegex = /(
|
|
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(
|
|
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 [
|
|
596
|
-
const truthyRegex = /(
|
|
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(
|
|
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
|
|
623
|
-
const tagRegex = /(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
(
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
(
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
(
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
|