@briza/illogical 1.7.0 → 1.7.2

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.
@@ -90,15 +90,9 @@ function areAllResults(values) {
90
90
  * @param {Result[]} results results or evaluables
91
91
  * @returns {boolean} type guard
92
92
  */
93
- function areAllNumbers$1(results) {
93
+ function areAllNumbers(results) {
94
94
  return results.every(isNumber);
95
95
  }
96
- function isUndefined(value) {
97
- return value === undefined;
98
- }
99
- function isNull(value) {
100
- return value === null;
101
- }
102
96
 
103
97
  /**
104
98
  * Valid types for context members
@@ -156,7 +150,7 @@ class Arithmetic {
156
150
  if (presentValues.length !== results.length) {
157
151
  return false;
158
152
  }
159
- if (!areAllNumbers$1(presentValues)) {
153
+ if (!areAllNumbers(presentValues)) {
160
154
  throw new Error(`operands must be numbers for ${this.constructor.name}`);
161
155
  }
162
156
  return presentValues;
@@ -472,29 +466,33 @@ const toDateNumber = value => {
472
466
 
473
467
  const keyWithArrayIndexRegex = /^(?<currentKey>[^[\]]+?)(?<indexes>(?:\[\d+])+)?$/;
474
468
  const arrayIndexRegex = /\[(\d+)]/g;
475
- const parseBacktickWrappedKey = key => key.startsWith('`') && key.endsWith('`') ? key.slice(1, -1) : key;
476
- const parseKey = key => {
477
- const keys = key.match(/(`[^[\]]+`(\[\d+\])*|[^`.]+)/g);
478
- return !keys ? [] : keys.flatMap(key => {
479
- const unwrappedKey = parseBacktickWrappedKey(key);
480
- const keys = [];
481
- const parseResult = keyWithArrayIndexRegex.exec(unwrappedKey);
482
- if (parseResult) {
483
- var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
484
- 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);
485
- keys.push(extractedKey);
486
- const rawIndexes = parseResult === null || parseResult === void 0 || (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
487
- if (rawIndexes) {
488
- for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
489
- keys.push(parseInt(indexResult[1]));
490
- }
469
+ function parseBacktickWrappedKey(key) {
470
+ return key[0] === '`' && key[key.length - 1] === '`' ? key.slice(1, -1) : key;
471
+ }
472
+ function parseKeyComponents(key) {
473
+ const unwrappedKey = parseBacktickWrappedKey(key);
474
+ const keys = [];
475
+ const parseResult = keyWithArrayIndexRegex.exec(unwrappedKey);
476
+ if (parseResult) {
477
+ var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
478
+ 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);
479
+ keys.push(extractedKey);
480
+ const rawIndexes = parseResult === null || parseResult === void 0 || (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
481
+ if (rawIndexes) {
482
+ for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
483
+ keys.push(parseInt(indexResult[1]));
491
484
  }
492
- } else {
493
- keys.push(unwrappedKey);
494
485
  }
495
- return keys;
496
- });
497
- };
486
+ } else {
487
+ keys.push(unwrappedKey);
488
+ }
489
+ return keys;
490
+ }
491
+ const parseKeyRegex = /(`[^[\]]+`(\[\d+\])*|[^`.]+)/g;
492
+ function parseKey(key) {
493
+ const keys = key.match(parseKeyRegex);
494
+ return !keys ? [] : keys.flatMap(parseKeyComponents);
495
+ }
498
496
  const complexKeyExpression = /{([^{}]+)}/;
499
497
  function extractComplexKeys(ctx, key) {
500
498
  // Resolve complex keys
@@ -551,6 +549,7 @@ let DataType = /*#__PURE__*/function (DataType) {
551
549
  // Equivalent to /^.+\.\((Number|String)\)$/
552
550
  const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
553
551
  const isComplexKey = key => key.indexOf('{') > -1;
552
+ const castingRegex = /\.\(.+\)$/;
554
553
 
555
554
  /**
556
555
  * Reference operand resolved within the context
@@ -573,9 +572,7 @@ class Reference extends Operand {
573
572
  const dataTypeMatch = dataTypeRegex.exec(this.key);
574
573
  if (dataTypeMatch) {
575
574
  this.dataType = DataType[dataTypeMatch[1]];
576
- }
577
- if (this.key.match(/.\(.+\)$/)) {
578
- this.key = this.key.replace(/.\(.+\)$/, '');
575
+ this.key = this.key.replace(castingRegex, '');
579
576
  }
580
577
  if (isComplexKey(this.key)) {
581
578
  this.valueLookup = context => complexValueLookup(context, this.key);
@@ -595,6 +592,9 @@ class Reference extends Operand {
595
592
  evaluate(ctx) {
596
593
  return this.toDataType(this.valueLookup(ctx));
597
594
  }
595
+ checkStrictAndOptional(key, strictKeys, optionalKeys) {
596
+ return strictKeys !== undefined && (Array.isArray(strictKeys) ? strictKeys.includes(key) : strictKeys.has(key)) || optionalKeys !== undefined && (Array.isArray(optionalKeys) ? !optionalKeys.includes(key) : !optionalKeys.has(key)) ? undefined : this;
597
+ }
598
598
 
599
599
  /**
600
600
  * {@link Evaluable.simplify}
@@ -608,7 +608,7 @@ class Reference extends Operand {
608
608
  if (!key || typeof key === 'number') {
609
609
  return this;
610
610
  }
611
- return strictKeys && strictKeys.includes(key) || optionalKeys && !optionalKeys.includes(key) ? undefined : this;
611
+ return this.checkStrictAndOptional(key, strictKeys, optionalKeys);
612
612
  }
613
613
 
614
614
  /**
@@ -1690,7 +1690,7 @@ class Collection extends Operand {
1690
1690
  * @return {boolean}
1691
1691
  */
1692
1692
  function defaultReferencePredicate(key) {
1693
- return isString(key) && key.startsWith('$');
1693
+ return key[0] === '$';
1694
1694
  }
1695
1695
 
1696
1696
  /**
@@ -1748,6 +1748,7 @@ class Parser {
1748
1748
  _defineProperty(this, "opts", void 0);
1749
1749
  _defineProperty(this, "expectedRootOperators", void 0);
1750
1750
  _defineProperty(this, "unexpectedRootSymbols", new Set([OPERATOR$i, OPERATOR$j, OPERATOR$k, OPERATOR$l]));
1751
+ _defineProperty(this, "referenceCache", new Map());
1751
1752
  this.opts = {
1752
1753
  ...defaultOptions
1753
1754
  };
@@ -1769,6 +1770,18 @@ class Parser {
1769
1770
  get options() {
1770
1771
  return this.opts;
1771
1772
  }
1773
+ getReference(key) {
1774
+ const cached = this.referenceCache.get(key);
1775
+ if (cached !== undefined) {
1776
+ return cached;
1777
+ }
1778
+ const reference = new Reference(this.opts.referenceTransform(key));
1779
+ this.referenceCache.set(key, reference);
1780
+ return reference;
1781
+ }
1782
+ resolve(raw) {
1783
+ return isString(raw) && this.opts.referencePredicate(raw) ? this.getReference(raw) : new Value(raw);
1784
+ }
1772
1785
 
1773
1786
  /**
1774
1787
  * Parse raw expression into evaluable expression.
@@ -1927,524 +1940,17 @@ class Parser {
1927
1940
  * @param raw Raw data
1928
1941
  */
1929
1942
  getOperand(raw) {
1930
- const resolve = raw => this.opts.referencePredicate(raw) ? new Reference(this.opts.referenceTransform(raw)) : new Value(raw);
1931
1943
  if (Array.isArray(raw)) {
1932
- return new Collection(raw.map(item => resolve(item)));
1944
+ const collectionItems = [];
1945
+ for (const item of raw) {
1946
+ collectionItems.push(this.resolve(item));
1947
+ }
1948
+ return new Collection(collectionItems);
1933
1949
  }
1934
- return resolve(raw);
1950
+ return this.resolve(raw);
1935
1951
  }
1936
1952
  }
1937
1953
 
1938
- const isTrueResult = value => value === true;
1939
- const isFalseResult = value => value === false;
1940
- const isNonFalseResult = operand => operand !== false && !isEvaluable(operand);
1941
- const isNonTrueResult = operand => operand !== true && !isEvaluable(operand);
1942
- const resultToInputInternal = value => {
1943
- if (isUndefined(value)) {
1944
- return undefined;
1945
- }
1946
- if (Array.isArray(value)) {
1947
- return undefined;
1948
- }
1949
- return value;
1950
- };
1951
- const resultToInput = value => {
1952
- if (isUndefined(value)) {
1953
- return undefined;
1954
- }
1955
- if (Array.isArray(value)) {
1956
- const definedValues = value.map(resultToInputInternal).filter(val => !isUndefined(val));
1957
- if (definedValues.length === 0) {
1958
- return undefined;
1959
- }
1960
- return definedValues;
1961
- }
1962
- return value;
1963
- };
1964
- const areAllNumbers = results => {
1965
- return results.every(isNumber);
1966
- };
1967
- const areAllInputs = values => values.every(value => !isEvaluable(value));
1968
- const getInputValues = results => {
1969
- const presentValues = results.filter(result => !isNull(result) && !isUndefined(result));
1970
- // If we have missing context values the result or we still have refences
1971
- // simplify to false.
1972
- if (presentValues.length !== results.length || !areAllNumbers(presentValues)) {
1973
- return false;
1974
- }
1975
- return presentValues;
1976
- };
1977
- const extractValues = input => {
1978
- const evaluable = isEvaluable(input);
1979
- if (!evaluable) {
1980
- return Array.isArray(input) ? input : [input];
1981
- }
1982
- if (input instanceof Collection) {
1983
- const results = input.getItems();
1984
- const values = results.map(item => item instanceof Value ? item.evaluate() : null).filter(value => !isNull(value));
1985
- return values;
1986
- }
1987
- return [];
1988
- };
1989
-
1990
- const simplifyAnd = simplifyInput => input => {
1991
- const [operator, ...operands] = input;
1992
- const simplifiedOperands = [];
1993
- for (const operand of operands) {
1994
- const simplification = simplifyInput(operand);
1995
- if (isUndefined(simplification) || isBoolean(simplification) && !isTrueResult(simplification)) {
1996
- // Short-circuit for AND
1997
- return false;
1998
- }
1999
- simplifiedOperands.push(simplification);
2000
- }
2001
-
2002
- // Remove false operands leaving only the Inputs
2003
- const simplified = simplifiedOperands.filter(isNonTrueResult);
2004
- if (simplified.length === 0) {
2005
- return true;
2006
- }
2007
- if (simplified.length === 1) {
2008
- return simplified[0];
2009
- }
2010
- return [operator, ...simplified];
2011
- };
2012
-
2013
- const simplify$3 = (simplifyInput, predicate) => input => {
2014
- const [, ...operands] = input;
2015
- const results = operands.map(simplifyInput);
2016
- if (areAllInputs(results)) {
2017
- const presentValues = getInputValues(results);
2018
- if (isFalseResult(presentValues)) {
2019
- return false;
2020
- }
2021
- return presentValues.reduce(predicate);
2022
- }
2023
- return input;
2024
- };
2025
- const simplifySum = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('sum'))(input);
2026
- const simplifySubtract = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('subtract'))(input);
2027
- const simplifyMultiply = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('multiply'))(input);
2028
- const simplifyDivide = simplifyInput => input => simplify$3(simplifyInput, (acc, result) => acc / result)(input);
2029
-
2030
- const simplifyComparison = predicate => (opts, simplifyInput) => input => {
2031
- const [operator, ...operands] = input;
2032
- const [left, right] = operands;
2033
- const leftSimplified = simplifyInput(left);
2034
- const rightSimplified = simplifyInput(right);
2035
- const isLeftEvaluable = isEvaluable(leftSimplified);
2036
- const isRightEvaluable = isEvaluable(rightSimplified);
2037
- if (isLeftEvaluable || isRightEvaluable) {
2038
- // If either left or right is an array, we cannot simplify further
2039
- return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
2040
- }
2041
- if (isNumber(leftSimplified) && isNumber(rightSimplified)) {
2042
- return predicate(leftSimplified, rightSimplified);
2043
- }
2044
- const leftDate = toDateNumber(leftSimplified);
2045
- const rightDate = toDateNumber(rightSimplified);
2046
- if (leftDate && rightDate) {
2047
- return predicate(leftDate, rightDate);
2048
- }
2049
- if (Array.isArray(leftSimplified) || Array.isArray(rightSimplified)) {
2050
- return [operator, leftSimplified, rightSimplified];
2051
- }
2052
- return false;
2053
- };
2054
- const simplifyGt = (opts, simplifyInput) => input => simplifyComparison((left, right) => left > right)(opts, simplifyInput)(input);
2055
- const simplifyGe = (opts, simplifyInput) => input => simplifyComparison((left, right) => left >= right)(opts, simplifyInput)(input);
2056
- const simplifyLt = (opts, simplifyInput) => input => simplifyComparison((left, right) => left < right)(opts, simplifyInput)(input);
2057
- const simplifyLe = (opts, simplifyInput) => input => simplifyComparison((left, right) => left <= right)(opts, simplifyInput)(input);
2058
-
2059
- const simplifyEquality = predicate => (opts, simplifyInput) => input => {
2060
- const [operator, ...operands] = input;
2061
- const [left, right] = operands;
2062
- const leftSimplified = simplifyInput(left);
2063
- const rightSimplified = simplifyInput(right);
2064
- const isLeftEvaluable = isEvaluable(leftSimplified);
2065
- const isRightEvaluable = isEvaluable(rightSimplified);
2066
- if (isLeftEvaluable || isRightEvaluable) {
2067
- // If either left or right is an array, we cannot simplify further
2068
- return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
2069
- }
2070
-
2071
- // See Equal.comparison
2072
- return predicate(leftSimplified, rightSimplified);
2073
- };
2074
- const simplifyEq = (opts, simplifyInput) => input => simplifyEquality((left, right) => left === right)(opts, simplifyInput)(input);
2075
- const simplifyNe = (opts, simplifyInput) => input => simplifyEquality((left, right) => left !== right)(opts, simplifyInput)(input);
2076
-
2077
- const simplify$2 = (originalInput, nonArrayInput, arrayInput) => {
2078
- // If we don't have the non-array operand, there is nothing to do.
2079
- if (isEvaluable(nonArrayInput)) {
2080
- return originalInput;
2081
- }
2082
-
2083
- // If we don't have all the values, try with what we have for the
2084
- // positive case, but otherwise return the original input.
2085
- if (isEvaluable(arrayInput)) {
2086
- const leftValues = extractValues(arrayInput);
2087
- const isFound = leftValues.indexOf(nonArrayInput) > -1;
2088
- return isFound ? true : originalInput;
2089
- }
2090
-
2091
- // If we have all the values, we can check if the non-array operand is
2092
- // included in the array operand.
2093
- return arrayInput.indexOf(nonArrayInput) > -1;
2094
- };
2095
- const simplifyIn = simplifyInput => input => {
2096
- const [, ...operands] = input;
2097
- const [left, right] = operands;
2098
- if (isNull(left) || isUndefined(left) || isNull(right) || isUndefined(right)) {
2099
- return false;
2100
- }
2101
- const leftSimplified = simplifyInput(left);
2102
- const rightSimplified = simplifyInput(right);
2103
- const isLeftArray = Array.isArray(leftSimplified) || isEvaluable(leftSimplified);
2104
- const isRightArray = Array.isArray(rightSimplified) || isEvaluable(rightSimplified);
2105
- if (isLeftArray) {
2106
- return simplify$2(input, rightSimplified, leftSimplified);
2107
- }
2108
- if (isRightArray) {
2109
- return simplify$2(input, leftSimplified, rightSimplified);
2110
- }
2111
- return false;
2112
- };
2113
-
2114
- const simplifyNor = (opts, simplifyInput) => input => {
2115
- const [operator, ...operands] = input;
2116
- const simplifiedOperands = [];
2117
- for (const operand of operands) {
2118
- const simplification = simplifyInput(operand);
2119
- if (isUndefined(simplification) || isBoolean(simplification) && isTrueResult(simplification)) {
2120
- // Short-circuit for AND
2121
- return false;
2122
- }
2123
- simplifiedOperands.push(simplification);
2124
- }
2125
-
2126
- // Remove true operands leaving only the Inputs
2127
- const simplified = simplifiedOperands.filter(isNonFalseResult);
2128
- if (simplified.length === 0) {
2129
- return true;
2130
- }
2131
- if (simplified.length === 1) {
2132
- var _opts$operatorMapping;
2133
- return [(_opts$operatorMapping = opts.operatorMapping.get(OPERATOR$3)) !== null && _opts$operatorMapping !== void 0 ? _opts$operatorMapping : 'NOT', simplified[0]];
2134
- }
2135
- return [operator, ...simplified];
2136
- };
2137
-
2138
- const simplifyNot = simplifyInput => input => {
2139
- const [, ...operands] = input;
2140
- const simplification = simplifyInput(operands[0]);
2141
- if (isBoolean(simplification)) {
2142
- return !simplification;
2143
- }
2144
- return input;
2145
- };
2146
-
2147
- const simplifyNotIn = simplifyInput => input => {
2148
- const [, ...operands] = input;
2149
- const [left, right] = operands;
2150
- const leftArray = Array.isArray(left);
2151
- const rightArray = Array.isArray(right);
2152
- if (isNull(left) || isUndefined(left) || isNull(right) || isUndefined(right) || leftArray && rightArray || !leftArray && !rightArray) {
2153
- return true;
2154
- }
2155
- if (leftArray) {
2156
- // If any operand is still an Evaluable, we cannot simplify further
2157
- const rightSimplified = simplifyInput(right);
2158
- if (isEvaluable(rightSimplified)) {
2159
- return input;
2160
- }
2161
- const leftSimplified = left.map(simplifyInput);
2162
- if (leftSimplified.some(isEvaluable)) {
2163
- return input;
2164
- }
2165
- return leftSimplified.indexOf(rightSimplified) === -1;
2166
- }
2167
- if (rightArray) {
2168
- const leftSimplified = simplifyInput(left);
2169
- if (isEvaluable(leftSimplified)) {
2170
- return input;
2171
- }
2172
- const rightSimplified = right.map(simplifyInput);
2173
- if (rightSimplified.some(isEvaluable)) {
2174
- return input;
2175
- }
2176
- return rightSimplified.indexOf(leftSimplified) === -1;
2177
- }
2178
- return input;
2179
- };
2180
-
2181
- const simplifyOr = simplifyInput => input => {
2182
- const [operator, ...operands] = input;
2183
- const simplifiedOperands = [];
2184
- for (const operand of operands) {
2185
- const simplification = simplifyInput(operand);
2186
- if (isBoolean(simplification) && isTrueResult(simplification)) {
2187
- // Short-circuit for OR
2188
- return true;
2189
- } else if (simplification) {
2190
- simplifiedOperands.push(simplification);
2191
- }
2192
- }
2193
- const simplified = simplifiedOperands.filter(isNonFalseResult);
2194
- if (simplified.length === 0) {
2195
- return false;
2196
- }
2197
- if (simplified.length === 1) {
2198
- return simplified[0];
2199
- }
2200
- return [operator, ...simplified];
2201
- };
2202
-
2203
- const simplifyOverlap = simplifyInput => input => {
2204
- const [, ...operands] = input;
2205
- const [left, right] = operands;
2206
- const leftSimplified = simplifyInput(left);
2207
- const rightSimplified = simplifyInput(right);
2208
- const isLeftEvaluable = isEvaluable(leftSimplified);
2209
- const isRightEvaluable = isEvaluable(rightSimplified);
2210
-
2211
- // If we don't have all operands simplified, we can try the positive case
2212
- // of the values we have satisfying the OVERLAP. But if not, we need to
2213
- // return the original input.
2214
- if (isLeftEvaluable || isRightEvaluable) {
2215
- const leftValues = extractValues(leftSimplified);
2216
- const rightValues = extractValues(rightSimplified);
2217
- const rightSet = new Set(rightValues);
2218
- const res = leftValues.some(element => rightSet.has(element));
2219
- if (res) {
2220
- return true;
2221
- }
2222
- return input;
2223
- }
2224
-
2225
- // If simplified results are not arrays, it means we had a strictKey
2226
- // without values provided. Simplify to false.
2227
- if (!Array.isArray(leftSimplified) || !Array.isArray(rightSimplified)) {
2228
- return false;
2229
- }
2230
- const rightSet = new Set(rightSimplified);
2231
- const res = leftSimplified.some(element => rightSet.has(element));
2232
- if (res) {
2233
- return true;
2234
- }
2235
- return false;
2236
- };
2237
-
2238
- const simplify$1 = (opts, simplifyInput, startsWith = true) => input => {
2239
- const [operator, ...operands] = input;
2240
- const [left, right] = operands;
2241
- const leftSimplified = simplifyInput(left);
2242
- const rightSimplified = simplifyInput(right);
2243
- const isLeftEvaluable = isEvaluable(leftSimplified);
2244
- const isRightEvaluable = isEvaluable(rightSimplified);
2245
- if (isLeftEvaluable || isRightEvaluable) {
2246
- // If either left or right is an array, we cannot simplify further
2247
- return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
2248
- }
2249
- if (isString(leftSimplified) && isString(rightSimplified)) {
2250
- return startsWith ? rightSimplified.startsWith(leftSimplified) : leftSimplified.endsWith(rightSimplified);
2251
- }
2252
- return false;
2253
- };
2254
- const simplifyPrefix = (opts, simplifyInput) => input => simplify$1(opts, simplifyInput)(input);
2255
- const simplifySuffix = (opts, simplifyInput) => input => simplify$1(opts, simplifyInput, false)(input);
2256
-
2257
- const simplify = (simplifyInput, predicate, present = true) => input => {
2258
- const [, ...operands] = input;
2259
- const [operand] = operands;
2260
- const simplified = simplifyInput(operand);
2261
- const isOperandEvaluable = isEvaluable(simplified);
2262
- if (isOperandEvaluable) {
2263
- return input;
2264
- }
2265
-
2266
- // Operand simplifies to itself when it is included in strictKeys or
2267
- // optionalKeys, thus it was undefined.
2268
- if (operand === simplified) {
2269
- return !present;
2270
- }
2271
- return predicate(simplified);
2272
- };
2273
- const simplifyPresent = simplifyInput => input => simplify(simplifyInput, input => !isUndefined(input) && !isNull(input))(input);
2274
- const simplifyUndefined = simplifyInput => input => simplify(simplifyInput, isUndefined, false)(input);
2275
-
2276
- const simplifyXor = (opts, simplifyInput) => input => {
2277
- const [operator, ...operands] = input;
2278
- let trueCount = 0;
2279
- const simplifiedOperands = [];
2280
- for (const operand of operands) {
2281
- const simplification = simplifyInput(operand);
2282
- if (isBoolean(simplification) && isTrueResult(simplification)) {
2283
- trueCount++;
2284
- continue;
2285
- }
2286
- if (isBoolean(simplification) && isFalseResult(simplification)) {
2287
- continue;
2288
- }
2289
- if (!isEvaluable(simplification)) {
2290
- simplifiedOperands.push(simplification);
2291
- }
2292
- }
2293
- if (trueCount > 1) {
2294
- return false;
2295
- }
2296
- if (simplifiedOperands.length === 0) {
2297
- return trueCount === 1;
2298
- }
2299
- if (simplifiedOperands.length === 1) {
2300
- if (trueCount === 1) {
2301
- var _opts$operatorMapping;
2302
- return [(_opts$operatorMapping = opts.operatorMapping.get(OPERATOR$3)) !== null && _opts$operatorMapping !== void 0 ? _opts$operatorMapping : 'NOT', simplifiedOperands[0]];
2303
- }
2304
- return simplifiedOperands[0];
2305
- }
2306
- if (trueCount === 1) {
2307
- var _opts$operatorMapping2;
2308
- return [(_opts$operatorMapping2 = opts.operatorMapping.get(OPERATOR$2)) !== null && _opts$operatorMapping2 !== void 0 ? _opts$operatorMapping2 : 'NOR', ...simplifiedOperands];
2309
- }
2310
- return [operator, ...simplifiedOperands];
2311
- };
2312
-
2313
- const unsafeSimplify = (context, opts, strictKeys, optionalKeys) => {
2314
- const simplifyInput = input => {
2315
- // Value or Reference
2316
- if (!Array.isArray(input)) {
2317
- // Reference
2318
- if (isString(input) && opts.referencePredicate(input)) {
2319
- const result = new Reference(opts.referenceTransform(input)).simplify(context, strictKeys, optionalKeys);
2320
- if (isEvaluable(result)) {
2321
- return result;
2322
- }
2323
- const inputResult = resultToInput(result);
2324
- if (!isUndefined(inputResult)) {
2325
- return inputResult;
2326
- }
2327
- // It should have been a boolean or an Evaluable, but just in case
2328
- // fallback to returning the input.
2329
- }
2330
- // Value
2331
- return input;
2332
- }
2333
- const [operator] = input;
2334
- switch (operator) {
2335
- // Logical operators
2336
- case opts.operatorMapping.get(OPERATOR$4):
2337
- {
2338
- return simplifyAnd(simplifyInput)(input);
2339
- }
2340
- case opts.operatorMapping.get(OPERATOR$1):
2341
- {
2342
- return simplifyOr(simplifyInput)(input);
2343
- }
2344
- case opts.operatorMapping.get(OPERATOR$2):
2345
- {
2346
- return simplifyNor(opts, simplifyInput)(input);
2347
- }
2348
- case opts.operatorMapping.get(OPERATOR):
2349
- {
2350
- return simplifyXor(opts, simplifyInput)(input);
2351
- }
2352
- case opts.operatorMapping.get(OPERATOR$3):
2353
- {
2354
- return simplifyNot(simplifyInput)(input);
2355
- }
2356
- // Comparison operators
2357
- case opts.operatorMapping.get(OPERATOR$h):
2358
- {
2359
- return simplifyEq(opts, simplifyInput)(input);
2360
- }
2361
- case opts.operatorMapping.get(OPERATOR$b):
2362
- {
2363
- return simplifyNe(opts, simplifyInput)(input);
2364
- }
2365
- case opts.operatorMapping.get(OPERATOR$f):
2366
- {
2367
- return simplifyGt(opts, simplifyInput)(input);
2368
- }
2369
- case opts.operatorMapping.get(OPERATOR$g):
2370
- {
2371
- return simplifyGe(opts, simplifyInput)(input);
2372
- }
2373
- case opts.operatorMapping.get(OPERATOR$c):
2374
- {
2375
- return simplifyLt(opts, simplifyInput)(input);
2376
- }
2377
- case opts.operatorMapping.get(OPERATOR$d):
2378
- {
2379
- return simplifyLe(opts, simplifyInput)(input);
2380
- }
2381
- case opts.operatorMapping.get(OPERATOR$e):
2382
- {
2383
- return simplifyIn(simplifyInput)(input);
2384
- }
2385
- case opts.operatorMapping.get(OPERATOR$a):
2386
- {
2387
- return simplifyNotIn(simplifyInput)(input);
2388
- }
2389
- case opts.operatorMapping.get(OPERATOR$8):
2390
- {
2391
- return simplifyPrefix(opts, simplifyInput)(input);
2392
- }
2393
- case opts.operatorMapping.get(OPERATOR$6):
2394
- {
2395
- return simplifySuffix(opts, simplifyInput)(input);
2396
- }
2397
- case opts.operatorMapping.get(OPERATOR$9):
2398
- {
2399
- return simplifyOverlap(simplifyInput)(input);
2400
- }
2401
- case opts.operatorMapping.get(OPERATOR$5):
2402
- {
2403
- return simplifyUndefined(simplifyInput)(input);
2404
- }
2405
- case opts.operatorMapping.get(OPERATOR$7):
2406
- {
2407
- return simplifyPresent(simplifyInput)(input);
2408
- }
2409
- // Arithmetic operators
2410
- case opts.operatorMapping.get(OPERATOR$i):
2411
- {
2412
- return simplifySum(simplifyInput)(input);
2413
- }
2414
- case opts.operatorMapping.get(OPERATOR$j):
2415
- {
2416
- return simplifySubtract(simplifyInput)(input);
2417
- }
2418
- case opts.operatorMapping.get(OPERATOR$k):
2419
- {
2420
- return simplifyMultiply(simplifyInput)(input);
2421
- }
2422
- case opts.operatorMapping.get(OPERATOR$l):
2423
- {
2424
- return simplifyDivide(simplifyInput)(input);
2425
- }
2426
- default:
2427
- {
2428
- // Handle as an array of References / Values if no operator matches
2429
- const result = input.map(simplifyInput);
2430
- if (!areAllInputs(result)) {
2431
- return new Collection(result.map(item => {
2432
- if (item instanceof Reference) {
2433
- return item;
2434
- }
2435
- if (!isEvaluable(item)) {
2436
- return new Value(item);
2437
- }
2438
- throw new Error('Unexpected expression found within a collection of values/references');
2439
- }));
2440
- }
2441
- return result;
2442
- }
2443
- }
2444
- };
2445
- return simplifyInput;
2446
- };
2447
-
2448
1954
  const unexpectedResultError = 'non expression or boolean result should be returned';
