@briza/illogical 1.5.2 → 1.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # illogical changelog
2
2
 
3
+ ## 1.5.5
4
+
5
+ - Expose default options for parser
6
+ - Expose isEvaluable
7
+ - Performance improvements in references
8
+
9
+ ## 1.5.4
10
+
11
+ - Update dependencies.
12
+
13
+ ## 1.5.3
14
+
15
+ - Fixed an issue where conditions with object data were not being simplified correctly.
16
+
3
17
  ## 1.5.2
4
18
 
5
19
  - Update dependencies.
@@ -1,3 +1,18 @@
1
+ function _defineProperty(obj, key, value) {
2
+ if (key in obj) {
3
+ Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ } else {
10
+ obj[key] = value;
11
+ }
12
+
13
+ return obj;
14
+ }
15
+
1
16
  /**
2
17
  * Is number predicate.
3
18
  * @param value Tested value.
@@ -45,22 +60,7 @@ function isBoolean(value) {
45
60
  */
46
61
 
47
62
  function isEvaluable(value) {
48
- return typeof value === 'object' && value !== null && !Array.isArray(value);
49
- }
50
-
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;
63
+ 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';
64
64
  }
65
65
 
66
66
  /**
@@ -97,12 +97,12 @@ class Comparison {
97
97
  * @param {Operand} right Right operand.
98
98
  */
99
99
  constructor(operator, operatorSymbol, left, right) {
100
- _defineProperty(this, "type", EvaluableType.Expression);
101
-
102
100
  this.operator = operator;
103
101
  this.operatorSymbol = operatorSymbol;
104
102
  this.left = left;
105
103
  this.right = right;
104
+
105
+ _defineProperty(this, "type", EvaluableType.Expression);
106
106
  }
107
107
  /**
108
108
  * {@link Evaluable.evaluate}
@@ -620,6 +620,9 @@ class Value extends Operand {
620
620
  }
621
621
 
622
622
  super();
623
+
624
+ _defineProperty(this, "value", void 0);
625
+
623
626
  this.value = value;
624
627
  }
625
628
  /**
@@ -816,11 +819,11 @@ class Logical {
816
819
  * @param {Evaluable[]} operands Collection of operands.
817
820
  */
818
821
  constructor(operator, operatorSymbol, operands) {
819
- _defineProperty(this, "type", EvaluableType.Expression);
820
-
821
822
  this.operator = operator;
822
823
  this.operatorSymbol = operatorSymbol;
823
824
  this.operands = operands;
825
+
826
+ _defineProperty(this, "type", EvaluableType.Expression);
824
827
  }
825
828
  /**
826
829
  * {@link Evaluable.evaluate}
@@ -1245,6 +1248,9 @@ class Collection extends Operand {
1245
1248
  */
1246
1249
  constructor(items) {
1247
1250
  super();
1251
+
1252
+ _defineProperty(this, "items", void 0);
1253
+
1248
1254
  this.items = items;
1249
1255
  }
