@briza/illogical 1.5.4 → 1.5.6

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