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