@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.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,152 +1190,97 @@ 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
|
-
const parseKey = key =>
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1239
|
+
const parseBacktickWrappedKey = key => key.startsWith('`') && key.endsWith('`') ? key.slice(1, -1) : key;
|
|
1240
|
+
const parseKey = key => {
|
|
1241
|
+
const keys = key.match(/(`[^[\]]+`(\[\d+\])*|[^`.]+)/g);
|
|
1242
|
+
return !keys ? [] : keys.flatMap(key => {
|
|
1243
|
+
const unwrappedKey = parseBacktickWrappedKey(key);
|
|
1244
|
+
const keys = [];
|
|
1245
|
+
const parseResult = keyWithArrayIndexRegex.exec(unwrappedKey);
|
|
1246
|
+
if (parseResult) {
|
|
1247
|
+
var _parseResult$groups$c, _parseResult$groups, _parseResult$groups2;
|
|
1248
|
+
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);
|
|
1249
|
+
keys.push(extractedKey);
|
|
1250
|
+
const rawIndexes = parseResult === null || parseResult === void 0 || (_parseResult$groups2 = parseResult.groups) === null || _parseResult$groups2 === void 0 ? void 0 : _parseResult$groups2.indexes;
|
|
1251
|
+
if (rawIndexes) {
|
|
1252
|
+
for (const indexResult of rawIndexes.matchAll(arrayIndexRegex)) {
|
|
1253
|
+
keys.push(parseInt(indexResult[1]));
|
|
1254
|
+
}
|
|
1361
1255
|
}
|
|
1256
|
+
} else {
|
|
1257
|
+
keys.push(unwrappedKey);
|
|
1362
1258
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
return keys;
|
|
1368
|
-
});
|
|
1369
|
-
|
|
1259
|
+
return keys;
|
|
1260
|
+
});
|
|
1261
|
+
};
|
|
1370
1262
|
const complexKeyExpression = /{([^{}]+)}/;
|
|
1371
|
-
|
|
1372
1263
|
function extractComplexKeys(ctx, key) {
|
|
1373
1264
|
// Resolve complex keys
|
|
1374
1265
|
let complexKeyMatches = complexKeyExpression.exec(key);
|
|
1375
|
-
|
|
1376
1266
|
while (complexKeyMatches) {
|
|
1377
1267
|
const resolvedValue = complexValueLookup(ctx, complexKeyMatches[1]);
|
|
1378
|
-
|
|
1379
1268
|
if (resolvedValue === undefined) {
|
|
1380
1269
|
return undefined;
|
|
1381
1270
|
}
|
|
1382
|
-
|
|
1383
1271
|
key = key.replace(complexKeyExpression, `${resolvedValue}`);
|
|
1384
1272
|
complexKeyMatches = complexKeyExpression.exec(key);
|
|
1385
1273
|
}
|
|
1386
|
-
|
|
1387
1274
|
return parseKey(key);
|
|
1388
1275
|
}
|
|
1389
|
-
|
|
1390
1276
|
const isContext = value => isObject(value);
|
|
1391
|
-
|
|
1392
1277
|
const simpleValueLookup = keys => ctx => {
|
|
1393
1278
|
let pointer = ctx;
|
|
1394
|
-
|
|
1395
1279
|
for (const key of keys) {
|
|
1396
1280
|
if (typeof key === 'number') {
|
|
1397
1281
|
if (!Array.isArray(pointer)) {
|
|
1398
1282
|
return undefined;
|
|
1399
1283
|
}
|
|
1400
|
-
|
|
1401
1284
|
pointer = pointer[key];
|
|
1402
1285
|
} else if (!isContext(pointer)) {
|
|
1403
1286
|
return undefined;
|
|
@@ -1405,9 +1288,9 @@ const simpleValueLookup = keys => ctx => {
|
|
|
1405
1288
|
pointer = pointer[key];
|
|
1406
1289
|
}
|
|
1407
1290
|
}
|
|
1408
|
-
|
|
1409
1291
|
return pointer;
|
|
1410
1292
|
};
|
|
1293
|
+
|
|
1411
1294
|
/**
|
|
1412
1295
|
* Lookup for the reference in the context.
|
|
1413
1296
|
* The nested context value is annotated with "." delimiter.
|
|
@@ -1416,33 +1299,26 @@ const simpleValueLookup = keys => ctx => {
|
|
|
1416
1299
|
* @param {string} key Context lookup key.
|
|
1417
1300
|
* @return {Result}
|
|
1418
1301
|
*/
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
1302
|
function complexValueLookup(ctx, key) {
|
|
1422
1303
|
const keys = extractComplexKeys(ctx, key);
|
|
1423
|
-
|
|
1424
1304
|
if (!keys) {
|
|
1425
1305
|
return undefined;
|
|
1426
1306
|
}
|
|
1427
|
-
|
|
1428
1307
|
return simpleValueLookup(keys !== null && keys !== void 0 ? keys : [])(ctx);
|
|
1429
1308
|
}
|
|
1430
|
-
|
|
1431
|
-
let DataType; // Equivalent to /^.+\.\((Number|String)\)$/
|
|
1432
|
-
|
|
1433
|
-
(function (DataType) {
|
|
1309
|
+
let DataType = /*#__PURE__*/function (DataType) {
|
|
1434
1310
|
DataType["Number"] = "Number";
|
|
1435
1311
|
DataType["String"] = "String";
|
|
1436
|
-
|
|
1312
|
+
return DataType;
|
|
1313
|
+
}({});
|
|
1437
1314
|
|
|
1315
|
+
// Equivalent to /^.+\.\((Number|String)\)$/
|
|
1438
1316
|
const dataTypeRegex = new RegExp(`^.+\\.\\((${Object.keys(DataType).join('|')})\\)$`);
|
|
1439
|
-
|
|
1440
1317
|
const isComplexKey = key => key.indexOf('{') > -1;
|
|
1318
|
+
|
|
1441
1319
|
/**
|
|
1442
1320
|
* Reference operand resolved within the context
|
|
1443
1321
|
*/
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
1322
|
class Reference extends Operand {
|
|
1447
1323
|
/**
|
|
1448
1324
|
* @constructor
|
|
@@ -1452,119 +1328,97 @@ class Reference extends Operand {
|
|
|
1452
1328
|
if (key.trim() === '') {
|
|
1453
1329
|
throw new Error('invalid reference key');
|
|
1454
1330
|
}
|
|
1455
|
-
|
|
1456
1331
|
super();
|
|
1457
|
-
|
|
1458
1332
|
_defineProperty(this, "key", void 0);
|
|
1459
|
-
|
|
1460
1333
|
_defineProperty(this, "dataType", void 0);
|
|
1461
|
-
|
|
1462
1334
|
_defineProperty(this, "valueLookup", void 0);
|
|
1463
|
-
|
|
1464
1335
|
_defineProperty(this, "getKeys", void 0);
|
|
1465
|
-
|
|
1466
1336
|
this.key = key;
|
|
1467
1337
|
const dataTypeMatch = dataTypeRegex.exec(this.key);
|
|
1468
|
-
|
|
1469
1338
|
if (dataTypeMatch) {
|
|
1470
1339
|
this.dataType = DataType[dataTypeMatch[1]];
|
|
1471
1340
|
}
|
|
1472
|
-
|
|
1473
1341
|
if (this.key.match(/.\(.+\)$/)) {
|
|
1474
1342
|
this.key = this.key.replace(/.\(.+\)$/, '');
|
|
1475
1343
|
}
|
|
1476
|
-
|
|
1477
1344
|
if (isComplexKey(this.key)) {
|
|
1478
1345
|
this.valueLookup = context => complexValueLookup(context, this.key);
|
|
1479
|
-
|
|
1480
1346
|
this.getKeys = context => extractComplexKeys(context, this.key);
|
|
1481
1347
|
} else {
|
|
1482
1348
|
const keys = parseKey(this.key);
|
|
1483
1349
|
this.valueLookup = simpleValueLookup(keys);
|
|
1484
|
-
|
|
1485
1350
|
this.getKeys = () => keys;
|
|
1486
1351
|
}
|
|
1487
1352
|
}
|
|
1353
|
+
|
|
1488
1354
|
/**
|
|
1489
1355
|
* Evaluate in the given context.
|
|
1490
1356
|
* @param {Context} ctx
|
|
1491
1357
|
* @return {boolean}
|
|
1492
1358
|
*/
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
1359
|
evaluate(ctx) {
|
|
1496
1360
|
return this.toDataType(this.valueLookup(ctx));
|
|
1497
1361
|
}
|
|
1362
|
+
|
|
1498
1363
|
/**
|
|
1499
1364
|
* {@link Evaluable.simplify}
|
|
1500
1365
|
*/
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
1366
|
simplify(ctx, strictKeys, optionalKeys) {
|
|
1504
1367
|
var _this$getKeys;
|
|
1505
|
-
|
|
1506
1368
|
const [key] = (_this$getKeys = this.getKeys(ctx)) !== null && _this$getKeys !== void 0 ? _this$getKeys : [];
|
|
1507
|
-
|
|
1508
1369
|
if (ctx[key] !== undefined) {
|
|
1509
1370
|
return this.evaluate(ctx);
|
|
1510
1371
|
}
|
|
1511
|
-
|
|
1512
1372
|
if (!key || typeof key === 'number') {
|
|
1513
1373
|
return this;
|
|
1514
1374
|
}
|
|
1515
|
-
|
|
1516
1375
|
return strictKeys && strictKeys.includes(key) || optionalKeys && !optionalKeys.includes(key) ? undefined : this;
|
|
1517
1376
|
}
|
|
1377
|
+
|
|
1518
1378
|
/**
|
|
1519
1379
|
* {@link Evaluable.serialize}
|
|
1520
1380
|
*/
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
let {
|
|
1525
|
-
referenceSerialization
|
|
1526
|
-
} = _ref;
|
|
1381
|
+
serialize({
|
|
1382
|
+
referenceSerialization
|
|
1383
|
+
}) {
|
|
1527
1384
|
const key = this.dataType ? `${this.key}.(${this.dataType})` : this.key;
|
|
1528
1385
|
return referenceSerialization(key);
|
|
1529
1386
|
}
|
|
1387
|
+
|
|
1530
1388
|
/**
|
|
1531
1389
|
* Get the strict representation of the operand.
|
|
1532
1390
|
* @return {string}
|
|
1533
1391
|
*/
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
1392
|
toString() {
|
|
1537
1393
|
return `{${this.key}}`;
|
|
1538
1394
|
}
|
|
1395
|
+
|
|
1539
1396
|
/**
|
|
1540
1397
|
* Converts a value to a specified data type
|
|
1541
1398
|
* Silently returns original value if data type conversion has not been implemented.
|
|
1542
1399
|
* @param value value to cast as data type
|
|
1543
1400
|
*/
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
1401
|
toDataType(value) {
|
|
1547
1402
|
let result = value;
|
|
1548
|
-
|
|
1549
1403
|
switch (this.dataType) {
|
|
1550
1404
|
case DataType.Number:
|
|
1551
1405
|
result = toNumber(value);
|
|
1552
1406
|
break;
|
|
1553
|
-
|
|
1554
1407
|
case DataType.String:
|
|
1555
1408
|
result = toString(value);
|
|
1556
1409
|
break;
|
|
1557
1410
|
}
|
|
1558
|
-
|
|
1559
1411
|
if (value && result === undefined) {
|
|
1560
1412
|
console.warn(`Casting ${value} to ${this.dataType} resulted in ${result}`);
|
|
1561
1413
|
}
|
|
1562
|
-
|
|
1563
1414
|
return result;
|
|
1564
1415
|
}
|
|
1565
|
-
|
|
1566
1416
|
}
|
|
1567
1417
|
|
|
1418
|
+
// Option value whitelist
|
|
1419
|
+
|
|
1420
|
+
// Parser options
|
|
1421
|
+
|
|
1568
1422
|
/**
|
|
1569
1423
|
* Default reference predicate.
|
|
1570
1424
|
* The "$" symbol at the begging of the operand is used
|
|
@@ -1576,28 +1430,31 @@ class Reference extends Operand {
|
|
|
1576
1430
|
function defaultReferencePredicate(key) {
|
|
1577
1431
|
return isString(key) && key.startsWith('$');
|
|
1578
1432
|
}
|
|
1433
|
+
|
|
1579
1434
|
/**
|
|
1580
1435
|
* Default reference transform.
|
|
1581
1436
|
* It removes the "$" symbol at the begging of the operand name.
|
|
1582
1437
|
* @param {string} key
|
|
1583
1438
|
* @return {string}
|
|
1584
1439
|
*/
|
|
1585
|
-
|
|
1586
1440
|
function defaultReferenceTransform(key) {
|
|
1587
1441
|
return key.slice(1);
|
|
1588
1442
|
}
|
|
1589
1443
|
function defaultReferenceSerialization(key) {
|
|
1590
1444
|
return `$${key}`;
|
|
1591
|
-
}
|
|
1592
|
-
// Unique operator key <-> raw expression key
|
|
1445
|
+
}
|
|
1593
1446
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1447
|
+
// Default operator mapping
|
|
1448
|
+
// Unique operator key <-> raw expression key
|
|
1449
|
+
const defaultOperatorMapping = new Map([
|
|
1450
|
+
// Comparison
|
|
1451
|
+
[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'],
|
|
1452
|
+
// Logical
|
|
1596
1453
|
[OPERATOR$4, 'AND'], [OPERATOR$1, 'OR'], [OPERATOR$2, 'NOR'], [OPERATOR, 'XOR'], [OPERATOR$3, 'NOT']]);
|
|
1454
|
+
|
|
1597
1455
|
/**
|
|
1598
1456
|
* Default parser options
|
|
1599
1457
|
*/
|
|
1600
|
-
|
|
1601
1458
|
const defaultOptions = {
|
|
1602
1459
|
referencePredicate: defaultReferencePredicate,
|
|
1603
1460
|
referenceTransform: defaultReferenceTransform,
|
|
@@ -1605,6 +1462,8 @@ const defaultOptions = {
|
|
|
1605
1462
|
operatorMapping: defaultOperatorMapping
|
|
1606
1463
|
};
|
|
1607
1464
|
|
|
1465
|
+
// Input types
|
|
1466
|
+
|
|
1608
1467
|
/**
|
|
1609
1468
|
* Parser of raw expressions into Evaluable expression
|
|
1610
1469
|
*/
|
|
@@ -1615,12 +1474,11 @@ class Parser {
|
|
|
1615
1474
|
*/
|
|
1616
1475
|
constructor(options) {
|
|
1617
1476
|
_defineProperty(this, "opts", void 0);
|
|
1618
|
-
|
|
1619
1477
|
_defineProperty(this, "expectedOperators", void 0);
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
};
|
|
1623
|
-
|
|
1478
|
+
this.opts = {
|
|
1479
|
+
...defaultOptions
|
|
1480
|
+
};
|
|
1481
|
+
// Apply exclusive options overrides
|
|
1624
1482
|
if (options) {
|
|
1625
1483
|
for (const key of Object.keys(options)) {
|
|
1626
1484
|
if (key in this.opts) {
|
|
@@ -1628,55 +1486,47 @@ class Parser {
|
|
|
1628
1486
|
}
|
|
1629
1487
|
}
|
|
1630
1488
|
}
|
|
1631
|
-
|
|
1632
1489
|
this.expectedOperators = new Set(this.opts.operatorMapping.values());
|
|
1633
1490
|
}
|
|
1491
|
+
|
|
1634
1492
|
/**
|
|
1635
1493
|
* Parser options
|
|
1636
1494
|
* @type {Options}
|
|
1637
1495
|
*/
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
1496
|
get options() {
|
|
1641
1497
|
return this.opts;
|
|
1642
1498
|
}
|
|
1499
|
+
|
|
1643
1500
|
/**
|
|
1644
1501
|
* Parse raw expression into evaluable expression.
|
|
1645
1502
|
* @param {ExpressionInput} raw Raw expression.
|
|
1646
1503
|
* @return {Evaluable}
|
|
1647
1504
|
*/
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
1505
|
parse(raw) {
|
|
1651
1506
|
if (raw === undefined || raw === null || Array.isArray(raw) === false) {
|
|
1652
1507
|
throw new Error('invalid expression');
|
|
1653
1508
|
}
|
|
1654
|
-
|
|
1655
1509
|
if (raw.length === 0 || !this.expectedOperators.has(`${raw[0]}`)) {
|
|
1656
1510
|
throw new Error('invalid expression');
|
|
1657
1511
|
}
|
|
1658
|
-
|
|
1659
1512
|
return this.parseRawExp(raw);
|
|
1660
1513
|
}
|
|
1514
|
+
|
|
1661
1515
|
/**
|
|
1662
1516
|
* Parse raw expression based on the expression type.
|
|
1663
1517
|
* @param {Input} raw Raw expression.
|
|
1664
1518
|
* @return {Evaluable}
|
|
1665
1519
|
*/
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
1520
|
parseRawExp(raw) {
|
|
1669
|
-
var _this = this;
|
|
1670
|
-
|
|
1671
1521
|
// Value / Reference
|
|
1672
1522
|
if (!Array.isArray(raw)) {
|
|
1673
1523
|
return this.getOperand(raw);
|
|
1674
1524
|
}
|
|
1675
|
-
|
|
1676
1525
|
let expression;
|
|
1677
1526
|
let operandParser = this.getOperand;
|
|
1678
1527
|
const operator = raw[0];
|
|
1679
1528
|
const operands = raw.slice(1);
|
|
1529
|
+
|
|
1680
1530
|
/**
|
|
1681
1531
|
* Simplify the logical expression if possible.
|
|
1682
1532
|
* - AND, OR with one operand is collapsed, i.e. reduced to inner expression
|
|
@@ -1688,149 +1538,101 @@ class Parser {
|
|
|
1688
1538
|
* @param operands
|
|
1689
1539
|
* @param collapsible
|
|
1690
1540
|
*/
|
|
1691
|
-
|
|
1692
|
-
const logicalExpressionReducer = function (operands) {
|
|
1693
|
-
let collapsible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
1694
|
-
|
|
1541
|
+
const logicalExpressionReducer = (operands, collapsible = false) => {
|
|
1695
1542
|
if (operands.length === 0 || operands.filter(operand => operand.type === EvaluableType.Expression).length === 0) {
|
|
1696
|
-
return
|
|
1543
|
+
return this.getOperand(raw);
|
|
1697
1544
|
}
|
|
1698
|
-
|
|
1699
1545
|
return collapsible && operands.length === 1 ? operands[0] : undefined;
|
|
1700
1546
|
};
|
|
1701
|
-
|
|
1702
1547
|
switch (operator) {
|
|
1703
1548
|
/**
|
|
1704
1549
|
* Logical
|
|
1705
1550
|
*/
|
|
1706
1551
|
case this.opts.operatorMapping.get(OPERATOR$4):
|
|
1707
1552
|
expression = operands => logicalExpressionReducer(operands, true) || new And(operands);
|
|
1708
|
-
|
|
1709
1553
|
operandParser = this.parseRawExp;
|
|
1710
1554
|
break;
|
|
1711
|
-
|
|
1712
1555
|
case this.opts.operatorMapping.get(OPERATOR$1):
|
|
1713
1556
|
expression = operands => logicalExpressionReducer(operands, true) || new Or(operands);
|
|
1714
|
-
|
|
1715
1557
|
operandParser = this.parseRawExp;
|
|
1716
1558
|
break;
|
|
1717
|
-
|
|
1718
1559
|
case this.opts.operatorMapping.get(OPERATOR$2):
|
|
1719
1560
|
expression = operands => logicalExpressionReducer(operands) || new Nor(operands);
|
|
1720
|
-
|
|
1721
1561
|
operandParser = this.parseRawExp;
|
|
1722
1562
|
break;
|
|
1723
|
-
|
|
1724
1563
|
case this.opts.operatorMapping.get(OPERATOR):
|
|
1725
1564
|
expression = operands => logicalExpressionReducer(operands) || new Xor(operands);
|
|
1726
|
-
|
|
1727
1565
|
operandParser = this.parseRawExp;
|
|
1728
1566
|
break;
|
|
1729
|
-
|
|
1730
1567
|
case this.opts.operatorMapping.get(OPERATOR$3):
|
|
1731
1568
|
expression = operands => logicalExpressionReducer(operands) || new Not(...operands);
|
|
1732
|
-
|
|
1733
1569
|
operandParser = this.parseRawExp;
|
|
1734
1570
|
break;
|
|
1735
|
-
|
|
1736
1571
|
/**
|
|
1737
1572
|
* Comparison
|
|
1738
1573
|
*/
|
|
1739
|
-
|
|
1740
1574
|
case this.opts.operatorMapping.get(OPERATOR$h):
|
|
1741
1575
|
expression = operands => new Equal(...operands);
|
|
1742
|
-
|
|
1743
1576
|
break;
|
|
1744
|
-
|
|
1745
1577
|
case this.opts.operatorMapping.get(OPERATOR$b):
|
|
1746
1578
|
expression = operands => new NotEqual(...operands);
|
|
1747
|
-
|
|
1748
1579
|
break;
|
|
1749
|
-
|
|
1750
1580
|
case this.opts.operatorMapping.get(OPERATOR$f):
|
|
1751
1581
|
expression = operands => new GreaterThan(...operands);
|
|
1752
|
-
|
|
1753
1582
|
break;
|
|
1754
|
-
|
|
1755
1583
|
case this.opts.operatorMapping.get(OPERATOR$g):
|
|
1756
1584
|
expression = operands => new GreaterThanOrEqual(...operands);
|
|
1757
|
-
|
|
1758
1585
|
break;
|
|
1759
|
-
|
|
1760
1586
|
case this.opts.operatorMapping.get(OPERATOR$c):
|
|
1761
1587
|
expression = operands => new LessThan(...operands);
|
|
1762
|
-
|
|
1763
1588
|
break;
|
|
1764
|
-
|
|
1765
1589
|
case this.opts.operatorMapping.get(OPERATOR$d):
|
|
1766
1590
|
expression = operands => new LessThanOrEqual(...operands);
|
|
1767
|
-
|
|
1768
1591
|
break;
|
|
1769
|
-
|
|
1770
1592
|
case this.opts.operatorMapping.get(OPERATOR$e):
|
|
1771
1593
|
expression = operands => new In(...operands);
|
|
1772
|
-
|
|
1773
1594
|
break;
|
|
1774
|
-
|
|
1775
1595
|
case this.opts.operatorMapping.get(OPERATOR$a):
|
|
1776
1596
|
expression = operands => new NotIn(...operands);
|
|
1777
|
-
|
|
1778
1597
|
break;
|
|
1779
|
-
|
|
1780
1598
|
case this.opts.operatorMapping.get(OPERATOR$8):
|
|
1781
1599
|
expression = operands => new Prefix(...operands);
|
|
1782
|
-
|
|
1783
1600
|
break;
|
|
1784
|
-
|
|
1785
1601
|
case this.opts.operatorMapping.get(OPERATOR$6):
|
|
1786
1602
|
expression = operands => new Suffix(...operands);
|
|
1787
|
-
|
|
1788
1603
|
break;
|
|
1789
|
-
|
|
1790
1604
|
case this.opts.operatorMapping.get(OPERATOR$9):
|
|
1791
1605
|
expression = operands => new Overlap(...operands);
|
|
1792
|
-
|
|
1793
1606
|
break;
|
|
1794
|
-
|
|
1795
1607
|
case this.opts.operatorMapping.get(OPERATOR$5):
|
|
1796
1608
|
expression = operands => new Undefined(...operands);
|
|
1797
|
-
|
|
1798
1609
|
break;
|
|
1799
|
-
|
|
1800
1610
|
case this.opts.operatorMapping.get(OPERATOR$7):
|
|
1801
1611
|
expression = operands => new Present(...operands);
|
|
1802
|
-
|
|
1803
1612
|
break;
|
|
1804
1613
|
// Collection
|
|
1805
|
-
|
|
1806
1614
|
default:
|
|
1807
1615
|
return this.getOperand(raw);
|
|
1808
1616
|
}
|
|
1809
|
-
|
|
1810
1617
|
return expression(operands.map(operandParser.bind(this)));
|
|
1811
1618
|
}
|
|
1619
|
+
|
|
1812
1620
|
/**
|
|
1813
1621
|
* Get resolved operand
|
|
1814
1622
|
* @param raw Raw data
|
|
1815
1623
|
*/
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
1624
|
getOperand(raw) {
|
|
1819
1625
|
const resolve = raw => this.opts.referencePredicate(raw) ? new Reference(this.opts.referenceTransform(raw)) : new Value(raw);
|
|
1820
|
-
|
|
1821
1626
|
if (Array.isArray(raw)) {
|
|
1822
1627
|
return new Collection(raw.map(item => resolve(item)));
|
|
1823
1628
|
}
|
|
1824
|
-
|
|
1825
1629
|
return resolve(raw);
|
|
1826
1630
|
}
|
|
1827
|
-
|
|
1828
1631
|
}
|
|
1829
1632
|
|
|
1830
1633
|
/**
|
|
1831
1634
|
* Condition engine
|
|
1832
1635
|
*/
|
|
1833
|
-
|
|
1834
1636
|
class Engine {
|
|
1835
1637
|
/**
|
|
1836
1638
|
* @constructor
|
|
@@ -1838,40 +1640,37 @@ class Engine {
|
|
|
1838
1640
|
*/
|
|
1839
1641
|
constructor(options) {
|
|
1840
1642
|
_defineProperty(this, "parser", void 0);
|
|
1841
|
-
|
|
1842
1643
|
this.parser = new Parser(options);
|
|
1843
1644
|
}
|
|
1645
|
+
|
|
1844
1646
|
/**
|
|
1845
1647
|
* Evaluate the expression.
|
|
1846
1648
|
* @param {ExpressionInput} exp Raw expression.
|
|
1847
1649
|
* @param {Context} ctx Evaluation data context.
|
|
1848
1650
|
* @return {boolean}
|
|
1849
1651
|
*/
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
1652
|
evaluate(exp, ctx) {
|
|
1853
1653
|
return this.parse(exp).evaluate(ctx);
|
|
1854
1654
|
}
|
|
1655
|
+
|
|
1855
1656
|
/**
|
|
1856
1657
|
* Get expression statement
|
|
1857
1658
|
* @param {ExpressionInput} exp Raw expression.
|
|
1858
1659
|
* @return {string}
|
|
1859
1660
|
*/
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
1661
|
statement(exp) {
|
|
1863
1662
|
return this.parse(exp).toString();
|
|
1864
1663
|
}
|
|
1664
|
+
|
|
1865
1665
|
/**
|
|
1866
1666
|
* Parse expression.
|
|
1867
1667
|
* @param {ExpressionInput} exp Raw expression.
|
|
1868
1668
|
* @return {Evaluable}
|
|
1869
1669
|
*/
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
1670
|
parse(exp) {
|
|
1873
1671
|
return this.parser.parse(exp);
|
|
1874
1672
|
}
|
|
1673
|
+
|
|
1875
1674
|
/**
|
|
1876
1675
|
* Simplifies an expression with values in context.
|
|
1877
1676
|
*
|
|
@@ -1887,22 +1686,16 @@ class Engine {
|
|
|
1887
1686
|
* `optionalKeys` is considered to be present and thus will be evaluated
|
|
1888
1687
|
* @returns {Inpunt | boolean}
|
|
1889
1688
|
*/
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
1689
|
simplify(exp, context, strictKeys, optionalKeys) {
|
|
1893
1690
|
const result = this.parse(exp).simplify(context, strictKeys, optionalKeys);
|
|
1894
|
-
|
|
1895
1691
|
if (isEvaluable(result)) {
|
|
1896
1692
|
return result.serialize(this.parser.options);
|
|
1897
1693
|
}
|
|
1898
|
-
|
|
1899
1694
|
if (isBoolean(result)) {
|
|
1900
1695
|
return result;
|
|
1901
1696
|
}
|
|
1902
|
-
|
|
1903
1697
|
throw new Error('non expression or boolean result should be returned');
|
|
1904
1698
|
}
|
|
1905
|
-
|
|
1906
1699
|
}
|
|
1907
1700
|
|
|
1908
1701
|
exports.OPERATOR_AND = OPERATOR$4;
|
|
@@ -1923,6 +1716,6 @@ exports.OPERATOR_PRESENT = OPERATOR$7;
|
|
|
1923
1716
|
exports.OPERATOR_SUFFIX = OPERATOR$6;
|
|
1924
1717
|
exports.OPERATOR_UNDEFINED = OPERATOR$5;
|
|
1925
1718
|
exports.OPERATOR_XOR = OPERATOR;
|
|
1926
|
-
exports
|
|
1719
|
+
exports.default = Engine;
|
|
1927
1720
|
exports.defaultOptions = defaultOptions;
|
|
1928
1721
|
exports.isEvaluable = isEvaluable;
|