@briza/illogical 1.6.1 → 1.7.1

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
@@ -5,16 +5,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  function _defineProperty(e, r, t) {
6
6
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
7
7
  value: t,
8
- enumerable: !0,
9
- configurable: !0,
10
- writable: !0
8
+ enumerable: true,
9
+ configurable: true,
10
+ writable: true
11
11
  }) : e[r] = t, e;
12
12
  }
13
13
  function _toPrimitive(t, r) {
14
14
  if ("object" != typeof t || !t) return t;
15
15
  var e = t[Symbol.toPrimitive];
16
16
  if (void 0 !== e) {
17
- var i = e.call(t, r || "default");
17
+ var i = e.call(t, r);
18
18
  if ("object" != typeof i) return i;
19
19
  throw new TypeError("@@toPrimitive must return a primitive value.");
20
20
  }
@@ -94,9 +94,15 @@ function areAllResults(values) {
94
94
  * @param {Result[]} results results or evaluables
95
95
  * @returns {boolean} type guard
96
96
  */
97
- function areAllNumbers(results) {
97
+ function areAllNumbers$1(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
+ }
100
106
 
101
107
  /**
102
108
  * Valid types for context members
@@ -154,7 +160,7 @@ class Arithmetic {
154
160
  if (presentValues.length !== results.length) {
155
161
  return false;
156
162
  }
157
- if (!areAllNumbers(presentValues)) {
163
+ if (!areAllNumbers$1(presentValues)) {
158
164
  throw new Error(`operands must be numbers for ${this.constructor.name}`);
159
165
  }
160
166
  return presentValues;
@@ -470,29 +476,33 @@ const toDateNumber = value => {
470
476
 
471
477
  const keyWithArrayIndexRegex = /^(?<currentKey>[^[\]]+?)(?<indexes>(?:\[\d+])+)?$/;
472
478
  const arrayIndexRegex = /\[(\d+)]/g;
473
- const parseBacktickWrappedKey = key => key.startsWith('`') && key.endsWith('`') ? key.slice(1, -1) : key;
474
- const parseKey = key => {
475
- const keys = key.match(/(`[^[\]]+`(\[\d+\])*|[^`.]+)/g);
476
- return !keys ? [] : keys.flatMap(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]));
488
- }
479
+ function parseBacktickWrappedKey(key) {
480
+ return key[0] === '`' && key[key.length - 1] === '`' ? key.slice(1, -1) : key;
481
+ }
482
+ function parseKeyComponents(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]));
489
494
  }
490
- } else {
491
- keys.push(unwrappedKey);
492
495
  }
493
- return keys;
494
- });
495
- };
496
+ } else {
497
+ keys.push(unwrappedKey);
498
+ }
499
+ return keys;
500
+ }
501
+ const parseKeyRegex = /(`[^[\]]+`(\[\d+\])*|[^`.]+)/g;
502
+ function parseKey(key) {
503
+ const keys = key.match(parseKeyRegex);
504
+ return !keys ? [] : keys.flatMap(parseKeyComponents);
505
+ }
496
506
  const complexKeyExpression = /{([^{}]+)}/;
497
507
  function extractComplexKeys(ctx, key) {
498
508
  // Resolve complex keys
@@ -549,6 +559,7 @@ let DataType = /*#__PURE__*/function (DataType) {
549
559
  // Equivalent to /^.+\.\((Number|String)\)$/
550
560
  const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
551
561
  const isComplexKey = key => key.indexOf('{') > -1;
562
+ const castingRegex = /\.\(.+\)$/;
552
563
 
553
564
  /**
554
565
  * Reference operand resolved within the context
@@ -571,9 +582,7 @@ class Reference extends Operand {
571
582
  const dataTypeMatch = dataTypeRegex.exec(this.key);
572
583
  if (dataTypeMatch) {
573
584
  this.dataType = DataType[dataTypeMatch[1]];
574
- }
575
- if (this.key.match(/.\(.+\)$/)) {
576
- this.key = this.key.replace(/.\(.+\)$/, '');
585
+ this.key = this.key.replace(castingRegex, '');
577
586
  }
578
587
  if (isComplexKey(this.key)) {
579
588
  this.valueLookup = context => complexValueLookup(context, this.key);
@@ -1617,6 +1626,14 @@ class Xor extends Logical {
1617
1626
  * Collection operand resolved containing mixture of value and references.
1618
1627
  */
1619
1628
  class Collection extends Operand {
1629
+ /**
1630
+ * Get the items in the collection.
1631
+ * @returns {Array<Value | Reference>}
1632
+ */
1633
+ getItems() {
1634
+ return this.items;
1635
+ }
1636
+
1620
1637
  /**
1621
1638
  * @constructor
1622
1639
  * @param {Operand[]} items Collection of operands.
@@ -1680,7 +1697,7 @@ class Collection extends Operand {
1680
1697
  * @return {boolean}
1681
1698
  */
1682
1699
  function defaultReferencePredicate(key) {
1683
- return isString(key) && key.startsWith('$');
1700
+ return key[0] === '$';
1684
1701
  }
1685
1702
 
1686
1703
  /**
@@ -1738,6 +1755,7 @@ class Parser {
1738
1755
  _defineProperty(this, "opts", void 0);
1739
1756
  _defineProperty(this, "expectedRootOperators", void 0);
1740
1757
  _defineProperty(this, "unexpectedRootSymbols", new Set([OPERATOR$i, OPERATOR$j, OPERATOR$k, OPERATOR$l]));
1758
+ _defineProperty(this, "referenceCache", new Map());
1741
1759
  this.opts = {
1742
1760
  ...defaultOptions
1743
1761
  };
@@ -1759,6 +1777,18 @@ class Parser {
1759
1777
  get options() {
1760
1778
  return this.opts;
1761
1779
  }
1780
+ getReference(key) {
1781
+ const cached = this.referenceCache.get(key);
1782
+ if (cached !== undefined) {
1783
+ return cached;
1784
+ }
1785
+ const reference = new Reference(this.opts.referenceTransform(key));
1786
+ this.referenceCache.set(key, reference);
1787
+ return reference;
1788
+ }
1789
+ resolve(raw) {
1790
+ return isString(raw) && this.opts.referencePredicate(raw) ? this.getReference(raw) : new Value(raw);
1791
+ }
1762
1792
 
1763
1793
  /**
1764
1794
  * Parse raw expression into evaluable expression.
@@ -1917,14 +1947,527 @@ class Parser {
1917
1947
  * @param raw Raw data
1918
1948
  */
1919
1949
  getOperand(raw) {
1920
- const resolve = raw => this.opts.referencePredicate(raw) ? new Reference(this.opts.referenceTransform(raw)) : new Value(raw);
1921
1950
  if (Array.isArray(raw)) {
1922
- return new Collection(raw.map(item => resolve(item)));
1951
+ const collectionItems = [];
1952
+ for (const item of raw) {
1953
+ collectionItems.push(this.resolve(item));
1954
+ }
1955
+ return new Collection(collectionItems);
1923
1956
  }
1924
- return resolve(raw);
1957
+ return this.resolve(raw);
1925
1958
  }
1926
1959
  }
1927
1960
 
1961
+ const isTrueResult = value => value === true;
1962
+ const isFalseResult = value => value === false;
1963
+ const isNonFalseResult = operand => operand !== false && !isEvaluable(operand);
1964
+ const isNonTrueResult = operand => operand !== true && !isEvaluable(operand);
1965
+ const resultToInputInternal = value => {
1966
+ if (isUndefined(value)) {
1967
+ return undefined;
1968
+ }
1969
+ if (Array.isArray(value)) {
1970
+ return undefined;
1971
+ }
1972
+ return value;
1973
+ };
1974
+ const resultToInput = value => {
1975
+ if (isUndefined(value)) {
1976
+ return undefined;
1977
+ }
1978
+ if (Array.isArray(value)) {
1979
+ const definedValues = value.map(resultToInputInternal).filter(val => !isUndefined(val));
1980
+ if (definedValues.length === 0) {
1981
+ return undefined;
1982
+ }
1983
+ return definedValues;
1984
+ }
1985
+ return value;
1986
+ };
1987
+ const areAllNumbers = results => {
1988
+ return results.every(isNumber);
1989
+ };
1990
+ const areAllInputs = values => values.every(value => !isEvaluable(value));
1991
+ const getInputValues = results => {
1992
+ const presentValues = results.filter(result => !isNull(result) && !isUndefined(result));
1993
+ // If we have missing context values the result or we still have refences
1994
+ // simplify to false.
1995
+ if (presentValues.length !== results.length || !areAllNumbers(presentValues)) {
1996
+ return false;
1997
+ }
1998
+ return presentValues;
1999
+ };
2000
+ const extractValues = input => {
2001
+ const evaluable = isEvaluable(input);
2002
+ if (!evaluable) {
2003
+ return Array.isArray(input) ? input : [input];
2004
+ }
2005
+ if (input instanceof Collection) {
2006
+ const results = input.getItems();
2007
+ const values = results.map(item => item instanceof Value ? item.evaluate() : null).filter(value => !isNull(value));
2008
+ return values;
2009
+ }
2010
+ return [];
2011
+ };
2012
+
2013
+ const simplifyAnd = simplifyInput => input => {
2014
+ const [operator, ...operands] = input;
2015
+ const simplifiedOperands = [];
2016
+ for (const operand of operands) {
2017
+ const simplification = simplifyInput(operand);
2018
+ if (isUndefined(simplification) || isBoolean(simplification) && !isTrueResult(simplification)) {
2019
+ // Short-circuit for AND
2020
+ return false;
2021
+ }
2022
+ simplifiedOperands.push(simplification);
2023
+ }
2024
+
2025
+ // Remove false operands leaving only the Inputs
2026
+ const simplified = simplifiedOperands.filter(isNonTrueResult);
2027
+ if (simplified.length === 0) {
2028
+ return true;
2029
+ }
2030
+ if (simplified.length === 1) {
2031
+ return simplified[0];
2032
+ }
2033
+ return [operator, ...simplified];
2034
+ };
2035
+
2036
+ const simplify$3 = (simplifyInput, predicate) => input => {
2037
+ const [, ...operands] = input;
2038
+ const results = operands.map(simplifyInput);
2039
+ if (areAllInputs(results)) {
2040
+ const presentValues = getInputValues(results);
2041
+ if (isFalseResult(presentValues)) {
2042
+ return false;
2043
+ }
2044
+ return presentValues.reduce(predicate);
2045
+ }
2046
+ return input;
2047
+ };
2048
+ const simplifySum = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('sum'))(input);
2049
+ const simplifySubtract = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('subtract'))(input);
2050
+ const simplifyMultiply = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('multiply'))(input);
2051
+ const simplifyDivide = simplifyInput => input => simplify$3(simplifyInput, (acc, result) => acc / result)(input);
2052
+
2053
+ const simplifyComparison = predicate => (opts, simplifyInput) => input => {
2054
+ const [operator, ...operands] = input;
2055
+ const [left, right] = operands;
2056
+ const leftSimplified = simplifyInput(left);
2057
+ const rightSimplified = simplifyInput(right);
2058
+ const isLeftEvaluable = isEvaluable(leftSimplified);
2059
+ const isRightEvaluable = isEvaluable(rightSimplified);
2060
+ if (isLeftEvaluable || isRightEvaluable) {
2061
+ // If either left or right is an array, we cannot simplify further
2062
+ return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
2063
+ }
2064
+ if (isNumber(leftSimplified) && isNumber(rightSimplified)) {
2065
+ return predicate(leftSimplified, rightSimplified);
2066
+ }
2067
+ const leftDate = toDateNumber(leftSimplified);
2068
+ const rightDate = toDateNumber(rightSimplified);
2069
+ if (leftDate && rightDate) {
2070
+ return predicate(leftDate, rightDate);
2071
+ }
2072
+ if (Array.isArray(leftSimplified) || Array.isArray(rightSimplified)) {
2073
+ return [operator, leftSimplified, rightSimplified];
2074
+ }
2075
+ return false;
2076
+ };
2077
+ const simplifyGt = (opts, simplifyInput) => input => simplifyComparison((left, right) => left > right)(opts, simplifyInput)(input);
2078
+ const simplifyGe = (opts, simplifyInput) => input => simplifyComparison((left, right) => left >= right)(opts, simplifyInput)(input);
2079
+ const simplifyLt = (opts, simplifyInput) => input => simplifyComparison((left, right) => left < right)(opts, simplifyInput)(input);
2080
+ const simplifyLe = (opts, simplifyInput) => input => simplifyComparison((left, right) => left <= right)(opts, simplifyInput)(input);
2081
+
2082
+ const simplifyEquality = predicate => (opts, simplifyInput) => input => {
2083
+ const [operator, ...operands] = input;
2084
+ const [left, right] = operands;
2085
+ const leftSimplified = simplifyInput(left);
2086
+ const rightSimplified = simplifyInput(right);
2087
+ const isLeftEvaluable = isEvaluable(leftSimplified);
2088
+ const isRightEvaluable = isEvaluable(rightSimplified);
2089
+ if (isLeftEvaluable || isRightEvaluable) {
2090
+ // If either left or right is an array, we cannot simplify further
2091
+ return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
2092
+ }
2093
+
2094
+ // See Equal.comparison
2095
+ return predicate(leftSimplified, rightSimplified);
2096
+ };
2097
+ const simplifyEq = (opts, simplifyInput) => input => simplifyEquality((left, right) => left === right)(opts, simplifyInput)(input);
2098
+ const simplifyNe = (opts, simplifyInput) => input => simplifyEquality((left, right) => left !== right)(opts, simplifyInput)(input);
2099
+
2100
+ const simplify$2 = (originalInput, nonArrayInput, arrayInput) => {
2101
+ // If we don't have the non-array operand, there is nothing to do.
2102
+ if (isEvaluable(nonArrayInput)) {
2103
+ return originalInput;
2104
+ }
2105
+
2106
+ // If we don't have all the values, try with what we have for the
2107
+ // positive case, but otherwise return the original input.
2108
+ if (isEvaluable(arrayInput)) {
2109
+ const leftValues = extractValues(arrayInput);
2110
+ const isFound = leftValues.indexOf(nonArrayInput) > -1;
2111
+ return isFound ? true : originalInput;
2112
+ }
2113
+
2114
+ // If we have all the values, we can check if the non-array operand is
2115
+ // included in the array operand.
2116
+ return arrayInput.indexOf(nonArrayInput) > -1;
2117
+ };
2118
+ const simplifyIn = simplifyInput => input => {
2119
+ const [, ...operands] = input;
2120
+ const [left, right] = operands;
2121
+ if (isNull(left) || isUndefined(left) || isNull(right) || isUndefined(right)) {
2122
+ return false;
2123
+ }
2124
+ const leftSimplified = simplifyInput(left);
2125
+ const rightSimplified = simplifyInput(right);
2126
+ const isLeftArray = Array.isArray(leftSimplified) || isEvaluable(leftSimplified);
2127
+ const isRightArray = Array.isArray(rightSimplified) || isEvaluable(rightSimplified);
2128
+ if (isLeftArray) {
2129
+ return simplify$2(input, rightSimplified, leftSimplified);
2130
+ }
2131
+ if (isRightArray) {
2132
+ return simplify$2(input, leftSimplified, rightSimplified);
2133
+ }
2134
+ return false;
2135
+ };
2136
+
2137
+ const simplifyNor = (opts, simplifyInput) => input => {
2138
+ const [operator, ...operands] = input;
2139
+ const simplifiedOperands = [];
2140
+ for (const operand of operands) {
2141
+ const simplification = simplifyInput(operand);
2142
+ if (isUndefined(simplification) || isBoolean(simplification) && isTrueResult(simplification)) {
2143
+ // Short-circuit for AND
2144
+ return false;
2145
+ }
2146
+ simplifiedOperands.push(simplification);
2147
+ }
2148
+
2149
+ // Remove true operands leaving only the Inputs
2150
+ const simplified = simplifiedOperands.filter(isNonFalseResult);
2151
+ if (simplified.length === 0) {
2152
+ return true;
2153
+ }
2154
+ if (simplified.length === 1) {
2155
+ var _opts$operatorMapping;
2156
+ return [(_opts$operatorMapping = opts.operatorMapping.get(OPERATOR$3)) !== null && _opts$operatorMapping !== void 0 ? _opts$operatorMapping : 'NOT', simplified[0]];
2157
+ }
2158
+ return [operator, ...simplified];
2159
+ };
2160
+
2161
+ const simplifyNot = simplifyInput => input => {
2162
+ const [, ...operands] = input;
2163
+ const simplification = simplifyInput(operands[0]);
2164
+ if (isBoolean(simplification)) {
2165
+ return !simplification;
2166
+ }
2167
+ return input;
2168
+ };
2169
+
2170
+ const simplifyNotIn = simplifyInput => input => {
2171
+ const [, ...operands] = input;
2172
+ const [left, right] = operands;
2173
+ const leftArray = Array.isArray(left);
2174
+ const rightArray = Array.isArray(right);
2175
+ if (isNull(left) || isUndefined(left) || isNull(right) || isUndefined(right) || leftArray && rightArray || !leftArray && !rightArray) {
2176
+ return true;
2177
+ }
2178
+ if (leftArray) {
2179
+ // If any operand is still an Evaluable, we cannot simplify further
2180
+ const rightSimplified = simplifyInput(right);
2181
+ if (isEvaluable(rightSimplified)) {
2182
+ return input;
2183
+ }
2184
+ const leftSimplified = left.map(simplifyInput);
2185
+ if (leftSimplified.some(isEvaluable)) {
2186
+ return input;
2187
+ }
2188
+ return leftSimplified.indexOf(rightSimplified) === -1;
2189
+ }
2190
+ if (rightArray) {
2191
+ const leftSimplified = simplifyInput(left);
2192
+ if (isEvaluable(leftSimplified)) {
2193
+ return input;
2194
+ }
2195
+ const rightSimplified = right.map(simplifyInput);
2196
+ if (rightSimplified.some(isEvaluable)) {
2197
+ return input;
2198
+ }
2199
+ return rightSimplified.indexOf(leftSimplified) === -1;
2200
+ }
2201
+ return input;
2202
+ };
2203
+
2204
+ const simplifyOr = simplifyInput => input => {
2205
+ const [operator, ...operands] = input;
2206
+ const simplifiedOperands = [];
2207
+ for (const operand of operands) {
2208
+ const simplification = simplifyInput(operand);
2209
+ if (isBoolean(simplification) && isTrueResult(simplification)) {
2210
+ // Short-circuit for OR
2211
+ return true;
2212
+ } else if (simplification) {
2213
+ simplifiedOperands.push(simplification);
2214
+ }
2215
+ }
2216
+ const simplified = simplifiedOperands.filter(isNonFalseResult);
2217
+ if (simplified.length === 0) {
2218
+ return false;
2219
+ }
2220
+ if (simplified.length === 1) {
2221
+ return simplified[0];
2222
+ }
2223
+ return [operator, ...simplified];
2224
+ };
2225
+
2226
+ const simplifyOverlap = simplifyInput => input => {
2227
+ const [, ...operands] = input;
2228
+ const [left, right] = operands;
2229
+ const leftSimplified = simplifyInput(left);
2230
+ const rightSimplified = simplifyInput(right);
2231
+ const isLeftEvaluable = isEvaluable(leftSimplified);
2232
+ const isRightEvaluable = isEvaluable(rightSimplified);
2233
+
2234
+ // If we don't have all operands simplified, we can try the positive case
2235
+ // of the values we have satisfying the OVERLAP. But if not, we need to
2236
+ // return the original input.
2237
+ if (isLeftEvaluable || isRightEvaluable) {
2238
+ const leftValues = extractValues(leftSimplified);
2239
+ const rightValues = extractValues(rightSimplified);
2240
+ const rightSet = new Set(rightValues);
2241
+ const res = leftValues.some(element => rightSet.has(element));
2242
+ if (res) {
2243
+ return true;
2244
+ }
2245
+ return input;
2246
+ }
2247
+
2248
+ // If simplified results are not arrays, it means we had a strictKey
2249
+ // without values provided. Simplify to false.
2250
+ if (!Array.isArray(leftSimplified) || !Array.isArray(rightSimplified)) {
2251
+ return false;
2252
+ }
2253
+ const rightSet = new Set(rightSimplified);
2254
+ const res = leftSimplified.some(element => rightSet.has(element));
2255
+ if (res) {
2256
+ return true;
2257
+ }
2258
+ return false;
2259
+ };
2260
+
2261
+ const simplify$1 = (opts, simplifyInput, startsWith = true) => input => {
2262
+ const [operator, ...operands] = input;
2263
+ const [left, right] = operands;
2264
+ const leftSimplified = simplifyInput(left);
2265
+ const rightSimplified = simplifyInput(right);
2266
+ const isLeftEvaluable = isEvaluable(leftSimplified);
2267
+ const isRightEvaluable = isEvaluable(rightSimplified);
2268
+ if (isLeftEvaluable || isRightEvaluable) {
2269
+ // If either left or right is an array, we cannot simplify further
2270
+ return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
2271
+ }
2272
+ if (isString(leftSimplified) && isString(rightSimplified)) {
2273
+ return startsWith ? rightSimplified.startsWith(leftSimplified) : leftSimplified.endsWith(rightSimplified);
2274
+ }
2275
+ return false;
2276
+ };
2277
+ const simplifyPrefix = (opts, simplifyInput) => input => simplify$1(opts, simplifyInput)(input);
2278
+ const simplifySuffix = (opts, simplifyInput) => input => simplify$1(opts, simplifyInput, false)(input);
2279
+
2280
+ const simplify = (simplifyInput, predicate, present = true) => input => {
2281
+ const [, ...operands] = input;
2282
+ const [operand] = operands;
2283
+ const simplified = simplifyInput(operand);
2284
+ const isOperandEvaluable = isEvaluable(simplified);
2285
+ if (isOperandEvaluable) {
2286
+ return input;
2287
+ }
2288
+
2289
+ // Operand simplifies to itself when it is included in strictKeys or
2290
+ // optionalKeys, thus it was undefined.
2291
+ if (operand === simplified) {
2292
+ return !present;
2293
+ }
2294
+ return predicate(simplified);
2295
+ };
2296
+ const simplifyPresent = simplifyInput => input => simplify(simplifyInput, input => !isUndefined(input) && !isNull(input))(input);
2297
+ const simplifyUndefined = simplifyInput => input => simplify(simplifyInput, isUndefined, false)(input);
2298
+
2299
+ const simplifyXor = (opts, simplifyInput) => input => {
2300
+ const [operator, ...operands] = input;
2301
+ let trueCount = 0;
2302
+ const simplifiedOperands = [];
2303
+ for (const operand of operands) {
2304
+ const simplification = simplifyInput(operand);
2305
+ if (isBoolean(simplification) && isTrueResult(simplification)) {
2306
+ trueCount++;
2307
+ continue;
2308
+ }
2309
+ if (isBoolean(simplification) && isFalseResult(simplification)) {
2310
+ continue;
2311
+ }
2312
+ if (!isEvaluable(simplification)) {
2313
+ simplifiedOperands.push(simplification);
2314
+ }
2315
+ }
2316
+ if (trueCount > 1) {
2317
+ return false;
2318
+ }
2319
+ if (simplifiedOperands.length === 0) {
2320
+ return trueCount === 1;
2321
+ }
2322
+ if (simplifiedOperands.length === 1) {
2323
+ if (trueCount === 1) {
2324
+ var _opts$operatorMapping;
2325
+ return [(_opts$operatorMapping = opts.operatorMapping.get(OPERATOR$3)) !== null && _opts$operatorMapping !== void 0 ? _opts$operatorMapping : 'NOT', simplifiedOperands[0]];
2326
+ }
2327
+ return simplifiedOperands[0];
2328
+ }
2329
+ if (trueCount === 1) {
2330
+ var _opts$operatorMapping2;
2331
+ return [(_opts$operatorMapping2 = opts.operatorMapping.get(OPERATOR$2)) !== null && _opts$operatorMapping2 !== void 0 ? _opts$operatorMapping2 : 'NOR', ...simplifiedOperands];
2332
+ }
2333
+ return [operator, ...simplifiedOperands];
2334
+ };
2335
+
2336
+ const unsafeSimplify = (context, opts, strictKeys, optionalKeys) => {
2337
+ const simplifyInput = input => {
2338
+ // Value or Reference
2339
+ if (!Array.isArray(input)) {
2340
+ // Reference
2341
+ if (isString(input) && opts.referencePredicate(input)) {
2342
+ const result = new Reference(opts.referenceTransform(input)).simplify(context, strictKeys, optionalKeys);
2343
+ if (isEvaluable(result)) {
2344
+ return result;
2345
+ }
2346
+ const inputResult = resultToInput(result);
2347
+ if (!isUndefined(inputResult)) {
2348
+ return inputResult;
2349
+ }
2350
+ // It should have been a boolean or an Evaluable, but just in case
2351
+ // fallback to returning the input.
2352
+ }
2353
+ // Value
2354
+ return input;
2355
+ }
2356
+ const [operator] = input;
2357
+ switch (operator) {
2358
+ // Logical operators
2359
+ case opts.operatorMapping.get(OPERATOR$4):
2360
+ {
2361
+ return simplifyAnd(simplifyInput)(input);
2362
+ }
2363
+ case opts.operatorMapping.get(OPERATOR$1):
2364
+ {
2365
+ return simplifyOr(simplifyInput)(input);
2366
+ }
2367
+ case opts.operatorMapping.get(OPERATOR$2):
2368
+ {
2369
+ return simplifyNor(opts, simplifyInput)(input);
2370
+ }
2371
+ case opts.operatorMapping.get(OPERATOR):
2372
+ {
2373
+ return simplifyXor(opts, simplifyInput)(input);
2374
+ }
2375
+ case opts.operatorMapping.get(OPERATOR$3):
2376
+ {
2377
+ return simplifyNot(simplifyInput)(input);
2378
+ }
2379
+ // Comparison operators
2380
+ case opts.operatorMapping.get(OPERATOR$h):
2381
+ {
2382
+ return simplifyEq(opts, simplifyInput)(input);
2383
+ }
2384
+ case opts.operatorMapping.get(OPERATOR$b):
2385
+ {
2386
+ return simplifyNe(opts, simplifyInput)(input);
2387
+ }
2388
+ case opts.operatorMapping.get(OPERATOR$f):
2389
+ {
2390
+ return simplifyGt(opts, simplifyInput)(input);
2391
+ }
2392
+ case opts.operatorMapping.get(OPERATOR$g):
2393
+ {
2394
+ return simplifyGe(opts, simplifyInput)(input);
2395
+ }
2396
+ case opts.operatorMapping.get(OPERATOR$c):
2397
+ {
2398
+ return simplifyLt(opts, simplifyInput)(input);
2399
+ }
2400
+ case opts.operatorMapping.get(OPERATOR$d):
2401
+ {
2402
+ return simplifyLe(opts, simplifyInput)(input);
2403
+ }
2404
+ case opts.operatorMapping.get(OPERATOR$e):
2405
+ {
2406
+ return simplifyIn(simplifyInput)(input);
2407
+ }
2408
+ case opts.operatorMapping.get(OPERATOR$a):
2409
+ {
2410
+ return simplifyNotIn(simplifyInput)(input);
2411
+ }
2412
+ case opts.operatorMapping.get(OPERATOR$8):
2413
+ {
2414
+ return simplifyPrefix(opts, simplifyInput)(input);
2415
+ }
2416
+ case opts.operatorMapping.get(OPERATOR$6):
2417
+ {
2418
+ return simplifySuffix(opts, simplifyInput)(input);
2419
+ }
2420
+ case opts.operatorMapping.get(OPERATOR$9):
2421
+ {
2422
+ return simplifyOverlap(simplifyInput)(input);
2423
+ }
2424
+ case opts.operatorMapping.get(OPERATOR$5):
2425
+ {
2426
+ return simplifyUndefined(simplifyInput)(input);
2427
+ }
2428
+ case opts.operatorMapping.get(OPERATOR$7):
2429
+ {
2430
+ return simplifyPresent(simplifyInput)(input);
2431
+ }
2432
+ // Arithmetic operators
2433
+ case opts.operatorMapping.get(OPERATOR$i):
2434
+ {
2435
+ return simplifySum(simplifyInput)(input);
2436
+ }
2437
+ case opts.operatorMapping.get(OPERATOR$j):
2438
+ {
2439
+ return simplifySubtract(simplifyInput)(input);
2440
+ }
2441
+ case opts.operatorMapping.get(OPERATOR$k):
2442
+ {
2443
+ return simplifyMultiply(simplifyInput)(input);
2444
+ }
2445
+ case opts.operatorMapping.get(OPERATOR$l):
2446
+ {
2447
+ return simplifyDivide(simplifyInput)(input);
2448
+ }
2449
+ default:
2450
+ {
2451
+ // Handle as an array of References / Values if no operator matches
2452
+ const result = input.map(simplifyInput);
2453
+ if (!areAllInputs(result)) {
2454
+ return new Collection(result.map(item => {
2455
+ if (item instanceof Reference) {
2456
+ return item;
2457
+ }
2458
+ if (!isEvaluable(item)) {
2459
+ return new Value(item);
2460
+ }
2461
+ throw new Error('Unexpected expression found within a collection of values/references');
2462
+ }));
2463
+ }
2464
+ return result;
2465
+ }
2466
+ }
2467
+ };
2468
+ return simplifyInput;
2469
+ };
2470
+
1928
2471
  const unexpectedResultError = 'non expression or boolean result should be returned';
1929
2472
 
1930
2473
  /**
@@ -1997,6 +2540,18 @@ class Engine {
1997
2540
  }
1998
2541
  throw new Error(unexpectedResultError);
1999
2542
  }
2543
+ unsafeSimplify(exp, context, strictKeys, optionalKeys) {
2544
+ const result = unsafeSimplify(context, this.parser.options, strictKeys, optionalKeys)(exp);
2545
+ if (isBoolean(result)) {
2546
+ return result;
2547
+ }
2548
+
2549
+ // The unsafe implementation should not expose the Evaluable interface
2550
+ if (isEvaluable(result)) {
2551
+ throw new Error('Unexpected Evaluable not serialized result');
2552
+ }
2553
+ return result;
2554
+ }
2000
2555
  }
2001
2556
 
2002
2557
  exports.OPERATOR_AND = OPERATOR$4;