1250
1256
  /**
@@ -1332,13 +1338,39 @@ const toString = value => {
1332
1338
  return undefined;
1333
1339
  };
1334
1340
 
1335
- function extractKeys(ctx, key) {
1341
+ const keyWithArrayIndexRegex = /^(?<currentKey>[^[\]]+?)(?<indexes>(?:\[\d+])+)?$/;
1342
+ const arrayIndexRegex = /\[(\d+)]/g;
1343
+
1344
+ const parseKey = key => key.split('.').flatMap(key => {
1345
+ const parseResult = keyWithArrayIndexRegex.exec(key);
1346
+ const keys = [];
1347
+
1348
+ if (parseResult) {
1349
+ var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
1350
+
1351
+ 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);
1352
+ const rawIndexes = parseResult === null || parseResult === void 0 ? void 0 : (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
1353
+
1354
+ if (rawIndexes) {
1355
+ for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
1356
+ keys.push(parseInt(indexResult[1]));
1357
+ }
1358
+ }
1359
+ } else {
1360
+ keys.push(key);
1361
+ }
1362
+
1363
+ return keys;
1364
+ });
1365
+
1366
+ const complexKeyExpression = /{([^{}]+)}/;
1367
+
1368
+ function extractComplexKeys(ctx, key) {
1336
1369
  // Resolve complex keys
1337
- const complexKeyExpression = /{([^{}]+)}/;
1338
1370
  let complexKeyMatches = complexKeyExpression.exec(key);
1339
1371
 
1340
1372
  while (complexKeyMatches) {
1341
- const resolvedValue = contextValueLookup(ctx, complexKeyMatches[1]);
1373
+ const resolvedValue = complexValueLookup(ctx, complexKeyMatches[1]);
1342
1374
 
1343
1375
  if (resolvedValue === undefined) {
1344
1376
  return undefined;
@@ -1348,14 +1380,30 @@ function extractKeys(ctx, key) {
1348
1380
  complexKeyMatches = complexKeyExpression.exec(key);
1349
1381
  }
1350
1382
 
1351
- let keys = [key]; // Nested reference
1383
+ return parseKey(key);
1384
+ }
1385
+
1386
+ const isContext = value => isObject(value);
1387
+
1388
+ const simpleValueLookup = keys => ctx => {
1389
+ let pointer = ctx;
1352
1390
 
1353
- if (key.includes('.')) {
1354
- keys = key.split('.');
1391
+ for (const key of keys) {
1392
+ if (typeof key === 'number') {
1393
+ if (!Array.isArray(pointer)) {
1394
+ return undefined;
1395
+ }
1396
+
1397
+ pointer = pointer[key];
1398
+ } else if (!isContext(pointer)) {
1399
+ return undefined;
1400
+ } else {
1401
+ pointer = pointer[key];
1402
+ }
1355
1403
  }
1356
1404
 
1357
- return keys;
1358
- }
1405
+ return pointer;
1406
+ };
1359
1407
  /**
1360
1408
  * Lookup for the reference in the context.
1361
1409
  * The nested context value is annotated with "." delimiter.
@@ -1366,42 +1414,14 @@ function extractKeys(ctx, key) {
1366
1414
  */
1367
1415
 
1368
1416
 
1369
- function contextValueLookup(ctx, key) {
1370
- const keys = extractKeys(ctx, key);
1417
+ function complexValueLookup(ctx, key) {
1418
+ const keys = extractComplexKeys(ctx, key);
1371
1419
 
1372
1420
  if (!keys) {
1373
1421
  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
1422
  }
1403
1423
 
1404
- return undefined;
1424
+ return simpleValueLookup(keys !== null && keys !== void 0 ? keys : [])(ctx);
1405
1425
  }
1406
1426
 
1407
1427
  let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
@@ -1412,10 +1432,13 @@ let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
1412
1432
  })(DataType || (DataType = {}));
1413
1433
 
1414
1434
  const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
1435
+
1436
+ const isComplexKey = key => key.indexOf('{') > -1;
1415
1437
  /**
1416
1438
  * Reference operand resolved within the context
1417
1439
  */
1418
1440
 
