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