@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.
Files changed (52) hide show
  1. package/__tests__/engine/runtime/expression/ExpressionArrayStringIndexing.ts +67 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/module.js +1 -1
  5. package/dist/module.js.map +1 -1
  6. package/dist/types.d.ts +10 -5
  7. package/dist/types.d.ts.map +1 -1
  8. package/package.json +57 -57
  9. package/src/engine/function/system/GenerateEvent.ts +23 -21
  10. package/src/engine/function/system/If.ts +2 -3
  11. package/src/engine/function/system/Print.ts +2 -3
  12. package/src/engine/function/system/Wait.ts +2 -3
  13. package/src/engine/function/system/array/ArrayFunctionRepository.ts +7 -9
  14. package/src/engine/function/system/array/Join.ts +29 -28
  15. package/src/engine/function/system/context/Create.ts +20 -22
  16. package/src/engine/function/system/context/Get.ts +19 -19
  17. package/src/engine/function/system/context/SetFunction.ts +17 -14
  18. package/src/engine/function/system/date/DateFunctionRepository.ts +6 -8
  19. package/src/engine/function/system/date/EpochToTimestamp.ts +1 -1
  20. package/src/engine/function/system/date/GetNames.ts +1 -1
  21. package/src/engine/function/system/date/IsValidISODate.ts +4 -6
  22. package/src/engine/function/system/loop/Break.ts +7 -7
  23. package/src/engine/function/system/loop/CountLoop.ts +13 -14
  24. package/src/engine/function/system/loop/ForEachLoop.ts +18 -19
  25. package/src/engine/function/system/loop/RangeLoop.ts +68 -69
  26. package/src/engine/function/system/math/Add.ts +11 -9
  27. package/src/engine/function/system/math/GenericMathFunction.ts +13 -13
  28. package/src/engine/function/system/math/Hypotenuse.ts +2 -2
  29. package/src/engine/function/system/math/MathFunctionRepository.ts +107 -90
  30. package/src/engine/function/system/math/Maximum.ts +12 -11
  31. package/src/engine/function/system/math/Minimum.ts +12 -11
  32. package/src/engine/function/system/math/Random.ts +2 -2
  33. package/src/engine/function/system/object/AbstractObjectFunction.ts +1 -2
  34. package/src/engine/function/system/object/ObjectConvert.ts +26 -26
  35. package/src/engine/function/system/object/ObjectDeleteKey.ts +1 -2
  36. package/src/engine/function/system/object/ObjectFunctionRepository.ts +18 -14
  37. package/src/engine/function/system/string/Concatenate.ts +8 -7
  38. package/src/engine/function/system/string/Matches.ts +2 -2
  39. package/src/engine/function/system/string/Reverse.ts +2 -2
  40. package/src/engine/function/system/string/Split.ts +16 -15
  41. package/src/engine/function/system/string/StringFunctionRepository.ts +6 -8
  42. package/src/engine/function/system/string/ToString.ts +9 -8
  43. package/src/engine/repository/KIRunFunctionRepository.ts +47 -39
  44. package/src/engine/repository/KIRunSchemaRepository.ts +75 -70
  45. package/src/engine/runtime/expression/Expression.ts +15 -1
  46. package/src/engine/runtime/expression/ExpressionEvaluator.ts +36 -31
  47. package/src/engine/runtime/expression/Operation.ts +10 -4
  48. package/src/engine/runtime/expression/operators/binary/ArrayRangeOperator.ts +7 -0
  49. package/src/engine/runtime/expression/operators/binary/index.ts +1 -0
  50. package/src/engine/runtime/expression/tokenextractor/TokenValueExtractor.ts +33 -6
  51. package/src/engine/util/duplicate.ts +1 -1
  52. 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