2449
1955
 
2450
1956
  /**
@@ -2501,10 +2007,12 @@ class Engine {
2501
2007
  *
2502
2008
  * @param {ExpressionInput} exp Raw expression.
2503
2009
  * @param {Context} context Evaluation data context.
2504
- * @param {string[]} strictKeys keys to be considered present even if they are not present in the context
2505
- * @param {string[]} optionalKeys keys to be considered not present unless they are in the context or in
2010
+ * @param {string[] | Set<string>} strictKeys keys to be considered present even if they are not present in the
2011
+ * context. Passing as a Set is recommended for performance reasons.
2012
+ * @param {string[] | Set<string>} optionalKeys keys to be considered not present unless they are in the context or in
2506
2013
  * `strictKeys`; when `strictKeys` is `undefined` and `optionalKeys` is an array, every key that is not in
2507
- * `optionalKeys` is considered to be present and thus will be evaluated
2014
+ * `optionalKeys` is considered to be present and thus will be evaluated. Passing as a Set is recommended for
2015
+ * performance reasons.
2508
2016
  * @returns {Inpunt | boolean}
2509
2017
  */
2510
2018
  simplify(exp, context, strictKeys, optionalKeys) {
@@ -2517,18 +2025,6 @@ class Engine {
2517
2025
  }
2518
2026
  throw new Error(unexpectedResultError);
2519
2027
  }
2520
- unsafeSimplify(exp, context, strictKeys, optionalKeys) {
2521
- const result = unsafeSimplify(context, this.parser.options, strictKeys, optionalKeys)(exp);
2522
- if (isBoolean(result)) {
2523
- return result;
2524
- }
2525
-
2526
- // The unsafe implementation should not expose the Evaluable interface
2527
- if (isEvaluable(result)) {
2528
- throw new Error('Unexpected Evaluable not serialized result');
2529
- }
2530
- return result;
2531
- }
2532
2028
  }
2533
2029
 
2534
2030
  export { OPERATOR$4 as OPERATOR_AND, OPERATOR$l as OPERATOR_DIVIDE, 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$k as OPERATOR_MULTIPLY, 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$j as OPERATOR_SUBTRACT, OPERATOR$6 as OPERATOR_SUFFIX, OPERATOR$i as OPERATOR_SUM, OPERATOR$5 as OPERATOR_UNDEFINED, OPERATOR as OPERATOR_XOR, Engine as default, defaultOptions, isEvaluable };