1441
+
1419
1442
  class Reference extends Operand {
1420
1443
  /**
1421
1444
  * @constructor
@@ -1427,6 +1450,15 @@ class Reference extends Operand {
1427
1450
  }
1428
1451
 
1429
1452
  super();
1453
+
1454
+ _defineProperty(this, "key", void 0);
1455
+
1456
+ _defineProperty(this, "dataType", void 0);
1457
+
1458
+ _defineProperty(this, "valueLookup", void 0);
1459
+
1460
+ _defineProperty(this, "getKeys", void 0);
1461
+
1430
1462
  this.key = key;
1431
1463
  const dataTypeMatch = dataTypeRegex.exec(this.key);
1432
1464
 
@@ -1437,6 +1469,17 @@ class Reference extends Operand {
1437
1469
  if (this.key.match(/.\(.+\)$/)) {
1438
1470
  this.key = this.key.replace(/.\(.+\)$/, '');
1439
1471
  }
1472
+
1473
+ if (isComplexKey(this.key)) {
1474
+ this.valueLookup = context => complexValueLookup(context, this.key);
1475
+
1476
+ this.getKeys = context => extractComplexKeys(context, this.key);
1477
+ } else {
1478
+ const keys = parseKey(this.key);
1479
+ this.valueLookup = simpleValueLookup(keys);
1480
+
1481
+ this.getKeys = () => keys;
1482
+ }
1440
1483
  }
1441
1484
  /**
1442
1485
  * Evaluate in the given context.
@@ -1446,7 +1489,7 @@ class Reference extends Operand {
1446
1489
 
1447
1490
 
1448
1491
  evaluate(ctx) {
1449
- return this.toDataType(contextValueLookup(ctx, this.key));
1492
+ return this.toDataType(this.valueLookup(ctx));
1450
1493
  }
1451
1494
  /**
1452
1495
  * {@link Evaluable.simplify}
@@ -1454,18 +1497,18 @@ class Reference extends Operand {
1454
1497
 
1455
1498
 
1456
1499
  simplify(ctx, strictKeys, optionalKeys) {
1457
- const keys = extractKeys(ctx, this.key);
1458
-
1459
- if (!keys) {
1460
- return this;
1461
- }
1500
+ var _this$getKeys;
1462
1501
 
1463
- const key = keys[0].replace(/\[.+$/, '');
1502
+ const [key] = (_this$getKeys = this.getKeys(ctx)) !== null && _this$getKeys !== void 0 ? _this$getKeys : [];
1464
1503
 
1465
1504
  if (ctx[key] !== undefined) {
1466
1505
  return this.evaluate(ctx);
1467
1506
  }
1468
1507
 
1508
+ if (!key || typeof key === 'number') {
1509
+ return this;
1510
+ }
1511
+
1469
1512
  return strictKeys && strictKeys.includes(key) || optionalKeys && !optionalKeys.includes(key) ? undefined : this;
1470
1513
  }
1471
1514
  /**
@@ -1567,6 +1610,10 @@ class Parser {
1567
1610
  * @param {Options?} options Parser options.
1568
1611
  */
1569
1612
  constructor(options) {
1613
+ _defineProperty(this, "opts", void 0);
1614
+
1615
+ _defineProperty(this, "expectedOperators", void 0);
1616
+
1570
1617
  this.opts = { ...defaultOptions
1571
1618
  }; // Apply exclusive options overrides
1572
1619
 
@@ -1776,10 +1823,6 @@ class Parser {
1776
1823
 
1777
1824
  }
1778
1825
 
1779
- /**
1780
- * Main module.
1781
- * @module illogical
1782
- */
1783
1826
  /**
1784
1827
  * Condition engine
1785
1828
  */
@@ -1790,6 +1833,8 @@ class Engine {
1790
1833
  * @param {Options?} options Parser options.
1791
1834
  */
1792
1835
  constructor(options) {
1836
+ _defineProperty(this, "parser", void 0);
1837
+
1793
1838
  this.parser = new Parser(options);
1794
1839
  }
1795
1840
  /**
@@ -1856,4 +1901,4 @@ class Engine {
1856
1901
 
1857
1902
  }
1858
1903
 
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 };
1904
+ 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 };
package/lib/illogical.js CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ function _defineProperty(obj, key, value) {
6
+ if (key in obj) {
7
+ Object.defineProperty(obj, key, {
8
+ value: value,
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true
12
+ });
13
+ } else {
14
+ obj[key] = value;
15
+ }
16
+
17
+ return obj;
18
+ }
19
+
5
20
  /**
6
21
  * Is number predicate.
7
22
  * @param value Tested value.
@@ -49,22 +64,7 @@ function isBoolean(value) {
49
64
  */
50
65
 
51
66
  function isEvaluable(value) {
52
- return typeof value === 'object' && value !== null && !Array.isArray(value);
53
- }
54
-
55
- function _defineProperty(obj, key, value) {
56
- if (key in obj) {
57
- Object.defineProperty(obj, key, {
58
- value: value,
59
- enumerable: true,
60
- configurable: true,
61
- writable: true
62
- });
63
- } else {
64
- obj[key] = value;
65
- }
66
-
67
- return obj;
67
+ 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
68
  }
69
69
 
70
70
  /**
@@ -101,12 +101,12 @@ class Comparison {
101
101
  * @param {Operand} right Right operand.
102
102
  */
103
103
  constructor(operator, operatorSymbol, left, right) {
104
- _defineProperty(this, "type", EvaluableType.Expression);
105
-
106
104
  this.operator = operator;
107
105
  this.operatorSymbol = operatorSymbol;
108
106
  this.left = left;
109
107
  this.right = right;
108
+
109
+ _defineProperty(this, "type", EvaluableType.Expression);
110
110
  }
111
111
  /**
112
112
  * {@link Evaluable.evaluate}
@@ -624,6 +624,9 @@ class Value extends Operand {
624
624
  }
625
625
 
626
626
  super();
627
+
628
+ _defineProperty(this, "value", void 0);
629
+
627
630
  this.value = value;
628
631
  }
629
632
  /**
@@ -820,11 +823,11 @@ class Logical {
820
823
  * @param {Evaluable[]} operands Collection of operands.
821
824
  */
822
825
  constructor(operator, operatorSymbol, operands) {
823
- _defineProperty(this, "type", EvaluableType.Expression);
824
-
825
826
  this.operator = operator;
826
827
  this.operatorSymbol = operatorSymbol;
827
828
  this.operands = operands;
829
+
830
+ _defineProperty(this, "type", EvaluableType.Expression);
828
831
  }
829
832
  /**
830
833
  * {@link Evaluable.evaluate}
@@ -1249,6 +1252,9 @@ class Collection extends Operand {
1249
1252
  */
1250
1253
  constructor(items) {
1251
1254
  super();
1255
+
1256
+ _defineProperty(this, "items", void 0);
1257
+
1252
1258
  this.items = items;
1253
1259
  }
1254
1260
  /**
@@ -1336,13 +1342,39 @@ const toString = value => {
1336
1342
  return undefined;
1337
1343
  };
1338
1344
 
1339
- function extractKeys(ctx, key) {
1345
+ const keyWithArrayIndexRegex = /^(?<currentKey>[^[\]]+?)(?<indexes>(?:\[\d+])+)?$/;
1346
+ 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]));
1361
+ }
1362
+ }
1363
+ } else {
1364
+ keys.push(key);
1365
+ }
1366
+
1367
+ return keys;
1368
+ });
1369
+
1370
+ const complexKeyExpression = /{([^{}]+)}/;
1371
+
1372
+ function extractComplexKeys(ctx, key) {
1340
1373
  // Resolve complex keys
1341
- const complexKeyExpression = /{([^{}]+)}/;
1342
1374
  let complexKeyMatches = complexKeyExpression.exec(key);
1343
1375
 
1344
1376
  while (complexKeyMatches) {
1345
- const resolvedValue = contextValueLookup(ctx, complexKeyMatches[1]);
1377
+ const resolvedValue = complexValueLookup(ctx, complexKeyMatches[1]);
1346
1378
 
1347
1379
  if (resolvedValue === undefined) {
1348
1380
  return undefined;
@@ -1352,14 +1384,30 @@ function extractKeys(ctx, key) {
1352
1384
  complexKeyMatches = complexKeyExpression.exec(key);
1353
1385
  }
1354
1386
 
1355
- let keys = [key]; // Nested reference
1387
+ return parseKey(key);
1388
+ }
1389
+
1390
+ const isContext = value => isObject(value);
1391
+
1392
+ const simpleValueLookup = keys => ctx => {
1393
+ let pointer = ctx;
1356
1394
 
1357
- if (key.includes('.')) {
1358
- keys = key.split('.');
1395
+ for (const key of keys) {
1396
+ if (typeof key === 'number') {
1397
+ if (!Array.isArray(pointer)) {
1398
+ return undefined;
1399
+ }
1400
+
1401
+ pointer = pointer[key];
1402
+ } else if (!isContext(pointer)) {
1403
+ return undefined;
1404
+ } else {
1405
+ pointer = pointer[key];
1406
+ }
1359
1407
  }
1360
1408
 
1361
- return keys;
1362
- }
1409
+ return pointer;
1410
+ };
1363
1411
  /**
1364
1412
  * Lookup for the reference in the context.
1365
1413
  * The nested context value is annotated with "." delimiter.
@@ -1370,42 +1418,14 @@ function extractKeys(ctx, key) {
1370
1418
  */
1371
1419
 
1372
1420
 
1373
- function contextValueLookup(ctx, key) {
1374
- const keys = extractKeys(ctx, key);
1421
+ function complexValueLookup(ctx, key) {
1422
+ const keys = extractComplexKeys(ctx, key);
1375
1423
 
1376
1424
  if (!keys) {
1377
1425
  return undefined;
1378
- } // Context pointer
1379
-
1380
-
1381
- let pointer = ctx;
1382
-
1383
- for (let i = 0; i < keys.length; i++) {
1384
- var _keys$i$match;
1385
-
1386
- const currentKey = keys[i].replace(/\[.+$/, '');
1387
- let currentValue = pointer[currentKey]; // Resolve array notation
1388
-
1389
- (_keys$i$match = keys[i].match(/\[\d+\]/g)) === null || _keys$i$match === void 0 ? void 0 : _keys$i$match.forEach(match => {
1390
- const arrayIndex = parseInt(match.replace(/[[\]]/g, ''));
1391
-
1392
- if (!Array.isArray(currentValue) || currentValue[arrayIndex] === undefined) {
1393
- currentValue = undefined;
1394
- } else {
1395
- currentValue = currentValue[arrayIndex];
1396
- }
1397
- }); // Last node
1398
-
1399
- if (i === keys.length - 1) {
1400
- return currentValue; // Nested path
1401
- } else if (currentValue !== undefined && isObject(currentValue)) {
1402
- pointer = currentValue; // Invalid nested reference path
1403
- } else {
1404
- break;
1405
- }
1406
1426
  }
1407
1427
 
1408
- return undefined;
1428
+ return simpleValueLookup(keys !== null && keys !== void 0 ? keys : [])(ctx);
1409
1429
  }
1410
1430
 
1411
1431
  let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
@@ -1416,10 +1436,13 @@ let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
1416
1436
  })(DataType || (DataType = {}));
1417
1437
 
1418
1438
  const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
1439
+
1440
+ const isComplexKey = key => key.indexOf('{') > -1;
1419
1441
  /**
1420
1442
  * Reference operand resolved within the context
1421
1443
  */
1422
1444
 
1445
+
1423
1446
  class Reference extends Operand {
1424
1447
  /**
1425
1448
  * @constructor
@@ -1431,6 +1454,15 @@ class Reference extends Operand {
1431
1454
  }
1432
1455
 
1433
1456
  super();
1457
+
1458
+ _defineProperty(this, "key", void 0);
1459
+
1460
+ _defineProperty(this, "dataType", void 0);
1461
+
1462
+ _defineProperty(this, "valueLookup", void 0);
1463
+
1464
+ _defineProperty(this, "getKeys", void 0);
1465
+
1434
1466
  this.key = key;
1435
1467
  const dataTypeMatch = dataTypeRegex.exec(this.key);
1436
1468
 
@@ -1441,6 +1473,17 @@ class Reference extends Operand {
1441
1473
  if (this.key.match(/.\(.+\)$/)) {
1442
1474
  this.key = this.key.replace(/.\(.+\)$/, '');
1443
1475
  }
1476
+
1477
+ if (isComplexKey(this.key)) {
1478
+ this.valueLookup = context => complexValueLookup(context, this.key);
1479
+
1480
+ this.getKeys = context => extractComplexKeys(context, this.key);
1481
+ } else {
1482
+ const keys = parseKey(this.key);
1483
+ this.valueLookup = simpleValueLookup(keys);
1484
+
1485
+ this.getKeys = () => keys;
1486
+ }
1444
1487
  }
1445
1488
  /**
1446
1489
  * Evaluate in the given context.
@@ -1450,7 +1493,7 @@ class Reference extends Operand {
1450
1493
 
1451
1494
 
1452
1495
  evaluate(ctx) {
1453
- return this.toDataType(contextValueLookup(ctx, this.key));
1496
+ return this.toDataType(this.valueLookup(ctx));
1454
1497
  }
1455
1498
  /**
1456
1499
  * {@link Evaluable.simplify}
@@ -1458,18 +1501,18 @@ class Reference extends Operand {
1458
1501
 
1459
1502
 
1460
1503
  simplify(ctx, strictKeys, optionalKeys) {
1461
- const keys = extractKeys(ctx, this.key);
1462
-
1463
- if (!keys) {
1464
- return this;
1465
- }
1504
+ var _this$getKeys;
1466
1505
 
1467
- const key = keys[0].replace(/\[.+$/, '');
1506
+ const [key] = (_this$getKeys = this.getKeys(ctx)) !== null && _this$getKeys !== void 0 ? _this$getKeys : [];
1468
1507
 
1469
1508
  if (ctx[key] !== undefined) {
1470
1509
  return this.evaluate(ctx);
1471
1510
  }
1472
1511
 
1512
+ if (!key || typeof key === 'number') {
1513
+ return this;
1514
+ }
1515
+
1473
1516
  return strictKeys && strictKeys.includes(key) || optionalKeys && !optionalKeys.includes(key) ? undefined : this;
1474
1517
  }
1475
1518
  /**
@@ -1571,6 +1614,10 @@ class Parser {
1571
1614
  * @param {Options?} options Parser options.
1572
1615
  */
1573
1616
  constructor(options) {
1617
+ _defineProperty(this, "opts", void 0);
1618
+
1619
+ _defineProperty(this, "expectedOperators", void 0);
1620
+
1574
1621
  this.opts = { ...defaultOptions
1575
1622
  }; // Apply exclusive options overrides
1576
1623
 
@@ -1780,10 +1827,6 @@ class Parser {
1780
1827
 
1781
1828
  }
1782
1829
 
1783
- /**
1784
- * Main module.
1785
- * @module illogical
1786
- */
1787
1830
  /**
1788
1831
  * Condition engine
1789
1832
  */
@@ -1794,6 +1837,8 @@ class Engine {
1794
1837
  * @param {Options?} options Parser options.
1795
1838
  */
1796
1839
  constructor(options) {
1840
+ _defineProperty(this, "parser", void 0);
1841
+
1797
1842
  this.parser = new Parser(options);
1798
1843
  }
1799
1844
  /**
@@ -1879,3 +1924,5 @@ exports.OPERATOR_SUFFIX = OPERATOR$6;
1879
1924
  exports.OPERATOR_UNDEFINED = OPERATOR$5;
1880
1925
  exports.OPERATOR_XOR = OPERATOR;
1881
1926
  exports["default"] = Engine;
1927
+ exports.defaultOptions = defaultOptions;
1928
+ exports.isEvaluable = isEvaluable;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@briza/illogical",
3
- "version": "1.5.2",
3
+ "version": "1.5.5",
4
4
  "description": "A micro conditional javascript engine used to parse the raw logical and comparison expressions, evaluate the expression in the given data context, and provide access to a text form of the given expressions.",
5
5
  "main": "lib/illogical.js",
6
6
  "module": "lib/illogical.esm.js",
@@ -42,31 +42,31 @@
42
42
  "rules"
43
43
  ],
44
44
  "devDependencies": {
45
- "@babel/core": "^7.16.12",
45
+ "@babel/core": "^7.17.9",
46
46
  "@babel/plugin-proposal-class-properties": "^7.16.7",
47
47
  "@babel/preset-env": "^7.16.11",
48
48
  "@babel/preset-typescript": "^7.16.7",
49
- "@rollup/plugin-babel": "^5.2.3",
50
- "@rollup/plugin-commonjs": "^21.0.1",
51
- "@rollup/plugin-node-resolve": "^13.1.3",
52
- "@types/jest": "^27.4.0",
53
- "@typescript-eslint/eslint-plugin": "^5.10.2",
54
- "@typescript-eslint/parser": "^5.10.2",
55
- "eslint": "^8.8.0",
56
- "eslint-config-prettier": "^8.3.0",
57
- "eslint-import-resolver-typescript": "^2.5.0",
58
- "eslint-plugin-import": "^2.25.4",
49
+ "@rollup/plugin-babel": "^5.3.1",
50
+ "@rollup/plugin-commonjs": "^21.0.3",
51
+ "@rollup/plugin-node-resolve": "^13.2.0",
52
+ "@types/jest": "^27.4.1",
53
+ "@typescript-eslint/eslint-plugin": "^5.19.0",
54
+ "@typescript-eslint/parser": "^5.19.0",
55
+ "eslint": "^8.13.0",
56
+ "eslint-config-prettier": "^8.5.0",
57
+ "eslint-import-resolver-typescript": "^2.7.1",
58
+ "eslint-plugin-import": "^2.26.0",
59
59
  "eslint-plugin-node": "^11.1.0",
60
60
  "eslint-plugin-prettier": "^3.4.1",
61
61
  "eslint-plugin-promise": "^6.0.0",
62
62
  "eslint-plugin-simple-import-sort": "^7.0.0",
63
- "jest": "^27.4.7",
63
+ "jest": "^27.5.1",
64
64
  "license-checker": "^25.0.1",
65
- "prettier": "^2.5.1",
66
- "rollup": "^2.66.1",
65
+ "prettier": "^2.6.2",
66
+ "rollup": "^2.70.1",
67
67
  "rollup-plugin-eslint": "^7.0.0",
68
- "ts-jest": "^27.1.3",
69
- "typedoc": "^0.22.11",
70
- "typescript": "^4.5.5"
68
+ "ts-jest": "^27.1.4",
69
+ "typedoc": "^0.22.15",
70
+ "typescript": "4.6.3"
71
71
  }
72
72
  }
package/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A micro conditional javascript engine used to parse the raw logical and comparison expressions, evaluate the expression in the given data context, and provide access to a text form of the given expressions.
4
4
 
5
- > Revision: February 1, 2022.
5
+ > Revision: March 22, 2022.
6
6
 
7
7
  ## About
8
8
 
@@ -15,7 +15,7 @@ export interface Context {
15
15
  /**
16
16
  * Evaluation result
17
17
  */
18
- export declare type Result = undefined | null | string | number | boolean | Array<Result>;
18
+ export declare type Result = undefined | null | string | number | boolean | Array<Result> | Record<string, unknown>;
19
19
  export declare enum EvaluableType {
20
20
  Operand = "Operand",
21
21
  Expression = "Expression"
package/types/index.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  * @module illogical
4
4
  */
5
5
  import { Context, Evaluable } from './common/evaluable';
6
+ import { isEvaluable } from './common/type-check';
6
7
  import { OPERATOR as OPERATOR_EQ } from './expression/comparison/eq';
7
8
  import { OPERATOR as OPERATOR_GE } from './expression/comparison/ge';
8
9
  import { OPERATOR as OPERATOR_GT } from './expression/comparison/gt';
@@ -23,7 +24,8 @@ import { OPERATOR as OPERATOR_OR } from './expression/logical/or';
23
24
  import { OPERATOR as OPERATOR_XOR } from './expression/logical/xor';
24
25
  import { ExpressionInput, Input } from './parser';
25
26
  import { Options } from './parser/options';
26
- export { OPERATOR_EQ, OPERATOR_NE, OPERATOR_GT, OPERATOR_GE, OPERATOR_LT, OPERATOR_LE, OPERATOR_IN, OPERATOR_NOT_IN, OPERATOR_PREFIX, OPERATOR_SUFFIX, OPERATOR_OVERLAP, OPERATOR_UNDEFINED, OPERATOR_PRESENT, OPERATOR_AND, OPERATOR_OR, OPERATOR_NOR, OPERATOR_XOR, OPERATOR_NOT, };
27
+ export { defaultOptions } from './parser/options';
28
+ export { isEvaluable, OPERATOR_EQ, OPERATOR_NE, OPERATOR_GT, OPERATOR_GE, OPERATOR_LT, OPERATOR_LE, OPERATOR_IN, OPERATOR_NOT_IN, OPERATOR_PREFIX, OPERATOR_SUFFIX, OPERATOR_OVERLAP, OPERATOR_UNDEFINED, OPERATOR_PRESENT, OPERATOR_AND, OPERATOR_OR, OPERATOR_NOR, OPERATOR_XOR, OPERATOR_NOT, };
27
29
  /**
28
30
  * Condition engine
29
31
  */
@@ -11,6 +11,8 @@ export declare enum DataType {
11
11
  export declare class Reference extends Operand {
12
12
  private readonly key;
13
13
  private readonly dataType;
14
+ private readonly valueLookup;
15
+ private readonly getKeys;
14
16
  /**
15
17
  * @constructor
16
18
  * @param {string} key Context key.