@fincity/kirun-js 2.3.2 → 2.5.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/function/system/date/AddTimeTest.ts +115 -0
- package/__tests__/engine/function/system/date/GetMonthTest.ts +3 -3
- package/__tests__/engine/function/system/date/SubtractTimeTest.ts +95 -0
- package/__tests__/engine/function/system/math/MathFunctionRepositoryTest.ts +7 -16
- package/__tests__/engine/repository/RepositoryFilterTest.ts +5 -4
- package/__tests__/engine/runtime/expression/ExpressionEvaluationTest.ts +80 -0
- package/__tests__/engine/runtime/expression/ExpressionEvaluatorStringLiteralTest.ts +73 -1
- 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 +1 -1
- package/dist/types.d.ts.map +1 -1
- package/generator/generateValidationCSV.ts +87 -0
- package/generator/validation-js.csv +1146 -0
- package/package.json +4 -4
- package/src/engine/function/system/date/AbstractDateFunction.ts +60 -2
- package/src/engine/function/system/date/DateFunctionRepository.ts +105 -2
- package/src/engine/function/system/math/MathFunctionRepository.ts +9 -9
- package/src/engine/runtime/expression/tokenextractor/TokenValueExtractor.ts +63 -59
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fincity/kirun-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Javascript Runtime for Kinetic Instructions",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"@parcel/transformer-typescript-types": "^2.7.0",
|
|
36
36
|
"@tsconfig/recommended": "^1.0.1",
|
|
37
37
|
"@types/jest": "^28.1.8",
|
|
38
|
+
"jest": "^29.5.0",
|
|
38
39
|
"parcel": "^2.7.0",
|
|
39
40
|
"prettier": "2.7.1",
|
|
40
|
-
"
|
|
41
|
+
"ts-jest": "^29.1.0",
|
|
41
42
|
"ts-loader": "^9.3.1",
|
|
42
|
-
"
|
|
43
|
-
"ts-jest": "^29.1.0"
|
|
43
|
+
"typescript": "^5.1.3"
|
|
44
44
|
},
|
|
45
45
|
"jest": {
|
|
46
46
|
"transform": {
|
|
@@ -22,6 +22,10 @@ export abstract class AbstractDateFunction extends AbstractFunction {
|
|
|
22
22
|
public static readonly PARAMETER_DATE_NAME: string = 'isoDate';
|
|
23
23
|
|
|
24
24
|
public static readonly PARAMETER_FIELD_NAME: string = 'value';
|
|
25
|
+
|
|
26
|
+
public static readonly PARAMETER_INT_NAME: string = "intValue";
|
|
27
|
+
|
|
28
|
+
public static readonly PARAMETER_UNIT_NAME: string = "unit";
|
|
25
29
|
|
|
26
30
|
protected static readonly PARAMETER_DATE: Parameter = new Parameter(
|
|
27
31
|
AbstractDateFunction.PARAMETER_DATE_NAME,
|
|
@@ -33,6 +37,17 @@ export abstract class AbstractDateFunction extends AbstractFunction {
|
|
|
33
37
|
Schema.ofInteger(this.PARAMETER_FIELD_NAME)
|
|
34
38
|
);
|
|
35
39
|
|
|
40
|
+
protected static readonly PARAMETER_INT : Parameter = new Parameter(
|
|
41
|
+
AbstractDateFunction.PARAMETER_INT_NAME,
|
|
42
|
+
Schema.ofInteger(this.PARAMETER_INT_NAME)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
protected static readonly PARAMETER_UNIT : Parameter = new Parameter(
|
|
46
|
+
AbstractDateFunction.PARAMETER_UNIT_NAME,
|
|
47
|
+
Schema.ofString(this.PARAMETER_UNIT_NAME)
|
|
48
|
+
.setEnums(["YEAR" , "MONTH" , "DAY" , "HOUR" , "MINUTE" , "SECOND" , "MILLISECOND"])
|
|
49
|
+
);
|
|
50
|
+
|
|
36
51
|
protected static readonly EVENT_INT: Event = new Event(
|
|
37
52
|
Event.OUTPUT,
|
|
38
53
|
MapUtil.of(
|
|
@@ -41,6 +56,22 @@ export abstract class AbstractDateFunction extends AbstractFunction {
|
|
|
41
56
|
),
|
|
42
57
|
);
|
|
43
58
|
|
|
59
|
+
protected static readonly EVENT_BOOLEAN: Event = new Event(
|
|
60
|
+
Event.OUTPUT,
|
|
61
|
+
MapUtil.of(
|
|
62
|
+
AbstractDateFunction.EVENT_RESULT_NAME,
|
|
63
|
+
Schema.ofBoolean(AbstractDateFunction.EVENT_RESULT_NAME)
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
protected static readonly EVENT_DATE : Event = new Event(
|
|
68
|
+
Event.OUTPUT,
|
|
69
|
+
MapUtil.of(
|
|
70
|
+
AbstractDateFunction.EVENT_RESULT_NAME,
|
|
71
|
+
Schema.ofString(AbstractDateFunction.EVENT_RESULT_NAME).setRef(Namespaces.DATE + ".timeStamp")
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
|
|
44
75
|
public getSignature(): FunctionSignature {
|
|
45
76
|
return this.signature;
|
|
46
77
|
}
|
|
@@ -79,7 +110,7 @@ export abstract class AbstractDateFunction extends AbstractFunction {
|
|
|
79
110
|
}
|
|
80
111
|
|
|
81
112
|
|
|
82
|
-
})(Namespaces.DATE, name, AbstractDateFunction.
|
|
113
|
+
})(Namespaces.DATE, name, AbstractDateFunction.EVENT_BOOLEAN, AbstractDateFunction.PARAMETER_DATE)];
|
|
83
114
|
}
|
|
84
115
|
|
|
85
116
|
public static ofEntryDateAndIntegerOutput(name: string, fun: (date: string) => number) : [string, Function] {
|
|
@@ -101,4 +132,31 @@ export abstract class AbstractDateFunction extends AbstractFunction {
|
|
|
101
132
|
})(Namespaces.DATE, name, AbstractDateFunction.EVENT_INT, AbstractDateFunction.PARAMETER_DATE)];
|
|
102
133
|
}
|
|
103
134
|
|
|
104
|
-
|
|
135
|
+
public static ofEntryDateWithIntegerUnitWithOutputName( functionName: string,
|
|
136
|
+
func: (date: string, amount: number, unit: string) => string): [string, Function] {
|
|
137
|
+
return [functionName, new (class extends AbstractDateFunction {
|
|
138
|
+
constructor(namespace: string, functionName: string, event: Event, ...parameter: Parameter[]) {
|
|
139
|
+
super(namespace, functionName, event, ...parameter);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
protected async internalExecute(context: FunctionExecutionParameters): Promise<FunctionOutput> {
|
|
143
|
+
|
|
144
|
+
const date = context.getArguments()?.get(AbstractDateFunction.PARAMETER_DATE_NAME);
|
|
145
|
+
|
|
146
|
+
if(isNullValue(date) || !ValidDateTimeUtil.validate(date))
|
|
147
|
+
throw new KIRuntimeException("Please provide a valid date object");
|
|
148
|
+
|
|
149
|
+
const value = context.getArguments()?.get(AbstractDateFunction.PARAMETER_INT_NAME);
|
|
150
|
+
|
|
151
|
+
const unit = context.getArguments()?.get(AbstractDateFunction.PARAMETER_UNIT_NAME);
|
|
152
|
+
|
|
153
|
+
return new FunctionOutput([EventResult.outputOf(MapUtil.of( AbstractDateFunction.EVENT_RESULT_NAME, func(date, value , unit)))]);
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
})(Namespaces.DATE, functionName, AbstractDateFunction.EVENT_DATE,
|
|
157
|
+
AbstractDateFunction.PARAMETER_DATE, AbstractDateFunction.PARAMETER_INT, AbstractDateFunction.PARAMETER_UNIT)];
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
}
|
|
@@ -3,12 +3,33 @@ import { Repository } from "../../../Repository";
|
|
|
3
3
|
import { MapUtil } from "../../../util/MapUtil";
|
|
4
4
|
import { AbstractDateFunction } from "./AbstractDateFunction";
|
|
5
5
|
import { Function } from '../../Function';
|
|
6
|
+
import { KIRuntimeException } from "../../../exception/KIRuntimeException";
|
|
7
|
+
import mapEntry from '../../../util/mapEntry';
|
|
8
|
+
import { DateToEpoch } from "./DateToEpoch";
|
|
9
|
+
import { DifferenceOfTimestamps } from "./DifferenceOfTimestamps";
|
|
10
|
+
import { EpochToDate } from "./EpochToDate";
|
|
11
|
+
import { GetCurrentTimeStamp } from "./GetCurrentTimeStamp";
|
|
12
|
+
import { GetTimeAsArray } from "./GetTimeAsArray";
|
|
13
|
+
import { GetTimeAsObject } from "./GetTimeAsObject";
|
|
14
|
+
import { IsValidISODate } from "./IsValidISODate";
|
|
15
|
+
import { MaximumTimestamp } from "./MaximumTimestamp";
|
|
16
|
+
import { MinimumTimestamp } from "./MinimumTimestamp";
|
|
6
17
|
|
|
7
18
|
|
|
8
19
|
export class DateFunctionRepository implements Repository<Function> {
|
|
9
20
|
|
|
10
21
|
private static readonly repoMap: Map<string, Function> = MapUtil.ofArrayEntries(
|
|
11
22
|
|
|
23
|
+
mapEntry(new DateToEpoch()),
|
|
24
|
+
mapEntry(new EpochToDate()),
|
|
25
|
+
mapEntry(new GetCurrentTimeStamp()),
|
|
26
|
+
mapEntry(new DifferenceOfTimestamps()),
|
|
27
|
+
mapEntry(new IsValidISODate()),
|
|
28
|
+
mapEntry(new GetTimeAsArray()),
|
|
29
|
+
mapEntry(new GetTimeAsObject()),
|
|
30
|
+
mapEntry(new MaximumTimestamp()),
|
|
31
|
+
mapEntry(new MinimumTimestamp()),
|
|
32
|
+
|
|
12
33
|
AbstractDateFunction.ofEntryDateAndBooleanOutput("IsLeapYear", date => {
|
|
13
34
|
const year = new Date(date).getUTCFullYear();
|
|
14
35
|
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
|
|
@@ -20,7 +41,7 @@ export class DateFunctionRepository implements Repository<Function> {
|
|
|
20
41
|
|
|
21
42
|
AbstractDateFunction.ofEntryDateAndIntegerOutput("GetFullYear", date => new Date(date).getUTCFullYear()),
|
|
22
43
|
|
|
23
|
-
AbstractDateFunction.ofEntryDateAndIntegerOutput("GetMonth", date => new Date(date).getUTCMonth()
|
|
44
|
+
AbstractDateFunction.ofEntryDateAndIntegerOutput("GetMonth", date => new Date(date).getUTCMonth()),
|
|
24
45
|
|
|
25
46
|
AbstractDateFunction.ofEntryDateAndIntegerOutput("GetHours", date => new Date(date).getUTCHours()),
|
|
26
47
|
|
|
@@ -31,13 +52,95 @@ export class DateFunctionRepository implements Repository<Function> {
|
|
|
31
52
|
AbstractDateFunction.ofEntryDateAndIntegerOutput("GetMilliSeconds", date => new Date(date).getUTCMilliseconds()),
|
|
32
53
|
|
|
33
54
|
AbstractDateFunction.ofEntryDateAndIntegerOutput("GetTime" , date => new Date(date).getTime()),
|
|
34
|
-
|
|
55
|
+
|
|
56
|
+
AbstractDateFunction.ofEntryDateWithIntegerUnitWithOutputName("AddTime",
|
|
57
|
+
(date , value , unit) => this.changeAmountToUnit(date, unit, value, true)
|
|
58
|
+
),
|
|
59
|
+
|
|
60
|
+
AbstractDateFunction.ofEntryDateWithIntegerUnitWithOutputName("SubtractTime",
|
|
61
|
+
(date , value , unit) => this.changeAmountToUnit(date, unit, value, false)
|
|
62
|
+
)
|
|
35
63
|
);
|
|
36
64
|
|
|
37
65
|
private static readonly filterableNames = Array.from(
|
|
38
66
|
DateFunctionRepository.repoMap.values(),
|
|
39
67
|
).map((e) => e.getSignature().getFullName());
|
|
68
|
+
|
|
69
|
+
private static changeAmountToUnit(inputDate: string , unit: string, value: number, isAdd: boolean): string{
|
|
70
|
+
|
|
71
|
+
const amount = isAdd ? value : -1 * value;
|
|
72
|
+
|
|
73
|
+
const date = this.getFullUTCDate(inputDate);
|
|
74
|
+
const originalOffset = this.getTimezoneOffset(inputDate);
|
|
75
|
+
|
|
76
|
+
switch(unit){
|
|
77
|
+
|
|
78
|
+
case "MILLISECOND" : date.setMilliseconds(date.getMilliseconds() + amount);
|
|
79
|
+
break;
|
|
80
|
+
case "SECOND" : date.setSeconds(date.getSeconds() + amount);
|
|
81
|
+
break;
|
|
82
|
+
case "MINUTE" : date.setMinutes(date.getMinutes() + amount);
|
|
83
|
+
break;
|
|
84
|
+
case "HOUR" : date.setHours(date.getHours() + amount);
|
|
85
|
+
break;
|
|
86
|
+
case "DAY" : date.setDate(date.getDate() + amount);
|
|
87
|
+
break;
|
|
88
|
+
case "MONTH" : date.setMonth(date.getMonth() + amount);
|
|
89
|
+
break;
|
|
90
|
+
case "YEAR" : date.setFullYear(date.getFullYear() + amount);
|
|
91
|
+
break;
|
|
92
|
+
default :
|
|
93
|
+
throw new KIRuntimeException("No such unit: " + unit)
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.formatDate(date, originalOffset);
|
|
98
|
+
}
|
|
40
99
|
|
|
100
|
+
private static getTimezoneOffset(dateString: string): string {
|
|
101
|
+
const lastChar = dateString.charAt(dateString.length - 1);
|
|
102
|
+
if (lastChar === 'Z') return '+00:00';
|
|
103
|
+
|
|
104
|
+
const offsetStart = dateString.indexOf('+') !== -1 ? dateString.lastIndexOf('+') : dateString.lastIndexOf('-');
|
|
105
|
+
if (offsetStart === -1) return '+00:00';
|
|
106
|
+
|
|
107
|
+
let offset = dateString.substring(offsetStart);
|
|
108
|
+
if (offset.length === 3) {
|
|
109
|
+
offset = offset.substring(0, 1) + '0' + offset.substring(1) + ':00';
|
|
110
|
+
} else if (offset.length === 5) {
|
|
111
|
+
offset = offset.substring(0, 3) + ':' + offset.substring(3);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return offset;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private static getFullUTCDate(inputDate:string): Date {
|
|
118
|
+
|
|
119
|
+
if(inputDate.lastIndexOf('+') !== -1)
|
|
120
|
+
inputDate = inputDate.substring(0, inputDate.lastIndexOf('+')) + 'Z';
|
|
121
|
+
else if(inputDate.lastIndexOf('-') !== -1)
|
|
122
|
+
inputDate = inputDate.substring(0, inputDate.lastIndexOf('-')) + 'Z';
|
|
123
|
+
|
|
124
|
+
const date: Date = new Date(inputDate);
|
|
125
|
+
|
|
126
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1,
|
|
127
|
+
date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(),
|
|
128
|
+
date.getUTCSeconds(), date.getUTCMilliseconds()));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private static formatDate(date: Date, offset: string): string {
|
|
132
|
+
const pad = (num: number) => num.toString().padStart(2, '0');
|
|
133
|
+
|
|
134
|
+
const year = date.getUTCMonth() === 0 ? date.getUTCFullYear() - 1 : date.getUTCFullYear();
|
|
135
|
+
const month = pad(date.getUTCMonth() === 0 ? 12 : date.getUTCMonth());
|
|
136
|
+
const day = pad(date.getUTCDate());
|
|
137
|
+
const hours = pad(date.getUTCHours());
|
|
138
|
+
const minutes = pad(date.getUTCMinutes());
|
|
139
|
+
const seconds = pad(date.getUTCSeconds());
|
|
140
|
+
const milliseconds = pad(date.getUTCMilliseconds());
|
|
141
|
+
|
|
142
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${offset}`;
|
|
143
|
+
}
|
|
41
144
|
|
|
42
145
|
find(namespace: string, name: string): Promise<Function | undefined> {
|
|
43
146
|
if (namespace != Namespaces.DATE) {
|
|
@@ -22,17 +22,17 @@ const functionObjectsIndex: { [key: string]: AbstractFunction } = {
|
|
|
22
22
|
SchemaType.FLOAT,
|
|
23
23
|
SchemaType.DOUBLE,
|
|
24
24
|
),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
ArcCosine: new GenericMathFunction('ArcCosine', (v) => Math.acos(v)),
|
|
26
|
+
ArcSine: new GenericMathFunction('ArcSine', (v) => Math.asin(v)),
|
|
27
|
+
ArcTangent: new GenericMathFunction('ArcTangent', (v) => Math.atan(v)),
|
|
28
28
|
Ceiling: new GenericMathFunction('Ceiling', (v) => Math.ceil(v)),
|
|
29
29
|
Cosine: new GenericMathFunction('Cosine', (v) => Math.cos(v)),
|
|
30
|
-
|
|
30
|
+
HyperbolicCosine: new GenericMathFunction('HyperbolicCosine', (v) => Math.cosh(v)),
|
|
31
31
|
CubeRoot: new GenericMathFunction('CubeRoot', (v) => Math.cbrt(v)),
|
|
32
32
|
Exponential: new GenericMathFunction('Exponential', (v) => Math.exp(v)),
|
|
33
|
-
|
|
33
|
+
ExponentialMinus1: new GenericMathFunction('ExponentialMinus1', (v) => Math.expm1(v)),
|
|
34
34
|
Floor: new GenericMathFunction('Floor', (v) => Math.floor(v)),
|
|
35
|
-
|
|
35
|
+
LogNatural: new GenericMathFunction('LogNatural', (v) => Math.log(v)),
|
|
36
36
|
Log10: new GenericMathFunction('Log10', (v) => Math.log10(v)),
|
|
37
37
|
Round: new GenericMathFunction(
|
|
38
38
|
'Round',
|
|
@@ -42,13 +42,13 @@ const functionObjectsIndex: { [key: string]: AbstractFunction } = {
|
|
|
42
42
|
SchemaType.LONG,
|
|
43
43
|
),
|
|
44
44
|
Sine: new GenericMathFunction('Sine', (v) => Math.sin(v)),
|
|
45
|
-
|
|
45
|
+
HyperbolicSine: new GenericMathFunction('HyperbolicSine', (v) => Math.sinh(v)),
|
|
46
46
|
Tangent: new GenericMathFunction('Tangent', (v) => Math.tan(v)),
|
|
47
|
-
|
|
47
|
+
HyperbolicTangent: new GenericMathFunction('HyperbolicTangent', (v) => Math.tanh(v)),
|
|
48
48
|
ToDegrees: new GenericMathFunction('ToDegrees', (v) => v * (Math.PI / 180)),
|
|
49
49
|
ToRadians: new GenericMathFunction('ToRadians', (v) => v * (180 / Math.PI)),
|
|
50
50
|
SquareRoot: new GenericMathFunction('SquareRoot', (v) => Math.sqrt(v)),
|
|
51
|
-
|
|
51
|
+
ArcTangent2: new GenericMathFunction('ArcTangent2', (v1, v2) => Math.atan2(v1, v2!), 2),
|
|
52
52
|
Power: new GenericMathFunction('Power', (v1, v2) => Math.pow(v1, v2!), 2),
|
|
53
53
|
Add: new Add(),
|
|
54
54
|
Hypotenuse: new Hypotenuse(),
|
|
@@ -52,8 +52,8 @@ export abstract class TokenValueExtractor {
|
|
|
52
52
|
.map((e) => e.trim())
|
|
53
53
|
.filter((e) => !StringUtil.isNullOrBlank(e))
|
|
54
54
|
.reduce(
|
|
55
|
-
(a, c
|
|
56
|
-
this.resolveForEachPartOfTokenWithBrackets(token, parts, partNumber, c, a
|
|
55
|
+
(a, c) =>
|
|
56
|
+
this.resolveForEachPartOfTokenWithBrackets(token, parts, partNumber, c, a),
|
|
57
57
|
jsonElement,
|
|
58
58
|
);
|
|
59
59
|
|
|
@@ -64,74 +64,78 @@ export abstract class TokenValueExtractor {
|
|
|
64
64
|
token: string,
|
|
65
65
|
parts: string[],
|
|
66
66
|
partNumber: number,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
i: any,
|
|
67
|
+
cPart: string,
|
|
68
|
+
cElement: any
|
|
70
69
|
): any {
|
|
71
|
-
if (isNullValue(
|
|
70
|
+
if (isNullValue(cElement)) return undefined;
|
|
72
71
|
|
|
73
|
-
if (
|
|
74
|
-
if (c === 'length') {
|
|
75
|
-
const type = typeof a;
|
|
76
|
-
if (type === 'string' || Array.isArray(a)) return a.length;
|
|
77
|
-
if (type === 'object') return Object.keys(a).length;
|
|
78
|
-
}
|
|
79
|
-
if (Array.isArray(a)) {
|
|
80
|
-
try {
|
|
81
|
-
let index: number = parseInt(c);
|
|
82
|
-
if (isNaN(index)) {
|
|
83
|
-
throw new Error(StringFormatter.format('$ is not a number', index));
|
|
84
|
-
}
|
|
85
|
-
if (index >= a.length) return undefined;
|
|
86
|
-
|
|
87
|
-
return a[index];
|
|
88
|
-
} catch (err: any) {
|
|
89
|
-
throw new ExpressionEvaluationException(
|
|
90
|
-
token,
|
|
91
|
-
StringFormatter.format("$ couldn't be parsed into integer in $", c, token),
|
|
92
|
-
err,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
72
|
+
if (cPart === 'length') return this.getLength(token, cElement);
|
|
96
73
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
74
|
+
if (Array.isArray(cElement)) return this.handleArrayAccess(token, cPart, cElement);
|
|
75
|
+
|
|
76
|
+
return this.handleObjectAccess(token, parts, partNumber, cPart, cElement);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private getLength(
|
|
80
|
+
token: string,
|
|
81
|
+
cElement: any
|
|
82
|
+
): any {
|
|
83
|
+
const type = typeof cElement;
|
|
105
84
|
|
|
106
|
-
|
|
107
|
-
|
|
85
|
+
if (type === 'string' || Array.isArray(cElement)) return cElement.length;
|
|
86
|
+
if (type === 'object') {
|
|
87
|
+
if ('length' in cElement) return cElement['length'];
|
|
88
|
+
else return Object.keys(cElement).length;
|
|
108
89
|
}
|
|
109
90
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
index,
|
|
121
|
-
token,
|
|
122
|
-
),
|
|
123
|
-
);
|
|
91
|
+
throw new ExpressionEvaluationException(token,
|
|
92
|
+
StringFormatter.format('Length can\'t be found in token $', token))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private handleArrayAccess(
|
|
96
|
+
token: string,
|
|
97
|
+
cPart: string,
|
|
98
|
+
cArray: any[]
|
|
99
|
+
): any {
|
|
100
|
+
const index: number = parseInt(cPart);
|
|
124
101
|
|
|
125
|
-
|
|
102
|
+
if (isNaN(index)) {
|
|
103
|
+
throw new ExpressionEvaluationException(
|
|
104
|
+
token,
|
|
105
|
+
StringFormatter.format('$ is not a number', cPart)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
126
108
|
|
|
127
|
-
|
|
128
|
-
} catch (err: any) {
|
|
109
|
+
if (index < 0 || index >= cArray.length) {
|
|
129
110
|
throw new ExpressionEvaluationException(
|
|
130
111
|
token,
|
|
131
|
-
StringFormatter.format(
|
|
132
|
-
err,
|
|
112
|
+
StringFormatter.format('Index $ is out of bounds for array of length $', index, cArray.length)
|
|
133
113
|
);
|
|
134
114
|
}
|
|
115
|
+
|
|
116
|
+
return cArray[index];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private handleObjectAccess(
|
|
120
|
+
token: string,
|
|
121
|
+
parts: string[],
|
|
122
|
+
partNumber: number,
|
|
123
|
+
cPart: string,
|
|
124
|
+
cObject: any
|
|
125
|
+
): any {
|
|
126
|
+
if (cPart.startsWith("\"")) {
|
|
127
|
+
if (!cPart.endsWith("\"") || cPart.length == 1 || cPart.length == 2) {
|
|
128
|
+
throw new ExpressionEvaluationException(
|
|
129
|
+
token,
|
|
130
|
+
StringFormatter.format("$ is missing a double quote or empty key found", token))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
cPart = cPart.substring(1, parts.length - 2);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.checkIfObject(token, parts, partNumber, cObject);
|
|
137
|
+
|
|
138
|
+
return cObject[cPart];
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
protected checkIfObject(
|
|
@@ -144,7 +148,7 @@ export abstract class TokenValueExtractor {
|
|
|
144
148
|
throw new ExpressionEvaluationException(
|
|
145
149
|
token,
|
|
146
150
|
StringFormatter.format(
|
|
147
|
-
'Unable to
|
|
151
|
+
'Unable to retrieve $ from $ in the path $',
|
|
148
152
|
parts[partNumber],
|
|
149
153
|
jsonElement.toString(),
|
|
150
154
|
token,
|