@fincity/kirun-js 1.1.7 → 1.3.1
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/__tests__/engine/function/system/math/RandomIntTest.ts +0 -1
- package/__tests__/engine/runtime/KIRuntimeTest.ts +75 -26
- package/__tests__/engine/runtime/KIRuntimeWithDefinitionTest.ts +10 -9
- package/__tests__/engine/runtime/expression/ExpressionEvaluationTest.ts +82 -1
- package/__tests__/engine/util/deepEqualTest.ts +13 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +28 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/engine/model/ParameterReference.ts +27 -9
- package/src/engine/model/Statement.ts +25 -13
- package/src/engine/runtime/KIRuntime.ts +4 -4
- package/src/engine/runtime/expression/ExpressionEvaluator.ts +82 -8
- package/src/engine/runtime/expression/Operation.ts +5 -0
- package/src/engine/runtime/expression/operators/binary/LogicalEqualOperator.ts +2 -7
- package/src/engine/runtime/expression/operators/binary/LogicalNotEqualOperator.ts +2 -7
- package/src/engine/runtime/expression/operators/binary/LogicalNullishCoalescingOperator.ts +8 -0
- package/src/engine/runtime/expression/operators/binary/index.ts +1 -0
- package/src/engine/util/MapUtil.ts +10 -0
- package/src/engine/util/Tuples.ts +49 -4
- package/src/engine/util/deepEqual.ts +49 -0
- package/src/index.ts +1 -0
|
@@ -8,6 +8,7 @@ import { Expression } from './Expression';
|
|
|
8
8
|
import { ExpressionToken } from './ExpressionToken';
|
|
9
9
|
import { ExpressionTokenValue } from './ExpressionTokenValue';
|
|
10
10
|
import { Operation } from './Operation';
|
|
11
|
+
import { LogicalNullishCoalescingOperator } from './operators/binary/LogicalNullishCoalescingOperator';
|
|
11
12
|
import { ArithmeticAdditionOperator } from './operators/binary/ArithmeticAdditionOperator';
|
|
12
13
|
import { ArithmeticDivisionOperator } from './operators/binary/ArithmeticDivisionOperator';
|
|
13
14
|
import { ArithmeticIntegerDivisionOperator } from './operators/binary/ArithmeticInetgerDivisionOperator';
|
|
@@ -38,6 +39,7 @@ import { LogicalNotOperator } from './operators/unary/LogicalNotOperator';
|
|
|
38
39
|
import { UnaryOperator } from './operators/unary/UnaryOperator';
|
|
39
40
|
import { LiteralTokenValueExtractor } from './tokenextractor/LiteralTokenValueExtractor';
|
|
40
41
|
import { TokenValueExtractor } from './tokenextractor/TokenValueExtractor';
|
|
42
|
+
import { Tuple2 } from '../../util/Tuples';
|
|
41
43
|
|
|
42
44
|
export class ExpressionEvaluator {
|
|
43
45
|
private static readonly UNARY_OPERATORS_MAP: Map<Operation, UnaryOperator> = new Map([
|
|
@@ -70,6 +72,7 @@ export class ExpressionEvaluator {
|
|
|
70
72
|
[Operation.LESS_THAN_EQUAL, new LogicalLessThanEqualOperator()],
|
|
71
73
|
[Operation.OR, new LogicalOrOperator()],
|
|
72
74
|
[Operation.NOT_EQUAL, new LogicalNotEqualOperator()],
|
|
75
|
+
[Operation.NULLISH_COALESCING_OPERATOR, new LogicalNullishCoalescingOperator()],
|
|
73
76
|
|
|
74
77
|
[Operation.ARRAY_OPERATOR, new ArrayOperator()],
|
|
75
78
|
[Operation.OBJECT_OPERATOR, new ObjectOperator()],
|
|
@@ -92,10 +95,79 @@ export class ExpressionEvaluator {
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
public evaluate(valuesMap: Map<string, TokenValueExtractor>): any {
|
|
95
|
-
|
|
98
|
+
const tuple: Tuple2<string, Expression> = this.processNestingExpression(
|
|
99
|
+
this.expression,
|
|
100
|
+
valuesMap,
|
|
101
|
+
);
|
|
102
|
+
this.expression = tuple.getT1();
|
|
103
|
+
this.exp = tuple.getT2();
|
|
104
|
+
|
|
96
105
|
return this.evaluateExpression(this.exp, valuesMap);
|
|
97
106
|
}
|
|
98
107
|
|
|
108
|
+
private processNestingExpression(
|
|
109
|
+
expression: string,
|
|
110
|
+
valuesMap: Map<string, TokenValueExtractor>,
|
|
111
|
+
): Tuple2<string, Expression> {
|
|
112
|
+
let start = 0;
|
|
113
|
+
let i = 0;
|
|
114
|
+
|
|
115
|
+
const tuples: LinkedList<Tuple2<number, number>> = new LinkedList();
|
|
116
|
+
|
|
117
|
+
while (i < expression.length - 1) {
|
|
118
|
+
if (expression.charAt(i) == '{' && expression.charAt(i + 1) == '{') {
|
|
119
|
+
if (start == 0) tuples.push(new Tuple2(i + 2, -1));
|
|
120
|
+
|
|
121
|
+
start++;
|
|
122
|
+
i++;
|
|
123
|
+
} else if (expression.charAt(i) == '}' && expression.charAt(i + 1) == '}') {
|
|
124
|
+
start--;
|
|
125
|
+
|
|
126
|
+
if (start < 0)
|
|
127
|
+
throw new ExpressionEvaluationException(
|
|
128
|
+
expression,
|
|
129
|
+
'Expecting {{ nesting path operator to be started before closing',
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (start == 0) {
|
|
133
|
+
tuples.push(tuples.pop().setT2(i));
|
|
134
|
+
}
|
|
135
|
+
i++;
|
|
136
|
+
}
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let newExpression = this.replaceNestingExpression(expression, valuesMap, tuples);
|
|
141
|
+
|
|
142
|
+
return new Tuple2(newExpression, new Expression(newExpression));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private replaceNestingExpression(
|
|
146
|
+
expression: string,
|
|
147
|
+
valuesMap: Map<string, TokenValueExtractor>,
|
|
148
|
+
tuples: LinkedList<Tuple2<number, number>>,
|
|
149
|
+
): string {
|
|
150
|
+
let newExpression = expression;
|
|
151
|
+
|
|
152
|
+
for (var tuple of tuples.toArray()) {
|
|
153
|
+
if (tuple.getT2() == -1)
|
|
154
|
+
throw new ExpressionEvaluationException(
|
|
155
|
+
expression,
|
|
156
|
+
'Expecting }} nesting path operator to be closed',
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
let expStr: string = new ExpressionEvaluator(
|
|
160
|
+
newExpression.substring(tuple.getT1(), tuple.getT2()),
|
|
161
|
+
).evaluate(valuesMap);
|
|
162
|
+
|
|
163
|
+
newExpression =
|
|
164
|
+
newExpression.substring(0, tuple.getT1() - 2) +
|
|
165
|
+
expStr +
|
|
166
|
+
newExpression.substring(tuple.getT2() + 2);
|
|
167
|
+
}
|
|
168
|
+
return newExpression;
|
|
169
|
+
}
|
|
170
|
+
|
|
99
171
|
public getExpression(): Expression {
|
|
100
172
|
if (!this.exp) this.exp = new Expression(this.expression);
|
|
101
173
|
|
|
@@ -161,8 +233,7 @@ export class ExpressionEvaluator {
|
|
|
161
233
|
const objTokens: LinkedList<ExpressionToken> = new LinkedList();
|
|
162
234
|
const objOperations: LinkedList<Operation> = new LinkedList();
|
|
163
235
|
|
|
164
|
-
if (!operator || !token)
|
|
165
|
-
return;
|
|
236
|
+
if (!operator || !token) return;
|
|
166
237
|
|
|
167
238
|
do {
|
|
168
239
|
objOperations.push(operator);
|
|
@@ -173,8 +244,7 @@ export class ExpressionEvaluator {
|
|
|
173
244
|
this.evaluateExpression(token as Expression, valuesMap),
|
|
174
245
|
),
|
|
175
246
|
);
|
|
176
|
-
else if (token)
|
|
177
|
-
objTokens.push(token);
|
|
247
|
+
else if (token) objTokens.push(token);
|
|
178
248
|
token = tokens.isEmpty() ? undefined : tokens.pop();
|
|
179
249
|
operator = ops.isEmpty() ? undefined : ops.pop();
|
|
180
250
|
} while (operator == Operation.OBJECT_OPERATOR || operator == Operation.ARRAY_OPERATOR);
|
|
@@ -229,7 +299,13 @@ export class ExpressionEvaluator {
|
|
|
229
299
|
let typv1: string = typeof v1;
|
|
230
300
|
let typv2: string = typeof v2;
|
|
231
301
|
|
|
232
|
-
|
|
302
|
+
let op: BinaryOperator | undefined = ExpressionEvaluator.BINARY_OPERATORS_MAP.get(operator);
|
|
303
|
+
|
|
304
|
+
if (
|
|
305
|
+
(typv1 === 'object' || typv2 === 'object') &&
|
|
306
|
+
operator !== Operation.EQUAL &&
|
|
307
|
+
operator !== Operation.NOT_EQUAL
|
|
308
|
+
)
|
|
233
309
|
throw new ExpressionEvaluationException(
|
|
234
310
|
this.expression,
|
|
235
311
|
StringFormatter.format(
|
|
@@ -240,8 +316,6 @@ export class ExpressionEvaluator {
|
|
|
240
316
|
),
|
|
241
317
|
);
|
|
242
318
|
|
|
243
|
-
let op: BinaryOperator | undefined = ExpressionEvaluator.BINARY_OPERATORS_MAP.get(operator);
|
|
244
|
-
|
|
245
319
|
if (!op)
|
|
246
320
|
throw new ExpressionEvaluationException(
|
|
247
321
|
this.expression,
|
|
@@ -32,6 +32,8 @@ export class Operation {
|
|
|
32
32
|
public static readonly ARRAY_OPERATOR: Operation = new Operation('[');
|
|
33
33
|
public static readonly OBJECT_OPERATOR: Operation = new Operation('.');
|
|
34
34
|
|
|
35
|
+
public static readonly NULLISH_COALESCING_OPERATOR: Operation = new Operation('??');
|
|
36
|
+
|
|
35
37
|
private static readonly VALUE_OF: Map<string, Operation> = new Map([
|
|
36
38
|
['MULTIPLICATION', Operation.MULTIPLICATION],
|
|
37
39
|
['DIVISION', Operation.DIVISION],
|
|
@@ -61,6 +63,7 @@ export class Operation {
|
|
|
61
63
|
['UNARY_BITWISE_COMPLEMENT', Operation.UNARY_BITWISE_COMPLEMENT],
|
|
62
64
|
['ARRAY_OPERATOR', Operation.ARRAY_OPERATOR],
|
|
63
65
|
['OBJECT_OPERATOR', Operation.OBJECT_OPERATOR],
|
|
66
|
+
['NULLISH_COALESCING_OPERATOR', Operation.NULLISH_COALESCING_OPERATOR],
|
|
64
67
|
]);
|
|
65
68
|
|
|
66
69
|
public static readonly UNARY_OPERATORS: Set<Operation> = new Set([
|
|
@@ -93,6 +96,7 @@ export class Operation {
|
|
|
93
96
|
Operation.GREATER_THAN_EQUAL,
|
|
94
97
|
Operation.EQUAL,
|
|
95
98
|
Operation.NOT_EQUAL,
|
|
99
|
+
Operation.NULLISH_COALESCING_OPERATOR,
|
|
96
100
|
]);
|
|
97
101
|
|
|
98
102
|
public static readonly BITWISE_OPERATORS: Set<Operation> = new Set([
|
|
@@ -132,6 +136,7 @@ export class Operation {
|
|
|
132
136
|
[Operation.BITWISE_OR, 9],
|
|
133
137
|
[Operation.AND, 10],
|
|
134
138
|
[Operation.OR, 11],
|
|
139
|
+
[Operation.NULLISH_COALESCING_OPERATOR, 11],
|
|
135
140
|
]);
|
|
136
141
|
|
|
137
142
|
public static readonly OPERATORS: Set<string> = new Set(
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PrimitiveUtil } from '../../../../util/primitive/PrimitiveUtil';
|
|
3
|
-
import { Tuple2 } from '../../../../util/Tuples';
|
|
1
|
+
import { deepEqual } from '../../../../util/deepEqual';
|
|
4
2
|
import { BinaryOperator } from './BinaryOperator';
|
|
5
3
|
|
|
6
4
|
export class LogicalEqualOperator extends BinaryOperator {
|
|
7
5
|
public apply(t: any, u: any): any {
|
|
8
|
-
|
|
9
|
-
const uType: Tuple2<SchemaType, any> = PrimitiveUtil.findPrimitiveNullAsBoolean(u);
|
|
10
|
-
|
|
11
|
-
return tType.getT2() == uType.getT2();
|
|
6
|
+
return deepEqual(t, u);
|
|
12
7
|
}
|
|
13
8
|
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PrimitiveUtil } from '../../../../util/primitive/PrimitiveUtil';
|
|
3
|
-
import { Tuple2 } from '../../../../util/Tuples';
|
|
1
|
+
import { deepEqual } from '../../../../util/deepEqual';
|
|
4
2
|
import { BinaryOperator } from './BinaryOperator';
|
|
5
3
|
|
|
6
4
|
export class LogicalNotEqualOperator extends BinaryOperator {
|
|
7
5
|
public apply(t: any, u: any): any {
|
|
8
|
-
|
|
9
|
-
const uType: Tuple2<SchemaType, any> = PrimitiveUtil.findPrimitiveNullAsBoolean(u);
|
|
10
|
-
|
|
11
|
-
return tType.getT2() != uType.getT2();
|
|
6
|
+
return !deepEqual(t, u);
|
|
12
7
|
}
|
|
13
8
|
}
|
|
@@ -72,6 +72,16 @@ export class MapUtil {
|
|
|
72
72
|
return map;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
public static ofEntriesArray<K, V>(...entry: [K, V][]): Map<K, V> {
|
|
76
|
+
const map: Map<K, V> = new Map();
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < entry.length; i++) {
|
|
79
|
+
map.set(entry[i][0], entry[i][1]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return map;
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
private constructor() {}
|
|
76
86
|
}
|
|
77
87
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export class Tuple2<F, S> {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
protected f: F;
|
|
3
|
+
protected s: S;
|
|
4
4
|
|
|
5
5
|
constructor(f: F, s: S) {
|
|
6
6
|
this.f = f;
|
|
@@ -14,10 +14,20 @@ export class Tuple2<F, S> {
|
|
|
14
14
|
public getT2(): S {
|
|
15
15
|
return this.s;
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
public setT1(f: F): Tuple2<F, S> {
|
|
19
|
+
this.f = f;
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public setT2(s: S): Tuple2<F, S> {
|
|
24
|
+
this.s = s;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
17
27
|
}
|
|
18
28
|
|
|
19
29
|
export class Tuple3<F, S, T> extends Tuple2<F, S> {
|
|
20
|
-
|
|
30
|
+
protected t: T;
|
|
21
31
|
|
|
22
32
|
constructor(f: F, s: S, t: T) {
|
|
23
33
|
super(f, s);
|
|
@@ -27,10 +37,25 @@ export class Tuple3<F, S, T> extends Tuple2<F, S> {
|
|
|
27
37
|
public getT3(): T {
|
|
28
38
|
return this.t;
|
|
29
39
|
}
|
|
40
|
+
|
|
41
|
+
public setT1(f: F): Tuple3<F, S, T> {
|
|
42
|
+
this.f = f;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public setT2(s: S): Tuple3<F, S, T> {
|
|
47
|
+
this.s = s;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public setT3(t: T): Tuple3<F, S, T> {
|
|
52
|
+
this.t = t;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
30
55
|
}
|
|
31
56
|
|
|
32
57
|
export class Tuple4<F, S, T, FR> extends Tuple3<F, S, T> {
|
|
33
|
-
|
|
58
|
+
protected fr: FR;
|
|
34
59
|
|
|
35
60
|
constructor(f: F, s: S, t: T, fr: FR) {
|
|
36
61
|
super(f, s, t);
|
|
@@ -40,4 +65,24 @@ export class Tuple4<F, S, T, FR> extends Tuple3<F, S, T> {
|
|
|
40
65
|
public getT4(): FR {
|
|
41
66
|
return this.fr;
|
|
42
67
|
}
|
|
68
|
+
|
|
69
|
+
public setT1(f: F): Tuple4<F, S, T, FR> {
|
|
70
|
+
this.f = f;
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public setT2(s: S): Tuple4<F, S, T, FR> {
|
|
75
|
+
this.s = s;
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public setT3(t: T): Tuple4<F, S, T, FR> {
|
|
80
|
+
this.t = t;
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public setT4(fr: FR): Tuple4<F, S, T, FR> {
|
|
85
|
+
this.fr = fr;
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
43
88
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { LinkedList } from './LinkedList';
|
|
2
|
+
|
|
3
|
+
export function deepEqual(x: any, y: any) {
|
|
4
|
+
let xa = new LinkedList();
|
|
5
|
+
xa.push(x);
|
|
6
|
+
let yb = new LinkedList();
|
|
7
|
+
yb.push(y);
|
|
8
|
+
|
|
9
|
+
while (!xa.isEmpty() && !yb.isEmpty()) {
|
|
10
|
+
const a: any = xa.pop();
|
|
11
|
+
const b: any = yb.pop();
|
|
12
|
+
|
|
13
|
+
if (a === b) continue;
|
|
14
|
+
|
|
15
|
+
const typeOfA = typeof a;
|
|
16
|
+
const typeOfB = typeof b;
|
|
17
|
+
|
|
18
|
+
if (typeOfA === 'undefined' || typeOfB === 'undefined') {
|
|
19
|
+
if (!a && !b) continue;
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeOfA !== typeOfB) return false;
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(a)) {
|
|
26
|
+
if (!Array.isArray(b) || a.length != b.length) return false;
|
|
27
|
+
for (let i = 0; i < a.length; i++) {
|
|
28
|
+
xa.push(a[i]);
|
|
29
|
+
yb.push(b[i]);
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeOfA === 'object') {
|
|
35
|
+
const entriesOfA = Object.entries(a);
|
|
36
|
+
const entriesOfB = Object.entries(b);
|
|
37
|
+
if (entriesOfA.length !== entriesOfB.length) return false;
|
|
38
|
+
for (const [k, v] of entriesOfA) {
|
|
39
|
+
xa.push(v);
|
|
40
|
+
yb.push(b[k]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return true;
|
|
49
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './engine/util/string/StringFormatter';
|
|
|
10
10
|
export * from './engine/util/string/StringUtil';
|
|
11
11
|
export * from './engine/util/Tuples';
|
|
12
12
|
export * from './engine/util/ArrayUtil';
|
|
13
|
+
export * from './engine/util/deepEqual';
|
|
13
14
|
export * from './engine/runtime/StatementExecution';
|
|
14
15
|
export * from './engine/runtime/StatementMessage';
|
|
15
16
|
export * from './engine/runtime/ContextElement';
|