@fincity/kirun-js 2.8.6 → 2.10.0
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/runtime/expression/ExpressionArrayStringIndexing.ts +67 -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 +10 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +57 -57
- package/src/engine/function/system/GenerateEvent.ts +23 -21
- package/src/engine/function/system/If.ts +2 -3
- package/src/engine/function/system/Print.ts +2 -3
- package/src/engine/function/system/Wait.ts +2 -3
- package/src/engine/function/system/array/ArrayFunctionRepository.ts +7 -9
- package/src/engine/function/system/array/Join.ts +29 -28
- package/src/engine/function/system/context/Create.ts +20 -22
- package/src/engine/function/system/context/Get.ts +19 -19
- package/src/engine/function/system/context/SetFunction.ts +17 -14
- package/src/engine/function/system/date/DateFunctionRepository.ts +6 -8
- package/src/engine/function/system/date/EpochToTimestamp.ts +1 -1
- package/src/engine/function/system/date/GetNames.ts +1 -1
- package/src/engine/function/system/date/IsValidISODate.ts +4 -6
- package/src/engine/function/system/loop/Break.ts +7 -7
- package/src/engine/function/system/loop/CountLoop.ts +13 -14
- package/src/engine/function/system/loop/ForEachLoop.ts +18 -19
- package/src/engine/function/system/loop/RangeLoop.ts +68 -69
- package/src/engine/function/system/math/Add.ts +11 -9
- package/src/engine/function/system/math/GenericMathFunction.ts +13 -13
- package/src/engine/function/system/math/Hypotenuse.ts +2 -2
- package/src/engine/function/system/math/MathFunctionRepository.ts +107 -90
- package/src/engine/function/system/math/Maximum.ts +12 -11
- package/src/engine/function/system/math/Minimum.ts +12 -11
- package/src/engine/function/system/math/Random.ts +2 -2
- package/src/engine/function/system/object/AbstractObjectFunction.ts +1 -2
- package/src/engine/function/system/object/ObjectConvert.ts +26 -26
- package/src/engine/function/system/object/ObjectDeleteKey.ts +1 -2
- package/src/engine/function/system/object/ObjectFunctionRepository.ts +18 -14
- package/src/engine/function/system/string/Concatenate.ts +8 -7
- package/src/engine/function/system/string/Matches.ts +2 -2
- package/src/engine/function/system/string/Reverse.ts +2 -2
- package/src/engine/function/system/string/Split.ts +16 -15
- package/src/engine/function/system/string/StringFunctionRepository.ts +6 -8
- package/src/engine/function/system/string/ToString.ts +9 -8
- package/src/engine/repository/KIRunFunctionRepository.ts +47 -39
- package/src/engine/repository/KIRunSchemaRepository.ts +75 -70
- package/src/engine/runtime/expression/Expression.ts +15 -1
- package/src/engine/runtime/expression/ExpressionEvaluator.ts +36 -31
- package/src/engine/runtime/expression/Operation.ts +10 -4
- package/src/engine/runtime/expression/operators/binary/ArrayRangeOperator.ts +7 -0
- package/src/engine/runtime/expression/operators/binary/index.ts +1 -0
- package/src/engine/runtime/expression/tokenextractor/TokenValueExtractor.ts +33 -6
- package/src/engine/util/duplicate.ts +1 -1
- package/tsconfig.json +4 -2
|
@@ -19,51 +19,59 @@ import { Wait } from '../function/system/Wait';
|
|
|
19
19
|
import { HybridRepository } from '../HybridRepository';
|
|
20
20
|
import { Namespaces } from '../namespaces/Namespaces';
|
|
21
21
|
import mapEntry from '../util/mapEntry';
|
|
22
|
+
import { Repository } from '../Repository';
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
new Map([mapEntry(new Create()), mapEntry(new Get()), mapEntry(new SetFunction())]),
|
|
27
|
-
],
|
|
28
|
-
[
|
|
29
|
-
Namespaces.SYSTEM_LOOP,
|
|
30
|
-
new Map([
|
|
31
|
-
mapEntry(new RangeLoop()),
|
|
32
|
-
mapEntry(new CountLoop()),
|
|
33
|
-
mapEntry(new Break()),
|
|
34
|
-
mapEntry(new ForEachLoop()),
|
|
35
|
-
]),
|
|
36
|
-
],
|
|
37
|
-
[
|
|
38
|
-
Namespaces.SYSTEM,
|
|
39
|
-
new Map([
|
|
40
|
-
mapEntry(new If()),
|
|
41
|
-
mapEntry(new GenerateEvent()),
|
|
42
|
-
mapEntry(new Print()),
|
|
43
|
-
mapEntry(new Wait()),
|
|
44
|
-
mapEntry(new Join()),
|
|
45
|
-
]),
|
|
46
|
-
],
|
|
47
|
-
]);
|
|
24
|
+
class SystemFunctionRepository implements Repository<Function> {
|
|
25
|
+
private readonly map: Map<string, Map<string, Function>>;
|
|
26
|
+
private readonly filterableNames: string[];
|
|
48
27
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
28
|
+
public constructor() {
|
|
29
|
+
this.map = new Map([
|
|
30
|
+
[
|
|
31
|
+
Namespaces.SYSTEM_CTX,
|
|
32
|
+
new Map([mapEntry(new Create()), mapEntry(new Get()), mapEntry(new SetFunction())]),
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
Namespaces.SYSTEM_LOOP,
|
|
36
|
+
new Map([
|
|
37
|
+
mapEntry(new RangeLoop()),
|
|
38
|
+
mapEntry(new CountLoop()),
|
|
39
|
+
mapEntry(new Break()),
|
|
40
|
+
mapEntry(new ForEachLoop()),
|
|
41
|
+
]),
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
Namespaces.SYSTEM,
|
|
45
|
+
new Map([
|
|
46
|
+
mapEntry(new If()),
|
|
47
|
+
mapEntry(new GenerateEvent()),
|
|
48
|
+
mapEntry(new Print()),
|
|
49
|
+
mapEntry(new Wait()),
|
|
50
|
+
mapEntry(new Join()),
|
|
51
|
+
]),
|
|
52
|
+
],
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
this.filterableNames = Array.from(this.map.values())
|
|
56
|
+
.flatMap((e) => Array.from(e.values()))
|
|
57
|
+
.map((e) => e.getSignature().getFullName());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async find(namespace: string, name: string): Promise<Function | undefined> {
|
|
61
|
+
return this.map.get(namespace)?.get(name);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async filter(name: string): Promise<string[]> {
|
|
65
|
+
return Array.from(this.filterableNames).filter(
|
|
66
|
+
(e) => e.toLowerCase().indexOf(name.toLowerCase()) !== -1,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
52
70
|
|
|
53
71
|
export class KIRunFunctionRepository extends HybridRepository<Function> {
|
|
54
72
|
public constructor() {
|
|
55
73
|
super(
|
|
56
|
-
|
|
57
|
-
async find(namespace: string, name: string): Promise<Function | undefined> {
|
|
58
|
-
return map.get(namespace)?.get(name);
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
async filter(name: string): Promise<string[]> {
|
|
62
|
-
return Array.from(filterableNames).filter(
|
|
63
|
-
(e) => e.toLowerCase().indexOf(name.toLowerCase()) !== -1,
|
|
64
|
-
);
|
|
65
|
-
},
|
|
66
|
-
},
|
|
74
|
+
new SystemFunctionRepository(),
|
|
67
75
|
new MathFunctionRepository(),
|
|
68
76
|
new StringFunctionRepository(),
|
|
69
77
|
new ArrayFunctionRepository(),
|
|
@@ -4,86 +4,91 @@ import { Namespaces } from '../namespaces/Namespaces';
|
|
|
4
4
|
import { Repository } from '../Repository';
|
|
5
5
|
import { MapUtil } from '../util/MapUtil';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
[
|
|
10
|
-
['double', Schema.ofDouble('double').setNamespace(Namespaces.SYSTEM)],
|
|
11
|
-
['float', Schema.ofFloat('float').setNamespace(Namespaces.SYSTEM)],
|
|
12
|
-
['integer', Schema.ofInteger('integer').setNamespace(Namespaces.SYSTEM)],
|
|
13
|
-
['long', Schema.ofLong('long').setNamespace(Namespaces.SYSTEM)],
|
|
14
|
-
['number', Schema.ofNumber('number').setNamespace(Namespaces.SYSTEM)],
|
|
15
|
-
['string', Schema.ofString('string').setNamespace(Namespaces.SYSTEM)],
|
|
16
|
-
['Timestamp', Schema.ofString('Timestamp').setNamespace(Namespaces.DATE)],
|
|
17
|
-
[
|
|
18
|
-
'Timeunit',
|
|
19
|
-
Schema.ofString('Timeunit')
|
|
20
|
-
.setNamespace(Namespaces.DATE)
|
|
21
|
-
.setEnums([
|
|
22
|
-
'YEARS',
|
|
23
|
-
'QUARTERS',
|
|
24
|
-
'MONTHS',
|
|
25
|
-
'WEEKS',
|
|
26
|
-
'DAYS',
|
|
27
|
-
'HOURS',
|
|
28
|
-
'MINUTES',
|
|
29
|
-
'SECONDS',
|
|
30
|
-
'MILLISECONDS',
|
|
31
|
-
]),
|
|
32
|
-
],
|
|
33
|
-
[
|
|
34
|
-
'Duration',
|
|
35
|
-
Schema.ofObject('Duration')
|
|
36
|
-
.setNamespace(Namespaces.DATE)
|
|
37
|
-
.setProperties(
|
|
38
|
-
MapUtil.ofArrayEntries(
|
|
39
|
-
['years', Schema.ofNumber('years')],
|
|
40
|
-
['quarters', Schema.ofNumber('quarters')],
|
|
41
|
-
['months', Schema.ofNumber('months')],
|
|
42
|
-
['weeks', Schema.ofNumber('weeks')],
|
|
43
|
-
['days', Schema.ofNumber('days')],
|
|
44
|
-
['hours', Schema.ofNumber('hours')],
|
|
45
|
-
['minutes', Schema.ofNumber('minutes')],
|
|
46
|
-
['seconds', Schema.ofNumber('seconds')],
|
|
47
|
-
['milliseconds', Schema.ofNumber('milliseconds')],
|
|
48
|
-
),
|
|
49
|
-
)
|
|
50
|
-
.setAdditionalItems(AdditionalType.from(false)!),
|
|
51
|
-
],
|
|
52
|
-
[
|
|
53
|
-
'TimeObject',
|
|
54
|
-
Schema.ofObject('TimeObject')
|
|
55
|
-
.setNamespace(Namespaces.DATE)
|
|
56
|
-
.setProperties(
|
|
57
|
-
MapUtil.ofArrayEntries(
|
|
58
|
-
['year', Schema.ofNumber('year')],
|
|
59
|
-
['month', Schema.ofNumber('month')],
|
|
60
|
-
['day', Schema.ofNumber('day')],
|
|
61
|
-
['hour', Schema.ofNumber('hour')],
|
|
62
|
-
['minute', Schema.ofNumber('minute')],
|
|
63
|
-
['second', Schema.ofNumber('second')],
|
|
64
|
-
['millisecond', Schema.ofNumber('millisecond')],
|
|
65
|
-
),
|
|
66
|
-
)
|
|
67
|
-
.setAdditionalItems(AdditionalType.from(false)!),
|
|
68
|
-
],
|
|
69
|
-
[Parameter.EXPRESSION.getName()!, Parameter.EXPRESSION],
|
|
70
|
-
[Schema.NULL.getName()!, Schema.NULL],
|
|
71
|
-
[Schema.SCHEMA.getName()!, Schema.SCHEMA],
|
|
72
|
-
]);
|
|
7
|
+
export class KIRunSchemaRepository implements Repository<Schema> {
|
|
8
|
+
private readonly map: Map<string, Schema>;
|
|
9
|
+
private readonly filterableNames: string[];
|
|
73
10
|
|
|
74
|
-
|
|
11
|
+
public constructor() {
|
|
12
|
+
this.map = new Map([
|
|
13
|
+
['any', Schema.ofAny('any').setNamespace(Namespaces.SYSTEM)],
|
|
14
|
+
['boolean', Schema.ofBoolean('boolean').setNamespace(Namespaces.SYSTEM)],
|
|
15
|
+
['double', Schema.ofDouble('double').setNamespace(Namespaces.SYSTEM)],
|
|
16
|
+
['float', Schema.ofFloat('float').setNamespace(Namespaces.SYSTEM)],
|
|
17
|
+
['integer', Schema.ofInteger('integer').setNamespace(Namespaces.SYSTEM)],
|
|
18
|
+
['long', Schema.ofLong('long').setNamespace(Namespaces.SYSTEM)],
|
|
19
|
+
['number', Schema.ofNumber('number').setNamespace(Namespaces.SYSTEM)],
|
|
20
|
+
['string', Schema.ofString('string').setNamespace(Namespaces.SYSTEM)],
|
|
21
|
+
['Timestamp', Schema.ofString('Timestamp').setNamespace(Namespaces.DATE)],
|
|
22
|
+
[
|
|
23
|
+
'Timeunit',
|
|
24
|
+
Schema.ofString('Timeunit')
|
|
25
|
+
.setNamespace(Namespaces.DATE)
|
|
26
|
+
.setEnums([
|
|
27
|
+
'YEARS',
|
|
28
|
+
'QUARTERS',
|
|
29
|
+
'MONTHS',
|
|
30
|
+
'WEEKS',
|
|
31
|
+
'DAYS',
|
|
32
|
+
'HOURS',
|
|
33
|
+
'MINUTES',
|
|
34
|
+
'SECONDS',
|
|
35
|
+
'MILLISECONDS',
|
|
36
|
+
]),
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
'Duration',
|
|
40
|
+
Schema.ofObject('Duration')
|
|
41
|
+
.setNamespace(Namespaces.DATE)
|
|
42
|
+
.setProperties(
|
|
43
|
+
MapUtil.ofArrayEntries(
|
|
44
|
+
['years', Schema.ofNumber('years')],
|
|
45
|
+
['quarters', Schema.ofNumber('quarters')],
|
|
46
|
+
['months', Schema.ofNumber('months')],
|
|
47
|
+
['weeks', Schema.ofNumber('weeks')],
|
|
48
|
+
['days', Schema.ofNumber('days')],
|
|
49
|
+
['hours', Schema.ofNumber('hours')],
|
|
50
|
+
['minutes', Schema.ofNumber('minutes')],
|
|
51
|
+
['seconds', Schema.ofNumber('seconds')],
|
|
52
|
+
['milliseconds', Schema.ofNumber('milliseconds')],
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
.setAdditionalItems(AdditionalType.from(false)!),
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
'TimeObject',
|
|
59
|
+
Schema.ofObject('TimeObject')
|
|
60
|
+
.setNamespace(Namespaces.DATE)
|
|
61
|
+
.setProperties(
|
|
62
|
+
MapUtil.ofArrayEntries(
|
|
63
|
+
['year', Schema.ofNumber('year')],
|
|
64
|
+
['month', Schema.ofNumber('month')],
|
|
65
|
+
['day', Schema.ofNumber('day')],
|
|
66
|
+
['hour', Schema.ofNumber('hour')],
|
|
67
|
+
['minute', Schema.ofNumber('minute')],
|
|
68
|
+
['second', Schema.ofNumber('second')],
|
|
69
|
+
['millisecond', Schema.ofNumber('millisecond')],
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
.setAdditionalItems(AdditionalType.from(false)!),
|
|
73
|
+
],
|
|
74
|
+
[Parameter.EXPRESSION.getName()!, Parameter.EXPRESSION],
|
|
75
|
+
[Schema.NULL.getName()!, Schema.NULL],
|
|
76
|
+
[Schema.SCHEMA.getName()!, Schema.SCHEMA],
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
this.filterableNames = Array.from(this.map.values()).map((e) => e.getFullName());
|
|
80
|
+
}
|
|
75
81
|
|
|
76
|
-
export class KIRunSchemaRepository implements Repository<Schema> {
|
|
77
82
|
public async find(namespace: string, name: string): Promise<Schema | undefined> {
|
|
78
83
|
if (Namespaces.SYSTEM != namespace && Namespaces.DATE != namespace)
|
|
79
84
|
return Promise.resolve(undefined);
|
|
80
85
|
|
|
81
|
-
return Promise.resolve(map.get(name));
|
|
86
|
+
return Promise.resolve(this.map.get(name));
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
public async filter(name: string): Promise<string[]> {
|
|
85
90
|
return Promise.resolve(
|
|
86
|
-
filterableNames.filter((e) => e.toLowerCase().indexOf(name.toLowerCase()) !== -1),
|
|
91
|
+
this.filterableNames.filter((e) => e.toLowerCase().indexOf(name.toLowerCase()) !== -1),
|
|
87
92
|
);
|
|
88
93
|
}
|
|
89
94
|
}
|
|
@@ -21,10 +21,21 @@ export class Expression extends ExpressionToken {
|
|
|
21
21
|
op?: Operation,
|
|
22
22
|
) {
|
|
23
23
|
super(expression ? expression : '');
|
|
24
|
+
if (op?.getOperator() == '..') {
|
|
25
|
+
if (!l) l = new ExpressionTokenValue('', '');
|
|
26
|
+
else if (!r) r = new ExpressionTokenValue('', '');
|
|
27
|
+
}
|
|
24
28
|
if (l) this.tokens.push(l);
|
|
25
29
|
if (r) this.tokens.push(r);
|
|
26
30
|
if (op) this.ops.push(op);
|
|
27
31
|
this.evaluate();
|
|
32
|
+
if (
|
|
33
|
+
!this.ops.isEmpty() &&
|
|
34
|
+
this.ops.peekLast().getOperator() == '..' &&
|
|
35
|
+
this.tokens.length == 1
|
|
36
|
+
) {
|
|
37
|
+
this.tokens.push(new ExpressionToken(''));
|
|
38
|
+
}
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
public getTokens(): LinkedList<ExpressionToken> {
|
|
@@ -198,6 +209,9 @@ export class Expression extends ExpressionToken {
|
|
|
198
209
|
if (!StringUtil.isNullOrBlank(buff)) {
|
|
199
210
|
this.tokens.push(new ExpressionToken(buff));
|
|
200
211
|
isPrevOp = false;
|
|
212
|
+
} else if (op == '..' && this.tokens.isEmpty()) {
|
|
213
|
+
this.tokens.push(new ExpressionToken('0'));
|
|
214
|
+
isPrevOp = false;
|
|
201
215
|
}
|
|
202
216
|
this.checkUnaryOperator(
|
|
203
217
|
this.tokens,
|
|
@@ -465,7 +479,7 @@ export class Expression extends ExpressionToken {
|
|
|
465
479
|
0,
|
|
466
480
|
temp instanceof Expression
|
|
467
481
|
? (temp as Expression).toString()
|
|
468
|
-
: temp
|
|
482
|
+
: temp?.toString(),
|
|
469
483
|
)
|
|
470
484
|
.insert(0, '(')
|
|
471
485
|
.append(')');
|
|
@@ -2,41 +2,45 @@ import { ExecutionException } from '../../exception/ExecutionException';
|
|
|
2
2
|
import { LinkedList } from '../../util/LinkedList';
|
|
3
3
|
import { StringBuilder } from '../../util/string/StringBuilder';
|
|
4
4
|
import { StringFormatter } from '../../util/string/StringFormatter';
|
|
5
|
-
import { FunctionExecutionParameters } from '../FunctionExecutionParameters';
|
|
6
5
|
import { ExpressionEvaluationException } from './exception/ExpressionEvaluationException';
|
|
7
6
|
import { Expression } from './Expression';
|
|
8
7
|
import { ExpressionToken } from './ExpressionToken';
|
|
9
8
|
import { ExpressionTokenValue } from './ExpressionTokenValue';
|
|
10
9
|
import { Operation } from './Operation';
|
|
11
|
-
import { LogicalNullishCoalescingOperator } from './operators/binary
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import {
|
|
39
|
-
|
|
10
|
+
import { LogicalNullishCoalescingOperator } from './operators/binary';
|
|
11
|
+
import {
|
|
12
|
+
ArithmeticAdditionOperator,
|
|
13
|
+
ArithmeticDivisionOperator,
|
|
14
|
+
ArithmeticIntegerDivisionOperator,
|
|
15
|
+
ArithmeticModulusOperator,
|
|
16
|
+
ArithmeticMultiplicationOperator,
|
|
17
|
+
ArithmeticSubtractionOperator,
|
|
18
|
+
ArrayOperator,
|
|
19
|
+
ArrayRangeOperator,
|
|
20
|
+
BinaryOperator,
|
|
21
|
+
BitwiseAndOperator,
|
|
22
|
+
BitwiseLeftShiftOperator,
|
|
23
|
+
BitwiseOrOperator,
|
|
24
|
+
BitwiseRightShiftOperator,
|
|
25
|
+
BitwiseUnsignedRightShiftOperator,
|
|
26
|
+
BitwiseXorOperator,
|
|
27
|
+
LogicalAndOperator,
|
|
28
|
+
LogicalEqualOperator,
|
|
29
|
+
LogicalGreaterThanEqualOperator,
|
|
30
|
+
LogicalGreaterThanOperator,
|
|
31
|
+
LogicalLessThanEqualOperator,
|
|
32
|
+
LogicalLessThanOperator,
|
|
33
|
+
LogicalNotEqualOperator,
|
|
34
|
+
LogicalOrOperator,
|
|
35
|
+
ObjectOperator,
|
|
36
|
+
} from './operators/binary/';
|
|
37
|
+
import {
|
|
38
|
+
ArithmeticUnaryMinusOperator,
|
|
39
|
+
ArithmeticUnaryPlusOperator,
|
|
40
|
+
BitwiseComplementOperator,
|
|
41
|
+
LogicalNotOperator,
|
|
42
|
+
UnaryOperator,
|
|
43
|
+
} from './operators/unary';
|
|
40
44
|
import { LiteralTokenValueExtractor } from './tokenextractor/LiteralTokenValueExtractor';
|
|
41
45
|
import { TokenValueExtractor } from './tokenextractor/TokenValueExtractor';
|
|
42
46
|
import { Tuple2 } from '../../util/Tuples';
|
|
@@ -82,6 +86,7 @@ export class ExpressionEvaluator {
|
|
|
82
86
|
[Operation.NULLISH_COALESCING_OPERATOR, new LogicalNullishCoalescingOperator()],
|
|
83
87
|
|
|
84
88
|
[Operation.ARRAY_OPERATOR, new ArrayOperator()],
|
|
89
|
+
[Operation.ARRAY_RANGE_INDEX_OPERATOR, new ArrayRangeOperator()],
|
|
85
90
|
[Operation.OBJECT_OPERATOR, new ObjectOperator()],
|
|
86
91
|
]);
|
|
87
92
|
|
|
@@ -315,7 +320,7 @@ export class ExpressionEvaluator {
|
|
|
315
320
|
if (key.length > 2 && valuesMap.has(key))
|
|
316
321
|
tokens.push(new ExpressionTokenValue(str, this.getValue(str, valuesMap)));
|
|
317
322
|
else {
|
|
318
|
-
let v: any
|
|
323
|
+
let v: any;
|
|
319
324
|
try {
|
|
320
325
|
v = LiteralTokenValueExtractor.INSTANCE.getValue(str);
|
|
321
326
|
} catch (err) {
|
|
@@ -30,6 +30,7 @@ export class Operation {
|
|
|
30
30
|
public static readonly UNARY_BITWISE_COMPLEMENT: Operation = new Operation('UN: ~', '~');
|
|
31
31
|
|
|
32
32
|
public static readonly ARRAY_OPERATOR: Operation = new Operation('[');
|
|
33
|
+
public static readonly ARRAY_RANGE_INDEX_OPERATOR: Operation = new Operation('..');
|
|
33
34
|
public static readonly OBJECT_OPERATOR: Operation = new Operation('.');
|
|
34
35
|
|
|
35
36
|
public static readonly NULLISH_COALESCING_OPERATOR: Operation = new Operation('??');
|
|
@@ -39,7 +40,7 @@ export class Operation {
|
|
|
39
40
|
private static readonly VALUE_OF: Map<string, Operation> = new Map([
|
|
40
41
|
['MULTIPLICATION', Operation.MULTIPLICATION],
|
|
41
42
|
['DIVISION', Operation.DIVISION],
|
|
42
|
-
['
|
|
43
|
+
['INTEGER_DIVISION', Operation.INTEGER_DIVISION],
|
|
43
44
|
['MOD', Operation.MOD],
|
|
44
45
|
['ADDITION', Operation.ADDITION],
|
|
45
46
|
['SUBTRACTION', Operation.SUBTRACTION],
|
|
@@ -64,6 +65,7 @@ export class Operation {
|
|
|
64
65
|
['UNARY_LOGICAL_NOT', Operation.UNARY_LOGICAL_NOT],
|
|
65
66
|
['UNARY_BITWISE_COMPLEMENT', Operation.UNARY_BITWISE_COMPLEMENT],
|
|
66
67
|
['ARRAY_OPERATOR', Operation.ARRAY_OPERATOR],
|
|
68
|
+
['ARRAY_RANGE_INDEX_OPERATOR', Operation.ARRAY_RANGE_INDEX_OPERATOR],
|
|
67
69
|
['OBJECT_OPERATOR', Operation.OBJECT_OPERATOR],
|
|
68
70
|
['NULLISH_COALESCING_OPERATOR', Operation.NULLISH_COALESCING_OPERATOR],
|
|
69
71
|
['CONDITIONAL_TERNARY_OPERATOR', Operation.CONDITIONAL_TERNARY_OPERATOR],
|
|
@@ -123,6 +125,7 @@ export class Operation {
|
|
|
123
125
|
[Operation.UNARY_BITWISE_COMPLEMENT, 1],
|
|
124
126
|
[Operation.ARRAY_OPERATOR, 1],
|
|
125
127
|
[Operation.OBJECT_OPERATOR, 1],
|
|
128
|
+
[Operation.ARRAY_RANGE_INDEX_OPERATOR, 2],
|
|
126
129
|
[Operation.MULTIPLICATION, 2],
|
|
127
130
|
[Operation.DIVISION, 2],
|
|
128
131
|
[Operation.INTEGER_DIVISION, 2],
|
|
@@ -153,6 +156,7 @@ export class Operation {
|
|
|
153
156
|
...Array.from(Operation.LOGICAL_OPERATORS),
|
|
154
157
|
...Array.from(Operation.BITWISE_OPERATORS),
|
|
155
158
|
Operation.ARRAY_OPERATOR,
|
|
159
|
+
Operation.ARRAY_RANGE_INDEX_OPERATOR,
|
|
156
160
|
Operation.OBJECT_OPERATOR,
|
|
157
161
|
...Array.from(Operation.CONDITIONAL_OPERATORS),
|
|
158
162
|
].map((e) => e.getOperator()),
|
|
@@ -164,6 +168,7 @@ export class Operation {
|
|
|
164
168
|
...Array.from(Operation.LOGICAL_OPERATORS),
|
|
165
169
|
...Array.from(Operation.BITWISE_OPERATORS),
|
|
166
170
|
Operation.ARRAY_OPERATOR,
|
|
171
|
+
Operation.ARRAY_RANGE_INDEX_OPERATOR,
|
|
167
172
|
Operation.OBJECT_OPERATOR,
|
|
168
173
|
...Array.from(Operation.CONDITIONAL_OPERATORS),
|
|
169
174
|
]
|
|
@@ -192,9 +197,10 @@ export class Operation {
|
|
|
192
197
|
.map((e) => e.length)
|
|
193
198
|
.reduce((a, c) => (a > c ? a : c), 0);
|
|
194
199
|
|
|
195
|
-
private operator: string;
|
|
196
|
-
private operatorName: string;
|
|
197
|
-
private _shouldBeWrappedInSpace: boolean;
|
|
200
|
+
private readonly operator: string;
|
|
201
|
+
private readonly operatorName: string;
|
|
202
|
+
private readonly _shouldBeWrappedInSpace: boolean;
|
|
203
|
+
|
|
198
204
|
public constructor(
|
|
199
205
|
operator: string,
|
|
200
206
|
operatorName?: string,
|
|
@@ -6,7 +6,7 @@ import { ExpressionEvaluationException } from '../exception/ExpressionEvaluation
|
|
|
6
6
|
|
|
7
7
|
export abstract class TokenValueExtractor {
|
|
8
8
|
public static readonly REGEX_SQUARE_BRACKETS: RegExp = /[\[\]]/;
|
|
9
|
-
public static readonly REGEX_DOT: RegExp =
|
|
9
|
+
public static readonly REGEX_DOT: RegExp = /(?<!\.)\.(?!\.)/;
|
|
10
10
|
|
|
11
11
|
public getValue(token: string): any {
|
|
12
12
|
let prefix: string = this.getPrefix();
|
|
@@ -71,7 +71,8 @@ export abstract class TokenValueExtractor {
|
|
|
71
71
|
|
|
72
72
|
if (cPart === 'length') return this.getLength(token, cElement);
|
|
73
73
|
|
|
74
|
-
if (Array.isArray(cElement))
|
|
74
|
+
if (typeof cElement == 'string' || Array.isArray(cElement))
|
|
75
|
+
return this.handleArrayAccess(token, cPart, cElement);
|
|
75
76
|
|
|
76
77
|
return this.handleObjectAccess(token, parts, partNumber, cPart, cElement);
|
|
77
78
|
}
|
|
@@ -91,8 +92,29 @@ export abstract class TokenValueExtractor {
|
|
|
91
92
|
);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
private handleArrayAccess(token: string, cPart: string, cArray: any[]): any {
|
|
95
|
-
const
|
|
95
|
+
private handleArrayAccess(token: string, cPart: string, cArray: any[] | string): any {
|
|
96
|
+
const dotDotIndex = cPart.indexOf('..');
|
|
97
|
+
if (dotDotIndex >= 0) {
|
|
98
|
+
const startIndex = cPart.substring(0, dotDotIndex);
|
|
99
|
+
const endIndex = cPart.substring(dotDotIndex + 2);
|
|
100
|
+
|
|
101
|
+
let intStart = startIndex.length == 0 ? 0 : parseInt(startIndex);
|
|
102
|
+
let intEnd = endIndex.length == 0 ? cArray.length : parseInt(endIndex);
|
|
103
|
+
|
|
104
|
+
if (isNaN(intStart) || isNaN(intEnd)) return undefined;
|
|
105
|
+
|
|
106
|
+
while (intStart < 0) intStart += cArray.length;
|
|
107
|
+
while (intEnd < 0) intEnd += cArray.length;
|
|
108
|
+
|
|
109
|
+
const cArrayType = typeof cArray;
|
|
110
|
+
if (intStart >= intEnd) return cArrayType == 'string' ? '' : [];
|
|
111
|
+
|
|
112
|
+
return cArrayType == 'string'
|
|
113
|
+
? (cArray as string).substring(intStart, intEnd)
|
|
114
|
+
: cArray.slice(intStart, intEnd);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let index: number = parseInt(cPart);
|
|
96
118
|
|
|
97
119
|
if (isNaN(index)) {
|
|
98
120
|
throw new ExpressionEvaluationException(
|
|
@@ -101,7 +123,8 @@ export abstract class TokenValueExtractor {
|
|
|
101
123
|
);
|
|
102
124
|
}
|
|
103
125
|
|
|
104
|
-
|
|
126
|
+
while (index < 0) index = cArray.length + index;
|
|
127
|
+
if (index >= cArray.length) {
|
|
105
128
|
return undefined;
|
|
106
129
|
}
|
|
107
130
|
|
|
@@ -137,7 +160,11 @@ export abstract class TokenValueExtractor {
|
|
|
137
160
|
partNumber: number,
|
|
138
161
|
jsonElement: any,
|
|
139
162
|
): void {
|
|
140
|
-
|
|
163
|
+
const jsonElementType = typeof jsonElement;
|
|
164
|
+
if (
|
|
165
|
+
(jsonElementType != 'object' && jsonElementType != 'string') ||
|
|
166
|
+
Array.isArray(jsonElement)
|
|
167
|
+
)
|
|
141
168
|
throw new ExpressionEvaluationException(
|
|
142
169
|
token,
|
|
143
170
|
StringFormatter.format(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function duplicate(obj: any): any {
|
|
2
2
|
if (!obj) return obj;
|
|
3
|
-
if (globalThis.structuredClone) return globalThis.structuredClone(obj);
|
|
3
|
+
if (typeof globalThis.structuredClone === 'function') return globalThis.structuredClone(obj);
|
|
4
4
|
return JSON.parse(JSON.stringify(obj));
|
|
5
5
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"module": "
|
|
3
|
+
"module": "ESNext",
|
|
4
|
+
"target": "ESNext",
|
|
4
5
|
"strict": true,
|
|
5
6
|
"esModuleInterop": true,
|
|
6
7
|
"skipLibCheck": true,
|
|
7
8
|
"forceConsistentCasingInFileNames": true,
|
|
8
|
-
"lib": ["ES2022"]
|
|
9
|
+
"lib": ["ES2022"],
|
|
10
|
+
"moduleResolution": "node"
|
|
9
11
|
}
|
|
10
12
|
}
|