@briza/illogical 1.5.5 → 1.5.8

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/lib/illogical.js CHANGED
@@ -2,7 +2,22 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ function _toPrimitive(t, r) {
6
+ if ("object" != typeof t || !t) return t;
7
+ var e = t[Symbol.toPrimitive];
8
+ if (void 0 !== e) {
9
+ var i = e.call(t, r || "default");
10
+ if ("object" != typeof i) return i;
11
+ throw new TypeError("@@toPrimitive must return a primitive value.");
12
+ }
13
+ return ("string" === r ? String : Number)(t);
14
+ }
15
+ function _toPropertyKey(t) {
16
+ var i = _toPrimitive(t, "string");
17
+ return "symbol" == typeof i ? i : String(i);
18
+ }
5
19
  function _defineProperty(obj, key, value) {
20
+ key = _toPropertyKey(key);
6
21
  if (key in obj) {
7
22
  Object.defineProperty(obj, key, {
8
23
  value: value,
@@ -13,7 +28,6 @@ function _defineProperty(obj, key, value) {
13
28
  } else {
14
29
  obj[key] = value;
15
30
  }
16
-
17
31
  return obj;
18
32
  }
19
33
 
@@ -24,45 +38,43 @@ function _defineProperty(obj, key, value) {
24
38
  function isNumber(value) {
25
39
  return typeof value === 'number' && isFinite(value);
26
40
  }
41
+
27
42
  /**
28
43
  * Is string type predicate.
29
44
  * @param value Tested value.
30
45
  */
31
-
32
46
  function isString(value) {
33
47
  return typeof value === 'string' || value instanceof String;
34
48
  }
49
+
35
50
  /**
36
51
  * Is Object
37
52
  * @param value tested value result of the test
38
53
  */
39
-
40
54
  function isObject(value) {
41
55
  if (value === null || value === undefined) {
42
56
  return false;
43
57
  }
44
-
45
58
  if (typeof value !== 'object' || (value === null || value === void 0 ? void 0 : value.constructor) !== Object) {
46
59
  return false;
47
60
  }
48
-
49
61
  return true;
50
62
  }
63
+
51
64
  /**
52
65
  * Is Boolean predicate.
53
66
  * @param value tested value.
54
67
  * @return result of the test
55
68
  */
56
-
57
69
  function isBoolean(value) {
58
70
  return typeof value === 'boolean';
59
71
  }
72
+
60
73
  /**
61
74
  * Check if a value is a an Evaluable
62
75
  * @param {Result | Evaluable} value value to check if is Evaluable
63
76
  * @returns {Evaluable}
64
77
  */
65
-
66
78
  function isEvaluable(value) {
67
79
  return typeof value === 'object' && value !== null && !Array.isArray(value) && typeof value.evaluate === 'function' && typeof value.simplify === 'function' && typeof value.serialize === 'function' && typeof value.toString === 'function';
68
80
  }
@@ -80,15 +92,16 @@ function isEvaluable(value) {
80
92
  /**
81
93
  * Evaluation result
82
94
  */
83
- let EvaluableType;
84
- /**
85
- * Evaluable
86
- */
87
95
 
88
- (function (EvaluableType) {
96
+ let EvaluableType = /*#__PURE__*/function (EvaluableType) {
89
97
  EvaluableType["Operand"] = "Operand";
90
98
  EvaluableType["Expression"] = "Expression";
91
- })(EvaluableType || (EvaluableType = {}));
99
+ return EvaluableType;
100
+ }({});
101
+
102
+ /**
103
+ * Evaluable
104
+ */
92
105
 
93
106
  /**
94
107
  * Abstract comparison expression
@@ -105,26 +118,24 @@ class Comparison {
105
118
  this.operatorSymbol = operatorSymbol;
106
119
  this.left = left;
107
120
  this.right = right;
108
-
109
121
  _defineProperty(this, "type", EvaluableType.Expression);
110
122
  }
123
+
111
124
  /**
112
125
  * {@link Evaluable.evaluate}
113
126
  */
114
-
115
-
116
127
  evaluate(ctx) {
117
128
  return this.comparison(this.left.evaluate(ctx), this.right.evaluate(ctx));
118
129
  }
130
+
119
131
  /**
120
132
  * Get the strict representation of the expression.
121
133
  * @return {string}
122
134
  */
123
-
124
-
125
135
  toString() {
126
136
  return `(${this.left.toString()} ${this.operator} ${this.right.toString()})`;
127
137
  }
138
+
128
139
  /**
129
140
  * Compares left and right operands evaluated values.
130
141
  * @param {Result} left left operand result value
@@ -132,450 +143,469 @@ class Comparison {
132
143
  * @returns {boolean}
133
144
  */
134
145
 
135
-
136
146
  /**
137
147
  * {@link Evaluable.simplify}
138
148
  */
139
- simplify() {
140
- const left = this.left.simplify(...arguments);
141
- const right = this.right.simplify(...arguments);
142
-
149
+ simplify(...args) {
150
+ const left = this.left.simplify(...args);
151
+ const right = this.right.simplify(...args);
143
152
  if (!isEvaluable(left) && !isEvaluable(right)) {
144
153
  return this.comparison(left, right);
145
154
  }
146
-
147
155
  return this;
148
156
  }
157
+
149
158
  /**
150
159
  * {@link Evaluable.serialize}
151
160
  */
152
-
153
-
154
161
  serialize(options) {
155
162
  const {
156
163
  operatorMapping
157
164
  } = options;
158
165
  const operator = operatorMapping.get(this.operatorSymbol);
159
-
160
166
  if (operator === undefined) {
161
167
  throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
162
168
  }
163
-
164
169
  return [operator, this.left.serialize(options), this.right.serialize(options)];
165
170
  }
166
-
167
171
  }
168
172
 
173
+ // Operator key
169
174
  const OPERATOR$h = Symbol('EQ');
175
+
170
176
  /**
171
177
  * Equal comparison expression
172
178
  */
173
-
174
179
  class Equal extends Comparison {
175
180
  /**
176
181
  * @constructor
177
182
  * @param {Evaluable} left Left operand.
178
183
  * @param {Evaluable} right Right operand.
179
184
  */
185
+
180
186
  constructor(left, right) {
181
187
  if (arguments.length !== 2) {
182
188
  throw new Error('comparison expression expects left and right operands');
183
189
  }
184
-
185
190
  super('==', OPERATOR$h, left, right);
186
191
  }
192
+
187
193
  /**
188
194
  * {@link Comparison.comparison}
189
195
  */
190
-
191
-
192
196
  comparison(left, right) {
193
197
  return left === right;
194
198
  }
195
-
196
199
  }
197
200
 
201
+ /**
202
+ * Convert a value to number if possible, otherwise return undefined
203
+ * @param value value to be converted to number
204
+ */
205
+ const toNumber = value => {
206
+ const isValueNumber = isNumber(value);
207
+ if (isValueNumber) {
208
+ return value;
209
+ } else if (isString(value)) {
210
+ if (value.match(/^\d+\.\d+$/)) {
211
+ return parseFloat(value);
212
+ } else if (value.match(/^0$|^[1-9]\d*$/)) {
213
+ return parseInt(value);
214
+ }
215
+ }
216
+ return undefined;
217
+ };
218
+
219
+ /**
220
+ * Convert a value to string if possible, otherwise return undefined
221
+ * @param value value to be converted to string
222
+ */
223
+ const toString = value => {
224
+ if (isNumber(value)) {
225
+ return `${value}`;
226
+ } else if (isString(value)) {
227
+ return value;
228
+ }
229
+ return undefined;
230
+ };
231
+ /**
232
+ * Convert a value to number if it's type is string, otherwise return NaN
233
+ * @param value value to be converted to number
234
+ */
235
+ const toDateNumber = value => {
236
+ if (isString(value)) {
237
+ return Date.parse(value);
238
+ }
239
+ return NaN;
240
+ };
241
+
242
+ // Operator key
198
243
  const OPERATOR$g = Symbol('GE');
244
+
199
245
  /**
200
246
  * Greater than or equal comparison expression
201
247
  */
202
-
203
248
  class GreaterThanOrEqual extends Comparison {
204
249
  /**
205
250
  * @constructor
206
251
  * @param {Evaluable} left Left operand.
207
252
  * @param {Evaluable} right Right operand.
208
253
  */
254
+
209
255
  constructor(left, right) {
210
256
  if (arguments.length !== 2) {
211
257
  throw new Error('comparison expression expects left and right operands');
212
258
  }
213
-
214
259
  super('>=', OPERATOR$g, left, right);
215
260
  }
261
+
216
262
  /**
217
263
  * {@link Comparison.comparison}
218
264
  */
219
-
220
-
221
265
  comparison(left, right) {
222
266
  if (isNumber(left) && isNumber(right)) {
223
267
  return left >= right;
224
268
  }
225
-
269
+ const leftDate = toDateNumber(left),
270
+ rightDate = toDateNumber(right);
271
+ if (leftDate && rightDate) {
272
+ return leftDate >= rightDate;
273
+ }
226
274
  return false;
227
275
  }
228
-
229
276
  }
230
277
 
278
+ // Operator key
231
279
  const OPERATOR$f = Symbol('GT');
280
+
232
281
  /**
233
282
  * Greater than comparison expression
234
283
  */
235
-
236
284
  class GreaterThan extends Comparison {
237
285
  /**
238
286
  * @constructor
239
287
  * @param {Evaluable} left Left operand.
240
288
  * @param {Evaluable} right Right operand.
241
289
  */
290
+
242
291
  constructor(left, right) {
243
292
  if (arguments.length !== 2) {
244
293
  throw new Error('comparison expression expects left and right operands');
245
294
  }
246
-
247
295
  super('>', OPERATOR$f, left, right);
248
296
  }
297
+
249
298
  /**
250
299
  * {@link Comparison.comparison}
251
300
  */
252
-
253
-
254
301
  comparison(left, right) {
255
302
  if (isNumber(left) && isNumber(right)) {
256
303
  return left > right;
257
304
  }
258
-
305
+ const leftDate = toDateNumber(left),
306
+ rightDate = toDateNumber(right);
307
+ if (leftDate && rightDate) {
308
+ return leftDate > rightDate;
309
+ }
259
310
  return false;
260
311
  }
261
-
262
312
  }
263
313
 
314
+ // Operator key
264
315
  const OPERATOR$e = Symbol('IN');
316
+
265
317
  /**
266
318
  * In comparison expression
267
319
  */
268
-
269
320
  class In extends Comparison {
270
321
  /**
271
322
  * @constructor
272
323
  * @param {Evaluable} left Left operand.
273
324
  * @param {Evaluable} right Right operand.
274
325
  */
326
+
275
327
  constructor(left, right) {
276
328
  if (arguments.length !== 2) {
277
329
  throw new Error('comparison expression expects left and right operands');
278
330
  }
279
-
280
331
  super('in', OPERATOR$e, left, right);
281
332
  }
333
+
282
334
  /**
283
335
  * {@link Comparison.comparison}
284
336
  */
285
-
286
-
287
337
  comparison(left, right) {
288
338
  if (left === undefined || left === null || right === undefined || right === null) {
289
339
  return false;
290
340
  }
291
-
292
341
  const leftArray = Array.isArray(left);
293
342
  const rightArray = Array.isArray(right);
294
-
295
343
  if (leftArray && rightArray) {
296
344
  throw new Error('invalid IN expression, both operands are array');
297
345
  }
298
-
299
346
  if (!leftArray && !rightArray) {
300
347
  throw new Error('invalid IN expression, non of the operands is array');
301
348
  }
302
-
303
349
  if (leftArray) {
304
350
  return left.indexOf(right) > -1;
305
351
  }
306
-
307
352
  return right.indexOf(left) > -1;
308
353
  }
354
+
309
355
  /**
310
356
  * Get the strict representation of the expression.
311
357
  * @return {string}
312
358
  */
313
-
314
-
315
359
  toString() {
316
360
  const left = this.left.toString();
317
361
  const right = this.right.toString();
318
-
319
362
  if (left.startsWith('[')) {
320
363
  return `(${right} ${this.operator} ${left})`;
321
364
  }
322
-
323
365
  return `(${left} ${this.operator} ${right})`;
324
366
  }
325
-
326
367
  }
327
368
 
369
+ // Operator key
328
370
  const OPERATOR$d = Symbol('LE');
371
+
329
372
  /**
330
373
  * Less than or equal comparison expression
331
374
  */
332
-
333
375
  class LessThanOrEqual extends Comparison {
334
376
  /**
335
377
  * @constructor
336
378
  * @param {Evaluable} left Left operand.
337
379
  * @param {Evaluable} right Right operand.
338
380
  */
381
+
339
382
  constructor(left, right) {
340
383
  if (arguments.length !== 2) {
341
384
  throw new Error('comparison expression expects left and right operands');
342
385
  }
343
-
344
386
  super('<=', OPERATOR$d, left, right);
345
387
  }
388
+
346
389
  /**
347
390
  * {@link Comparison.comparison}
348
391
  */
349
-
350
-
351
392
  comparison(left, right) {
352
393
  if (isNumber(left) && isNumber(right)) {
353
394
  return left <= right;
354
395
  }
355
-
396
+ const leftDate = toDateNumber(left),
397
+ rightDate = toDateNumber(right);
398
+ if (leftDate && rightDate) {
399
+ return leftDate <= rightDate;
400
+ }
356
401
  return false;
357
402
  }
358
-
359
403
  }
360
404
 
405
+ // Operator key
361
406
  const OPERATOR$c = Symbol('LT');
407
+
362
408
  /**
363
409
  * Less than comparison expression
364
410
  */
365
-
366
411
  class LessThan extends Comparison {
367
412
  /**
368
413
  * @constructor
369
414
  * @param {Evaluable} left Left operand.
370
415
  * @param {Evaluable} right Right operand.
371
416
  */
417
+
372
418
  constructor(left, right) {
373
419
  if (arguments.length !== 2) {
374
420
  throw new Error('comparison expression expects left and right operands');
375
421
  }
376
-
377
422
  super('<', OPERATOR$c, left, right);
378
423
  }
424
+
379
425
  /**
380
426
  * {@link Comparison.comparison}
381
427
  */
382
-
383
-
384
428
  comparison(left, right) {
385
429
  if (isNumber(left) && isNumber(right)) {
386
430
  return left < right;
387
431
  }
388
-
432
+ const leftDate = toDateNumber(left),
433
+ rightDate = toDateNumber(right);
434
+ if (leftDate && rightDate) {
435
+ return leftDate < rightDate;
436
+ }
389
437
  return false;
390
438
  }
391
-
392
439
  }
393
440
 
441
+ // Operator key
394
442
  const OPERATOR$b = Symbol('NE');
443
+
395
444
  /**
396
445
  * Not equal comparison expression
397
446
  */
398
-
399
447
  class NotEqual extends Comparison {
400
448
  /**
401
449
  * @constructor
402
450
  * @param {Evaluable} left Left operand.
403
451
  * @param {Evaluable} right Right operand.
404
452
  */
453
+
405
454
  constructor(left, right) {
406
455
  if (arguments.length !== 2) {
407
456
  throw new Error('comparison expression expects left and right operands');
408
457
  }
409
-
410
458
  super('!=', OPERATOR$b, left, right);
411
459
  }
460
+
412
461
  /**
413
462
  * {@link Comparison.comparison}
414
463
  */
415
-
416
-
417
464
  comparison(left, right) {
418
465
  return left !== right;
419
466
  }
420
-
421
467
  }
422
468
 
469
+ // Operator key
423
470
  const OPERATOR$a = Symbol('NOT IN');
471
+
424
472
  /**
425
473
  * Not in comparison expression
426
474
  */
427
-
428
475
  class NotIn extends Comparison {
429
476
  /**
430
477
  * @constructor
431
478
  * @param {Evaluable} left Left operand.
432
479
  * @param {Evaluable} right Right operand.
433
480
  */
481
+
434
482
  constructor(left, right) {
435
483
  if (arguments.length !== 2) {
436
484
  throw new Error('comparison expression expects left and right operands');
437
485
  }
438
-
439
486
  super('not in', OPERATOR$a, left, right);
440
487
  }
488
+
441
489
  /**
442
490
  * {@link Comparison.comparison}
443
491
  */
444
-
445
-
446
492
  comparison(left, right) {
447
493
  if (left === undefined || left === null || right === undefined || right === null) {
448
494
  return true;
449
495
  }
450
-
451
496
  const leftArray = Array.isArray(left);
452
497
  const rightArray = Array.isArray(right);
453
-
454
498
  if (leftArray && rightArray) {
455
499
  throw new Error('invalid NOT IN expression, both operands are array');
456
500
  }
457
-
458
501
  if (!leftArray && !rightArray) {
459
502
  throw new Error('invalid NOT IN expression, one operand must be array');
460
503
  }
461
-
462
504
  if (leftArray) {
463
505
  return left.indexOf(right) === -1;
464
506
  }
465
-
466
507
  return right.indexOf(left) === -1;
467
508
  }
509
+
468
510
  /**
469
511
  * Get the strict representation of the expression
470
512
  * @return {string}
471
513
  */
472
-
473
-
474
514
  toString() {
475
515
  const left = this.left.toString();
476
516
  const right = this.right.toString();
477
-
478
517
  if (left.startsWith('[')) {
479
518
  return `(${right} ${this.operator} ${left})`;
480
519
  }
481
-
482
520
  return `(${left} ${this.operator} ${right})`;
483
521
  }
484
-
485
522
  }
486
523
 
524
+ // Operator key
487
525
  const OPERATOR$9 = Symbol('OVERLAP');
526
+
488
527
  /**
489
528
  * Overlap comparison expression
490
529
  */
491
-
492
530
  class Overlap extends Comparison {
493
531
  /**
494
532
  * @constructor
495
533
  * @param {Evaluable} left Left operand.
496
534
  * @param {Evaluable} right Right operand.
497
535
  */
536
+
498
537
  constructor(left, right) {
499
538
  if (arguments.length !== 2) {
500
539
  throw new Error('comparison expression expects left and right operands');
501
540
  }
502
-
503
541
  super('overlap', OPERATOR$9, left, right);
504
542
  }
543
+
505
544
  /**
506
545
  * {@link Comparison.comparison}
507
546
  */
508
-
509
-
510
547
  comparison(left, right) {
511
548
  if (left === undefined || left === null || right === undefined || right === null) {
512
549
  return false;
513
550
  }
514
-
515
551
  if (!Array.isArray(left) || !Array.isArray(right)) {
516
552
  throw new Error('invalid OVERLAP expression, both operands must be array');
517
553
  }
518
-
519
554
  const leftArray = left;
520
555
  const rightArray = right;
521
556
  return leftArray.some(element => rightArray.includes(element));
522
557
  }
558
+
523
559
  /**
524
560
  * Get the strict representation of the expression.
525
561
  * @return {string}
526
562
  */
527
-
528
-
529
563
  toString() {
530
564
  const left = this.left.toString();
531
565
  const right = this.right.toString();
532
566
  return `(${left} ${this.operator} ${right})`;
533
567
  }
534
-
535
568
  }
536
569
 
570
+ // Operator key
537
571
  const OPERATOR$8 = Symbol('PREFIX');
572
+
538
573
  /**
539
574
  * Prefix comparison expression
540
575
  */
541
-
542
576
  class Prefix extends Comparison {
543
577
  /**
544
578
  * @constructor
545
579
  * @param {Evaluable} left Left operand.
546
580
  * @param {Evaluable} right Right operand.
547
581
  */
582
+
548
583
  constructor(left, right) {
549
584
  if (arguments.length !== 2) {
550
585
  throw new Error('comparison expression expects left and right operands');
551
586
  }
552
-
553
587
  super('prefix', OPERATOR$8, left, right);
554
588
  }
589
+
555
590
  /**
556
591
  * {@link Comparison.comparison}
557
592
  */
558
-
559
-
560
593
  comparison(left, right) {
561
594
  if (isString(left) === false || isString(right) === false) {
562
595
  return false;
563
596
  }
564
-
565
597
  return right.startsWith(left);
566
598
  }
599
+
567
600
  /**
568
601
  * Get the strict representation of the expression.
569
602
  * @return {string}
570
603
  */
571
-
572
-
573
604
  toString() {
574
605
  const left = this.left.toString();
575
606
  const right = this.right.toString();
576
607
  return `(<${left}>${right})`;
577
608
  }
578
-
579
609
  }
580
610
 
581
611
  /**
@@ -585,14 +615,21 @@ class Operand {
585
615
  constructor() {
586
616
  _defineProperty(this, "type", EvaluableType.Operand);
587
617
  }
588
-
618
+ /**
619
+ * {@link Evaluable.evaluate}
620
+ */
621
+ /**
622
+ * {@link Evaluable.simplify}
623
+ */
624
+ /**
625
+ * {@link Evaluable.serialize}
626
+ */
589
627
  /**
590
628
  * Get the strict representation.
591
629
  */
592
630
  toString() {
593
631
  throw new Error('not implemented exception');
594
632
  }
595
-
596
633
  }
597
634
 
598
635
  /**
@@ -600,19 +637,16 @@ class Operand {
600
637
  * @param {Result} value
601
638
  * @return {string}
602
639
  */
603
-
604
640
  function printValue(value) {
605
641
  if (isString(value)) {
606
642
  return `"${value}"`;
607
643
  }
608
-
609
644
  return `${value}`;
610
645
  }
646
+
611
647
  /**
612
648
  * Static value operand
613
649
  */
614
-
615
-
616
650
  class Value extends Operand {
617
651
  /**
618
652
  * @constructor
@@ -622,195 +656,174 @@ class Value extends Operand {
622
656
  if (Array.isArray(value)) {
623
657
  throw new Error('deprecated direct usage of array, please use Collection operand');
624
658
  }
625
-
626
659
  super();
627
-
628
660
  _defineProperty(this, "value", void 0);
629
-
630
661
  this.value = value;
631
662
  }
663
+
632
664
  /**
633
665
  * {@link Evaluable.evaluate}
634
666
  */
635
-
636
-
637
667
  evaluate() {
638
668
  return this.value;
639
669
  }
670
+
640
671
  /**
641
672
  * {@link Evaluable.simplify}
642
673
  */
643
-
644
-
645
674
  simplify() {
646
675
  return this.value;
647
676
  }
677
+
648
678
  /**
649
679
  * {@link Evaluable.serialize}
650
680
  */
651
-
652
-
653
681
  serialize() {
654
682
  return this.value;
655
683
  }
684
+
656
685
  /**
657
686
  * Get the strict representation of the operand.
658
687
  * @return {string}
659
688
  */
660
-
661
-
662
689
  toString() {
663
690
  return printValue(this.value);
664
691
  }
665
-
666
692
  }
667
693
 
694
+ // Operator key
668
695
  const OPERATOR$7 = Symbol('PRESENT');
696
+
669
697
  /**
670
698
  * Present comparison expression
671
699
  */
672
-
673
700
  class Present extends Comparison {
674
701
  /**
675
702
  * @constructor
676
703
  * @param {Evaluable} operand
677
704
  */
705
+
678
706
  constructor(operand) {
679
707
  if (arguments.length !== 1) {
680
708
  throw new Error('comparison expression PRESENT expects exactly one operand');
681
709
  }
682
-
683
710
  super('PRESENT', OPERATOR$7, operand, new Value(true));
684
711
  }
712
+
685
713
  /**
686
714
  * {@link Comparison.comparison}
687
715
  */
688
-
689
-
690
716
  comparison(left) {
691
717
  return left !== undefined && left !== null;
692
718
  }
719
+
693
720
  /**
694
721
  * Get the strict representation of the expression.
695
722
  * @return {string}
696
723
  */
697
-
698
-
699
724
  toString() {
700
725
  return `(${this.left.toString()} is ${this.operator})`;
701
726
  }
702
-
703
727
  serialize(options) {
704
728
  const {
705
729
  operatorMapping
706
730
  } = options;
707
731
  const operator = operatorMapping.get(this.operatorSymbol);
708
-
709
732
  if (operator === undefined) {
710
733
  throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
711
734
  }
712
-
713
735
  return [operator, this.left.serialize(options)];
714
736
  }
715
-
716
737
  }
717
738
 
739
+ // Operator key
718
740
  const OPERATOR$6 = Symbol('PREFIX');
741
+
719
742
  /**
720
743
  * Suffix comparison expression
721
744
  */
722
-
723
745
  class Suffix extends Comparison {
724
746
  /**
725
747
  * @constructor
726
748
  * @param {Evaluable} left Left operand.
727
749
  * @param {Evaluable} right Right operand.
728
750
  */
751
+
729
752
  constructor(left, right) {
730
753
  if (arguments.length !== 2) {
731
754
  throw new Error('comparison expression expects left and right operands');
732
755
  }
733
-
734
756
  super('suffix', OPERATOR$6, left, right);
735
757
  }
758
+
736
759
  /**
737
760
  * {@link Comparison.comparison}
738
761
  */
739
-
740
-
741
762
  comparison(left, right) {
742
763
  if (isString(left) === false || isString(right) === false) {
743
764
  return false;
744
765
  }
745
-
746
766
  return left.endsWith(right);
747
767
  }
768
+
748
769
  /**
749
770
  * Get the strict representation of the expression.
750
771
  * @return {string}
751
772
  */
752
-
753
-
754
773
  toString() {
755
774
  const left = this.left.toString();
756
775
  const right = this.right.toString();
757
776
  return `(${left}<${right}>)`;
758
777
  }
759
-
760
778
  }
761
779
 
780
+ // Operator key
762
781
  const OPERATOR$5 = Symbol('UNDEFINED');
782
+
763
783
  /**
764
784
  * Undefined comparison expression
765
785
  */
766
-
767
786
  class Undefined extends Comparison {
768
787
  /**
769
788
  * @constructor
770
789
  * @param {Evaluable} operand
771
790
  */
791
+
772
792
  constructor(operand) {
773
793
  if (arguments.length !== 1) {
774
794
  throw new Error('comparison expression UNDEFINED expects exactly one operand');
775
795
  }
776
-
777
796
  super('UNDEFINED', OPERATOR$5, operand, new Value(true));
778
797
  }
798
+
779
799
  /**
780
800
  * {@link Comparison.comparison}
781
801
  */
782
-
783
-
784
802
  comparison(left) {
785
803
  return left === undefined;
786
804
  }
805
+
787
806
  /**
788
807
  * Get the strict representation of the expression.
789
808
  * @return {string}
790
809
  */
791
-
792
-
793
810
  toString() {
794
811
  return `(${this.left.toString()} is ${this.operator})`;
795
812
  }
813
+
796
814
  /**
797
815
  * {@link Evaluable.serialize}
798
816
  */
799
-
800
-
801
817
  serialize(options) {
802
818
  const {
803
819
  operatorMapping
804
820
  } = options;
805
821
  const operator = operatorMapping.get(this.operatorSymbol);
806
-
807
822
  if (operator === undefined) {
808
823
  throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
809
824
  }
810
-
811
825
  return [operator, this.left.serialize(options)];
812
826
  }
813
-
814
827
  }
815
828
 
816
829
  /**
@@ -826,13 +839,16 @@ class Logical {
826
839
  this.operator = operator;
827
840
  this.operatorSymbol = operatorSymbol;
828
841
  this.operands = operands;
829
-
830
842
  _defineProperty(this, "type", EvaluableType.Expression);
831
843
  }
844
+
832
845
  /**
833
846
  * {@link Evaluable.evaluate}
834
847
  */
835
848
 
849
+ /**
850
+ * {@link Evaluable.simplify}
851
+ */
836
852
 
837
853
  /**
838
854
  * Get the strict representation of the expression.
@@ -841,27 +857,24 @@ class Logical {
841
857
  toString() {
842
858
  return '(' + this.operands.map(operand => operand.toString()).join(` ${this.operator} `) + ')';
843
859
  }
844
-
845
860
  serialize(options) {
846
861
  const {
847
862
  operatorMapping
848
863
  } = options;
849
864
  const operator = operatorMapping.get(this.operatorSymbol);
850
-
851
865
  if (operator === undefined) {
852
866
  throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
853
867
  }
854
-
855
868
  return [operator, ...this.operands.map(operand => operand.serialize(options))];
856
869
  }
857
-
858
870
  }
859
871
 
872
+ // Operator key
860
873
  const OPERATOR$4 = Symbol('AND');
874
+
861
875
  /**
862
876
  * And logical expression
863
877
  */
864
-
865
878
  class And extends Logical {
866
879
  /**
867
880
  * @constructor
@@ -871,127 +884,105 @@ class And extends Logical {
871
884
  if (operands.length < 2) {
872
885
  throw new Error('logical expression must have at least two operands');
873
886
  }
874
-
875
887
  super('AND', OPERATOR$4, operands);
876
888
  }
889
+
877
890
  /**
878
891
  * Evaluate in the given context.
879
892
  * @param {Context} ctx
880
893
  * @return {Result}
881
894
  */
882
-
883
-
884
895
  evaluate(ctx) {
885
896
  for (const operand of this.operands) {
886
897
  if (operand.evaluate(ctx) === false) {
887
898
  return false;
888
899
  }
889
900
  }
890
-
891
901
  return true;
892
902
  }
903
+
893
904
  /**
894
905
  * {@link Evaluable.simplify}
895
906
  */
896
-
897
-
898
- simplify() {
899
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
900
- args[_key] = arguments[_key];
901
- }
902
-
907
+ simplify(...args) {
903
908
  const simplified = this.operands.reduce((result, child) => {
904
909
  if (result !== false) {
905
910
  const childResult = child.simplify(...args);
906
-
907
911
  if (isEvaluable(childResult)) {
908
912
  if (isBoolean(result)) {
909
913
  return [childResult];
910
914
  }
911
-
912
915
  return [...result, childResult];
913
916
  }
914
-
915
917
  if (!childResult) {
916
918
  return false;
917
919
  }
918
920
  }
919
-
920
921
  return result;
921
922
  }, true);
922
-
923
923
  if (Array.isArray(simplified)) {
924
924
  if (simplified.length === 1) {
925
925
  return simplified[0];
926
926
  }
927
-
928
927
  return new And(simplified);
929
928
  }
930
-
931
929
  return simplified;
932
930
  }
933
-
934
931
  }
935
932
 
933
+ // Operator key
936
934
  const OPERATOR$3 = Symbol('NOT');
935
+
937
936
  /**
938
937
  * Not logical expression
939
938
  */
940
-
941
939
  class Not extends Logical {
942
940
  /**
943
941
  * @constructor
944
942
  * @param {Evaluable} operand
945
943
  */
944
+
946
945
  constructor(operand) {
947
946
  if (arguments.length !== 1) {
948
947
  throw new Error('logical NOT expression must have exactly one operand');
949
948
  }
950
-
951
949
  super('NOT', OPERATOR$3, [operand]);
952
950
  }
951
+
953
952
  /**
954
953
  * Evaluate in the given context.
955
954
  * @param {Context} ctx
956
955
  * @return {Result}
957
956
  */
958
-
959
-
960
957
  evaluate(ctx) {
961
958
  const result = this.operands[0].evaluate(ctx);
962
-
963
959
  if (result !== true && result !== false) {
964
960
  throw new Error("logical NOT expression's operand must be evaluated to boolean value");
965
961
  }
966
-
967
962
  return !result;
968
963
  }
964
+
969
965
  /**
970
966
  * {@link Evaluable.simplify}
971
967
  */
972
-
973
-
974
- simplify() {
975
- const simplified = this.operands[0].simplify(...arguments);
976
-
968
+ simplify(...args) {
969
+ const simplified = this.operands[0].simplify(...args);
977
970
  if (isBoolean(simplified)) {
978
971
  return !simplified;
979
972
  }
980
-
981
973
  if (isEvaluable(simplified)) {
982
974
  return new Not(simplified);
983
975
  }
984
-
985
976
  throw new Error("logical NOT expression's operand must be evaluated to boolean value");
986
977
  }
987
-
988
978
  }
989
979
 
980
+ // Operator key
990
981
  const OPERATOR$2 = Symbol('NOR');
982
+
991
983
  /**
992
984
  * Nor logical expression
993
985
  */
994
-
995
986
  class Nor extends Logical {
996
987
  /**
997
988
  * @constructor
@@ -1001,73 +992,58 @@ class Nor extends Logical {
1001
992
  if (operands.length < 2) {
1002
993
  throw new Error('logical expression must have at least two operands');
1003
994
  }
1004
-
1005
995
  super('NOR', OPERATOR$2, operands);
1006
996
  }
997
+
1007
998
  /**
1008
999
  * Evaluate in the given context.
1009
1000
  * @param {Context} ctx
1010
1001
  * @return {Result}
1011
1002
  */
1012
-
1013
-
1014
1003
  evaluate(ctx) {
1015
1004
  for (const operand of this.operands) {
1016
1005
  if (operand.evaluate(ctx) === true) {
1017
1006
  return false;
1018
1007
  }
1019
1008
  }
1020
-
1021
1009
  return true;
1022
1010
  }
1011
+
1023
1012
  /**
1024
1013
  * {@link Evaluable.simplify}
1025
1014
  */
1026
-
1027
-
1028
- simplify() {
1029
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1030
- args[_key] = arguments[_key];
1031
- }
1032
-
1015
+ simplify(...args) {
1033
1016
  const simplified = this.operands.reduce((result, child) => {
1034
1017
  if (result !== false) {
1035
1018
  const childResult = child.simplify(...args);
1036
-
1037
1019
  if (isEvaluable(childResult)) {
1038
1020
  if (isBoolean(result)) {
1039
1021
  return [childResult];
1040
1022
  }
1041
-
1042
1023
  return [...result, childResult];
1043
1024
  }
1044
-
1045
1025
  if (childResult) {
1046
1026
  return false;
1047
1027
  }
1048
1028
  }
1049
-
1050
1029
  return result;
1051
1030
  }, true);
1052
-
1053
1031
  if (Array.isArray(simplified)) {
1054
1032
  if (simplified.length === 1) {
1055
1033
  return new Not(...simplified);
1056
1034
  }
1057
-
1058
1035
  return new Nor(simplified);
1059
1036
  }
1060
-
1061
1037
  return simplified;
1062
1038
  }
1063
-
1064
1039
  }
1065
1040
 
1041
+ // Operator key
1066
1042
  const OPERATOR$1 = Symbol('OR');
1043
+
1067
1044
  /**
1068
1045
  * Or logical expression
1069
1046
  */
1070
-
1071
1047
  class Or extends Logical {
1072
1048
  /**
1073
1049
  * @constructor
@@ -1077,84 +1053,68 @@ class Or extends Logical {
1077
1053
  if (operands.length < 2) {
1078
1054
  throw new Error('logical expression must have at least two operands');
1079
1055
  }
1080
-
1081
1056
  super('OR', OPERATOR$1, operands);
1082
1057
  }
1058
+
1083
1059
  /**
1084
1060
  * Evaluate in the given context.
1085
1061
  * @param {Context} ctx
1086
1062
  * @return {Result}
1087
1063
  */
1088
-
1089
-
1090
1064
  evaluate(ctx) {
1091
1065
  for (const operand of this.operands) {
1092
1066
  if (operand.evaluate(ctx) === true) {
1093
1067
  return true;
1094
1068
  }
1095
1069
  }
1096
-
1097
1070
  return false;
1098
1071
  }
1072
+
1099
1073
  /**
1100
1074
  * {@link Evaluable.simplify}
1101
1075
  */
1102
-
1103
-
1104
- simplify() {
1105
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1106
- args[_key] = arguments[_key];
1107
- }
1108
-
1076
+ simplify(...args) {
1109
1077
  const simplified = this.operands.reduce((result, child) => {
1110
1078
  if (result !== true) {
1111
1079
  const childResult = child.simplify(...args);
1112
-
1113
1080
  if (isEvaluable(childResult)) {
1114
1081
  if (isBoolean(result)) {
1115
1082
  return [childResult];
1116
1083
  }
1117
-
1118
1084
  return [...result, childResult];
1119
1085
  }
1120
-
1121
1086
  if (childResult) {
1122
1087
  return true;
1123
1088
  }
1124
1089
  }
1125
-
1126
1090
  return result;
1127
1091
  }, false);
1128
-
1129
1092
  if (Array.isArray(simplified)) {
1130
1093
  if (simplified.length === 1) {
1131
1094
  return simplified[0];
1132
1095
  }
1133
-
1134
1096
  return new Or(simplified);
1135
1097
  }
1136
-
1137
1098
  return simplified;
1138
1099
  }
1139
-
1140
1100
  }
1141
1101
 
1102
+ // Operator key
1142
1103
  const OPERATOR = Symbol('XOR');
1104
+
1143
1105
  /**
1144
1106
  * Logical xor
1145
1107
  * @param {boolean} a
1146
1108
  * @param {boolean} b
1147
1109
  * @return {boolean}
1148
1110
  */
1149
-
1150
1111
  function xor(a, b) {
1151
1112
  return (a || b) && !(a && b);
1152
1113
  }
1114
+
1153
1115
  /**
1154
1116
  * Xor logical expression
1155
1117
  */
1156
-
1157
-
1158
1118
  class Xor extends Logical {
1159
1119
  /**
1160
1120
  * @constructor
@@ -1164,19 +1124,16 @@ class Xor extends Logical {
1164
1124
  if (operands.length < 2) {
1165
1125
  throw new Error('logical expression must have at least two operands');
1166
1126
  }
1167
-
1168
1127
  super('XOR', OPERATOR, operands);
1169
1128
  }
1129
+
1170
1130
  /**
1171
1131
  * Evaluate in the given context.
1172
1132
  * @param {Context} ctx
1173
1133
  * @return {Result}
1174
1134
  */
1175
-
1176
-
1177
1135
  evaluate(ctx) {
1178
1136
  let res = null;
1179
-
1180
1137
  for (const operand of this.operands) {
1181
1138
  if (res === null) {
1182
1139
  res = operand.evaluate(ctx);
@@ -1184,62 +1141,43 @@ class Xor extends Logical {
1184
1141
  res = xor(res, operand.evaluate(ctx));
1185
1142
  }
1186
1143
  }
1187
-
1188
1144
  return res;
1189
1145
  }
1146
+
1190
1147
  /**
1191
1148
  * {@link Evaluable.simplify}
1192
1149
  */
1193
-
1194
-
1195
- simplify() {
1196
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1197
- args[_key] = arguments[_key];
1198
- }
1199
-
1200
- const [evaluablesLeft, trueCount] = this.operands.reduce((_ref, child) => {
1201
- let [notSimplifiedConditions, trueCount] = _ref;
1202
-
1150
+ simplify(...args) {
1151
+ const [evaluablesLeft, trueCount] = this.operands.reduce(([notSimplifiedConditions, trueCount], child) => {
1203
1152
  if (trueCount > 1) {
1204
1153
  return [notSimplifiedConditions, trueCount];
1205
1154
  }
1206
-
1207
1155
  const childResult = child.simplify(...args);
1208
-
1209
1156
  if (isEvaluable(childResult)) {
1210
1157
  return [[...notSimplifiedConditions, childResult], trueCount];
1211
1158
  }
1212
-
1213
1159
  if (childResult) {
1214
1160
  return [notSimplifiedConditions, trueCount + 1];
1215
1161
  }
1216
-
1217
1162
  return [notSimplifiedConditions, trueCount];
1218
1163
  }, [[], 0]);
1219
-
1220
1164
  if (trueCount > 1) {
1221
1165
  return false;
1222
1166
  }
1223
-
1224
1167
  if (evaluablesLeft.length === 0) {
1225
1168
  return trueCount === 1;
1226
1169
  }
1227
-
1228
1170
  if (evaluablesLeft.length === 1) {
1229
1171
  if (trueCount === 1) {
1230
1172
  return new Not(...evaluablesLeft);
1231
1173
  }
1232
-
1233
1174
  return evaluablesLeft[0];
1234
1175
  }
1235
-
1236
1176
  if (trueCount === 1) {
1237
1177
  return new Nor(evaluablesLeft);
1238
1178
  }
1239
-
1240
1179
  return new Xor(evaluablesLeft);
1241
1180
  }
1242
-
1243
1181
  }
1244
1182
 
1245
1183
  /**
@@ -1252,152 +1190,97 @@ class Collection extends Operand {
1252
1190
  */
1253
1191
  constructor(items) {
1254
1192
  super();
1255
-
1256
1193
  _defineProperty(this, "items", void 0);
1257
-
1258
1194
  this.items = items;
1259
1195
  }
1196
+
1260
1197
  /**
1261
1198
  * Evaluate in the given context.
1262
1199
  * @param {Context} ctx
1263
1200
  * @return {boolean}
1264
1201
  */
1265
-
1266
-
1267
1202
  evaluate(ctx) {
1268
1203
  return this.items.map(item => item.evaluate(ctx));
1269
1204
  }
1205
+
1270
1206
  /**
1271
1207
  * {@link Evaluable.simplify}
1272
1208
  */
1273
-
1274
-
1275
- simplify() {
1209
+ simplify(...args) {
1276
1210
  const values = [];
1277
-
1278
1211
  for (const item of this.items) {
1279
- const simplifiedItem = item.simplify(...arguments);
1280
-
1212
+ const simplifiedItem = item.simplify(...args);
1281
1213
  if (isEvaluable(simplifiedItem)) {
1282
1214
  return this;
1283
1215
  }
1284
-
1285
1216
  values.push(simplifiedItem);
1286
1217
  }
1287
-
1288
1218
  return values;
1289
1219
  }
1220
+
1290
1221
  /**
1291
1222
  * {@link Evaluable.serialize}
1292
1223
  */
1293
-
1294
-
1295
1224
  serialize(options) {
1296
1225
  return this.items.map(item => isEvaluable(item) ? item.serialize(options) : item);
1297
1226
  }
1227
+
1298
1228
  /**
1299
1229
  * Get the strict representation of the operand.
1300
1230
  * @return {string}
1301
1231
  */
1302
-
1303
-
1304
1232
  toString() {
1305
1233
  return '[' + this.items.map(item => item.toString()).join(', ') + ']';
1306
1234
  }
1307
-
1308
1235
  }
1309
1236
 
1310
- /**
1311
- * Convert a value to number if possible, otherwise return undefined
1312
- * @param value value to be converted to number
1313
- */
1314
-
1315
- const toNumber = value => {
1316
- const isValueNumber = isNumber(value);
1317
-
1318
- if (isValueNumber) {
1319
- return value;
1320
- } else if (isString(value)) {
1321
- if (value.match(/^\d+\.\d+$/)) {
1322
- return parseFloat(value);
1323
- } else if (value.match(/^0$|^[1-9]\d*$/)) {
1324
- return parseInt(value);
1325
- }
1326
- }
1327
-
1328
- return undefined;
1329
- };
1330
- /**
1331
- * Convert a value to string if possible, otherwise return undefined
1332
- * @param value value to be converted to string
1333
- */
1334
-
1335
- const toString = value => {
1336
- if (isNumber(value)) {
1337
- return `${value}`;
1338
- } else if (isString(value)) {
1339
- return value;
1340
- }
1341
-
1342
- return undefined;
1343
- };
1344
-
1345
1237
  const keyWithArrayIndexRegex = /^(?<currentKey>[^[\]]+?)(?<indexes>(?:\[\d+])+)?$/;
1346
1238
  const arrayIndexRegex = /\[(\d+)]/g;
1347
-
1348
- const parseKey = key => key.split('.').flatMap(key => {
1349
- const parseResult = keyWithArrayIndexRegex.exec(key);
1350
- const keys = [];
1351
-
1352
- if (parseResult) {
1353
- var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
1354
-
1355
- keys.push((_parseResult$groups$c = parseResult === null || parseResult === void 0 ? void 0 : (_parseResult$groups = parseResult.groups) === null || _parseResult$groups === void 0 ? void 0 : _parseResult$groups.currentKey) !== null && _parseResult$groups$c !== void 0 ? _parseResult$groups$c : key);
1356
- const rawIndexes = parseResult === null || parseResult === void 0 ? void 0 : (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
1357
-
1358
- if (rawIndexes) {
1359
- for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
1360
- keys.push(parseInt(indexResult[1]));
1239
+ const parseBacktickWrappedKey = key => key.startsWith('`') && key.endsWith('`') ? key.slice(1, -1) : key;
1240
+ const parseKey = key => {
1241
+ const keys = key.match(/(`[^[\]]+`(\[\d+\])*|[^`.]+)/g);
1242
+ return !keys ? [] : keys.flatMap(key => {
1243
+ const unwrappedKey = parseBacktickWrappedKey(key);
1244
+ const keys = [];
1245
+ const parseResult = keyWithArrayIndexRegex.exec(unwrappedKey);
1246
+ if (parseResult) {
1247
+ var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
1248
+ const extractedKey = parseBacktickWrappedKey((_parseResult$groups$c = parseResult === null || parseResult === void 0 || (_parseResult$groups = parseResult.groups) === null || _parseResult$groups === void 0 ? void 0 : _parseResult$groups.currentKey) !== null && _parseResult$groups$c !== void 0 ? _parseResult$groups$c : unwrappedKey);
1249
+ keys.push(extractedKey);
1250
+ const rawIndexes = parseResult === null || parseResult === void 0 || (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
1251
+ if (rawIndexes) {
1252
+ for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
1253
+ keys.push(parseInt(indexResult[1]));
1254
+ }
1361
1255
  }
1256
+ } else {
1257
+ keys.push(unwrappedKey);
1362
1258
  }
1363
- } else {
1364
- keys.push(key);
1365
- }
1366
-
1367
- return keys;
1368
- });
1369
-
1259
+ return keys;
1260
+ });
1261
+ };
1370
1262
  const complexKeyExpression = /{([^{}]+)}/;
1371
-
1372
1263
  function extractComplexKeys(ctx, key) {
1373
1264
  // Resolve complex keys
1374
1265
  let complexKeyMatches = complexKeyExpression.exec(key);
1375
-
1376
1266
  while (complexKeyMatches) {
1377
1267
  const resolvedValue = complexValueLookup(ctx, complexKeyMatches[1]);
1378
-
1379
1268
  if (resolvedValue === undefined) {
1380
1269
  return undefined;
1381
1270
  }
1382
-
1383
1271
  key = key.replace(complexKeyExpression, `${resolvedValue}`);
1384
1272
  complexKeyMatches = complexKeyExpression.exec(key);
1385
1273
  }
1386
-
1387
1274
  return parseKey(key);
1388
1275
  }
1389
-
1390
1276
  const isContext = value => isObject(value);
1391
-
1392
1277
  const simpleValueLookup = keys => ctx => {
1393
1278
  let pointer = ctx;
1394
-
1395
1279
  for (const key of keys) {
1396
1280
  if (typeof key === 'number') {
1397
1281
  if (!Array.isArray(pointer)) {
1398
1282
  return undefined;
1399
1283
  }
1400
-
1401
1284
  pointer = pointer[key];
1402
1285
  } else if (!isContext(pointer)) {
1403
1286
  return undefined;
@@ -1405,9 +1288,9 @@ const simpleValueLookup = keys => ctx => {
1405
1288
  pointer = pointer[key];
1406
1289
  }
1407
1290
  }
1408
-
1409
1291
  return pointer;
1410
1292
  };
1293
+
1411
1294
  /**
1412
1295
  * Lookup for the reference in the context.
1413
1296
  * The nested context value is annotated with "." delimiter.
@@ -1416,33 +1299,26 @@ const simpleValueLookup = keys => ctx => {
1416
1299
  * @param {string} key Context lookup key.
1417
1300
  * @return {Result}
1418
1301
  */
1419
-
1420
-
1421
1302
  function complexValueLookup(ctx, key) {
1422
1303
  const keys = extractComplexKeys(ctx, key);
1423
-
1424
1304
  if (!keys) {
1425
1305
  return undefined;
1426
1306
  }
1427
-
1428
1307
  return simpleValueLookup(keys !== null && keys !== void 0 ? keys : [])(ctx);
1429
1308
  }
1430
-
1431
- let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
1432
-
1433
- (function (DataType) {
1309
+ let DataType = /*#__PURE__*/function (DataType) {
1434
1310
  DataType["Number"] = "Number";
1435
1311
  DataType["String"] = "String";
1436
- })(DataType || (DataType = {}));
1312
+ return DataType;
1313
+ }({});
1437
1314
 
1315
+ // Equivalent to /^.+\.\((Number|String)\)$/
1438
1316
  const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
1439
-
1440
1317
  const isComplexKey = key => key.indexOf('{') > -1;
1318
+
1441
1319
  /**
1442
1320
  * Reference operand resolved within the context
1443
1321
  */
1444
-
1445
-
1446
1322
  class Reference extends Operand {
1447
1323
  /**
1448
1324
  * @constructor
@@ -1452,119 +1328,97 @@ class Reference extends Operand {
1452
1328
  if (key.trim() === '') {
1453
1329
  throw new Error('invalid reference key');
1454
1330
  }
1455
-
1456
1331
  super();
1457
-
1458
1332
  _defineProperty(this, "key", void 0);
1459
-
1460
1333
  _defineProperty(this, "dataType", void 0);
1461
-
1462
1334
  _defineProperty(this, "valueLookup", void 0);
1463
-
1464
1335
  _defineProperty(this, "getKeys", void 0);
1465
-
1466
1336
  this.key = key;
1467
1337
  const dataTypeMatch = dataTypeRegex.exec(this.key);
1468
-
1469
1338
  if (dataTypeMatch) {
1470
1339
  this.dataType = DataType[dataTypeMatch[1]];
1471
1340
  }
1472
-
1473
1341
  if (this.key.match(/.\(.+\)$/)) {
1474
1342
  this.key = this.key.replace(/.\(.+\)$/, '');
1475
1343
  }
1476
-
1477
1344
  if (isComplexKey(this.key)) {
1478
1345
  this.valueLookup = context => complexValueLookup(context, this.key);
1479
-
1480
1346
  this.getKeys = context => extractComplexKeys(context, this.key);
1481
1347
  } else {
1482
1348
  const keys = parseKey(this.key);
1483
1349
  this.valueLookup = simpleValueLookup(keys);
1484
-
1485
1350
  this.getKeys = () => keys;
1486
1351
  }
1487
1352
  }
1353
+
1488
1354
  /**
1489
1355
  * Evaluate in the given context.
1490
1356
  * @param {Context} ctx
1491
1357
  * @return {boolean}
1492
1358
  */
1493
-
1494
-
1495
1359
  evaluate(ctx) {
1496
1360
  return this.toDataType(this.valueLookup(ctx));
1497
1361
  }
1362
+
1498
1363
  /**
1499
1364
  * {@link Evaluable.simplify}
1500
1365
  */
1501
-
1502
-
1503
1366
  simplify(ctx, strictKeys, optionalKeys) {
1504
1367
  var _this$getKeys;
1505
-
1506
1368
  const [key] = (_this$getKeys = this.getKeys(ctx)) !== null && _this$getKeys !== void 0 ? _this$getKeys : [];
1507
-
1508
1369
  if (ctx[key] !== undefined) {
1509
1370
  return this.evaluate(ctx);
1510
1371
  }
1511
-
1512
1372
  if (!key || typeof key === 'number') {
1513
1373
  return this;
1514
1374
  }
1515
-
1516
1375
  return strictKeys && strictKeys.includes(key) || optionalKeys && !optionalKeys.includes(key) ? undefined : this;
1517
1376
  }
1377
+
1518
1378
  /**
1519
1379
  * {@link Evaluable.serialize}
1520
1380
  */
1521
-
1522
-
1523
- serialize(_ref) {
1524
- let {
1525
- referenceSerialization
1526
- } = _ref;
1381
+ serialize({
1382
+ referenceSerialization
1383
+ }) {
1527
1384
  const key = this.dataType ? `${this.key}.(${this.dataType})` : this.key;
1528
1385
  return referenceSerialization(key);
1529
1386
  }
1387
+
1530
1388
  /**
1531
1389
  * Get the strict representation of the operand.
1532
1390
  * @return {string}
1533
1391
  */
1534
-
1535
-
1536
1392
  toString() {
1537
1393
  return `{${this.key}}`;
1538
1394
  }
1395
+
1539
1396
  /**
1540
1397
  * Converts a value to a specified data type
1541
1398
  * Silently returns original value if data type conversion has not been implemented.
1542
1399
  * @param value value to cast as data type
1543
1400
  */
1544
-
1545
-
1546
1401
  toDataType(value) {
1547
1402
  let result = value;
1548
-
1549
1403
  switch (this.dataType) {
1550
1404
  case DataType.Number:
1551
1405
  result = toNumber(value);
1552
1406
  break;
1553
-
1554
1407
  case DataType.String:
1555
1408
  result = toString(value);
1556
1409
  break;
1557
1410
  }
1558
-
1559
1411
  if (value && result === undefined) {
1560
1412
  console.warn(`Casting ${value} to ${this.dataType} resulted in ${result}`);
1561
1413
  }
1562
-
1563
1414
  return result;
1564
1415
  }
1565
-
1566
1416
  }
1567
1417
 
1418
+ // Option value whitelist
1419
+
1420
+ // Parser options
1421
+
1568
1422
  /**
1569
1423
  * Default reference predicate.
1570
1424
  * The "$" symbol at the begging of the operand is used
@@ -1576,28 +1430,31 @@ class Reference extends Operand {
1576
1430
  function defaultReferencePredicate(key) {
1577
1431
  return isString(key) && key.startsWith('$');
1578
1432
  }
1433
+
1579
1434
  /**
1580
1435
  * Default reference transform.
1581
1436
  * It removes the "$" symbol at the begging of the operand name.
1582
1437
  * @param {string} key
1583
1438
  * @return {string}
1584
1439
  */
1585
-
1586
1440
  function defaultReferenceTransform(key) {
1587
1441
  return key.slice(1);
1588
1442
  }
1589
1443
  function defaultReferenceSerialization(key) {
1590
1444
  return `$${key}`;
1591
- } // Default operator mapping
1592
- // Unique operator key <-> raw expression key
1445
+ }
1593
1446
 
1594
- const defaultOperatorMapping = new Map([// Comparison
1595
- [OPERATOR$h, '=='], [OPERATOR$b, '!='], [OPERATOR$f, '>'], [OPERATOR$g, '>='], [OPERATOR$c, '<'], [OPERATOR$d, '<='], [OPERATOR$e, 'IN'], [OPERATOR$a, 'NOT IN'], [OPERATOR$8, 'PREFIX'], [OPERATOR$6, 'SUFFIX'], [OPERATOR$9, 'OVERLAP'], [OPERATOR$5, 'UNDEFINED'], [OPERATOR$7, 'PRESENT'], // Logical
1447
+ // Default operator mapping
1448
+ // Unique operator key <-> raw expression key
1449
+ const defaultOperatorMapping = new Map([
1450
+ // Comparison
1451
+ [OPERATOR$h, '=='], [OPERATOR$b, '!='], [OPERATOR$f, '>'], [OPERATOR$g, '>='], [OPERATOR$c, '<'], [OPERATOR$d, '<='], [OPERATOR$e, 'IN'], [OPERATOR$a, 'NOT IN'], [OPERATOR$8, 'PREFIX'], [OPERATOR$6, 'SUFFIX'], [OPERATOR$9, 'OVERLAP'], [OPERATOR$5, 'UNDEFINED'], [OPERATOR$7, 'PRESENT'],
1452
+ // Logical
1596
1453
  [OPERATOR$4, 'AND'], [OPERATOR$1, 'OR'], [OPERATOR$2, 'NOR'], [OPERATOR, 'XOR'], [OPERATOR$3, 'NOT']]);
1454
+
1597
1455
  /**
1598
1456
  * Default parser options
1599
1457
  */
1600
-
1601
1458
  const defaultOptions = {
1602
1459
  referencePredicate: defaultReferencePredicate,
1603
1460
  referenceTransform: defaultReferenceTransform,
@@ -1605,6 +1462,8 @@ const defaultOptions = {
1605
1462
  operatorMapping: defaultOperatorMapping
1606
1463
  };
1607
1464
 
1465
+ // Input types
1466
+
1608
1467
  /**
1609
1468
  * Parser of raw expressions into Evaluable expression
1610
1469
  */
@@ -1615,12 +1474,11 @@ class Parser {
1615
1474
  */
1616
1475
  constructor(options) {
1617
1476
  _defineProperty(this, "opts", void 0);
1618
-
1619
1477
  _defineProperty(this, "expectedOperators", void 0);
1620
-
1621
- this.opts = { ...defaultOptions
1622
- }; // Apply exclusive options overrides
1623
-
1478
+ this.opts = {
1479
+ ...defaultOptions
1480
+ };
1481
+ // Apply exclusive options overrides
1624
1482
  if (options) {
1625
1483
  for (const key of Object.keys(options)) {
1626
1484
  if (key in this.opts) {
@@ -1628,55 +1486,47 @@ class Parser {
1628
1486
  }
1629
1487
  }
1630
1488
  }
1631
-
1632
1489
  this.expectedOperators = new Set(this.opts.operatorMapping.values());
1633
1490
  }
1491
+
1634
1492
  /**
1635
1493
  * Parser options
1636
1494
  * @type {Options}
1637
1495
  */
1638
-
1639
-
1640
1496
  get options() {
1641
1497
  return this.opts;
1642
1498
  }
1499
+
1643
1500
  /**
1644
1501
  * Parse raw expression into evaluable expression.
1645
1502
  * @param {ExpressionInput} raw Raw expression.
1646
1503
  * @return {Evaluable}
1647
1504
  */
1648
-
1649
-
1650
1505
  parse(raw) {
1651
1506
  if (raw === undefined || raw === null || Array.isArray(raw) === false) {
1652
1507
  throw new Error('invalid expression');
1653
1508
  }
1654
-
1655
1509
  if (raw.length === 0 || !this.expectedOperators.has(`${raw[0]}`)) {
1656
1510
  throw new Error('invalid expression');
1657
1511
  }
1658
-
1659
1512
  return this.parseRawExp(raw);
1660
1513
  }
1514
+
1661
1515
  /**
1662
1516
  * Parse raw expression based on the expression type.
1663
1517
  * @param {Input} raw Raw expression.
1664
1518
  * @return {Evaluable}
1665
1519
  */
1666
-
1667
-
1668
1520
  parseRawExp(raw) {
1669
- var _this = this;
1670
-
1671
1521
  // Value / Reference
1672
1522
  if (!Array.isArray(raw)) {
1673
1523
  return this.getOperand(raw);
1674
1524
  }
1675
-
1676
1525
  let expression;
1677
1526
  let operandParser = this.getOperand;
1678
1527
  const operator = raw[0];
1679
1528
  const operands = raw.slice(1);
1529
+
1680
1530
  /**
1681
1531
  * Simplify the logical expression if possible.
1682
1532
  * - AND, OR with one operand is collapsed, i.e. reduced to inner expression
@@ -1688,149 +1538,101 @@ class Parser {
1688
1538
  * @param operands
1689
1539
  * @param collapsible
1690
1540
  */
1691
-
1692
- const logicalExpressionReducer = function (operands) {
1693
- let collapsible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1694
-
1541
+ const logicalExpressionReducer = (operands, collapsible = false) => {
1695
1542
  if (operands.length === 0 || operands.filter(operand => operand.type === EvaluableType.Expression).length === 0) {
1696
- return _this.getOperand(raw);
1543
+ return this.getOperand(raw);
1697
1544
  }
1698
-
1699
1545
  return collapsible && operands.length === 1 ? operands[0] : undefined;
1700
1546
  };
1701
-
1702
1547
  switch (operator) {
1703
1548
  /**
1704
1549
  * Logical
1705
1550
  */
1706
1551
  case this.opts.operatorMapping.get(OPERATOR$4):
1707
1552
  expression = operands => logicalExpressionReducer(operands, true) || new And(operands);
1708
-
1709
1553
  operandParser = this.parseRawExp;
1710
1554
  break;
1711
-
1712
1555
  case this.opts.operatorMapping.get(OPERATOR$1):
1713
1556
  expression = operands => logicalExpressionReducer(operands, true) || new Or(operands);
1714
-
1715
1557
  operandParser = this.parseRawExp;
1716
1558
  break;
1717
-
1718
1559
  case this.opts.operatorMapping.get(OPERATOR$2):
1719
1560
  expression = operands => logicalExpressionReducer(operands) || new Nor(operands);
1720
-
1721
1561
  operandParser = this.parseRawExp;
1722
1562
  break;
1723
-
1724
1563
  case this.opts.operatorMapping.get(OPERATOR):
1725
1564
  expression = operands => logicalExpressionReducer(operands) || new Xor(operands);
1726
-
1727
1565
  operandParser = this.parseRawExp;
1728
1566
  break;
1729
-
1730
1567
  case this.opts.operatorMapping.get(OPERATOR$3):
1731
1568
  expression = operands => logicalExpressionReducer(operands) || new Not(...operands);
1732
-
1733
1569
  operandParser = this.parseRawExp;
1734
1570
  break;
1735
-
1736
1571
  /**
1737
1572
  * Comparison
1738
1573
  */
1739
-
1740
1574
  case this.opts.operatorMapping.get(OPERATOR$h):
1741
1575
  expression = operands => new Equal(...operands);
1742
-
1743
1576
  break;
1744
-
1745
1577
  case this.opts.operatorMapping.get(OPERATOR$b):
1746
1578
  expression = operands => new NotEqual(...operands);
1747
-
1748
1579
  break;
1749
-
1750
1580
  case this.opts.operatorMapping.get(OPERATOR$f):
1751
1581
  expression = operands => new GreaterThan(...operands);
1752
-
1753
1582
  break;
1754
-
1755
1583
  case this.opts.operatorMapping.get(OPERATOR$g):
1756
1584
  expression = operands => new GreaterThanOrEqual(...operands);
1757
-
1758
1585
  break;
1759
-
1760
1586
  case this.opts.operatorMapping.get(OPERATOR$c):
1761
1587
  expression = operands => new LessThan(...operands);
1762
-
1763
1588
  break;
1764
-
1765
1589
  case this.opts.operatorMapping.get(OPERATOR$d):
1766
1590
  expression = operands => new LessThanOrEqual(...operands);
1767
-
1768
1591
  break;
1769
-
1770
1592
  case this.opts.operatorMapping.get(OPERATOR$e):
1771
1593
  expression = operands => new In(...operands);
1772
-
1773
1594
  break;
1774
-
1775
1595
  case this.opts.operatorMapping.get(OPERATOR$a):
1776
1596
  expression = operands => new NotIn(...operands);
1777
-
1778
1597
  break;
1779
-
1780
1598
  case this.opts.operatorMapping.get(OPERATOR$8):
1781
1599
  expression = operands => new Prefix(...operands);
1782
-
1783
1600
  break;
1784
-
1785
1601
  case this.opts.operatorMapping.get(OPERATOR$6):
1786
1602
  expression = operands => new Suffix(...operands);
1787
-
1788
1603
  break;
1789
-
1790
1604
  case this.opts.operatorMapping.get(OPERATOR$9):
1791
1605
  expression = operands => new Overlap(...operands);
1792
-
1793
1606
  break;
1794
-
1795
1607
  case this.opts.operatorMapping.get(OPERATOR$5):
1796
1608
  expression = operands => new Undefined(...operands);
1797
-
1798
1609
  break;
1799
-
1800
1610
  case this.opts.operatorMapping.get(OPERATOR$7):
1801
1611
  expression = operands => new Present(...operands);
1802
-
1803
1612
  break;
1804
1613
  // Collection
1805
-
1806
1614
  default:
1807
1615
  return this.getOperand(raw);
1808
1616
  }
1809
-
1810
1617
  return expression(operands.map(operandParser.bind(this)));
1811
1618
  }
1619
+
1812
1620
  /**
1813
1621
  * Get resolved operand
1814
1622
  * @param raw Raw data
1815
1623
  */
1816
-
1817
-
1818
1624
  getOperand(raw) {
1819
1625
  const resolve = raw => this.opts.referencePredicate(raw) ? new Reference(this.opts.referenceTransform(raw)) : new Value(raw);
1820
-
1821
1626
  if (Array.isArray(raw)) {
1822
1627
  return new Collection(raw.map(item => resolve(item)));
1823
1628
  }
1824
-
1825
1629
  return resolve(raw);
1826
1630
  }
1827
-
1828
1631
  }
1829
1632
 
1830
1633
  /**
1831
1634
  * Condition engine
1832
1635
  */
1833
-
1834
1636
  class Engine {
1835
1637
  /**
1836
1638
  * @constructor
@@ -1838,40 +1640,37 @@ class Engine {
1838
1640
  */
1839
1641
  constructor(options) {
1840
1642
  _defineProperty(this, "parser", void 0);
1841
-
1842
1643
  this.parser = new Parser(options);
1843
1644
  }
1645
+
1844
1646
  /**
1845
1647
  * Evaluate the expression.
1846
1648
  * @param {ExpressionInput} exp Raw expression.
1847
1649
  * @param {Context} ctx Evaluation data context.
1848
1650
  * @return {boolean}
1849
1651
  */
1850
-
1851
-
1852
1652
  evaluate(exp, ctx) {
1853
1653
  return this.parse(exp).evaluate(ctx);
1854
1654
  }
1655
+
1855
1656
  /**
1856
1657
  * Get expression statement
1857
1658
  * @param {ExpressionInput} exp Raw expression.
1858
1659
  * @return {string}
1859
1660
  */
1860
-
1861
-
1862
1661
  statement(exp) {
1863
1662
  return this.parse(exp).toString();
1864
1663
  }
1664
+
1865
1665
  /**
1866
1666
  * Parse expression.
1867
1667
  * @param {ExpressionInput} exp Raw expression.
1868
1668
  * @return {Evaluable}
1869
1669
  */
1870
-
1871
-
1872
1670
  parse(exp) {
1873
1671
  return this.parser.parse(exp);
1874
1672
  }
1673
+
1875
1674
  /**
1876
1675
  * Simplifies an expression with values in context.
1877
1676
  *
@@ -1887,22 +1686,16 @@ class Engine {
1887
1686
  * `optionalKeys` is considered to be present and thus will be evaluated
1888
1687
  * @returns {Inpunt | boolean}
1889
1688
  */
1890
-
1891
-
1892
1689
  simplify(exp, context, strictKeys, optionalKeys) {
1893
1690
  const result = this.parse(exp).simplify(context, strictKeys, optionalKeys);
1894
-
1895
1691
  if (isEvaluable(result)) {
1896
1692
  return result.serialize(this.parser.options);
1897
1693
  }
1898
-
1899
1694
  if (isBoolean(result)) {
1900
1695
  return result;
1901
1696
  }
1902
-
1903
1697
  throw new Error('non expression or boolean result should be returned');
1904
1698
  }
1905
-
1906
1699
  }
1907
1700
 
1908
1701
  exports.OPERATOR_AND = OPERATOR$4;
@@ -1923,6 +1716,6 @@ exports.OPERATOR_PRESENT = OPERATOR$7;
1923
1716
  exports.OPERATOR_SUFFIX = OPERATOR$6;
1924
1717
  exports.OPERATOR_UNDEFINED = OPERATOR$5;
1925
1718
  exports.OPERATOR_XOR = OPERATOR;
1926
- exports["default"] = Engine;
1719
+ exports.default = Engine;
1927
1720
  exports.defaultOptions = defaultOptions;
1928
1721
  exports.isEvaluable = isEvaluable;