- const map: Map<string, Map<string, Function>> = new Map([
24
- [
25
- Namespaces.SYSTEM_CTX,
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
- const filterableNames = Array.from(map.values())
50
- .flatMap((e) => Array.from(e.values()))
51
- .map((e) => e.getSignature().getFullName());
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
- const map: Map<string, Schema> = new Map([
8
- ['any', Schema.ofAny('any').setNamespace(Namespaces.SYSTEM)],
9
- ['boolean', Schema.ofBoolean('boolean').setNamespace(Namespaces.SYSTEM)],
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
- const filterableNames = Array.from(map.values()).map((e) => e.getFullName());
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.toString(),
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/LogicalNullishCoalescingOperator';
12
- import { ArithmeticAdditionOperator } from './operators/binary/ArithmeticAdditionOperator';
13
- import { ArithmeticDivisionOperator } from './operators/binary/ArithmeticDivisionOperator';
14
- import { ArithmeticIntegerDivisionOperator } from './operators/binary/ArithmeticInetgerDivisionOperator';
15
- import { ArithmeticModulusOperator } from './operators/binary/ArithmeticModulusOperator';
16
- import { ArithmeticMultiplicationOperator } from './operators/binary/ArithmeticMultiplicationOperator';
17
- import { ArithmeticSubtractionOperator } from './operators/binary/ArithmeticSubtractionOperator';
18
- import { ArrayOperator } from './operators/binary/ArrayOperator';
19
- import { BinaryOperator } from './operators/binary/BinaryOperator';
20
- import { BitwiseAndOperator } from './operators/binary/BitwiseAndOperator';
21
- import { BitwiseLeftShiftOperator } from './operators/binary/BitwiseLeftShiftOperator';
22
- import { BitwiseOrOperator } from './operators/binary/BitwiseOrOperator';
23
- import { BitwiseRightShiftOperator } from './operators/binary/BitwiseRightShiftOperator';
24
- import { BitwiseUnsignedRightShiftOperator } from './operators/binary/BitwiseUnsignedRightShiftOperator';
25
- import { BitwiseXorOperator } from './operators/binary/BitwiseXorOperator';
26
- import { LogicalAndOperator } from './operators/binary/LogicalAndOperator';
27
- import { LogicalEqualOperator } from './operators/binary/LogicalEqualOperator';
28
- import { LogicalGreaterThanEqualOperator } from './operators/binary/LogicalGreaterThanEqualOperator';
29
- import { LogicalGreaterThanOperator } from './operators/binary/LogicalGreaterThanOperator';
30
- import { LogicalLessThanEqualOperator } from './operators/binary/LogicalLessThanEqualOperator';
31
- import { LogicalLessThanOperator } from './operators/binary/LogicalLessThanOperator';
32
- import { LogicalNotEqualOperator } from './operators/binary/LogicalNotEqualOperator';
33
- import { LogicalOrOperator } from './operators/binary/LogicalOrOperator';
34
- import { ObjectOperator } from './operators/binary/ObjectOperator';
35
- import { ArithmeticUnaryMinusOperator } from './operators/unary/ArithmeticUnaryMinusOperator';
36
- import { ArithmeticUnaryPlusOperator } from './operators/unary/ArithmeticUnaryPlusOperator';
37
- import { BitwiseComplementOperator } from './operators/unary/BitwiseComplementOperator';
38
- import { LogicalNotOperator } from './operators/unary/LogicalNotOperator';
39
- import { UnaryOperator } from './operators/unary/UnaryOperator';
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 = undefined;
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
- ['INTEGER_DIVISON', Operation.INTEGER_DIVISION],
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,
@@ -0,0 +1,7 @@
1
+ import { BinaryOperator } from './BinaryOperator';
2
+
3
+ export class ArrayRangeOperator extends BinaryOperator {
4
+ public apply(t: any, u: any): any {
5
+ return `${t ?? ''}..${u ?? ''}`;
6
+ }
7
+ }
@@ -22,3 +22,4 @@ export * from './LogicalLessThanOperator';
22
22
  export * from './LogicalOrOperator';
23
23
  export * from './ObjectOperator';
24
24
  export * from './LogicalNullishCoalescingOperator';
25
+ export * from './ArrayRangeOperator';
@@ -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)) return this.handleArrayAccess(token, cPart, 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 index: number = parseInt(cPart);
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
- if (index < 0 || index >= cArray.length) {
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
- if (typeof jsonElement != 'object' || Array.isArray(jsonElement))
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": "commonjs",
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
  }