@@ -70,8 +70,8 @@ class Rule extends EventEmitter {
70
70
* @param {object } conditions - conditions, root element must be a boolean operator
71
71
*/
72
72
setConditions ( conditions ) {
73
- if ( ! Object . prototype . hasOwnProperty . call ( conditions , 'all' ) && ! Object . prototype . hasOwnProperty . call ( conditions , 'any' ) ) {
74
- throw new Error ( '"conditions" root must contain a single instance of "all" or "any "' )
73
+ if ( ! Object . prototype . hasOwnProperty . call ( conditions , 'all' ) && ! Object . prototype . hasOwnProperty . call ( conditions , 'any' ) && ! Object . prototype . hasOwnProperty . call ( conditions , 'not' ) ) {
74
+ throw new Error ( '"conditions" root must contain a single instance of "all", "any", or "not "' )
75
75
}
76
76
this . conditions = new Condition ( conditions )
77
77
return this
@@ -193,10 +193,12 @@ class Rule extends EventEmitter {
193
193
let comparisonPromise
194
194
if ( condition . operator === 'all' ) {
195
195
comparisonPromise = all ( subConditions )
196
- } else {
196
+ } else if ( condition . operator === 'any' ) {
197
197
comparisonPromise = any ( subConditions )
198
+ } else {
199
+ comparisonPromise = not ( subConditions )
198
200
}
199
- // for booleans, rule passing is determined by the all/any result
201
+ // for booleans, rule passing is determined by the all/any/not result
200
202
return comparisonPromise . then ( comparisonValue => {
201
203
const passes = comparisonValue === true
202
204
condition . result = passes
@@ -230,19 +232,25 @@ class Rule extends EventEmitter {
230
232
}
231
233
232
234
/**
233
- * Evaluates a set of conditions based on an 'all' or 'any ' operator.
235
+ * Evaluates a set of conditions based on an 'all', 'any', or 'not ' operator.
234
236
* First, orders the top level conditions based on priority
235
237
* Iterates over each priority set, evaluating each condition
236
238
* If any condition results in the rule to be guaranteed truthy or falsey,
237
239
* it will short-circuit and not bother evaluating any additional rules
238
240
* @param {Condition[] } conditions - conditions to be evaluated
239
- * @param {string('all'|'any') } operator
241
+ * @param {string('all'|'any'|'not' ) } operator
240
242
* @return {Promise(boolean) } rule evaluation result
241
243
*/
242
244
const prioritizeAndRun = ( conditions , operator ) => {
243
245
if ( conditions . length === 0 ) {
244
246
return Promise . resolve ( true )
245
247
}
248
+ if ( conditions . length === 1 ) {
249
+ // no prioritizing is necessary, just evaluate the single condition
250
+ // 'all' and 'any' will give the same results with a single condition so no method is necessary
251
+ // this also covers the 'not' case which should only ever have a single condition
252
+ return evaluateCondition ( conditions [ 0 ] )
253
+ }
246
254
let method = Array . prototype . some
247
255
if ( operator === 'all' ) {
248
256
method = Array . prototype . every
@@ -292,6 +300,15 @@ class Rule extends EventEmitter {
292
300
return prioritizeAndRun ( conditions , 'all' )
293
301
}
294
302
303
+ /**
304
+ * Runs a 'not' boolean operator on a single condition
305
+ * @param {Condition } condition to be evaluated
306
+ * @return {Promise(boolean) } condition evaluation result
307
+ */
308
+ const not = ( condition ) => {
309
+ return prioritizeAndRun ( [ condition ] , 'not' ) . then ( result => ! result )
310
+ }
311
+
295
312
/**
296
313
* Emits based on rule evaluation result, and decorates ruleResult with 'result' property
297
314
* @param {RuleResult } ruleResult
@@ -305,9 +322,12 @@ class Rule extends EventEmitter {
305
322
if ( ruleResult . conditions . any ) {
306
323
return any ( ruleResult . conditions . any )
307
324
. then ( result => processResult ( result ) )
308
- } else {
325
+ } else if ( ruleResult . conditions . all ) {
309
326
return all ( ruleResult . conditions . all )
310
327
. then ( result => processResult ( result ) )
328
+ } else {
329
+ return not ( ruleResult . conditions . not )
330
+ . then ( result => processResult ( result ) )
311
331
}
312
332
}
313
333
}
0 commit comments