@briza/illogical 1.5.5 → 1.5.6
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 +253 -466
- package/lib/illogical.js +254 -467
- package/package.json +25 -25
- package/readme.md +20 -4
- package/types/common/evaluable.d.ts +3 -3
- package/types/common/util.d.ts +5 -0
- package/types/parser/index.d.ts +3 -3
- package/types/parser/options.d.ts +1 -1
package/lib/illogical.js
CHANGED
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
function _toPrimitive(t, r) {
|
|
6
|
+
if ("object" != typeof t || !t) return t;
|
|
7
|
+
var e = t[Symbol.toPrimitive];
|
|
8
|
+
if (void 0 !== e) {
|
|
9
|
+
var i = e.call(t, r || "default");
|
|
10
|
+
if ("object" != typeof i) return i;
|
|
11
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
12
|
+
}
|
|
13
|
+
return ("string" === r ? String : Number)(t);
|
|
14
|
+
}
|
|
15
|
+
function _toPropertyKey(t) {
|
|
16
|
+
var i = _toPrimitive(t, "string");
|
|
17
|
+
return "symbol" == typeof i ? i : String(i);
|
|
18
|
+
}
|
|
5
19
|
function _defineProperty(obj, key, value) {
|
|
20
|
+
key = _toPropertyKey(key);
|
|
6
21
|
if (key in obj) {
|
|
7
22
|
Object.defineProperty(obj, key, {
|
|
8
23
|
value: value,
|
|
@@ -13,7 +28,6 @@ function _defineProperty(obj, key, value) {
|
|
|
13
28
|
} else {
|
|
14
29
|
obj[key] = value;
|
|
15
30
|
}
|
|
16
|
-
|
|
17
31
|
return obj;
|
|
18
32
|
}
|
|
19
33
|
|
|
@@ -24,45 +38,43 @@ function _defineProperty(obj, key, value) {
|
|
|
24
38
|
function isNumber(value) {
|
|
25
39
|
return typeof value === 'number' && isFinite(value);
|
|
26
40
|
}
|
|
41
|
+
|
|
27
42
|
/**
|
|
28
43
|
* Is string type predicate.
|
|
29
44
|
* @param value Tested value.
|
|
30
45
|
*/
|
|
31
|
-
|
|
32
46
|
function isString(value) {
|
|
33
47
|
return typeof value === 'string' || value instanceof String;
|
|
34
48
|
}
|
|
49
|
+
|
|
35
50
|
/**
|
|
36
51
|
* Is Object
|
|
37
52
|
* @param value tested value result of the test
|
|
38
53
|
*/
|
|
39
|
-
|
|
40
54
|
function isObject(value) {
|
|
41
55
|
if (value === null || value === undefined) {
|
|
42
56
|
return false;
|
|
43
57
|
}
|
|
44
|
-
|
|
45
58
|
if (typeof value !== 'object' || (value === null || value === void 0 ? void 0 : value.constructor) !== Object) {
|
|
46
59
|
return false;
|
|
47
60
|
}
|
|
48
|
-
|
|
49
61
|
return true;
|
|
50
62
|
}
|
|
63
|
+
|
|
51
64
|
/**
|
|
52
65
|
* Is Boolean predicate.
|
|
53
66
|
* @param value tested value.
|
|
54
67
|
* @return result of the test
|
|
55
68
|
*/
|
|
56
|
-
|
|
57
69
|
function isBoolean(value) {
|
|
58
70
|
return typeof value === 'boolean';
|
|
59
71
|
}
|
|
72
|
+
|
|
60
73
|
/**
|
|
61
74
|
* Check if a value is a an Evaluable
|
|
62
75
|
* @param {Result | Evaluable} value value to check if is Evaluable
|
|
63
76
|
* @returns {Evaluable}
|
|
64
77
|
*/
|
|
65
|
-
|
|
66
78
|
function isEvaluable(value) {
|
|
67
79
|
return typeof value === 'object' && value !== null && !Array.isArray(value) && typeof value.evaluate === 'function' && typeof value.simplify === 'function' && typeof value.serialize === 'function' && typeof value.toString === 'function';
|
|
68
80
|
}
|
|
@@ -80,15 +92,16 @@ function isEvaluable(value) {
|
|
|
80
92
|
/**
|
|
81
93
|
* Evaluation result
|
|
82
94
|
*/
|
|
83
|
-
let EvaluableType;
|
|
84
|
-
/**
|
|
85
|
-
* Evaluable
|
|
86
|
-
*/
|
|
87
95
|
|
|
88
|
-
|
|
96
|
+
let EvaluableType = /*#__PURE__*/function (EvaluableType) {
|
|
89
97
|
EvaluableType["Operand"] = "Operand";
|
|
90
98
|
EvaluableType["Expression"] = "Expression";
|
|
91
|
-
|
|
99
|
+
return EvaluableType;
|
|
100
|
+
}({});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Evaluable
|
|
104
|
+
*/
|
|
92
105
|
|
|
93
106
|
/**
|
|
94
107
|
* Abstract comparison expression
|
|
@@ -105,26 +118,24 @@ class Comparison {
|
|
|
105
118
|
this.operatorSymbol = operatorSymbol;
|
|
106
119
|
this.left = left;
|
|
107
120
|
this.right = right;
|
|
108
|
-
|
|
109
121
|
_defineProperty(this, "type", EvaluableType.Expression);
|
|
110
122
|
}
|
|
123
|
+
|
|
111
124
|
/**
|
|
112
125
|
* {@link Evaluable.evaluate}
|
|
113
126
|
*/
|
|
114
|
-
|
|
115
|
-
|
|
116
127
|
evaluate(ctx) {
|
|
117
128
|
return this.comparison(this.left.evaluate(ctx), this.right.evaluate(ctx));
|
|
118
129
|
}
|
|
130
|
+
|
|
119
131
|
/**
|
|
120
132
|
* Get the strict representation of the expression.
|
|
121
133
|
* @return {string}
|
|
122
134
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
125
135
|
toString() {
|
|
126
136
|
return `(${this.left.toString()} ${this.operator} ${this.right.toString()})`;
|
|
127
137
|
}
|
|
138
|
+
|
|
128
139
|
/**
|
|
129
140
|
* Compares left and right operands evaluated values.
|
|
130
141
|
* @param {Result} left left operand result value
|
|
@@ -132,450 +143,469 @@ class Comparison {
|
|
|
132
143
|
* @returns {boolean}
|
|
133
144
|
*/
|
|
134
145
|
|
|
135
|
-
|
|
136
146
|
/**
|
|
137
147
|
* {@link Evaluable.simplify}
|
|
138
148
|
*/
|
|
139
|
-
simplify() {
|
|
140
|
-
const left = this.left.simplify(...
|
|
141
|
-
const right = this.right.simplify(...
|
|
142
|
-
|
|
149
|
+
simplify(...args) {
|
|
150
|
+
const left = this.left.simplify(...args);
|
|
151
|
+
const right = this.right.simplify(...args);
|
|
143
152
|
if (!isEvaluable(left) && !isEvaluable(right)) {
|
|
144
153
|
return this.comparison(left, right);
|
|
145
154
|
}
|
|
146
|
-
|
|
147
155
|
return this;
|
|
148
156
|
}
|
|
157
|
+
|
|
149
158
|
/**
|
|
150
159
|
* {@link Evaluable.serialize}
|
|
151
160
|
*/
|
|
152
|
-
|
|
153
|
-
|
|
154
161
|
serialize(options) {
|
|
155
162
|
const {
|
|
156
163
|
operatorMapping
|
|
157
164
|
} = options;
|
|
158
165
|
const operator = operatorMapping.get(this.operatorSymbol);
|
|
159
|
-
|
|
160
166
|
if (operator === undefined) {
|
|
161
167
|
throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
|
|
162
168
|
}
|
|
163
|
-
|
|
164
169
|
return [operator, this.left.serialize(options), this.right.serialize(options)];
|
|
165
170
|
}
|
|
166
|
-
|
|
167
171
|
}
|
|
168
172
|
|
|
173
|
+
// Operator key
|
|
169
174
|
const OPERATOR$h = Symbol('EQ');
|
|
175
|
+
|
|
170
176
|
/**
|
|
171
177
|
* Equal comparison expression
|
|
172
178
|
*/
|
|
173
|
-
|
|
174
179
|
class Equal extends Comparison {
|
|
175
180
|
/**
|
|
176
181
|
* @constructor
|
|
177
182
|
* @param {Evaluable} left Left operand.
|
|
178
183
|
* @param {Evaluable} right Right operand.
|
|
179
184
|
*/
|
|
185
|
+
|
|
180
186
|
constructor(left, right) {
|
|
181
187
|
if (arguments.length !== 2) {
|
|
182
188
|
throw new Error('comparison expression expects left and right operands');
|
|
183
189
|
}
|
|
184
|
-
|
|
185
190
|
super('==', OPERATOR$h, left, right);
|
|
186
191
|
}
|
|
192
|
+
|
|
187
193
|
/**
|
|
188
194
|
* {@link Comparison.comparison}
|
|
189
195
|
*/
|
|
190
|
-
|
|
191
|
-
|
|
192
196
|
comparison(left, right) {
|
|
193
197
|
return left === right;
|
|
194
198
|
}
|
|
195
|
-
|
|
196
199
|
}
|
|
197
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Convert a value to number if possible, otherwise return undefined
|
|
203
|
+
* @param value value to be converted to number
|
|
204
|
+
*/
|
|
205
|
+
const toNumber = value => {
|
|
206
|
+
const isValueNumber = isNumber(value);
|
|
207
|
+
if (isValueNumber) {
|
|
208
|
+
return value;
|
|
209
|
+
} else if (isString(value)) {
|
|
210
|
+
if (value.match(/^\d+\.\d+$/)) {
|
|
211
|
+
return parseFloat(value);
|
|
212
|
+
} else if (value.match(/^0$|^[1-9]\d*$/)) {
|
|
213
|
+
return parseInt(value);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return undefined;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Convert a value to string if possible, otherwise return undefined
|
|
221
|
+
* @param value value to be converted to string
|
|
222
|
+
*/
|
|
223
|
+
const toString = value => {
|
|
224
|
+
if (isNumber(value)) {
|
|
225
|
+
return `${value}`;
|
|
226
|
+
} else if (isString(value)) {
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
return undefined;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Convert a value to number if it's type is string, otherwise return NaN
|
|
233
|
+
* @param value value to be converted to number
|
|
234
|
+
*/
|
|
235
|
+
const toDateNumber = value => {
|
|
236
|
+
if (isString(value)) {
|
|
237
|
+
return Date.parse(value);
|
|
238
|
+
}
|
|
239
|
+
return NaN;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Operator key
|
|
198
243
|
const OPERATOR$g = Symbol('GE');
|
|
244
|
+
|
|
199
245
|
/**
|
|
200
246
|
* Greater than or equal comparison expression
|
|
201
247
|
*/
|
|
202
|
-
|
|
203
248
|
class GreaterThanOrEqual extends Comparison {
|
|
204
249
|
/**
|
|
205
250
|
* @constructor
|
|
206
251
|
* @param {Evaluable} left Left operand.
|
|
207
252
|
* @param {Evaluable} right Right operand.
|
|
208
253
|
*/
|
|
254
|
+
|
|
209
255
|
constructor(left, right) {
|
|
210
256
|
if (arguments.length !== 2) {
|
|
211
257
|
throw new Error('comparison expression expects left and right operands');
|
|
212
258
|
}
|
|
213
|
-
|
|
214
259
|
super('>=', OPERATOR$g, left, right);
|
|
215
260
|
}
|
|
261
|
+
|
|
216
262
|
/**
|
|
217
263
|
* {@link Comparison.comparison}
|
|
218
264
|
*/
|
|
219
|
-
|
|
220
|
-
|
|
221
265
|
comparison(left, right) {
|
|
222
266
|
if (isNumber(left) && isNumber(right)) {
|
|
223
267
|
return left >= right;
|
|
224
268
|
}
|
|
225
|
-
|
|
269
|
+
const leftDate = toDateNumber(left),
|
|
270
|
+
rightDate = toDateNumber(right);
|
|
271
|
+
if (leftDate && rightDate) {
|
|
272
|
+
return leftDate >= rightDate;
|
|
273
|
+
}
|
|
226
274
|
return false;
|
|
227
275
|
}
|
|
228
|
-
|
|
229
276
|
}
|
|
230
277
|
|
|
278
|
+
// Operator key
|
|
231
279
|
const OPERATOR$f = Symbol('GT');
|
|
280
|
+
|
|
232
281
|
/**
|
|
233
282
|
* Greater than comparison expression
|
|
234
283
|
*/
|
|
235
|
-
|
|
236
284
|
class GreaterThan extends Comparison {
|
|
237
285
|
/**
|
|
238
286
|
* @constructor
|
|
239
287
|
* @param {Evaluable} left Left operand.
|
|
240
288
|
* @param {Evaluable} right Right operand.
|
|
241
289
|
*/
|
|
290
|
+
|
|
242
291
|
constructor(left, right) {
|
|
243
292
|
if (arguments.length !== 2) {
|
|
244
293
|
throw new Error('comparison expression expects left and right operands');
|
|
245
294
|
}
|
|
246
|
-
|
|
247
295
|
super('>', OPERATOR$f, left, right);
|
|
248
296
|
}
|
|
297
|
+
|
|
249
298
|
/**
|
|
250
299
|
* {@link Comparison.comparison}
|
|
251
300
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
254
301
|
comparison(left, right) {
|
|
255
302
|
if (isNumber(left) && isNumber(right)) {
|
|
256
303
|
return left > right;
|
|
257
304
|
}
|
|
258
|
-
|
|
305
|
+
const leftDate = toDateNumber(left),
|
|
306
|
+
rightDate = toDateNumber(right);
|
|
307
|
+
if (leftDate && rightDate) {
|
|
308
|
+
return leftDate > rightDate;
|
|
309
|
+
}
|
|
259
310
|
return false;
|
|
260
311
|
}
|
|
261
|
-
|
|
262
312
|
}
|
|
263
313
|
|
|
314
|
+
// Operator key
|
|
264
315
|
const OPERATOR$e = Symbol('IN');
|
|
316
|
+
|
|
265
317
|
/**
|
|
266
318
|
* In comparison expression
|
|
267
319
|
*/
|
|
268
|
-
|
|
269
320
|
class In extends Comparison {
|
|
270
321
|
/**
|
|
271
322
|
* @constructor
|
|
272
323
|
* @param {Evaluable} left Left operand.
|
|
273
324
|
* @param {Evaluable} right Right operand.
|
|
274
325
|
*/
|
|
326
|
+
|
|
275
327
|
constructor(left, right) {
|
|
276
328
|
if (arguments.length !== 2) {
|
|
277
329
|
throw new Error('comparison expression expects left and right operands');
|
|
278
330
|
}
|
|
279
|
-
|
|
280
331
|
super('in', OPERATOR$e, left, right);
|
|
281
332
|
}
|
|
333
|
+
|
|
282
334
|
/**
|
|
283
335
|
* {@link Comparison.comparison}
|
|
284
336
|
*/
|
|
285
|
-
|
|
286
|
-
|
|
287
337
|
comparison(left, right) {
|
|
288
338
|
if (left === undefined || left === null || right === undefined || right === null) {
|
|
289
339
|
return false;
|
|
290
340
|
}
|
|
291
|
-
|
|
292
341
|
const leftArray = Array.isArray(left);
|
|
293
342
|
const rightArray = Array.isArray(right);
|
|
294
|
-
|
|
295
343
|
if (leftArray && rightArray) {
|
|
296
344
|
throw new Error('invalid IN expression, both operands are array');
|
|
297
345
|
}
|
|
298
|
-
|
|
299
346
|
if (!leftArray && !rightArray) {
|
|
300
347
|
throw new Error('invalid IN expression, non of the operands is array');
|
|
301
348
|
}
|
|
302
|
-
|
|
303
349
|
if (leftArray) {
|
|
304
350
|
return left.indexOf(right) > -1;
|
|
305
351
|
}
|
|
306
|
-
|
|
307
352
|
return right.indexOf(left) > -1;
|
|
308
353
|
}
|
|
354
|
+
|
|
309
355
|
/**
|
|
310
356
|
* Get the strict representation of the expression.
|
|
311
357
|
* @return {string}
|
|
312
358
|
*/
|
|
313
|
-
|
|
314
|
-
|
|
315
359
|
toString() {
|
|
316
360
|
const left = this.left.toString();
|
|
317
361
|
const right = this.right.toString();
|
|
318
|
-
|
|
319
362
|
if (left.startsWith('[')) {
|
|
320
363
|
return `(${right} ${this.operator} ${left})`;
|
|
321
364
|
}
|
|
322
|
-
|
|
323
365
|
return `(${left} ${this.operator} ${right})`;
|
|
324
366
|
}
|
|
325
|
-
|
|
326
367
|
}
|
|
327
368
|
|
|
369
|
+
// Operator key
|
|
328
370
|
const OPERATOR$d = Symbol('LE');
|
|
371
|
+
|
|
329
372
|
/**
|
|
330
373
|
* Less than or equal comparison expression
|
|
331
374
|
*/
|
|
332
|
-
|
|
333
375
|
class LessThanOrEqual extends Comparison {
|
|
334
376
|
/**
|
|
335
377
|
* @constructor
|
|
336
378
|
* @param {Evaluable} left Left operand.
|
|
337
379
|
* @param {Evaluable} right Right operand.
|
|
338
380
|
*/
|
|
381
|
+
|
|
339
382
|
constructor(left, right) {
|
|
340
383
|
if (arguments.length !== 2) {
|
|
341
384
|
throw new Error('comparison expression expects left and right operands');
|
|
342
385
|
}
|
|
343
|
-
|
|
344
386
|
super('<=', OPERATOR$d, left, right);
|
|
345
387
|
}
|
|
388
|
+
|
|
346
389
|
/**
|
|
347
390
|
* {@link Comparison.comparison}
|
|
348
391
|
*/
|
|
349
|
-
|
|
350
|
-
|
|
351
392
|
comparison(left, right) {
|
|
352
393
|
if (isNumber(left) && isNumber(right)) {
|
|
353
394
|
return left <= right;
|
|
354
395
|
}
|
|
355
|
-
|
|
396
|
+
const leftDate = toDateNumber(left),
|
|
397
|
+
rightDate = toDateNumber(right);
|
|
398
|
+
if (leftDate && rightDate) {
|
|
399
|
+
return leftDate <= rightDate;
|
|
400
|
+
}
|
|
356
401
|
return false;
|
|
357
402
|
}
|
|
358
|
-
|
|
359
403
|
}
|
|
360
404
|
|
|
405
|
+
// Operator key
|
|
361
406
|
const OPERATOR$c = Symbol('LT');
|
|
407
|
+
|
|
362
408
|
/**
|
|
363
409
|
* Less than comparison expression
|
|
364
410
|
*/
|
|
365
|
-
|
|
366
411
|
class LessThan extends Comparison {
|
|
367
412
|
/**
|
|
368
413
|
* @constructor
|
|
369
414
|
* @param {Evaluable} left Left operand.
|
|
370
415
|
* @param {Evaluable} right Right operand.
|
|
371
416
|
*/
|
|
417
|
+
|
|
372
418
|
constructor(left, right) {
|
|
373
419
|
if (arguments.length !== 2) {
|
|
374
420
|
throw new Error('comparison expression expects left and right operands');
|
|
375
421
|
}
|
|
376
|
-
|
|
377
422
|
super('<', OPERATOR$c, left, right);
|
|
378
423
|
}
|
|
424
|
+
|
|
379
425
|
/**
|
|
380
426
|
* {@link Comparison.comparison}
|
|
381
427
|
*/
|
|
382
|
-
|
|
383
|
-
|
|
384
428
|
comparison(left, right) {
|
|
385
429
|
if (isNumber(left) && isNumber(right)) {
|
|
386
430
|
return left < right;
|
|
387
431
|
}
|
|
388
|
-
|
|
432
|
+
const leftDate = toDateNumber(left),
|
|
433
|
+
rightDate = toDateNumber(right);
|
|
434
|
+
if (leftDate && rightDate) {
|
|
435
|
+
return leftDate < rightDate;
|
|
436
|
+
}
|
|
389
437
|
return false;
|
|
390
438
|
}
|
|
391
|
-
|
|
392
439
|
}
|
|
393
440
|
|
|
441
|
+
// Operator key
|
|
394
442
|
const OPERATOR$b = Symbol('NE');
|
|
443
|
+
|
|
395
444
|
/**
|
|
396
445
|
* Not equal comparison expression
|
|
397
446
|
*/
|
|
398
|
-
|
|
399
447
|
class NotEqual extends Comparison {
|
|
400
448
|
/**
|
|
401
449
|
* @constructor
|
|
402
450
|
* @param {Evaluable} left Left operand.
|
|
403
451
|
* @param {Evaluable} right Right operand.
|
|
404
452
|
*/
|
|
453
|
+
|
|
405
454
|
constructor(left, right) {
|
|
406
455
|
if (arguments.length !== 2) {
|
|
407
456
|
throw new Error('comparison expression expects left and right operands');
|
|
408
457
|
}
|
|
409
|
-
|
|
410
458
|
super('!=', OPERATOR$b, left, right);
|
|
411
459
|
}
|
|
460
|
+
|
|
412
461
|
/**
|
|
413
462
|
* {@link Comparison.comparison}
|
|
414
463
|
*/
|
|
415
|
-
|
|
416
|
-
|
|
417
464
|
comparison(left, right) {
|
|
418
465
|
return left !== right;
|
|
419
466
|
}
|
|
420
|
-
|
|
421
467
|
}
|
|
422
468
|
|
|
469
|
+
// Operator key
|
|
423
470
|
const OPERATOR$a = Symbol('NOT IN');
|
|
471
|
+
|
|
424
472
|
/**
|
|
425
473
|
* Not in comparison expression
|
|
426
474
|
*/
|
|
427
|
-
|
|
428
475
|
class NotIn extends Comparison {
|
|
429
476
|
/**
|
|
430
477
|
* @constructor
|
|
431
478
|
* @param {Evaluable} left Left operand.
|
|
432
479
|
* @param {Evaluable} right Right operand.
|
|
433
480
|
*/
|
|
481
|
+
|
|
434
482
|
constructor(left, right) {
|
|
435
483
|
if (arguments.length !== 2) {
|
|
436
484
|
throw new Error('comparison expression expects left and right operands');
|
|
437
485
|
}
|
|
438
|
-
|
|
439
486
|
super('not in', OPERATOR$a, left, right);
|
|
440
487
|
}
|
|
488
|
+
|
|
441
489
|
/**
|
|
442
490
|
* {@link Comparison.comparison}
|
|
443
491
|
*/
|
|
444
|
-
|
|
445
|
-
|
|
446
492
|
comparison(left, right) {
|
|
447
493
|
if (left === undefined || left === null || right === undefined || right === null) {
|
|
448
494
|
return true;
|
|
449
495
|
}
|
|
450
|
-
|
|
451
496
|
const leftArray = Array.isArray(left);
|
|
452
497
|
const rightArray = Array.isArray(right);
|
|
453
|
-
|
|
454
498
|
if (leftArray && rightArray) {
|
|
455
499
|
throw new Error('invalid NOT IN expression, both operands are array');
|
|
456
500
|
}
|
|
457
|
-
|
|
458
501
|
if (!leftArray && !rightArray) {
|
|
459
502
|
throw new Error('invalid NOT IN expression, one operand must be array');
|
|
460
503
|
}
|
|
461
|
-
|
|
462
504
|
if (leftArray) {
|
|
463
505
|
return left.indexOf(right) === -1;
|
|
464
506
|
}
|
|
465
|
-
|
|
466
507
|
return right.indexOf(left) === -1;
|
|
467
508
|
}
|
|
509
|
+
|
|
468
510
|
/**
|
|
469
511
|
* Get the strict representation of the expression
|
|
470
512
|
* @return {string}
|
|
471
513
|
*/
|
|
472
|
-
|
|
473
|
-
|
|
474
514
|
toString() {
|
|
475
515
|
const left = this.left.toString();
|
|
476
516
|
const right = this.right.toString();
|
|
477
|
-
|
|
478
517
|
if (left.startsWith('[')) {
|
|
479
518
|
return `(${right} ${this.operator} ${left})`;
|
|
480
519
|
}
|
|
481
|
-
|
|
482
520
|
return `(${left} ${this.operator} ${right})`;
|
|
483
521
|
}
|
|
484
|
-
|
|
485
522
|
}
|
|
486
523
|
|
|
524
|
+
// Operator key
|
|
487
525
|
const OPERATOR$9 = Symbol('OVERLAP');
|
|
526
|
+
|
|
488
527
|
/**
|
|
489
528
|
* Overlap comparison expression
|
|
490
529
|
*/
|
|
491
|
-
|
|
492
530
|
class Overlap extends Comparison {
|
|
493
531
|
/**
|
|
494
532
|
* @constructor
|
|
495
533
|
* @param {Evaluable} left Left operand.
|
|
496
534
|
* @param {Evaluable} right Right operand.
|
|
497
535
|
*/
|
|
536
|
+
|
|
498
537
|
constructor(left, right) {
|
|
499
538
|
if (arguments.length !== 2) {
|
|
500
539
|
throw new Error('comparison expression expects left and right operands');
|
|
501
540
|
}
|
|
502
|
-
|
|
503
541
|
super('overlap', OPERATOR$9, left, right);
|
|
504
542
|
}
|
|
543
|
+
|
|
505
544
|
/**
|
|
506
545
|
* {@link Comparison.comparison}
|
|
507
546
|
*/
|
|
508
|
-
|
|
509
|
-
|
|
510
547
|
comparison(left, right) {
|
|
511
548
|
if (left === undefined || left === null || right === undefined || right === null) {
|
|
512
549
|
return false;
|
|
513
550
|
}
|
|
514
|
-
|
|
515
551
|
if (!Array.isArray(left) || !Array.isArray(right)) {
|
|
516
552
|
throw new Error('invalid OVERLAP expression, both operands must be array');
|
|
517
553
|
}
|
|
518
|
-
|
|
519
554
|
const leftArray = left;
|
|
520
555
|
const rightArray = right;
|
|
521
556
|
return leftArray.some(element => rightArray.includes(element));
|
|
522
557
|
}
|
|
558
|
+
|
|
523
559
|
/**
|
|
524
560
|
* Get the strict representation of the expression.
|
|
525
561
|
* @return {string}
|
|
526
562
|
*/
|
|
527
|
-
|
|
528
|
-
|
|
529
563
|
toString() {
|
|
530
564
|
const left = this.left.toString();
|
|
531
565
|
const right = this.right.toString();
|
|
532
566
|
return `(${left} ${this.operator} ${right})`;
|
|
533
567
|
}
|
|
534
|
-
|
|
535
568
|
}
|
|
536
569
|
|
|
570
|
+
// Operator key
|
|
537
571
|
const OPERATOR$8 = Symbol('PREFIX');
|
|
572
|
+
|
|
538
573
|
/**
|
|
539
574
|
* Prefix comparison expression
|
|
540
575
|
*/
|
|
541
|
-
|
|
542
576
|
class Prefix extends Comparison {
|
|
543
577
|
/**
|
|
544
578
|
* @constructor
|
|
545
579
|
* @param {Evaluable} left Left operand.
|
|
546
580
|
* @param {Evaluable} right Right operand.
|
|
547
581
|
*/
|
|
582
|
+
|
|
548
583
|
constructor(left, right) {
|
|
549
584
|
if (arguments.length !== 2) {
|
|
550
585
|
throw new Error('comparison expression expects left and right operands');
|
|
551
586
|
}
|
|
552
|
-
|
|
553
587
|
super('prefix', OPERATOR$8, left, right);
|
|
554
588
|
}
|
|
589
|
+
|
|
555
590
|
/**
|
|
556
591
|
* {@link Comparison.comparison}
|
|
557
592
|
*/
|
|
558
|
-
|
|
559
|
-
|
|
560
593
|
comparison(left, right) {
|
|
561
594
|
if (isString(left) === false || isString(right) === false) {
|
|
562
595
|
return false;
|
|
563
596
|
}
|
|
564
|
-
|
|
565
597
|
return right.startsWith(left);
|
|
566
598
|
}
|
|
599
|
+
|
|
567
600
|
/**
|
|
568
601
|
* Get the strict representation of the expression.
|
|
569
602
|
* @return {string}
|
|
570
603
|
*/
|
|
571
|
-
|
|
572
|
-
|
|
573
604
|
toString() {
|
|
574
605
|
const left = this.left.toString();
|
|
575
606
|
const right = this.right.toString();
|
|
576
607
|
return `(<${left}>${right})`;
|
|
577
608
|
}
|
|
578
|
-
|
|
579
609
|
}
|
|
580
610
|
|
|
581
611
|
/**
|
|
@@ -585,14 +615,21 @@ class Operand {
|
|
|
585
615
|
constructor() {
|
|
586
616
|
_defineProperty(this, "type", EvaluableType.Operand);
|
|
587
617
|
}
|
|
588
|
-
|
|
618
|
+
/**
|
|
619
|
+
* {@link Evaluable.evaluate}
|
|
620
|
+
*/
|
|
621
|
+
/**
|
|
622
|
+
* {@link Evaluable.simplify}
|
|
623
|
+
*/
|
|
624
|
+
/**
|
|
625
|
+
* {@link Evaluable.serialize}
|
|
626
|
+
*/
|
|
589
627
|
/**
|
|
590
628
|
* Get the strict representation.
|
|
591
629
|
*/
|
|
592
630
|
toString() {
|
|
593
631
|
throw new Error('not implemented exception');
|
|
594
632
|
}
|
|
595
|
-
|
|
596
633
|
}
|
|
597
634
|
|
|
598
635
|
/**
|
|
@@ -600,19 +637,16 @@ class Operand {
|
|
|
600
637
|
* @param {Result} value
|
|
601
638
|
* @return {string}
|
|
602
639
|
*/
|
|
603
|
-
|
|
604
640
|
function printValue(value) {
|
|
605
641
|
if (isString(value)) {
|
|
606
642
|
return `"${value}"`;
|
|
607
643
|
}
|
|
608
|
-
|
|
609
644
|
return `${value}`;
|
|
610
645
|
}
|
|
646
|
+
|
|
611
647
|
/**
|
|
612
648
|
* Static value operand
|
|
613
649
|
*/
|
|
614
|
-
|
|
615
|
-
|
|
616
650
|
class Value extends Operand {
|
|
617
651
|
/**
|
|
618
652
|
* @constructor
|
|
@@ -622,195 +656,174 @@ class Value extends Operand {
|
|
|
622
656
|
if (Array.isArray(value)) {
|
|
623
657
|
throw new Error('deprecated direct usage of array, please use Collection operand');
|
|
624
658
|
}
|
|
625
|
-
|
|
626
659
|
super();
|
|
627
|
-
|
|
628
660
|
_defineProperty(this, "value", void 0);
|
|
629
|
-
|
|
630
661
|
this.value = value;
|
|
631
662
|
}
|
|
663
|
+
|
|
632
664
|
/**
|
|
633
665
|
* {@link Evaluable.evaluate}
|
|
634
666
|
*/
|
|
635
|
-
|
|
636
|
-
|
|
637
667
|
evaluate() {
|
|
638
668
|
return this.value;
|
|
639
669
|
}
|
|
670
|
+
|
|
640
671
|
/**
|
|
641
672
|
* {@link Evaluable.simplify}
|
|
642
673
|
*/
|
|
643
|
-
|
|
644
|
-
|
|
645
674
|
simplify() {
|
|
646
675
|
return this.value;
|
|
647
676
|
}
|
|
677
|
+
|
|
648
678
|
/**
|
|
649
679
|
* {@link Evaluable.serialize}
|
|
650
680
|
*/
|
|
651
|
-
|
|
652
|
-
|
|
653
681
|
serialize() {
|
|
654
682
|
return this.value;
|
|
655
683
|
}
|
|
684
|
+
|
|
656
685
|
/**
|
|
657
686
|
* Get the strict representation of the operand.
|
|
658
687
|
* @return {string}
|
|
659
688
|
*/
|
|
660
|
-
|
|
661
|
-
|
|
662
689
|
toString() {
|
|
663
690
|
return printValue(this.value);
|
|
664
691
|
}
|
|
665
|
-
|
|
666
692
|
}
|
|
667
693
|
|
|
694
|
+
// Operator key
|
|
668
695
|
const OPERATOR$7 = Symbol('PRESENT');
|
|
696
|
+
|
|
669
697
|
/**
|
|
670
698
|
* Present comparison expression
|
|
671
699
|
*/
|
|
672
|
-
|
|
673
700
|
class Present extends Comparison {
|
|
674
701
|
/**
|
|
675
702
|
* @constructor
|
|
676
703
|
* @param {Evaluable} operand
|
|
677
704
|
*/
|
|
705
|
+
|
|
678
706
|
constructor(operand) {
|
|
679
707
|
if (arguments.length !== 1) {
|
|
680
708
|
throw new Error('comparison expression PRESENT expects exactly one operand');
|
|
681
709
|
}
|
|
682
|
-
|
|
683
710
|
super('PRESENT', OPERATOR$7, operand, new Value(true));
|
|
684
711
|
}
|
|
712
|
+
|
|
685
713
|
/**
|
|
686
714
|
* {@link Comparison.comparison}
|
|
687
715
|
*/
|
|
688
|
-
|
|
689
|
-
|
|
690
716
|
comparison(left) {
|
|
691
717
|
return left !== undefined && left !== null;
|
|
692
718
|
}
|
|
719
|
+
|
|
693
720
|
/**
|
|
694
721
|
* Get the strict representation of the expression.
|
|
695
722
|
* @return {string}
|
|
696
723
|
*/
|
|
697
|
-
|
|
698
|
-
|
|
699
724
|
toString() {
|
|
700
725
|
return `(${this.left.toString()} is ${this.operator})`;
|
|
701
726
|
}
|
|
702
|
-
|
|
703
727
|
serialize(options) {
|
|
704
728
|
const {
|
|
705
729
|
operatorMapping
|
|
706
730
|
} = options;
|
|
707
731
|
const operator = operatorMapping.get(this.operatorSymbol);
|
|
708
|
-
|
|
709
732
|
if (operator === undefined) {
|
|
710
733
|
throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
|
|
711
734
|
}
|
|
712
|
-
|
|
713
735
|
return [operator, this.left.serialize(options)];
|
|
714
736
|
}
|
|
715
|
-
|
|
716
737
|
}
|
|
717
738
|
|
|
739
|
+
// Operator key
|
|
718
740
|
const OPERATOR$6 = Symbol('PREFIX');
|
|
741
|
+
|
|
719
742
|
/**
|
|
720
743
|
* Suffix comparison expression
|
|
721
744
|
*/
|
|
722
|
-
|
|
723
745
|
class Suffix extends Comparison {
|
|
724
746
|
/**
|
|
725
747
|
* @constructor
|
|
726
748
|
* @param {Evaluable} left Left operand.
|
|
727
749
|
* @param {Evaluable} right Right operand.
|
|
728
750
|
*/
|
|
751
|
+
|
|
729
752
|
constructor(left, right) {
|
|
730
753
|
if (arguments.length !== 2) {
|
|
731
754
|
throw new Error('comparison expression expects left and right operands');
|
|
732
755
|
}
|
|
733
|
-
|
|
734
756
|
super('suffix', OPERATOR$6, left, right);
|
|
735
757
|
}
|
|
758
|
+
|
|
736
759
|
/**
|
|
737
760
|
* {@link Comparison.comparison}
|
|
738
761
|
*/
|
|
739
|
-
|
|
740
|
-
|
|
741
762
|
comparison(left, right) {
|
|
742
763
|
if (isString(left) === false || isString(right) === false) {
|
|
743
764
|
return false;
|
|
744
765
|
}
|
|
745
|
-
|
|
746
766
|
return left.endsWith(right);
|
|
747
767
|
}
|
|
768
|
+
|
|
748
769
|
/**
|
|
749
770
|
* Get the strict representation of the expression.
|
|
750
771
|
* @return {string}
|
|
751
772
|
*/
|
|
752
|
-
|
|
753
|
-
|
|
754
773
|
toString() {
|
|
755
774
|
const left = this.left.toString();
|
|
756
775
|
const right = this.right.toString();
|
|
757
776
|
return `(${left}<${right}>)`;
|
|
758
777
|
}
|
|
759
|
-
|
|
760
778
|
}
|
|
761
779
|
|
|
780
|
+
// Operator key
|
|
762
781
|
const OPERATOR$5 = Symbol('UNDEFINED');
|
|
782
|
+
|
|
763
783
|
/**
|
|
764
784
|
* Undefined comparison expression
|
|
765
785
|
*/
|
|
766
|
-
|
|
767
786
|
class Undefined extends Comparison {
|
|
768
787
|
/**
|
|
769
788
|
* @constructor
|
|
770
789
|
* @param {Evaluable} operand
|
|
771
790
|
*/
|
|
791
|
+
|
|
772
792
|
constructor(operand) {
|
|
773
793
|
if (arguments.length !== 1) {
|
|
774
794
|
throw new Error('comparison expression UNDEFINED expects exactly one operand');
|
|
775
795
|
}
|
|
776
|
-
|
|
777
796
|
super('UNDEFINED', OPERATOR$5, operand, new Value(true));
|
|
778
797
|
}
|
|
798
|
+
|
|
779
799
|
/**
|
|
780
800
|
* {@link Comparison.comparison}
|
|
781
801
|
*/
|
|
782
|
-
|
|
783
|
-
|
|
784
802
|
comparison(left) {
|
|
785
803
|
return left === undefined;
|
|
786
804
|
}
|
|
805
|
+
|
|
787
806
|
/**
|
|
788
807
|
* Get the strict representation of the expression.
|
|
789
808
|
* @return {string}
|
|
790
809
|
*/
|
|
791
|
-
|
|
792
|
-
|
|
793
810
|
toString() {
|
|
794
811
|
return `(${this.left.toString()} is ${this.operator})`;
|
|
795
812
|
}
|
|
813
|
+
|
|
796
814
|
/**
|
|
797
815
|
* {@link Evaluable.serialize}
|
|
798
816
|
*/
|
|
799
|
-
|
|
800
|
-
|
|
801
817
|
serialize(options) {
|
|
802
818
|
const {
|
|
803
819
|
operatorMapping
|
|
804
820
|
} = options;
|
|
805
821
|
const operator = operatorMapping.get(this.operatorSymbol);
|
|
806
|
-
|
|
807
822
|
if (operator === undefined) {
|
|
808
823
|
throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
|
|
809
824
|
}
|
|
810
|
-
|
|
811
825
|
return [operator, this.left.serialize(options)];
|
|
812
826
|
}
|
|
813
|
-
|
|
814
827
|
}
|
|
815
828
|
|
|
816
829
|
/**
|
|
@@ -826,13 +839,16 @@ class Logical {
|
|
|
826
839
|
this.operator = operator;
|
|
827
840
|
this.operatorSymbol = operatorSymbol;
|
|
828
841
|
this.operands = operands;
|
|
829
|
-
|
|
830
842
|
_defineProperty(this, "type", EvaluableType.Expression);
|
|
831
843
|
}
|
|
844
|
+
|
|
832
845
|
/**
|
|
833
846
|
* {@link Evaluable.evaluate}
|
|
834
847
|
*/
|
|
835
848
|
|
|
849
|
+
/**
|
|
850
|
+
* {@link Evaluable.simplify}
|
|
851
|
+
*/
|
|
836
852
|
|
|
837
853
|
/**
|
|
838
854
|
* Get the strict representation of the expression.
|
|
@@ -841,27 +857,24 @@ class Logical {
|
|
|
841
857
|
toString() {
|
|
842
858
|
return '(' + this.operands.map(operand => operand.toString()).join(` ${this.operator} `) + ')';
|
|
843
859
|
}
|
|
844
|
-
|
|
845
860
|
serialize(options) {
|
|
846
861
|
const {
|
|
847
862
|
operatorMapping
|
|
848
863
|
} = options;
|
|
849
864
|
const operator = operatorMapping.get(this.operatorSymbol);
|
|
850
|
-
|
|
851
865
|
if (operator === undefined) {
|
|
852
866
|
throw new Error(`missing operator ${this.operatorSymbol.toString()}`);
|
|
853
867
|
}
|
|
854
|
-
|
|
855
868
|
return [operator, ...this.operands.map(operand => operand.serialize(options))];
|
|
856
869
|
}
|
|
857
|
-
|
|
858
870
|
}
|
|
859
871
|
|
|
872
|
+
// Operator key
|
|
860
873
|
const OPERATOR$4 = Symbol('AND');
|
|
874
|
+
|
|
861
875
|
/**
|
|
862
876
|
* And logical expression
|
|
863
877
|
*/
|
|
864
|
-
|
|
865
878
|
class And extends Logical {
|
|
866
879
|
/**
|
|
867
880
|
* @constructor
|
|
@@ -871,127 +884,105 @@ class And extends Logical {
|
|
|
871
884
|
if (operands.length < 2) {
|
|
872
885
|
throw new Error('logical expression must have at least two operands');
|
|
873
886
|
}
|
|
874
|
-
|
|
875
887
|
super('AND', OPERATOR$4, operands);
|
|
876
888
|
}
|
|
889
|
+
|
|
877
890
|
/**
|
|
878
891
|
* Evaluate in the given context.
|
|
879
892
|
* @param {Context} ctx
|
|
880
893
|
* @return {Result}
|
|
881
894
|
*/
|
|
882
|
-
|
|
883
|
-
|
|
884
895
|
evaluate(ctx) {
|
|
885
896
|
for (const operand of this.operands) {
|
|
886
897
|
if (operand.evaluate(ctx) === false) {
|
|
887
898
|
return false;
|
|
888
899
|
}
|
|
889
900
|
}
|
|
890
|
-
|
|
891
901
|
return true;
|
|
892
902
|
}
|
|
903
|
+
|
|
893
904
|
/**
|
|
894
905
|
* {@link Evaluable.simplify}
|
|
895
906
|
*/
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
simplify() {
|
|
899
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
900
|
-
args[_key] = arguments[_key];
|
|
901
|
-
}
|
|
902
|
-
|
|
907
|
+
simplify(...args) {
|
|
903
908
|
const simplified = this.operands.reduce((result, child) => {
|
|
904
909
|
if (result !== false) {
|
|
905
910
|
const childResult = child.simplify(...args);
|
|
906
|
-
|
|
907
911
|
if (isEvaluable(childResult)) {
|
|
908
912
|
if (isBoolean(result)) {
|
|
909
913
|
return [childResult];
|
|
910
914
|
}
|
|
911
|
-
|
|
912
915
|
return [...result, childResult];
|
|
913
916
|
}
|
|
914
|
-
|
|
915
917
|
if (!childResult) {
|
|
916
918
|
return false;
|
|
917
919
|
}
|
|
918
920
|
}
|
|
919
|
-
|
|
920
921
|
return result;
|
|
921
922
|
}, true);
|
|
922
|
-
|
|
923
923
|
if (Array.isArray(simplified)) {
|
|
924
924
|
if (simplified.length === 1) {
|
|
925
925
|
return simplified[0];
|
|
926
926
|
}
|
|
927
|
-
|
|
928
927
|
return new And(simplified);
|
|
929
928
|
}
|
|
930
|
-
|
|
931
929
|
return simplified;
|
|
932
930
|
}
|
|
933
|
-
|
|
934
931
|
}
|
|
935
932
|
|
|
933
|
+
// Operator key
|
|
936
934
|
const OPERATOR$3 = Symbol('NOT');
|
|
935
|
+
|
|
937
936
|
/**
|
|
938
937
|
* Not logical expression
|
|
939
938
|
*/
|
|
940
|
-
|
|
941
939
|
class Not extends Logical {
|
|
942
940
|
/**
|
|
943
941
|
* @constructor
|
|
944
942
|
* @param {Evaluable} operand
|
|
945
943
|
*/
|
|
944
|
+
|
|
946
945
|
constructor(operand) {
|
|
947
946
|
if (arguments.length !== 1) {
|
|
948
947
|
throw new Error('logical NOT expression must have exactly one operand');
|
|
949
948
|
}
|
|
950
|
-
|
|
951
949
|
super('NOT', OPERATOR$3, [operand]);
|
|
952
950
|
}
|
|
951
|
+
|
|
953
952
|
/**
|
|
954
953
|
* Evaluate in the given context.
|
|
955
954
|
* @param {Context} ctx
|
|
956
955
|
* @return {Result}
|
|
957
956
|
*/
|
|
958
|
-
|
|
959
|
-
|
|
960
957
|
evaluate(ctx) {
|
|
961
958
|
const result = this.operands[0].evaluate(ctx);
|
|
962
|
-
|
|
963
959
|
if (result !== true && result !== false) {
|
|
964
960
|
throw new Error("logical NOT expression's operand must be evaluated to boolean value");
|
|
965
961
|
}
|
|
966
|
-
|
|
967
962
|
return !result;
|
|
968
963
|
}
|
|
964
|
+
|
|
969
965
|
/**
|
|
970
966
|
* {@link Evaluable.simplify}
|
|
971
967
|
*/
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
simplify() {
|
|
975
|
-
const simplified = this.operands[0].simplify(...arguments);
|
|
976
|
-
|
|
968
|
+
simplify(...args) {
|
|
969
|
+
const simplified = this.operands[0].simplify(...args);
|
|
977
970
|
if (isBoolean(simplified)) {
|
|
978
971
|
return !simplified;
|
|
979
972
|
}
|
|
980
|
-
|
|
981
973
|
if (isEvaluable(simplified)) {
|
|
982
974
|
return new Not(simplified);
|
|
983
975
|
}
|
|
984
|
-
|
|
985
976
|
throw new Error("logical NOT expression's operand must be evaluated to boolean value");
|
|
986
977
|
}
|
|
987
|
-
|
|
988
978
|
}
|
|
989
979
|
|
|
980
|
+
// Operator key
|
|
990
981
|
const OPERATOR$2 = Symbol('NOR');
|
|
982
|
+
|
|
991
983
|
/**
|
|
992
984
|
* Nor logical expression
|
|
993
985
|
*/
|
|
994
|
-
|
|
995
986
|
class Nor extends Logical {
|
|
996
987
|
/**
|
|
997
988
|
* @constructor
|
|
@@ -1001,73 +992,58 @@ class Nor extends Logical {
|
|
|
1001
992
|
if (operands.length < 2) {
|
|
1002
993
|
throw new Error('logical expression must have at least two operands');
|
|
1003
994
|
}
|
|
1004
|
-
|
|
1005
995
|
super('NOR', OPERATOR$2, operands);
|
|
1006
996
|
}
|
|
997
|
+
|
|
1007
998
|
/**
|
|
1008
999
|
* Evaluate in the given context.
|
|
1009
1000
|
* @param {Context} ctx
|
|
1010
1001
|
* @return {Result}
|
|
1011
1002
|
*/
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
1003
|
evaluate(ctx) {
|
|
1015
1004
|
for (const operand of this.operands) {
|
|
1016
1005
|
if (operand.evaluate(ctx) === true) {
|
|
1017
1006
|
return false;
|
|
1018
1007
|
}
|
|
1019
1008
|
}
|
|
1020
|
-
|
|
1021
1009
|
return true;
|
|
1022
1010
|
}
|
|
1011
|
+
|
|
1023
1012
|
/**
|
|
1024
1013
|
* {@link Evaluable.simplify}
|
|
1025
1014
|
*/
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
simplify() {
|
|
1029
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
1030
|
-
args[_key] = arguments[_key];
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1015
|
+
simplify(...args) {
|
|
1033
1016
|
const simplified = this.operands.reduce((result, child) => {
|
|
1034
1017
|
if (result !== false) {
|
|
1035
1018
|
const childResult = child.simplify(...args);
|
|
1036
|
-
|
|
1037
1019
|
if (isEvaluable(childResult)) {
|
|
1038
1020
|
if (isBoolean(result)) {
|
|
1039
1021
|
return [childResult];
|
|
1040
1022
|
}
|
|
1041
|
-
|
|
1042
1023
|
return [...result, childResult];
|
|
1043
1024
|
}
|
|
1044
|
-
|
|
1045
1025
|
if (childResult) {
|
|
1046
1026
|
return false;
|
|
1047
1027
|
}
|
|
1048
1028
|
}
|
|
1049
|
-
|
|
1050
1029
|
return result;
|
|
1051
1030
|
}, true);
|
|
1052
|
-
|
|
1053
1031
|
if (Array.isArray(simplified)) {
|
|
1054
1032
|
if (simplified.length === 1) {
|
|
1055
1033
|
return new Not(...simplified);
|
|
1056
1034
|
}
|
|
1057
|
-
|
|
1058
1035
|
return new Nor(simplified);
|
|
1059
1036
|
}
|
|
1060
|
-
|
|
1061
1037
|
return simplified;
|
|
1062
1038
|
}
|
|
1063
|
-
|
|
1064
1039
|
}
|
|
1065
1040
|
|
|
1041
|
+
// Operator key
|
|
1066
1042
|
const OPERATOR$1 = Symbol('OR');
|
|
1043
|
+
|
|
1067
1044
|
/**
|
|
1068
1045
|
* Or logical expression
|
|
1069
1046
|
*/
|
|
1070
|
-
|
|
1071
1047
|
class Or extends Logical {
|
|
1072
1048
|
/**
|
|
1073
1049
|
* @constructor
|
|
@@ -1077,84 +1053,68 @@ class Or extends Logical {
|
|
|
1077
1053
|
if (operands.length < 2) {
|
|
1078
1054
|
throw new Error('logical expression must have at least two operands');
|
|
1079
1055
|
}
|
|
1080
|
-
|
|
1081
1056
|
super('OR', OPERATOR$1, operands);
|
|
1082
1057
|
}
|
|
1058
|
+
|
|
1083
1059
|
/**
|
|
1084
1060
|
* Evaluate in the given context.
|
|
1085
1061
|
* @param {Context} ctx
|
|
1086
1062
|
* @return {Result}
|
|
1087
1063
|
*/
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
1064
|
evaluate(ctx) {
|
|
1091
1065
|
for (const operand of this.operands) {
|
|
1092
1066
|
if (operand.evaluate(ctx) === true) {
|
|
1093
1067
|
return true;
|
|
1094
1068
|
}
|
|
1095
1069
|
}
|
|
1096
|
-
|
|
1097
1070
|
return false;
|
|
1098
1071
|
}
|
|
1072
|
+
|
|
1099
1073
|
/**
|
|
1100
1074
|
* {@link Evaluable.simplify}
|
|
1101
1075
|
*/
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
simplify() {
|
|
1105
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
1106
|
-
args[_key] = arguments[_key];
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1076
|
+
simplify(...args) {
|
|
1109
1077
|
const simplified = this.operands.reduce((result, child) => {
|
|
1110
1078
|
if (result !== true) {
|
|
1111
1079
|
const childResult = child.simplify(...args);
|
|
1112
|
-
|
|
1113
1080
|
if (isEvaluable(childResult)) {
|
|
1114
1081
|
if (isBoolean(result)) {
|
|
1115
1082
|
return [childResult];
|
|
1116
1083
|
}
|
|
1117
|
-
|
|
1118
1084
|
return [...result, childResult];
|
|
1119
1085
|
}
|
|
1120
|
-
|
|
1121
1086
|
if (childResult) {
|
|
1122
1087
|
return true;
|
|
1123
1088
|
}
|
|
1124
1089
|
}
|
|
1125
|
-
|
|
1126
1090
|
return result;
|
|
1127
1091
|
}, false);
|
|
1128
|
-
|
|
1129
1092
|
if (Array.isArray(simplified)) {
|
|
1130
1093
|
if (simplified.length === 1) {
|
|
1131
1094
|
return simplified[0];
|
|
1132
1095
|
}
|
|
1133
|
-
|
|
1134
1096
|
return new Or(simplified);
|
|
1135
1097
|
}
|
|
1136
|
-
|
|
1137
1098
|
return simplified;
|
|
1138
1099
|
}
|
|
1139
|
-
|
|
1140
1100
|
}
|
|
1141
1101
|
|
|
1102
|
+
// Operator key
|
|
1142
1103
|
const OPERATOR = Symbol('XOR');
|
|
1104
|
+
|
|
1143
1105
|
/**
|
|
1144
1106
|
* Logical xor
|
|
1145
1107
|
* @param {boolean} a
|
|
1146
1108
|
* @param {boolean} b
|
|
1147
1109
|
* @return {boolean}
|
|
1148
1110
|
*/
|
|
1149
|
-
|
|
1150
1111
|
function xor(a, b) {
|
|
1151
1112
|
return (a || b) && !(a && b);
|
|
1152
1113
|
}
|
|
1114
|
+
|
|
1153
1115
|
/**
|
|
1154
1116
|
* Xor logical expression
|
|
1155
1117
|
*/
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
1118
|
class Xor extends Logical {
|
|
1159
1119
|
/**
|
|
1160
1120
|
* @constructor
|
|
@@ -1164,19 +1124,16 @@ class Xor extends Logical {
|
|
|
1164
1124
|
if (operands.length < 2) {
|
|
1165
1125
|
throw new Error('logical expression must have at least two operands');
|
|
1166
1126
|
}
|
|
1167
|
-
|
|
1168
1127
|
super('XOR', OPERATOR, operands);
|
|
1169
1128
|
}
|
|
1129
|
+
|
|
1170
1130
|
/**
|
|
1171
1131
|
* Evaluate in the given context.
|
|
1172
1132
|
* @param {Context} ctx
|
|
1173
1133
|
* @return {Result}
|
|
1174
1134
|
*/
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
1135
|
evaluate(ctx) {
|
|
1178
1136
|
let res = null;
|
|
1179
|
-
|
|
1180
1137
|
for (const operand of this.operands) {
|
|
1181
1138
|
if (res === null) {
|
|
1182
1139
|
res = operand.evaluate(ctx);
|
|
@@ -1184,62 +1141,43 @@ class Xor extends Logical {
|
|
|
1184
1141
|
res = xor(res, operand.evaluate(ctx));
|
|
1185
1142
|
}
|
|
1186
1143
|
}
|
|
1187
|
-
|
|
1188
1144
|
return res;
|
|
1189
1145
|
}
|
|
1146
|
+
|
|
1190
1147
|
/**
|
|
1191
1148
|
* {@link Evaluable.simplify}
|
|
1192
1149
|
*/
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
simplify() {
|
|
1196
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
1197
|
-
args[_key] = arguments[_key];
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
const [evaluablesLeft, trueCount] = this.operands.reduce((_ref, child) => {
|
|
1201
|
-
let [notSimplifiedConditions, trueCount] = _ref;
|
|
1202
|
-
|
|
1150
|
+
simplify(...args) {
|
|
1151
|
+
const [evaluablesLeft, trueCount] = this.operands.reduce(([notSimplifiedConditions, trueCount], child) => {
|
|
1203
1152
|
if (trueCount > 1) {
|
|
1204
1153
|
return [notSimplifiedConditions, trueCount];
|
|
1205
1154
|
}
|
|
1206
|
-
|
|
1207
1155
|
const childResult = child.simplify(...args);
|
|
1208
|
-
|
|
1209
1156
|
if (isEvaluable(childResult)) {
|
|
1210
1157
|
return [[...notSimplifiedConditions, childResult], trueCount];
|
|
1211
1158
|
}
|
|
1212
|
-
|
|
1213
1159
|
if (childResult) {
|
|
1214
1160
|
return [notSimplifiedConditions, trueCount + 1];
|
|
1215
1161
|
}
|
|
1216
|
-
|
|
1217
1162
|
return [notSimplifiedConditions, trueCount];
|
|
1218
1163
|
}, [[], 0]);
|
|
1219
|
-
|
|
1220
1164
|
if (trueCount > 1) {
|
|
1221
1165
|
return false;
|
|
1222
1166
|
}
|
|
1223
|
-
|
|
1224
1167
|
if (evaluablesLeft.length === 0) {
|
|
1225
1168
|
return trueCount === 1;
|
|
1226
1169
|
}
|
|
1227
|
-
|
|
1228
1170
|
if (evaluablesLeft.length === 1) {
|
|
1229
1171
|
if (trueCount === 1) {
|
|
1230
1172
|
return new Not(...evaluablesLeft);
|
|
1231
1173
|
}
|
|
1232
|
-
|
|
1233
1174
|
return evaluablesLeft[0];
|
|
1234
1175
|
}
|
|
1235
|
-
|
|
1236
1176
|
if (trueCount === 1) {
|
|
1237
1177
|
return new Nor(evaluablesLeft);
|
|
1238
1178
|
}
|
|
1239
|
-
|
|
1240
1179
|
return new Xor(evaluablesLeft);
|
|
1241
1180
|
}
|
|
1242
|
-
|
|
1243
1181
|
}
|
|
1244
1182
|
|
|
1245
1183
|
/**
|
|
@@ -1252,109 +1190,59 @@ class Collection extends Operand {
|
|
|
1252
1190
|
*/
|
|
1253
1191
|
constructor(items) {
|
|
1254
1192
|
super();
|
|
1255
|
-
|
|
1256
1193
|
_defineProperty(this, "items", void 0);
|
|
1257
|
-
|
|
1258
1194
|
this.items = items;
|
|
1259
1195
|
}
|
|
1196
|
+
|
|
1260
1197
|
/**
|
|
1261
1198
|
* Evaluate in the given context.
|
|
1262
1199
|
* @param {Context} ctx
|
|
1263
1200
|
* @return {boolean}
|
|
1264
1201
|
*/
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
1202
|
evaluate(ctx) {
|
|
1268
1203
|
return this.items.map(item => item.evaluate(ctx));
|
|
1269
1204
|
}
|
|
1205
|
+
|
|
1270
1206
|
/**
|
|
1271
1207
|
* {@link Evaluable.simplify}
|
|
1272
1208
|
*/
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
simplify() {
|
|
1209
|
+
simplify(...args) {
|
|
1276
1210
|
const values = [];
|
|
1277
|
-
|
|
1278
1211
|
for (const item of this.items) {
|
|
1279
|
-
const simplifiedItem = item.simplify(...
|
|
1280
|
-
|
|
1212
|
+
const simplifiedItem = item.simplify(...args);
|
|
1281
1213
|
if (isEvaluable(simplifiedItem)) {
|
|
1282
1214
|
return this;
|
|
1283
1215
|
}
|
|
1284
|
-
|
|
1285
1216
|
values.push(simplifiedItem);
|
|
1286
1217
|
}
|
|
1287
|
-
|
|
1288
1218
|
return values;
|
|
1289
1219
|
}
|
|
1220
|
+
|
|
1290
1221
|
/**
|
|
1291
1222
|
* {@link Evaluable.serialize}
|
|
1292
1223
|
*/
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
1224
|
serialize(options) {
|
|
1296
1225
|
return this.items.map(item => isEvaluable(item) ? item.serialize(options) : item);
|
|
1297
1226
|
}
|
|
1227
|
+
|
|
1298
1228
|
/**
|
|
1299
1229
|
* Get the strict representation of the operand.
|
|
1300
1230
|
* @return {string}
|
|
1301
1231
|
*/
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
1232
|
toString() {
|
|
1305
1233
|
return '[' + this.items.map(item => item.toString()).join(', ') + ']';
|
|
1306
1234
|
}
|
|
1307
|
-
|
|
1308
1235
|
}
|
|
1309
1236
|
|
|
1310
|
-
/**
|
|
1311
|
-
* Convert a value to number if possible, otherwise return undefined
|
|
1312
|
-
* @param value value to be converted to number
|
|
1313
|
-
*/
|
|
1314
|
-
|
|
1315
|
-
const toNumber = value => {
|
|
1316
|
-
const isValueNumber = isNumber(value);
|
|
1317
|
-
|
|
1318
|
-
if (isValueNumber) {
|
|
1319
|
-
return value;
|
|
1320
|
-
} else if (isString(value)) {
|
|
1321
|
-
if (value.match(/^\d+\.\d+$/)) {
|
|
1322
|
-
return parseFloat(value);
|
|
1323
|
-
} else if (value.match(/^0$|^[1-9]\d*$/)) {
|
|
1324
|
-
return parseInt(value);
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
return undefined;
|
|
1329
|
-
};
|
|
1330
|
-
/**
|
|
1331
|
-
* Convert a value to string if possible, otherwise return undefined
|
|
1332
|
-
* @param value value to be converted to string
|
|
1333
|
-
*/
|
|
1334
|
-
|
|
1335
|
-
const toString = value => {
|
|
1336
|
-
if (isNumber(value)) {
|
|
1337
|
-
return `${value}`;
|
|
1338
|
-
} else if (isString(value)) {
|
|
1339
|
-
return value;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
return undefined;
|
|
1343
|
-
};
|
|
1344
|
-
|
|
1345
1237
|
const keyWithArrayIndexRegex = /^(?<currentKey>[^[\]]+?)(?<indexes>(?:\[\d+])+)?$/;
|
|
1346
1238
|
const arrayIndexRegex = /\[(\d+)]/g;
|
|
1347
|
-
|
|
1348
1239
|
const parseKey = key => key.split('.').flatMap(key => {
|
|
1349
1240
|
const parseResult = keyWithArrayIndexRegex.exec(key);
|
|
1350
1241
|
const keys = [];
|
|
1351
|
-
|
|
1352
1242
|
if (parseResult) {
|
|
1353
1243
|
var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const rawIndexes = parseResult === null || parseResult === void 0 ? void 0 : (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
|
|
1357
|
-
|
|
1244
|
+
keys.push((_parseResult$groups$c = parseResult === null || parseResult === void 0 || (_parseResult$groups = parseResult.groups) === null || _parseResult$groups === void 0 ? void 0 : _parseResult$groups.currentKey) !== null && _parseResult$groups$c !== void 0 ? _parseResult$groups$c : key);
|
|
1245
|
+
const rawIndexes = parseResult === null || parseResult === void 0 || (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
|
|
1358
1246
|
if (rawIndexes) {
|
|
1359
1247
|
for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
|
|
1360
1248
|
keys.push(parseInt(indexResult[1]));
|
|
@@ -1363,41 +1251,30 @@ const parseKey = key => key.split('.').flatMap(key => {
|
|
|
1363
1251
|
} else {
|
|
1364
1252
|
keys.push(key);
|
|
1365
1253
|
}
|
|
1366
|
-
|
|
1367
1254
|
return keys;
|
|
1368
1255
|
});
|
|
1369
|
-
|
|
1370
1256
|
const complexKeyExpression = /{([^{}]+)}/;
|
|
1371
|
-
|
|
1372
1257
|
function extractComplexKeys(ctx, key) {
|
|
1373
1258
|
// Resolve complex keys
|
|
1374
1259
|
let complexKeyMatches = complexKeyExpression.exec(key);
|
|
1375
|
-
|
|
1376
1260
|
while (complexKeyMatches) {
|
|
1377
1261
|
const resolvedValue = complexValueLookup(ctx, complexKeyMatches[1]);
|
|
1378
|
-
|
|
1379
1262
|
if (resolvedValue === undefined) {
|
|
1380
1263
|
return undefined;
|
|
1381
1264
|
}
|
|
1382
|
-
|
|
1383
1265
|
key = key.replace(complexKeyExpression, `${resolvedValue}`);
|
|
1384
1266
|
complexKeyMatches = complexKeyExpression.exec(key);
|
|
1385
1267
|
}
|
|
1386
|
-
|
|
1387
1268
|
return parseKey(key);
|
|
1388
1269
|
}
|
|
1389
|
-
|
|
1390
1270
|
const isContext = value => isObject(value);
|
|
1391
|
-
|
|
1392
1271
|
const simpleValueLookup = keys => ctx => {
|
|
1393
1272
|
let pointer = ctx;
|
|
1394
|
-
|
|
1395
1273
|
for (const key of keys) {
|
|
1396
1274
|
if (typeof key === 'number') {
|
|
1397
1275
|
if (!Array.isArray(pointer)) {
|
|
1398
1276
|
return undefined;
|
|
1399
1277
|
}
|
|
1400
|
-
|
|
1401
1278
|
pointer = pointer[key];
|
|
1402
1279
|
} else if (!isContext(pointer)) {
|
|
1403
1280
|
return undefined;
|
|
@@ -1405,9 +1282,9 @@ const simpleValueLookup = keys => ctx => {
|
|
|
1405
1282
|
pointer = pointer[key];
|
|
1406
1283
|
}
|
|
1407
1284
|
}
|
|
1408
|
-
|
|
1409
1285
|
return pointer;
|
|
1410
1286
|
};
|
|
1287
|
+
|
|
1411
1288
|
/**
|
|
1412
1289
|
* Lookup for the reference in the context.
|
|
1413
1290
|
* The nested context value is annotated with "." delimiter.
|
|
@@ -1416,33 +1293,26 @@ const simpleValueLookup = keys => ctx => {
|
|
|
1416
1293
|
* @param {string} key Context lookup key.
|
|
1417
1294
|
* @return {Result}
|
|
1418
1295
|
*/
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
1296
|
function complexValueLookup(ctx, key) {
|
|
1422
1297
|
const keys = extractComplexKeys(ctx, key);
|
|
1423
|
-
|
|
1424
1298
|
if (!keys) {
|
|
1425
1299
|
return undefined;
|
|
1426
1300
|
}
|
|
1427
|
-
|
|
1428
1301
|
return simpleValueLookup(keys !== null && keys !== void 0 ? keys : [])(ctx);
|
|
1429
1302
|
}
|
|
1430
|
-
|
|
1431
|
-
let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
|
|
1432
|
-
|
|
1433
|
-
(function (DataType) {
|
|
1303
|
+
let DataType = /*#__PURE__*/function (DataType) {
|
|
1434
1304
|
DataType["Number"] = "Number";
|
|
1435
1305
|
DataType["String"] = "String";
|
|
1436
|
-
|
|
1306
|
+
return DataType;
|
|
1307
|
+
}({});
|
|
1437
1308
|
|
|
1309
|
+
// Equivalent to /^.+\.\((Number|String)\)$/
|
|
1438
1310
|
const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
|
|
1439
|
-
|
|
1440
1311
|
const isComplexKey = key => key.indexOf('{') > -1;
|
|
1312
|
+
|
|
1441
1313
|
/**
|
|
1442
1314
|
* Reference operand resolved within the context
|
|
1443
1315
|
*/
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
1316
|
class Reference extends Operand {
|
|
1447
1317
|
/**
|
|
1448
1318
|
* @constructor
|
|
@@ -1452,119 +1322,97 @@ class Reference extends Operand {
|
|
|
1452
1322
|
if (key.trim() === '') {
|
|
1453
1323
|
throw new Error('invalid reference key');
|
|
1454
1324
|
}
|
|
1455
|
-
|
|
1456
1325
|
super();
|
|
1457
|
-
|
|
1458
1326
|
_defineProperty(this, "key", void 0);
|
|
1459
|
-
|
|
1460
1327
|
_defineProperty(this, "dataType", void 0);
|
|
1461
|
-
|
|
1462
1328
|
_defineProperty(this, "valueLookup", void 0);
|
|
1463
|
-
|
|
1464
1329
|
_defineProperty(this, "getKeys", void 0);
|
|
1465
|
-
|
|
1466
1330
|
this.key = key;
|
|
1467
1331
|
const dataTypeMatch = dataTypeRegex.exec(this.key);
|
|
1468
|
-
|
|
1469
1332
|
if (dataTypeMatch) {
|
|
1470
1333
|
this.dataType = DataType[dataTypeMatch[1]];
|
|
1471
1334
|
}
|
|
1472
|
-
|
|
1473
1335
|
if (this.key.match(/.\(.+\)$/)) {
|
|
1474
1336
|
this.key = this.key.replace(/.\(.+\)$/, '');
|
|
1475
1337
|
}
|
|
1476
|
-
|
|
1477
1338
|
if (isComplexKey(this.key)) {
|
|
1478
1339
|
this.valueLookup = context => complexValueLookup(context, this.key);
|
|
1479
|
-
|
|
1480
1340
|
this.getKeys = context => extractComplexKeys(context, this.key);
|
|
1481
1341
|
} else {
|
|
1482
1342
|
const keys = parseKey(this.key);
|
|
1483
1343
|
this.valueLookup = simpleValueLookup(keys);
|
|
1484
|
-
|
|
1485
1344
|
this.getKeys = () => keys;
|
|
1486
1345
|
}
|
|
1487
1346
|
}
|
|
1347
|
+
|
|
1488
1348
|
/**
|
|
1489
1349
|
* Evaluate in the given context.
|
|
1490
1350
|
* @param {Context} ctx
|
|
1491
1351
|
* @return {boolean}
|
|
1492
1352
|
*/
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
1353
|
evaluate(ctx) {
|
|
1496
1354
|
return this.toDataType(this.valueLookup(ctx));
|
|
1497
1355
|
}
|
|
1356
|
+
|
|
1498
1357
|
/**
|
|
1499
1358
|
* {@link Evaluable.simplify}
|
|
1500
1359
|
*/
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
1360
|
simplify(ctx, strictKeys, optionalKeys) {
|
|
1504
1361
|
var _this$getKeys;
|
|
1505
|
-
|
|
1506
1362
|
const [key] = (_this$getKeys = this.getKeys(ctx)) !== null && _this$getKeys !== void 0 ? _this$getKeys : [];
|
|
1507
|
-
|
|
1508
1363
|
if (ctx[key] !== undefined) {
|
|
1509
1364
|
return this.evaluate(ctx);
|
|
1510
1365
|
}
|
|
1511
|
-
|
|
1512
1366
|
if (!key || typeof key === 'number') {
|
|
1513
1367
|
return this;
|
|
1514
1368
|
}
|
|
1515
|
-
|
|
1516
1369
|
return strictKeys && strictKeys.includes(key) || optionalKeys && !optionalKeys.includes(key) ? undefined : this;
|
|
1517
1370
|
}
|
|
1371
|
+
|
|
1518
1372
|
/**
|
|
1519
1373
|
* {@link Evaluable.serialize}
|
|
1520
1374
|
*/
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
let {
|
|
1525
|
-
referenceSerialization
|
|
1526
|
-
} = _ref;
|
|
1375
|
+
serialize({
|
|
1376
|
+
referenceSerialization
|
|
1377
|
+
}) {
|
|
1527
1378
|
const key = this.dataType ? `${this.key}.(${this.dataType})` : this.key;
|
|
1528
1379
|
return referenceSerialization(key);
|
|
1529
1380
|
}
|
|
1381
|
+
|
|
1530
1382
|
/**
|
|
1531
1383
|
* Get the strict representation of the operand.
|
|
1532
1384
|
* @return {string}
|
|
1533
1385
|
*/
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
1386
|
toString() {
|
|
1537
1387
|
return `{${this.key}}`;
|
|
1538
1388
|
}
|
|
1389
|
+
|
|
1539
1390
|
/**
|
|
1540
1391
|
* Converts a value to a specified data type
|
|
1541
1392
|
* Silently returns original value if data type conversion has not been implemented.
|
|
1542
1393
|
* @param value value to cast as data type
|
|
1543
1394
|
*/
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
1395
|
toDataType(value) {
|
|
1547
1396
|
let result = value;
|
|
1548
|
-
|
|
1549
1397
|
switch (this.dataType) {
|
|
1550
1398
|
case DataType.Number:
|
|
1551
1399
|
result = toNumber(value);
|
|
1552
1400
|
break;
|
|
1553
|
-
|
|
1554
1401
|
case DataType.String:
|
|
1555
1402
|
result = toString(value);
|
|
1556
1403
|
break;
|
|
1557
1404
|
}
|
|
1558
|
-
|
|
1559
1405
|
if (value && result === undefined) {
|
|
1560
1406
|
console.warn(`Casting ${value} to ${this.dataType} resulted in ${result}`);
|
|
1561
1407
|
}
|
|
1562
|
-
|
|
1563
1408
|
return result;
|
|
1564
1409
|
}
|
|
1565
|
-
|
|
1566
1410
|
}
|
|
1567
1411
|
|
|
1412
|
+
// Option value whitelist
|
|
1413
|
+
|
|
1414
|
+
// Parser options
|
|
1415
|
+
|
|
1568
1416
|
/**
|
|
1569
1417
|
* Default reference predicate.
|
|
1570
1418
|
* The "$" symbol at the begging of the operand is used
|
|
@@ -1576,28 +1424,31 @@ class Reference extends Operand {
|
|
|
1576
1424
|
function defaultReferencePredicate(key) {
|
|
1577
1425
|
return isString(key) && key.startsWith('$');
|
|
1578
1426
|
}
|
|
1427
|
+
|
|
1579
1428
|
/**
|
|
1580
1429
|
* Default reference transform.
|
|
1581
1430
|
* It removes the "$" symbol at the begging of the operand name.
|
|
1582
1431
|
* @param {string} key
|
|
1583
1432
|
* @return {string}
|
|
1584
1433
|
*/
|
|
1585
|
-
|
|
1586
1434
|
function defaultReferenceTransform(key) {
|
|
1587
1435
|
return key.slice(1);
|
|
1588
1436
|
}
|
|
1589
1437
|
function defaultReferenceSerialization(key) {
|
|
1590
1438
|
return `$${key}`;
|
|
1591
|
-
}
|
|
1592
|
-
// Unique operator key <-> raw expression key
|
|
1439
|
+
}
|
|
1593
1440
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1441
|
+
// Default operator mapping
|
|
1442
|
+
// Unique operator key <-> raw expression key
|
|
1443
|
+
const defaultOperatorMapping = new Map([
|
|
1444
|
+
// Comparison
|
|
1445
|
+
[OPERATOR$h, '=='], [OPERATOR$b, '!='], [OPERATOR$f, '>'], [OPERATOR$g, '>='], [OPERATOR$c, '<'], [OPERATOR$d, '<='], [OPERATOR$e, 'IN'], [OPERATOR$a, 'NOT IN'], [OPERATOR$8, 'PREFIX'], [OPERATOR$6, 'SUFFIX'], [OPERATOR$9, 'OVERLAP'], [OPERATOR$5, 'UNDEFINED'], [OPERATOR$7, 'PRESENT'],
|
|
1446
|
+
// Logical
|
|
1596
1447
|
[OPERATOR$4, 'AND'], [OPERATOR$1, 'OR'], [OPERATOR$2, 'NOR'], [OPERATOR, 'XOR'], [OPERATOR$3, 'NOT']]);
|
|
1448
|
+
|
|
1597
1449
|
/**
|
|
1598
1450
|
* Default parser options
|
|
1599
1451
|
*/
|
|
1600
|
-
|
|
1601
1452
|
const defaultOptions = {
|
|
1602
1453
|
referencePredicate: defaultReferencePredicate,
|
|
1603
1454
|
referenceTransform: defaultReferenceTransform,
|
|
@@ -1605,6 +1456,8 @@ const defaultOptions = {
|
|
|
1605
1456
|
operatorMapping: defaultOperatorMapping
|
|
1606
1457
|
};
|
|
1607
1458
|
|
|
1459
|
+
// Input types
|
|
1460
|
+
|
|
1608
1461
|
/**
|
|
1609
1462
|
* Parser of raw expressions into Evaluable expression
|
|
1610
1463
|
*/
|
|
@@ -1615,12 +1468,11 @@ class Parser {
|
|
|
1615
1468
|
*/
|
|
1616
1469
|
constructor(options) {
|
|
1617
1470
|
_defineProperty(this, "opts", void 0);
|
|
1618
|
-
|
|
1619
1471
|
_defineProperty(this, "expectedOperators", void 0);
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
};
|
|
1623
|
-
|
|
1472
|
+
this.opts = {
|
|
1473
|
+
...defaultOptions
|
|
1474
|
+
};
|
|
1475
|
+
// Apply exclusive options overrides
|
|
1624
1476
|
if (options) {
|
|
1625
1477
|
for (const key of Object.keys(options)) {
|
|
1626
1478
|
if (key in this.opts) {
|
|
@@ -1628,55 +1480,47 @@ class Parser {
|
|
|
1628
1480
|
}
|
|
1629
1481
|
}
|
|
1630
1482
|
}
|
|
1631
|
-
|
|
1632
1483
|
this.expectedOperators = new Set(this.opts.operatorMapping.values());
|
|
1633
1484
|
}
|
|
1485
|
+
|
|
1634
1486
|
/**
|
|
1635
1487
|
* Parser options
|
|
1636
1488
|
* @type {Options}
|
|
1637
1489
|
*/
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
1490
|
get options() {
|
|
1641
1491
|
return this.opts;
|
|
1642
1492
|
}
|
|
1493
|
+
|
|
1643
1494
|
/**
|
|
1644
1495
|
* Parse raw expression into evaluable expression.
|
|
1645
1496
|
* @param {ExpressionInput} raw Raw expression.
|
|
1646
1497
|
* @return {Evaluable}
|
|
1647
1498
|
*/
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
1499
|
parse(raw) {
|
|
1651
1500
|
if (raw === undefined || raw === null || Array.isArray(raw) === false) {
|
|
1652
1501
|
throw new Error('invalid expression');
|
|
1653
1502
|
}
|
|
1654
|
-
|
|
1655
1503
|
if (raw.length === 0 || !this.expectedOperators.has(`${raw[0]}`)) {
|
|
1656
1504
|
throw new Error('invalid expression');
|
|
1657
1505
|
}
|
|
1658
|
-
|
|
1659
1506
|
return this.parseRawExp(raw);
|
|
1660
1507
|
}
|
|
1508
|
+
|
|
1661
1509
|
/**
|
|
1662
1510
|
* Parse raw expression based on the expression type.
|
|
1663
1511
|
* @param {Input} raw Raw expression.
|
|
1664
1512
|
* @return {Evaluable}
|
|
1665
1513
|
*/
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
1514
|
parseRawExp(raw) {
|
|
1669
|
-
var _this = this;
|
|
1670
|
-
|
|
1671
1515
|
// Value / Reference
|
|
1672
1516
|
if (!Array.isArray(raw)) {
|
|
1673
1517
|
return this.getOperand(raw);
|
|
1674
1518
|
}
|
|
1675
|
-
|
|
1676
1519
|
let expression;
|
|
1677
1520
|
let operandParser = this.getOperand;
|
|
1678
1521
|
const operator = raw[0];
|
|
1679
1522
|
const operands = raw.slice(1);
|
|
1523
|
+
|
|
1680
1524
|
/**
|
|
1681
1525
|
* Simplify the logical expression if possible.
|
|
1682
1526
|
* - AND, OR with one operand is collapsed, i.e. reduced to inner expression
|
|
@@ -1688,149 +1532,101 @@ class Parser {
|
|
|
1688
1532
|
* @param operands
|
|
1689
1533
|
* @param collapsible
|
|
1690
1534
|
*/
|
|
1691
|
-
|
|
1692
|
-
const logicalExpressionReducer = function (operands) {
|
|
1693
|
-
let collapsible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
1694
|
-
|
|
1535
|
+
const logicalExpressionReducer = (operands, collapsible = false) => {
|
|
1695
1536
|
if (operands.length === 0 || operands.filter(operand => operand.type === EvaluableType.Expression).length === 0) {
|
|
1696
|
-
return
|
|
1537
|
+
return this.getOperand(raw);
|
|
1697
1538
|
}
|
|
1698
|
-
|
|
1699
1539
|
return collapsible && operands.length === 1 ? operands[0] : undefined;
|
|
1700
1540
|
};
|
|
1701
|
-
|
|
1702
1541
|
switch (operator) {
|
|
1703
1542
|
/**
|
|
1704
1543
|
* Logical
|
|
1705
1544
|
*/
|
|
1706
1545
|
case this.opts.operatorMapping.get(OPERATOR$4):
|
|
1707
1546
|
expression = operands => logicalExpressionReducer(operands, true) || new And(operands);
|
|
1708
|
-
|
|
1709
1547
|
operandParser = this.parseRawExp;
|
|
1710
1548
|
break;
|
|
1711
|
-
|
|
1712
1549
|
case this.opts.operatorMapping.get(OPERATOR$1):
|
|
1713
1550
|
expression = operands => logicalExpressionReducer(operands, true) || new Or(operands);
|
|
1714
|
-
|
|
1715
1551
|
operandParser = this.parseRawExp;
|
|
1716
1552
|
break;
|
|
1717
|
-
|
|
1718
1553
|
case this.opts.operatorMapping.get(OPERATOR$2):
|
|
1719
1554
|
expression = operands => logicalExpressionReducer(operands) || new Nor(operands);
|
|
1720
|
-
|
|
1721
1555
|
operandParser = this.parseRawExp;
|
|
1722
1556
|
break;
|
|
1723
|
-
|
|
1724
1557
|
case this.opts.operatorMapping.get(OPERATOR):
|
|
1725
1558
|
expression = operands => logicalExpressionReducer(operands) || new Xor(operands);
|
|
1726
|
-
|
|
1727
1559
|
operandParser = this.parseRawExp;
|
|
1728
1560
|
break;
|
|
1729
|
-
|
|
1730
1561
|
case this.opts.operatorMapping.get(OPERATOR$3):
|
|
1731
1562
|
expression = operands => logicalExpressionReducer(operands) || new Not(...operands);
|
|
1732
|
-
|
|
1733
1563
|
operandParser = this.parseRawExp;
|
|
1734
1564
|
break;
|
|
1735
|
-
|
|
1736
1565
|
/**
|
|
1737
1566
|
* Comparison
|
|
1738
1567
|
*/
|
|
1739
|
-
|
|
1740
1568
|
case this.opts.operatorMapping.get(OPERATOR$h):
|
|
1741
1569
|
expression = operands => new Equal(...operands);
|
|
1742
|
-
|
|
1743
1570
|
break;
|
|
1744
|
-
|
|
1745
1571
|
case this.opts.operatorMapping.get(OPERATOR$b):
|
|
1746
1572
|
expression = operands => new NotEqual(...operands);
|
|
1747
|
-
|
|
1748
1573
|
break;
|
|
1749
|
-
|
|
1750
1574
|
case this.opts.operatorMapping.get(OPERATOR$f):
|
|
1751
1575
|
expression = operands => new GreaterThan(...operands);
|
|
1752
|
-
|
|
1753
1576
|
break;
|
|
1754
|
-
|
|
1755
1577
|
case this.opts.operatorMapping.get(OPERATOR$g):
|
|
1756
1578
|
expression = operands => new GreaterThanOrEqual(...operands);
|
|
1757
|
-
|
|
1758
1579
|
break;
|
|
1759
|
-
|
|
1760
1580
|
case this.opts.operatorMapping.get(OPERATOR$c):
|
|
1761
1581
|
expression = operands => new LessThan(...operands);
|
|
1762
|
-
|
|
1763
1582
|
break;
|
|
1764
|
-
|
|
1765
1583
|
case this.opts.operatorMapping.get(OPERATOR$d):
|
|
1766
1584
|
expression = operands => new LessThanOrEqual(...operands);
|
|
1767
|
-
|
|
1768
1585
|
break;
|
|
1769
|
-
|
|
1770
1586
|
case this.opts.operatorMapping.get(OPERATOR$e):
|
|
1771
1587
|
expression = operands => new In(...operands);
|
|
1772
|
-
|
|
1773
1588
|
break;
|
|
1774
|
-
|
|
1775
1589
|
case this.opts.operatorMapping.get(OPERATOR$a):
|
|
1776
1590
|
expression = operands => new NotIn(...operands);
|
|
1777
|
-
|
|
1778
1591
|
break;
|
|
1779
|
-
|
|
1780
1592
|
case this.opts.operatorMapping.get(OPERATOR$8):
|
|
1781
1593
|
expression = operands => new Prefix(...operands);
|
|
1782
|
-
|
|
1783
1594
|
break;
|
|
1784
|
-
|
|
1785
1595
|
case this.opts.operatorMapping.get(OPERATOR$6):
|
|
1786
1596
|
expression = operands => new Suffix(...operands);
|
|
1787
|
-
|
|
1788
1597
|
break;
|
|
1789
|
-
|
|
1790
1598
|
case this.opts.operatorMapping.get(OPERATOR$9):
|
|
1791
1599
|
expression = operands => new Overlap(...operands);
|
|
1792
|
-
|
|
1793
1600
|
break;
|
|
1794
|
-
|
|
1795
1601
|
case this.opts.operatorMapping.get(OPERATOR$5):
|
|
1796
1602
|
expression = operands => new Undefined(...operands);
|
|
1797
|
-
|
|
1798
1603
|
break;
|
|
1799
|
-
|
|
1800
1604
|
case this.opts.operatorMapping.get(OPERATOR$7):
|
|
1801
1605
|
expression = operands => new Present(...operands);
|
|
1802
|
-
|
|
1803
1606
|
break;
|
|
1804
1607
|
// Collection
|
|
1805
|
-
|
|
1806
1608
|
default:
|
|
1807
1609
|
return this.getOperand(raw);
|
|
1808
1610
|
}
|
|
1809
|
-
|
|
1810
1611
|
return expression(operands.map(operandParser.bind(this)));
|
|
1811
1612
|
}
|
|
1613
|
+
|
|
1812
1614
|
/**
|
|
1813
1615
|
* Get resolved operand
|
|
1814
1616
|
* @param raw Raw data
|
|
1815
1617
|
*/
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
1618
|
getOperand(raw) {
|
|
1819
1619
|
const resolve = raw => this.opts.referencePredicate(raw) ? new Reference(this.opts.referenceTransform(raw)) : new Value(raw);
|
|
1820
|
-
|
|
1821
1620
|
if (Array.isArray(raw)) {
|
|
1822
1621
|
return new Collection(raw.map(item => resolve(item)));
|
|
1823
1622
|
}
|
|
1824
|
-
|
|
1825
1623
|
return resolve(raw);
|
|
1826
1624
|
}
|
|
1827
|
-
|
|
1828
1625
|
}
|
|
1829
1626
|
|
|
1830
1627
|
/**
|
|
1831
1628
|
* Condition engine
|
|
1832
1629
|
*/
|
|
1833
|
-
|
|
1834
1630
|
class Engine {
|
|
1835
1631
|
/**
|
|
1836
1632
|
* @constructor
|
|
@@ -1838,40 +1634,37 @@ class Engine {
|
|
|
1838
1634
|
*/
|
|
1839
1635
|
constructor(options) {
|
|
1840
1636
|
_defineProperty(this, "parser", void 0);
|
|
1841
|
-
|
|
1842
1637
|
this.parser = new Parser(options);
|
|
1843
1638
|
}
|
|
1639
|
+
|
|
1844
1640
|
/**
|
|
1845
1641
|
* Evaluate the expression.
|
|
1846
1642
|
* @param {ExpressionInput} exp Raw expression.
|
|
1847
1643
|
* @param {Context} ctx Evaluation data context.
|
|
1848
1644
|
* @return {boolean}
|
|
1849
1645
|
*/
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
1646
|
evaluate(exp, ctx) {
|
|
1853
1647
|
return this.parse(exp).evaluate(ctx);
|
|
1854
1648
|
}
|
|
1649
|
+
|
|
1855
1650
|
/**
|
|
1856
1651
|
* Get expression statement
|
|
1857
1652
|
* @param {ExpressionInput} exp Raw expression.
|
|
1858
1653
|
* @return {string}
|
|
1859
1654
|
*/
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
1655
|
statement(exp) {
|
|
1863
1656
|
return this.parse(exp).toString();
|
|
1864
1657
|
}
|
|
1658
|
+
|
|
1865
1659
|
/**
|
|
1866
1660
|
* Parse expression.
|
|
1867
1661
|
* @param {ExpressionInput} exp Raw expression.
|
|
1868
1662
|
* @return {Evaluable}
|
|
1869
1663
|
*/
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
1664
|
parse(exp) {
|
|
1873
1665
|
return this.parser.parse(exp);
|
|
1874
1666
|
}
|
|
1667
|
+
|
|
1875
1668
|
/**
|
|
1876
1669
|
* Simplifies an expression with values in context.
|
|
1877
1670
|
*
|
|
@@ -1887,22 +1680,16 @@ class Engine {
|
|
|
1887
1680
|
* `optionalKeys` is considered to be present and thus will be evaluated
|
|
1888
1681
|
* @returns {Inpunt | boolean}
|
|
1889
1682
|
*/
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
1683
|
simplify(exp, context, strictKeys, optionalKeys) {
|
|
1893
1684
|
const result = this.parse(exp).simplify(context, strictKeys, optionalKeys);
|
|
1894
|
-
|
|
1895
1685
|
if (isEvaluable(result)) {
|
|
1896
1686
|
return result.serialize(this.parser.options);
|
|
1897
1687
|
}
|
|
1898
|
-
|
|
1899
1688
|
if (isBoolean(result)) {
|
|
1900
1689
|
return result;
|
|
1901
1690
|
}
|
|
1902
|
-
|
|
1903
1691
|
throw new Error('non expression or boolean result should be returned');
|
|
1904
1692
|
}
|
|
1905
|
-
|
|
1906
1693
|
}
|
|
1907
1694
|
|
|
1908
1695
|
exports.OPERATOR_AND = OPERATOR$4;
|
|
@@ -1923,6 +1710,6 @@ exports.OPERATOR_PRESENT = OPERATOR$7;
|
|
|
1923
1710
|
exports.OPERATOR_SUFFIX = OPERATOR$6;
|
|
1924
1711
|
exports.OPERATOR_UNDEFINED = OPERATOR$5;
|
|
1925
1712
|
exports.OPERATOR_XOR = OPERATOR;
|
|
1926
|
-
exports
|
|
1713
|
+
exports.default = Engine;
|
|
1927
1714
|
exports.defaultOptions = defaultOptions;
|
|
1928
1715
|
exports.isEvaluable = isEvaluable;
|