@briza/illogical 1.7.1 → 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/changelog.md +4 -0
- package/lib/illogical.esm.js +11 -534
- package/lib/illogical.js +11 -534
- package/package.json +1 -1
- package/readme.md +0 -13
- package/types/common/evaluable.d.ts +6 -4
- package/types/expression/logical/index.d.ts +1 -1
- package/types/index.d.ts +6 -5
- package/types/operand/index.d.ts +1 -1
- package/types/operand/reference.d.ts +2 -1
- package/types/unsafe/simplify.d.ts +1 -1
package/changelog.md
CHANGED
package/lib/illogical.esm.js
CHANGED
|
@@ -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
|
|
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
|
|
153
|
+
if (!areAllNumbers(presentValues)) {
|
|
160
154
|
throw new Error(`operands must be numbers for ${this.constructor.name}`);
|
|
161
155
|
}
|
|
162
156
|
return presentValues;
|
|
@@ -598,6 +592,9 @@ class Reference extends Operand {
|
|
|
598
592
|
evaluate(ctx) {
|
|
599
593
|
return this.toDataType(this.valueLookup(ctx));
|
|
600
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
|
+
}
|
|
601
598
|
|
|
602
599
|
/**
|
|
603
600
|
* {@link Evaluable.simplify}
|
|
@@ -611,7 +608,7 @@ class Reference extends Operand {
|
|
|
611
608
|
if (!key || typeof key === 'number') {
|
|
612
609
|
return this;
|
|
613
610
|
}
|
|
614
|
-
return
|
|
611
|
+
return this.checkStrictAndOptional(key, strictKeys, optionalKeys);
|
|
615
612
|
}
|
|
616
613
|
|
|
617
614
|
/**
|
|
@@ -1954,516 +1951,6 @@ class Parser {
|
|
|
1954
1951
|
}
|
|
1955
1952
|
}
|
|
1956
1953
|
|
|
1957
|
-
const isTrueResult = value => value === true;
|
|
1958
|
-
const isFalseResult = value => value === false;
|
|
1959
|
-
const isNonFalseResult = operand => operand !== false && !isEvaluable(operand);
|
|
1960
|
-
const isNonTrueResult = operand => operand !== true && !isEvaluable(operand);
|
|
1961
|
-
const resultToInputInternal = value => {
|
|
1962
|
-
if (isUndefined(value)) {
|
|
1963
|
-
return undefined;
|
|
1964
|
-
}
|
|
1965
|
-
if (Array.isArray(value)) {
|
|
1966
|
-
return undefined;
|
|
1967
|
-
}
|
|
1968
|
-
return value;
|
|
1969
|
-
};
|
|
1970
|
-
const resultToInput = value => {
|
|
1971
|
-
if (isUndefined(value)) {
|
|
1972
|
-
return undefined;
|
|
1973
|
-
}
|
|
1974
|
-
if (Array.isArray(value)) {
|
|
1975
|
-
const definedValues = value.map(resultToInputInternal).filter(val => !isUndefined(val));
|
|
1976
|
-
if (definedValues.length === 0) {
|
|
1977
|
-
return undefined;
|
|
1978
|
-
}
|
|
1979
|
-
return definedValues;
|
|
1980
|
-
}
|
|
1981
|
-
return value;
|
|
1982
|
-
};
|
|
1983
|
-
const areAllNumbers = results => {
|
|
1984
|
-
return results.every(isNumber);
|
|
1985
|
-
};
|
|
1986
|
-
const areAllInputs = values => values.every(value => !isEvaluable(value));
|
|
1987
|
-
const getInputValues = results => {
|
|
1988
|
-
const presentValues = results.filter(result => !isNull(result) && !isUndefined(result));
|
|
1989
|
-
// If we have missing context values the result or we still have refences
|
|
1990
|
-
// simplify to false.
|
|
1991
|
-
if (presentValues.length !== results.length || !areAllNumbers(presentValues)) {
|
|
1992
|
-
return false;
|
|
1993
|
-
}
|
|
1994
|
-
return presentValues;
|
|
1995
|
-
};
|
|
1996
|
-
const extractValues = input => {
|
|
1997
|
-
const evaluable = isEvaluable(input);
|
|
1998
|
-
if (!evaluable) {
|
|
1999
|
-
return Array.isArray(input) ? input : [input];
|
|
2000
|
-
}
|
|
2001
|
-
if (input instanceof Collection) {
|
|
2002
|
-
const results = input.getItems();
|
|
2003
|
-
const values = results.map(item => item instanceof Value ? item.evaluate() : null).filter(value => !isNull(value));
|
|
2004
|
-
return values;
|
|
2005
|
-
}
|
|
2006
|
-
return [];
|
|
2007
|
-
};
|
|
2008
|
-
|
|
2009
|
-
const simplifyAnd = simplifyInput => input => {
|
|
2010
|
-
const [operator, ...operands] = input;
|
|
2011
|
-
const simplifiedOperands = [];
|
|
2012
|
-
for (const operand of operands) {
|
|
2013
|
-
const simplification = simplifyInput(operand);
|
|
2014
|
-
if (isUndefined(simplification) || isBoolean(simplification) && !isTrueResult(simplification)) {
|
|
2015
|
-
// Short-circuit for AND
|
|
2016
|
-
return false;
|
|
2017
|
-
}
|
|
2018
|
-
simplifiedOperands.push(simplification);
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2021
|
-
// Remove false operands leaving only the Inputs
|
|
2022
|
-
const simplified = simplifiedOperands.filter(isNonTrueResult);
|
|
2023
|
-
if (simplified.length === 0) {
|
|
2024
|
-
return true;
|
|
2025
|
-
}
|
|
2026
|
-
if (simplified.length === 1) {
|
|
2027
|
-
return simplified[0];
|
|
2028
|
-
}
|
|
2029
|
-
return [operator, ...simplified];
|
|
2030
|
-
};
|
|
2031
|
-
|
|
2032
|
-
const simplify$3 = (simplifyInput, predicate) => input => {
|
|
2033
|
-
const [, ...operands] = input;
|
|
2034
|
-
const results = operands.map(simplifyInput);
|
|
2035
|
-
if (areAllInputs(results)) {
|
|
2036
|
-
const presentValues = getInputValues(results);
|
|
2037
|
-
if (isFalseResult(presentValues)) {
|
|
2038
|
-
return false;
|
|
2039
|
-
}
|
|
2040
|
-
return presentValues.reduce(predicate);
|
|
2041
|
-
}
|
|
2042
|
-
return input;
|
|
2043
|
-
};
|
|
2044
|
-
const simplifySum = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('sum'))(input);
|
|
2045
|
-
const simplifySubtract = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('subtract'))(input);
|
|
2046
|
-
const simplifyMultiply = simplifyInput => input => simplify$3(simplifyInput, operateWithExpectedDecimals('multiply'))(input);
|
|
2047
|
-
const simplifyDivide = simplifyInput => input => simplify$3(simplifyInput, (acc, result) => acc / result)(input);
|
|
2048
|
-
|
|
2049
|
-
const simplifyComparison = predicate => (opts, simplifyInput) => input => {
|
|
2050
|
-
const [operator, ...operands] = input;
|
|
2051
|
-
const [left, right] = operands;
|
|
2052
|
-
const leftSimplified = simplifyInput(left);
|
|
2053
|
-
const rightSimplified = simplifyInput(right);
|
|
2054
|
-
const isLeftEvaluable = isEvaluable(leftSimplified);
|
|
2055
|
-
const isRightEvaluable = isEvaluable(rightSimplified);
|
|
2056
|
-
if (isLeftEvaluable || isRightEvaluable) {
|
|
2057
|
-
// If either left or right is an array, we cannot simplify further
|
|
2058
|
-
return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
|
|
2059
|
-
}
|
|
2060
|
-
if (isNumber(leftSimplified) && isNumber(rightSimplified)) {
|
|
2061
|
-
return predicate(leftSimplified, rightSimplified);
|
|
2062
|
-
}
|
|
2063
|
-
const leftDate = toDateNumber(leftSimplified);
|
|
2064
|
-
const rightDate = toDateNumber(rightSimplified);
|
|
2065
|
-
if (leftDate && rightDate) {
|
|
2066
|
-
return predicate(leftDate, rightDate);
|
|
2067
|
-
}
|
|
2068
|
-
if (Array.isArray(leftSimplified) || Array.isArray(rightSimplified)) {
|
|
2069
|
-
return [operator, leftSimplified, rightSimplified];
|
|
2070
|
-
}
|
|
2071
|
-
return false;
|
|
2072
|
-
};
|
|
2073
|
-
const simplifyGt = (opts, simplifyInput) => input => simplifyComparison((left, right) => left > right)(opts, simplifyInput)(input);
|
|
2074
|
-
const simplifyGe = (opts, simplifyInput) => input => simplifyComparison((left, right) => left >= right)(opts, simplifyInput)(input);
|
|
2075
|
-
const simplifyLt = (opts, simplifyInput) => input => simplifyComparison((left, right) => left < right)(opts, simplifyInput)(input);
|
|
2076
|
-
const simplifyLe = (opts, simplifyInput) => input => simplifyComparison((left, right) => left <= right)(opts, simplifyInput)(input);
|
|
2077
|
-
|
|
2078
|
-
const simplifyEquality = predicate => (opts, simplifyInput) => input => {
|
|
2079
|
-
const [operator, ...operands] = input;
|
|
2080
|
-
const [left, right] = operands;
|
|
2081
|
-
const leftSimplified = simplifyInput(left);
|
|
2082
|
-
const rightSimplified = simplifyInput(right);
|
|
2083
|
-
const isLeftEvaluable = isEvaluable(leftSimplified);
|
|
2084
|
-
const isRightEvaluable = isEvaluable(rightSimplified);
|
|
2085
|
-
if (isLeftEvaluable || isRightEvaluable) {
|
|
2086
|
-
// If either left or right is an array, we cannot simplify further
|
|
2087
|
-
return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
// See Equal.comparison
|
|
2091
|
-
return predicate(leftSimplified, rightSimplified);
|
|
2092
|
-
};
|
|
2093
|
-
const simplifyEq = (opts, simplifyInput) => input => simplifyEquality((left, right) => left === right)(opts, simplifyInput)(input);
|
|
2094
|
-
const simplifyNe = (opts, simplifyInput) => input => simplifyEquality((left, right) => left !== right)(opts, simplifyInput)(input);
|
|
2095
|
-
|
|
2096
|
-
const simplify$2 = (originalInput, nonArrayInput, arrayInput) => {
|
|
2097
|
-
// If we don't have the non-array operand, there is nothing to do.
|
|
2098
|
-
if (isEvaluable(nonArrayInput)) {
|
|
2099
|
-
return originalInput;
|
|
2100
|
-
}
|
|
2101
|
-
|
|
2102
|
-
// If we don't have all the values, try with what we have for the
|
|
2103
|
-
// positive case, but otherwise return the original input.
|
|
2104
|
-
if (isEvaluable(arrayInput)) {
|
|
2105
|
-
const leftValues = extractValues(arrayInput);
|
|
2106
|
-
const isFound = leftValues.indexOf(nonArrayInput) > -1;
|
|
2107
|
-
return isFound ? true : originalInput;
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2110
|
-
// If we have all the values, we can check if the non-array operand is
|
|
2111
|
-
// included in the array operand.
|
|
2112
|
-
return arrayInput.indexOf(nonArrayInput) > -1;
|
|
2113
|
-
};
|
|
2114
|
-
const simplifyIn = simplifyInput => input => {
|
|
2115
|
-
const [, ...operands] = input;
|
|
2116
|
-
const [left, right] = operands;
|
|
2117
|
-
if (isNull(left) || isUndefined(left) || isNull(right) || isUndefined(right)) {
|
|
2118
|
-
return false;
|
|
2119
|
-
}
|
|
2120
|
-
const leftSimplified = simplifyInput(left);
|
|
2121
|
-
const rightSimplified = simplifyInput(right);
|
|
2122
|
-
const isLeftArray = Array.isArray(leftSimplified) || isEvaluable(leftSimplified);
|
|
2123
|
-
const isRightArray = Array.isArray(rightSimplified) || isEvaluable(rightSimplified);
|
|
2124
|
-
if (isLeftArray) {
|
|
2125
|
-
return simplify$2(input, rightSimplified, leftSimplified);
|
|
2126
|
-
}
|
|
2127
|
-
if (isRightArray) {
|
|
2128
|
-
return simplify$2(input, leftSimplified, rightSimplified);
|
|
2129
|
-
}
|
|
2130
|
-
return false;
|
|
2131
|
-
};
|
|
2132
|
-
|
|
2133
|
-
const simplifyNor = (opts, simplifyInput) => input => {
|
|
2134
|
-
const [operator, ...operands] = input;
|
|
2135
|
-
const simplifiedOperands = [];
|
|
2136
|
-
for (const operand of operands) {
|
|
2137
|
-
const simplification = simplifyInput(operand);
|
|
2138
|
-
if (isUndefined(simplification) || isBoolean(simplification) && isTrueResult(simplification)) {
|
|
2139
|
-
// Short-circuit for AND
|
|
2140
|
-
return false;
|
|
2141
|
-
}
|
|
2142
|
-
simplifiedOperands.push(simplification);
|
|
2143
|
-
}
|
|
2144
|
-
|
|
2145
|
-
// Remove true operands leaving only the Inputs
|
|
2146
|
-
const simplified = simplifiedOperands.filter(isNonFalseResult);
|
|
2147
|
-
if (simplified.length === 0) {
|
|
2148
|
-
return true;
|
|
2149
|
-
}
|
|
2150
|
-
if (simplified.length === 1) {
|
|
2151
|
-
var _opts$operatorMapping;
|
|
2152
|
-
return [(_opts$operatorMapping = opts.operatorMapping.get(OPERATOR$3)) !== null && _opts$operatorMapping !== void 0 ? _opts$operatorMapping : 'NOT', simplified[0]];
|
|
2153
|
-
}
|
|
2154
|
-
return [operator, ...simplified];
|
|
2155
|
-
};
|
|
2156
|
-
|
|
2157
|
-
const simplifyNot = simplifyInput => input => {
|
|
2158
|
-
const [, ...operands] = input;
|
|
2159
|
-
const simplification = simplifyInput(operands[0]);
|
|
2160
|
-
if (isBoolean(simplification)) {
|
|
2161
|
-
return !simplification;
|
|
2162
|
-
}
|
|
2163
|
-
return input;
|
|
2164
|
-
};
|
|
2165
|
-
|
|
2166
|
-
const simplifyNotIn = simplifyInput => input => {
|
|
2167
|
-
const [, ...operands] = input;
|
|
2168
|
-
const [left, right] = operands;
|
|
2169
|
-
const leftArray = Array.isArray(left);
|
|
2170
|
-
const rightArray = Array.isArray(right);
|
|
2171
|
-
if (isNull(left) || isUndefined(left) || isNull(right) || isUndefined(right) || leftArray && rightArray || !leftArray && !rightArray) {
|
|
2172
|
-
return true;
|
|
2173
|
-
}
|
|
2174
|
-
if (leftArray) {
|
|
2175
|
-
// If any operand is still an Evaluable, we cannot simplify further
|
|
2176
|
-
const rightSimplified = simplifyInput(right);
|
|
2177
|
-
if (isEvaluable(rightSimplified)) {
|
|
2178
|
-
return input;
|
|
2179
|
-
}
|
|
2180
|
-
const leftSimplified = left.map(simplifyInput);
|
|
2181
|
-
if (leftSimplified.some(isEvaluable)) {
|
|
2182
|
-
return input;
|
|
2183
|
-
}
|
|
2184
|
-
return leftSimplified.indexOf(rightSimplified) === -1;
|
|
2185
|
-
}
|
|
2186
|
-
if (rightArray) {
|
|
2187
|
-
const leftSimplified = simplifyInput(left);
|
|
2188
|
-
if (isEvaluable(leftSimplified)) {
|
|
2189
|
-
return input;
|
|
2190
|
-
}
|
|
2191
|
-
const rightSimplified = right.map(simplifyInput);
|
|
2192
|
-
if (rightSimplified.some(isEvaluable)) {
|
|
2193
|
-
return input;
|
|
2194
|
-
}
|
|
2195
|
-
return rightSimplified.indexOf(leftSimplified) === -1;
|
|
2196
|
-
}
|
|
2197
|
-
return input;
|
|
2198
|
-
};
|
|
2199
|
-
|
|
2200
|
-
const simplifyOr = simplifyInput => input => {
|
|
2201
|
-
const [operator, ...operands] = input;
|
|
2202
|
-
const simplifiedOperands = [];
|
|
2203
|
-
for (const operand of operands) {
|
|
2204
|
-
const simplification = simplifyInput(operand);
|
|
2205
|
-
if (isBoolean(simplification) && isTrueResult(simplification)) {
|
|
2206
|
-
// Short-circuit for OR
|
|
2207
|
-
return true;
|
|
2208
|
-
} else if (simplification) {
|
|
2209
|
-
simplifiedOperands.push(simplification);
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
const simplified = simplifiedOperands.filter(isNonFalseResult);
|
|
2213
|
-
if (simplified.length === 0) {
|
|
2214
|
-
return false;
|
|
2215
|
-
}
|
|
2216
|
-
if (simplified.length === 1) {
|
|
2217
|
-
return simplified[0];
|
|
2218
|
-
}
|
|
2219
|
-
return [operator, ...simplified];
|
|
2220
|
-
};
|
|
2221
|
-
|
|
2222
|
-
const simplifyOverlap = simplifyInput => input => {
|
|
2223
|
-
const [, ...operands] = input;
|
|
2224
|
-
const [left, right] = operands;
|
|
2225
|
-
const leftSimplified = simplifyInput(left);
|
|
2226
|
-
const rightSimplified = simplifyInput(right);
|
|
2227
|
-
const isLeftEvaluable = isEvaluable(leftSimplified);
|
|
2228
|
-
const isRightEvaluable = isEvaluable(rightSimplified);
|
|
2229
|
-
|
|
2230
|
-
// If we don't have all operands simplified, we can try the positive case
|
|
2231
|
-
// of the values we have satisfying the OVERLAP. But if not, we need to
|
|
2232
|
-
// return the original input.
|
|
2233
|
-
if (isLeftEvaluable || isRightEvaluable) {
|
|
2234
|
-
const leftValues = extractValues(leftSimplified);
|
|
2235
|
-
const rightValues = extractValues(rightSimplified);
|
|
2236
|
-
const rightSet = new Set(rightValues);
|
|
2237
|
-
const res = leftValues.some(element => rightSet.has(element));
|
|
2238
|
-
if (res) {
|
|
2239
|
-
return true;
|
|
2240
|
-
}
|
|
2241
|
-
return input;
|
|
2242
|
-
}
|
|
2243
|
-
|
|
2244
|
-
// If simplified results are not arrays, it means we had a strictKey
|
|
2245
|
-
// without values provided. Simplify to false.
|
|
2246
|
-
if (!Array.isArray(leftSimplified) || !Array.isArray(rightSimplified)) {
|
|
2247
|
-
return false;
|
|
2248
|
-
}
|
|
2249
|
-
const rightSet = new Set(rightSimplified);
|
|
2250
|
-
const res = leftSimplified.some(element => rightSet.has(element));
|
|
2251
|
-
if (res) {
|
|
2252
|
-
return true;
|
|
2253
|
-
}
|
|
2254
|
-
return false;
|
|
2255
|
-
};
|
|
2256
|
-
|
|
2257
|
-
const simplify$1 = (opts, simplifyInput, startsWith = true) => input => {
|
|
2258
|
-
const [operator, ...operands] = input;
|
|
2259
|
-
const [left, right] = operands;
|
|
2260
|
-
const leftSimplified = simplifyInput(left);
|
|
2261
|
-
const rightSimplified = simplifyInput(right);
|
|
2262
|
-
const isLeftEvaluable = isEvaluable(leftSimplified);
|
|
2263
|
-
const isRightEvaluable = isEvaluable(rightSimplified);
|
|
2264
|
-
if (isLeftEvaluable || isRightEvaluable) {
|
|
2265
|
-
// If either left or right is an array, we cannot simplify further
|
|
2266
|
-
return [operator, isLeftEvaluable ? leftSimplified.serialize(opts) : left, isRightEvaluable ? rightSimplified.serialize(opts) : right];
|
|
2267
|
-
}
|
|
2268
|
-
if (isString(leftSimplified) && isString(rightSimplified)) {
|
|
2269
|
-
return startsWith ? rightSimplified.startsWith(leftSimplified) : leftSimplified.endsWith(rightSimplified);
|
|
2270
|
-
}
|
|
2271
|
-
return false;
|
|
2272
|
-
};
|
|
2273
|
-
const simplifyPrefix = (opts, simplifyInput) => input => simplify$1(opts, simplifyInput)(input);
|
|
2274
|
-
const simplifySuffix = (opts, simplifyInput) => input => simplify$1(opts, simplifyInput, false)(input);
|
|
2275
|
-
|
|
2276
|
-
const simplify = (simplifyInput, predicate, present = true) => input => {
|
|
2277
|
-
const [, ...operands] = input;
|
|
2278
|
-
const [operand] = operands;
|
|
2279
|
-
const simplified = simplifyInput(operand);
|
|
2280
|
-
const isOperandEvaluable = isEvaluable(simplified);
|
|
2281
|
-
if (isOperandEvaluable) {
|
|
2282
|
-
return input;
|
|
2283
|
-
}
|
|
2284
|
-
|
|
2285
|
-
// Operand simplifies to itself when it is included in strictKeys or
|
|
2286
|
-
// optionalKeys, thus it was undefined.
|
|
2287
|
-
if (operand === simplified) {
|
|
2288
|
-
return !present;
|
|
2289
|
-
}
|
|
2290
|
-
return predicate(simplified);
|
|
2291
|
-
};
|
|
2292
|
-
const simplifyPresent = simplifyInput => input => simplify(simplifyInput, input => !isUndefined(input) && !isNull(input))(input);
|
|
2293
|
-
const simplifyUndefined = simplifyInput => input => simplify(simplifyInput, isUndefined, false)(input);
|
|
2294
|
-
|
|
2295
|
-
const simplifyXor = (opts, simplifyInput) => input => {
|
|
2296
|
-
const [operator, ...operands] = input;
|
|
2297
|
-
let trueCount = 0;
|
|
2298
|
-
const simplifiedOperands = [];
|
|
2299
|
-
for (const operand of operands) {
|
|
2300
|
-
const simplification = simplifyInput(operand);
|
|
2301
|
-
if (isBoolean(simplification) && isTrueResult(simplification)) {
|
|
2302
|
-
trueCount++;
|
|
2303
|
-
continue;
|
|
2304
|
-
}
|
|
2305
|
-
if (isBoolean(simplification) && isFalseResult(simplification)) {
|
|
2306
|
-
continue;
|
|
2307
|
-
}
|
|
2308
|
-
if (!isEvaluable(simplification)) {
|
|
2309
|
-
simplifiedOperands.push(simplification);
|
|
2310
|
-
}
|
|
2311
|
-
}
|
|
2312
|
-
if (trueCount > 1) {
|
|
2313
|
-
return false;
|
|
2314
|
-
}
|
|
2315
|
-
if (simplifiedOperands.length === 0) {
|
|
2316
|
-
return trueCount === 1;
|
|
2317
|
-
}
|
|
2318
|
-
if (simplifiedOperands.length === 1) {
|
|
2319
|
-
if (trueCount === 1) {
|
|
2320
|
-
var _opts$operatorMapping;
|
|
2321
|
-
return [(_opts$operatorMapping = opts.operatorMapping.get(OPERATOR$3)) !== null && _opts$operatorMapping !== void 0 ? _opts$operatorMapping : 'NOT', simplifiedOperands[0]];
|
|
2322
|
-
}
|
|
2323
|
-
return simplifiedOperands[0];
|
|
2324
|
-
}
|
|
2325
|
-
if (trueCount === 1) {
|
|
2326
|
-
var _opts$operatorMapping2;
|
|
2327
|
-
return [(_opts$operatorMapping2 = opts.operatorMapping.get(OPERATOR$2)) !== null && _opts$operatorMapping2 !== void 0 ? _opts$operatorMapping2 : 'NOR', ...simplifiedOperands];
|
|
2328
|
-
}
|
|
2329
|
-
return [operator, ...simplifiedOperands];
|
|
2330
|
-
};
|
|
2331
|
-
|
|
2332
|
-
const unsafeSimplify = (context, opts, strictKeys, optionalKeys) => {
|
|
2333
|
-
const simplifyInput = input => {
|
|
2334
|
-
// Value or Reference
|
|
2335
|
-
if (!Array.isArray(input)) {
|
|
2336
|
-
// Reference
|
|
2337
|
-
if (isString(input) && opts.referencePredicate(input)) {
|
|
2338
|
-
const result = new Reference(opts.referenceTransform(input)).simplify(context, strictKeys, optionalKeys);
|
|
2339
|
-
if (isEvaluable(result)) {
|
|
2340
|
-
return result;
|
|
2341
|
-
}
|
|
2342
|
-
const inputResult = resultToInput(result);
|
|
2343
|
-
if (!isUndefined(inputResult)) {
|
|
2344
|
-
return inputResult;
|
|
2345
|
-
}
|
|
2346
|
-
// It should have been a boolean or an Evaluable, but just in case
|
|
2347
|
-
// fallback to returning the input.
|
|
2348
|
-
}
|
|
2349
|
-
// Value
|
|
2350
|
-
return input;
|
|
2351
|
-
}
|
|
2352
|
-
const [operator] = input;
|
|
2353
|
-
switch (operator) {
|
|
2354
|
-
// Logical operators
|
|
2355
|
-
case opts.operatorMapping.get(OPERATOR$4):
|
|
2356
|
-
{
|
|
2357
|
-
return simplifyAnd(simplifyInput)(input);
|
|
2358
|
-
}
|
|
2359
|
-
case opts.operatorMapping.get(OPERATOR$1):
|
|
2360
|
-
{
|
|
2361
|
-
return simplifyOr(simplifyInput)(input);
|
|
2362
|
-
}
|
|
2363
|
-
case opts.operatorMapping.get(OPERATOR$2):
|
|
2364
|
-
{
|
|
2365
|
-
return simplifyNor(opts, simplifyInput)(input);
|
|
2366
|
-
}
|
|
2367
|
-
case opts.operatorMapping.get(OPERATOR):
|
|
2368
|
-
{
|
|
2369
|
-
return simplifyXor(opts, simplifyInput)(input);
|
|
2370
|
-
}
|
|
2371
|
-
case opts.operatorMapping.get(OPERATOR$3):
|
|
2372
|
-
{
|
|
2373
|
-
return simplifyNot(simplifyInput)(input);
|
|
2374
|
-
}
|
|
2375
|
-
// Comparison operators
|
|
2376
|
-
case opts.operatorMapping.get(OPERATOR$h):
|
|
2377
|
-
{
|
|
2378
|
-
return simplifyEq(opts, simplifyInput)(input);
|
|
2379
|
-
}
|
|
2380
|
-
case opts.operatorMapping.get(OPERATOR$b):
|
|
2381
|
-
{
|
|
2382
|
-
return simplifyNe(opts, simplifyInput)(input);
|
|
2383
|
-
}
|
|
2384
|
-
case opts.operatorMapping.get(OPERATOR$f):
|
|
2385
|
-
{
|
|
2386
|
-
return simplifyGt(opts, simplifyInput)(input);
|
|
2387
|
-
}
|
|
2388
|
-
case opts.operatorMapping.get(OPERATOR$g):
|
|
2389
|
-
{
|
|
2390
|
-
return simplifyGe(opts, simplifyInput)(input);
|
|
2391
|
-
}
|
|
2392
|
-
case opts.operatorMapping.get(OPERATOR$c):
|
|
2393
|
-
{
|
|
2394
|
-
return simplifyLt(opts, simplifyInput)(input);
|
|
2395
|
-
}
|
|
2396
|
-
case opts.operatorMapping.get(OPERATOR$d):
|
|
2397
|
-
{
|
|
2398
|
-
return simplifyLe(opts, simplifyInput)(input);
|
|
2399
|
-
}
|
|
2400
|
-
case opts.operatorMapping.get(OPERATOR$e):
|
|
2401
|
-
{
|
|
2402
|
-
return simplifyIn(simplifyInput)(input);
|
|
2403
|
-
}
|
|
2404
|
-
case opts.operatorMapping.get(OPERATOR$a):
|
|
2405
|
-
{
|
|
2406
|
-
return simplifyNotIn(simplifyInput)(input);
|
|
2407
|
-
}
|
|
2408
|
-
case opts.operatorMapping.get(OPERATOR$8):
|
|
2409
|
-
{
|
|
2410
|
-
return simplifyPrefix(opts, simplifyInput)(input);
|
|
2411
|
-
}
|
|
2412
|
-
case opts.operatorMapping.get(OPERATOR$6):
|
|
2413
|
-
{
|
|
2414
|
-
return simplifySuffix(opts, simplifyInput)(input);
|
|
2415
|
-
}
|
|
2416
|
-
case opts.operatorMapping.get(OPERATOR$9):
|
|
2417
|
-
{
|
|
2418
|
-
return simplifyOverlap(simplifyInput)(input);
|
|
2419
|
-
}
|
|
2420
|
-
case opts.operatorMapping.get(OPERATOR$5):
|
|
2421
|
-
{
|
|
2422
|
-
return simplifyUndefined(simplifyInput)(input);
|
|
2423
|
-
}
|
|
2424
|
-
case opts.operatorMapping.get(OPERATOR$7):
|
|
2425
|
-
{
|
|
2426
|
-
return simplifyPresent(simplifyInput)(input);
|
|
2427
|
-
}
|
|
2428
|
-
// Arithmetic operators
|
|
2429
|
-
case opts.operatorMapping.get(OPERATOR$i):
|
|
2430
|
-
{
|
|
2431
|
-
return simplifySum(simplifyInput)(input);
|
|
2432
|
-
}
|
|
2433
|
-
case opts.operatorMapping.get(OPERATOR$j):
|
|
2434
|
-
{
|
|
2435
|
-
return simplifySubtract(simplifyInput)(input);
|
|
2436
|
-
}
|
|
2437
|
-
case opts.operatorMapping.get(OPERATOR$k):
|
|
2438
|
-
{
|
|
2439
|
-
return simplifyMultiply(simplifyInput)(input);
|
|
2440
|
-
}
|
|
2441
|
-
case opts.operatorMapping.get(OPERATOR$l):
|
|
2442
|
-
{
|
|
2443
|
-
return simplifyDivide(simplifyInput)(input);
|
|
2444
|
-
}
|
|
2445
|
-
default:
|
|
2446
|
-
{
|
|
2447
|
-
// Handle as an array of References / Values if no operator matches
|
|
2448
|
-
const result = input.map(simplifyInput);
|
|
2449
|
-
if (!areAllInputs(result)) {
|
|
2450
|
-
return new Collection(result.map(item => {
|
|
2451
|
-
if (item instanceof Reference) {
|
|
2452
|
-
return item;
|
|
2453
|
-
}
|
|
2454
|
-
if (!isEvaluable(item)) {
|
|
2455
|
-
return new Value(item);
|
|
2456
|
-
}
|
|
2457
|
-
throw new Error('Unexpected expression found within a collection of values/references');
|
|
2458
|
-
}));
|
|
2459
|
-
}
|
|
2460
|
-
return result;
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
};
|
|
2464
|
-
return simplifyInput;
|
|
2465
|
-
};
|
|
2466
|
-
|
|
2467
1954
|
const unexpectedResultError = 'non expression or boolean result should be returned';
|
|
2468
1955
|
|
|
2469
1956
|
/**
|
|
@@ -2520,10 +2007,12 @@ class Engine {
|
|
|
2520
2007
|
*
|
|
2521
2008
|
* @param {ExpressionInput} exp Raw expression.
|
|
2522
2009
|
* @param {Context} context Evaluation data context.
|
|
2523
|
-
* @param {string[]} strictKeys keys to be considered present even if they are not present in the
|
|
2524
|
-
*
|
|
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
|
|
2525
2013
|
* `strictKeys`; when `strictKeys` is `undefined` and `optionalKeys` is an array, every key that is not in
|
|
2526
|
-
* `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.
|
|
2527
2016
|
* @returns {Inpunt | boolean}
|
|
2528
2017
|
*/
|
|
2529
2018
|
simplify(exp, context, strictKeys, optionalKeys) {
|
|
@@ -2536,18 +2025,6 @@ class Engine {
|
|
|
2536
2025
|
}
|
|
2537
2026
|
throw new Error(unexpectedResultError);
|
|
2538
2027
|
}
|
|
2539
|
-
unsafeSimplify(exp, context, strictKeys, optionalKeys) {
|
|
2540
|
-
const result = unsafeSimplify(context, this.parser.options, strictKeys, optionalKeys)(exp);
|
|
2541
|
-
if (isBoolean(result)) {
|
|
2542
|
-
return result;
|
|
2543
|
-
}
|
|
2544
|
-
|
|
2545
|
-
// The unsafe implementation should not expose the Evaluable interface
|
|
2546
|
-
if (isEvaluable(result)) {
|
|
2547
|
-
throw new Error('Unexpected Evaluable not serialized result');
|
|
2548
|
-
}
|
|
2549
|
-
return result;
|
|
2550
|
-
}
|
|
2551
2028
|
}
|
|
2552
2029
|
|
|
2553
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 };
|
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
|
|
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
|
|
157
|
+
if (!areAllNumbers(presentValues)) {
|
|
164
158
|
throw new Error(`operands must be numbers for ${this.constructor.name}`);
|
|
165
159
|
}
|
|
166
160
|
return presentValues;
|
|
@@ -602,6 +596,9 @@ class Reference extends Operand {
|
|
|
602
596
|
evaluate(ctx) {
|
|
603
597
|
return this.toDataType(this.valueLookup(ctx));
|
|
604
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
|
+
}
|
|
605
602
|
|
|
606
603
|
/**
|
|
607
604
|
* {@link Evaluable.simplify}
|
|
@@ -615,7 +612,7 @@ class Reference extends Operand {
|
|
|
615
612
|
if (!key || typeof key === 'number') {
|
|
616
613
|
return this;
|
|
617
614
|
}
|
|
618
|
-
return
|
|
615
|
+
return this.checkStrictAndOptional(key, strictKeys, optionalKeys);
|
|
619
616
|
}
|
|
620
617
|
|
|
621
618
|
/**
|
|
@@ -1958,516 +1955,6 @@ class Parser {
|
|
|
1958
1955
|
}
|
|
1959
1956
|
}
|
|
1960
1957
|
|
|
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
|
-
|
|
2471
1958
|
const unexpectedResultError = 'non expression or boolean result should be returned';
|
|
2472
1959
|
|
|
2473
1960
|
/**
|
|
@@ -2524,10 +2011,12 @@ class Engine {
|
|
|
2524
2011
|
*
|
|
2525
2012
|
* @param {ExpressionInput} exp Raw expression.
|
|
2526
2013
|
* @param {Context} context Evaluation data context.
|
|
2527
|
-
* @param {string[]} strictKeys keys to be considered present even if they are not present in the
|
|
2528
|
-
*
|
|
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
|
|
2529
2017
|
* `strictKeys`; when `strictKeys` is `undefined` and `optionalKeys` is an array, every key that is not in
|
|
2530
|
-
* `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.
|
|
2531
2020
|
* @returns {Inpunt | boolean}
|
|
2532
2021
|
*/
|
|
2533
2022
|
simplify(exp, context, strictKeys, optionalKeys) {
|
|
@@ -2540,18 +2029,6 @@ class Engine {
|
|
|
2540
2029
|
}
|
|
2541
2030
|
throw new Error(unexpectedResultError);
|
|
2542
2031
|
}
|
|
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
|
-
}
|
|
2555
2032
|
}
|
|
2556
2033
|
|
|
2557
2034
|
exports.OPERATOR_AND = OPERATOR$4;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@briza/illogical",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "A micro conditional javascript engine used to parse the raw logical and comparison expressions, evaluate the expression in the given data context, and provide access to a text form of the given expressions.",
|
|
5
5
|
"main": "lib/illogical.js",
|
|
6
6
|
"module": "lib/illogical.esm.js",
|
package/readme.md
CHANGED
|
@@ -222,19 +222,6 @@ engine.simplify(
|
|
|
222
222
|
) // ['==', '$b', 20]
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
### Unsafe Simplify
|
|
226
|
-
|
|
227
|
-
Simplifies an expression with a given context, but without parsing and ensuring the condition is
|
|
228
|
-
syntatically correct. This can be used in situations where you can decouple the parsing from
|
|
229
|
-
the simplification and extra performance is needed in runtime.
|
|
230
|
-
|
|
231
|
-
```js
|
|
232
|
-
engine.unsafeSimplify(
|
|
233
|
-
['OR', ['==', '$a', 10], ['==', '$b', 20], ['==', '$c', 20]],
|
|
234
|
-
{ a: 10 }
|
|
235
|
-
) // true due to $a. Expressions for $b and $c won't even be parsed.
|
|
236
|
-
```
|
|
237
|
-
|
|
238
225
|
## Working with Expressions
|
|
239
226
|
|
|
240
227
|
### Evaluation Data Context
|
|
@@ -35,13 +35,15 @@ export interface Evaluable {
|
|
|
35
35
|
* Simplifies this Evaluable when possible.
|
|
36
36
|
*
|
|
37
37
|
* @param {Context} ctx context for the evaluation
|
|
38
|
-
* @param {string[]} strictKeys keys to be considered present even if they are not present in the
|
|
39
|
-
*
|
|
38
|
+
* @param {string[] | Set<string>} strictKeys keys to be considered present even if they are not present in the
|
|
39
|
+
* context. Passing as a Set is recommended for performance reasons.
|
|
40
|
+
* @param {string[] | Set<string>} optionalKeys keys to be considered not present unless they are in the context or in
|
|
40
41
|
* `strictKeys`; when `strictKeys` is `undefined` and `optionalKeys` is an array, every key that is not in
|
|
41
|
-
* `optionalKeys` is considered to be present and thus will be evaluated
|
|
42
|
+
* `optionalKeys` is considered to be present and thus will be evaluated. Passing as a Set is recommended for
|
|
43
|
+
* performance reasons.
|
|
42
44
|
* @returns {Result | Evaluable} simplified value or itself
|
|
43
45
|
*/
|
|
44
|
-
simplify(ctx: Context, strictKeys?: string[]
|
|
46
|
+
simplify(ctx: Context, strictKeys?: string[] | Set<string>, optionalKeys?: string[] | Set<string>): Result | Evaluable;
|
|
45
47
|
/**
|
|
46
48
|
* Serializes the Evaluable to its input format.
|
|
47
49
|
*
|
|
@@ -22,7 +22,7 @@ export declare abstract class Logical implements Evaluable {
|
|
|
22
22
|
/**
|
|
23
23
|
* {@link Evaluable.simplify}
|
|
24
24
|
*/
|
|
25
|
-
abstract simplify(ctx: Context, strictKeys?: string[]
|
|
25
|
+
abstract simplify(ctx: Context, strictKeys?: string[] | Set<string>, optionalKeys?: string[] | Set<string>): Result | Evaluable;
|
|
26
26
|
/**
|
|
27
27
|
* Get the strict representation of the expression.
|
|
28
28
|
* @return {string}
|
package/types/index.d.ts
CHANGED
|
@@ -68,13 +68,14 @@ declare class Engine {
|
|
|
68
68
|
*
|
|
69
69
|
* @param {ExpressionInput} exp Raw expression.
|
|
70
70
|
* @param {Context} context Evaluation data context.
|
|
71
|
-
* @param {string[]} strictKeys keys to be considered present even if they are not present in the
|
|
72
|
-
*
|
|
71
|
+
* @param {string[] | Set<string>} strictKeys keys to be considered present even if they are not present in the
|
|
72
|
+
* context. Passing as a Set is recommended for performance reasons.
|
|
73
|
+
* @param {string[] | Set<string>} optionalKeys keys to be considered not present unless they are in the context or in
|
|
73
74
|
* `strictKeys`; when `strictKeys` is `undefined` and `optionalKeys` is an array, every key that is not in
|
|
74
|
-
* `optionalKeys` is considered to be present and thus will be evaluated
|
|
75
|
+
* `optionalKeys` is considered to be present and thus will be evaluated. Passing as a Set is recommended for
|
|
76
|
+
* performance reasons.
|
|
75
77
|
* @returns {Inpunt | boolean}
|
|
76
78
|
*/
|
|
77
|
-
simplify(exp: ExpressionInput, context: Context, strictKeys?: string[]
|
|
78
|
-
unsafeSimplify(exp: ExpressionInput, context: Context, strictKeys?: string[], optionalKeys?: string[]): Input | boolean;
|
|
79
|
+
simplify(exp: ExpressionInput, context: Context, strictKeys?: string[] | Set<string>, optionalKeys?: string[] | Set<string>): Input | boolean;
|
|
79
80
|
}
|
|
80
81
|
export default Engine;
|
package/types/operand/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare abstract class Operand implements Evaluable {
|
|
|
13
13
|
/**
|
|
14
14
|
* {@link Evaluable.simplify}
|
|
15
15
|
*/
|
|
16
|
-
abstract simplify(ctx: Context, strictKeys?: string[]
|
|
16
|
+
abstract simplify(ctx: Context, strictKeys?: string[] | Set<string>, optionalKeys?: string[] | Set<string>): Result | Evaluable;
|
|
17
17
|
/**
|
|
18
18
|
* {@link Evaluable.serialize}
|
|
19
19
|
*/
|
|
@@ -24,10 +24,11 @@ export declare class Reference extends Operand {
|
|
|
24
24
|
* @return {boolean}
|
|
25
25
|
*/
|
|
26
26
|
evaluate(ctx: Context): Result;
|
|
27
|
+
private checkStrictAndOptional;
|
|
27
28
|
/**
|
|
28
29
|
* {@link Evaluable.simplify}
|
|
29
30
|
*/
|
|
30
|
-
simplify(ctx: Context, strictKeys?: string[]
|
|
31
|
+
simplify(ctx: Context, strictKeys?: string[] | Set<string>, optionalKeys?: string[] | Set<string>): Result | Evaluable;
|
|
31
32
|
/**
|
|
32
33
|
* {@link Evaluable.serialize}
|
|
33
34
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Context, Evaluable } from '../common/evaluable';
|
|
2
2
|
import { Input } from '../parser';
|
|
3
3
|
import { Options } from '../parser/options';
|
|
4
|
-
export declare const unsafeSimplify: (context: Context, opts: Options, strictKeys?: string
|
|
4
|
+
export declare const unsafeSimplify: (context: Context, opts: Options, strictKeys?: Set<string>, optionalKeys?: Set<string>) => (input: Input) => Input | Evaluable;
|