@briza/illogical 1.6.0 → 1.7.0

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,12 +1,22 @@
1
1
  # illogical changelog
2
2
 
3
+ ## 1.7.0
4
+
5
+ - Introducing unsafeSimplify which simplifies the condition without fully parsing it beforehand.
6
+ Useful when processing complex conditions that have been previously parsed. Should be faster
7
+ compared to the standard simplify when it can short circuit logical expressions.
8
+
9
+ ## 1.6.1
10
+
11
+ - Bugfix on Arithmetic evaluate. Returns false when ContextValue is not present in the Context.
12
+
3
13
  ## 1.6.0
4
14
 
5
15
  - Added support for Arithmetic expressions within other Comparison expressions. This allows for
6
- more complex and dynamic comparisons to be made. Now, you can perform mathematical operations
7
- within your conditional expressions, making them even more powerful and flexible. Whether you need
8
- to calculate sums, differences, products, or divisions, the new Arithmetic expression feature has
9
- got you covered. There are no breaking changes if this new kind of expression isn't being used.
16
+ more complex and dynamic comparisons to be made. Now, you can perform mathematical operations
17
+ within your conditional expressions, making them even more powerful and flexible. Whether you need
18
+ to calculate sums, differences, products, or divisions, the new Arithmetic expression feature has
19
+ got you covered. There are no breaking changes if this new kind of expression isn't being used.
10
20
 
11
21
  ## 1.5.9
12
22
 
@@ -1,16 +1,16 @@
1
1
  function _defineProperty(e, r, t) {
2
2
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
3
3
  value: t,
4
- enumerable: !0,
5
- configurable: !0,
6
- writable: !0
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true
7
7
  }) : e[r] = t, e;
8
8
  }
9
9
  function _toPrimitive(t, r) {
10
10
  if ("object" != typeof t || !t) return t;
11
11
  var e = t[Symbol.toPrimitive];
12
12
  if (void 0 !== e) {
13
- var i = e.call(t, r || "default");
13
+ var i = e.call(t, r);
14
14
  if ("object" != typeof i) return i;
15
15
  throw new TypeError("@@toPrimitive must return a primitive value.");
16
16
  }
@@ -90,9 +90,15 @@ function areAllResults(values) {
90
90
  * @param {Result[]} results results or evaluables
91
91
  * @returns {boolean} type guard
92
92
  */
93
- function areAllNumbers(results) {
93
+ function areAllNumbers$1(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
+ }
96
102
 
97
103
  /**
98
104
  * Valid types for context members
@@ -135,6 +141,27 @@ class Arithmetic {
135
141
  _defineProperty(this, "type", EvaluableType.Expression);
136
142
  }
137
143
 
144
+ /**
145
+ * Helper function to assist with arithmetic evaluation. Ensures that all
146
+ * operands are present and are numbers. Throws error if any operand is not a
147
+ * number.
148
+ *
149
+ * @param {Result[]} results
150
+ * @returns {number[] | false} false if any operand is missing, otherwise the
151
+ * array of numbers
152
+ */
153
+ getResultValues(results) {
154
+ const presentValues = results.filter(result => result !== null && result !== undefined);
155
+ // If we have missing context values the result must be false
156
+ if (presentValues.length !== results.length) {
157
+ return false;
158
+ }
159
+ if (!areAllNumbers$1(presentValues)) {
160
+ throw new Error(`operands must be numbers for ${this.constructor.name}`);
161
+ }
162
+ return presentValues;
163
+ }
164
+
138
165
  /**
139
166
  * Performs the arithmetic operation on the operands evaluated values.
140
167
  * @param {Result[]} results Operand result values.
@@ -204,11 +231,11 @@ class Divide extends Arithmetic {
204
231
  super('/', OPERATOR$l, operands);
205
232
  }
206
233
  operate(results) {
207
- if (!areAllNumbers(results)) {
208
- throw new Error('operands must be numbers for divide');
234
+ const presentResults = this.getResultValues(results);
235
+ if (presentResults === false) {
236
+ return false;
209
237
  }
210
- const result = results.reduce((acc, result) => acc / result);
211
- return result;
238
+ return presentResults.reduce((acc, result) => acc / result);
212
239
  }
213
240
  }
214
241
 
@@ -247,10 +274,11 @@ class Multiply extends Arithmetic {
247
274
  super('*', OPERATOR$k, operands);
248
275
  }
249
276
  operate(results) {
250
- if (!areAllNumbers(results)) {
251
- throw new Error('operands must be numbers for multiply');
277
+ const presentResults = this.getResultValues(results);
278
+ if (presentResults === false) {
279
+ return false;
252
280
  }
253
- return results.reduce((acc, result) => multiplyWithExpectedDecimals(acc, result));
281
+ return presentResults.reduce((acc, result) => multiplyWithExpectedDecimals(acc, result));
254
282
  }
255
283
  }
256
284
 
@@ -278,10 +306,11 @@ class Subtract extends Arithmetic {
278
306
  super('-', OPERATOR$j, operands);
279
307
  }
280
308
  operate(results) {
281
- if (!areAllNumbers(results)) {
282
- throw new Error('operands must be numbers for subtract');
309
+ const presentResults = this.getResultValues(results);
310
+ if (presentResults === false) {
311
+ return false;
283
312
  }
284
- return results.reduce((acc, result) => subtractWithExpectedDecimals(acc, result));
313
+ return presentResults.reduce((acc, result) => subtractWithExpectedDecimals(acc, result));
285
314
  }
286
315
  }
287
316
 
@@ -309,10 +338,11 @@ class Sum extends Arithmetic {
309
338
  super('+', OPERATOR$i, operands);
310
339
  }
311
340
  operate(results) {
312
- if (!areAllNumbers(results)) {
313
- throw new Error('operands must be numbers for sum');
341
+ const presentResults = this.getResultValues(results);
342
+ if (presentResults === false) {
343
+ return false;
314
344
  }
315
- return results.reduce((acc, result) => addWithExpectedDecimals(acc, result));
345
+ return presentResults.reduce((acc, result) => addWithExpectedDecimals(acc, result));
316
346
  }
317
347
  }
318
348
 
@@ -1589,6 +1619,14 @@ class Xor extends Logical {
1589
1619
  * Collection operand resolved containing mixture of value and references.
1590
1620
  */
1591
1621
  class Collection extends Operand {
1622
+ /**
1623
+ * Get the items in the collection.
1624
+ * @returns {Array<Value | Reference>}
1625
+ */
1626
+ getItems() {
1627
+ return this.items;
1628
+ }
1629
+
1592
1630
  /**
1593
1631
  * @constructor
1594
1632
  * @param {Operand[]} items Collection of operands.
@@ -1897,6 +1935,516 @@ class Parser {
1897
1935
  }
1898
1936
  }
1899
1937
 
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
+
1900
2448
  const unexpectedResultError = 'non expression or boolean result should be returned';
1901
2449
 
1902
2450
  /**
@@ -1969,6 +2517,18 @@ class Engine {
1969
2517
  }
1970
2518
  throw new Error(unexpectedResultError);
1971
2519
  }
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
+ }
1972
2532
  }
1973
2533
 
1974
2534
  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 };