@fincity/kirun-js 3.3.0 → 3.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/array/ReverseTest.ts +84 -0
- package/__tests__/engine/function/system/string/ReverseTest.ts +51 -6
- package/__tests__/engine/runtime/KIRuntimeParallelTest.ts +200 -0
- package/__tests__/engine/runtime/expression/ExpressionDoubleEqualsChipLabelTest.ts +84 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/module.js +2 -2
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/engine/function/system/array/Reverse.ts +1 -1
- package/src/engine/runtime/expression/ExpressionEvaluator.ts +12 -11
- package/src/engine/runtime/expression/exception/ExpressionEvaluationException.ts +15 -4
- package/src/engine/runtime/expression/tokenextractor/LiteralTokenValueExtractor.ts +62 -8
- package/src/engine/runtime/expression/tokenextractor/TokenValueExtractor.ts +3 -2
|
@@ -197,6 +197,90 @@ test('Rev test 4', async () => {
|
|
|
197
197
|
expect((await rev.execute(fep)).allResults()[0].getResult().get('result')).toMatchObject(res1);
|
|
198
198
|
});
|
|
199
199
|
|
|
200
|
+
test('Reverse test - full array reverse with len -1', async () => {
|
|
201
|
+
let src: any[] = [1, 2, 3, 4, 5];
|
|
202
|
+
|
|
203
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
204
|
+
new KIRunFunctionRepository(),
|
|
205
|
+
new KIRunSchemaRepository(),
|
|
206
|
+
)
|
|
207
|
+
.setArguments(
|
|
208
|
+
new Map<string, any>([
|
|
209
|
+
[Reverse.PARAMETER_ARRAY_SOURCE.getParameterName(), src],
|
|
210
|
+
[Reverse.PARAMETER_INT_SOURCE_FROM.getParameterName(), 0],
|
|
211
|
+
[Reverse.PARAMETER_INT_LENGTH.getParameterName(), -1],
|
|
212
|
+
]),
|
|
213
|
+
)
|
|
214
|
+
.setContext(new Map([]))
|
|
215
|
+
.setSteps(new Map([]));
|
|
216
|
+
|
|
217
|
+
let res = [5, 4, 3, 2, 1];
|
|
218
|
+
expect((await rev.execute(fep)).allResults()[0].getResult().get('result')).toStrictEqual(res);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test('Reverse test - full array reverse with explicit length', async () => {
|
|
222
|
+
let src: any[] = ['a', 'b', 'c', 'd'];
|
|
223
|
+
|
|
224
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
225
|
+
new KIRunFunctionRepository(),
|
|
226
|
+
new KIRunSchemaRepository(),
|
|
227
|
+
)
|
|
228
|
+
.setArguments(
|
|
229
|
+
new Map<string, any>([
|
|
230
|
+
[Reverse.PARAMETER_ARRAY_SOURCE.getParameterName(), src],
|
|
231
|
+
[Reverse.PARAMETER_INT_SOURCE_FROM.getParameterName(), 0],
|
|
232
|
+
[Reverse.PARAMETER_INT_LENGTH.getParameterName(), 4],
|
|
233
|
+
]),
|
|
234
|
+
)
|
|
235
|
+
.setContext(new Map([]))
|
|
236
|
+
.setSteps(new Map([]));
|
|
237
|
+
|
|
238
|
+
let res = ['d', 'c', 'b', 'a'];
|
|
239
|
+
expect((await rev.execute(fep)).allResults()[0].getResult().get('result')).toStrictEqual(res);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test('Reverse test - single element array', async () => {
|
|
243
|
+
let src: any[] = [42];
|
|
244
|
+
|
|
245
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
246
|
+
new KIRunFunctionRepository(),
|
|
247
|
+
new KIRunSchemaRepository(),
|
|
248
|
+
)
|
|
249
|
+
.setArguments(
|
|
250
|
+
new Map<string, any>([
|
|
251
|
+
[Reverse.PARAMETER_ARRAY_SOURCE.getParameterName(), src],
|
|
252
|
+
[Reverse.PARAMETER_INT_SOURCE_FROM.getParameterName(), 0],
|
|
253
|
+
[Reverse.PARAMETER_INT_LENGTH.getParameterName(), -1],
|
|
254
|
+
]),
|
|
255
|
+
)
|
|
256
|
+
.setContext(new Map([]))
|
|
257
|
+
.setSteps(new Map([]));
|
|
258
|
+
|
|
259
|
+
let res = [42];
|
|
260
|
+
expect((await rev.execute(fep)).allResults()[0].getResult().get('result')).toStrictEqual(res);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('Reverse test - full reverse from non-zero start', async () => {
|
|
264
|
+
let src: any[] = [1, 2, 3, 4, 5];
|
|
265
|
+
|
|
266
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
267
|
+
new KIRunFunctionRepository(),
|
|
268
|
+
new KIRunSchemaRepository(),
|
|
269
|
+
)
|
|
270
|
+
.setArguments(
|
|
271
|
+
new Map<string, any>([
|
|
272
|
+
[Reverse.PARAMETER_ARRAY_SOURCE.getParameterName(), src],
|
|
273
|
+
[Reverse.PARAMETER_INT_SOURCE_FROM.getParameterName(), 0],
|
|
274
|
+
[Reverse.PARAMETER_INT_LENGTH.getParameterName(), 5],
|
|
275
|
+
]),
|
|
276
|
+
)
|
|
277
|
+
.setContext(new Map([]))
|
|
278
|
+
.setSteps(new Map([]));
|
|
279
|
+
|
|
280
|
+
let res = [5, 4, 3, 2, 1];
|
|
281
|
+
expect((await rev.execute(fep)).allResults()[0].getResult().get('result')).toStrictEqual(res);
|
|
282
|
+
});
|
|
283
|
+
|
|
200
284
|
test('rev test 5', async () => {
|
|
201
285
|
let arr: any[] = [];
|
|
202
286
|
arr.push('a');
|
|
@@ -32,12 +32,57 @@ test('reverse test2', async () => {
|
|
|
32
32
|
expect((await reve.execute(fep)).allResults()[0].getResult().get('value')).toBe(reveresed);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
test('reverse test - empty string', async () => {
|
|
36
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
37
|
+
new KIRunFunctionRepository(),
|
|
38
|
+
new KIRunSchemaRepository(),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
fep.setArguments(MapUtil.of('value', ''));
|
|
42
|
+
|
|
43
|
+
expect((await reve.execute(fep)).allResults()[0].getResult().get('value')).toBe('');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('reverse test - single character', async () => {
|
|
47
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
48
|
+
new KIRunFunctionRepository(),
|
|
49
|
+
new KIRunSchemaRepository(),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
fep.setArguments(MapUtil.of('value', 'a'));
|
|
53
|
+
|
|
54
|
+
expect((await reve.execute(fep)).allResults()[0].getResult().get('value')).toBe('a');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('reverse test - palindrome', async () => {
|
|
58
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
59
|
+
new KIRunFunctionRepository(),
|
|
60
|
+
new KIRunSchemaRepository(),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
fep.setArguments(MapUtil.of('value', 'racecar'));
|
|
64
|
+
|
|
65
|
+
expect((await reve.execute(fep)).allResults()[0].getResult().get('value')).toBe('racecar');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('reverse test - special characters', async () => {
|
|
69
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
70
|
+
new KIRunFunctionRepository(),
|
|
71
|
+
new KIRunSchemaRepository(),
|
|
72
|
+
);
|
|
37
73
|
|
|
38
|
-
|
|
74
|
+
fep.setArguments(MapUtil.of('value', '!@#$%'));
|
|
39
75
|
|
|
40
|
-
|
|
76
|
+
expect((await reve.execute(fep)).allResults()[0].getResult().get('value')).toBe('%$#@!');
|
|
77
|
+
});
|
|
41
78
|
|
|
42
|
-
|
|
43
|
-
|
|
79
|
+
test('reverse test - numbers in string', async () => {
|
|
80
|
+
let fep: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
81
|
+
new KIRunFunctionRepository(),
|
|
82
|
+
new KIRunSchemaRepository(),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
fep.setArguments(MapUtil.of('value', '12345'));
|
|
86
|
+
|
|
87
|
+
expect((await reve.execute(fep)).allResults()[0].getResult().get('value')).toBe('54321');
|
|
88
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Function,
|
|
3
|
+
FunctionDefinition,
|
|
4
|
+
HybridRepository,
|
|
5
|
+
KIRunFunctionRepository,
|
|
6
|
+
Repository,
|
|
7
|
+
KIRuntime,
|
|
8
|
+
FunctionExecutionParameters,
|
|
9
|
+
KIRunSchemaRepository,
|
|
10
|
+
} from '../../../src';
|
|
11
|
+
|
|
12
|
+
const oldLog = console.log;
|
|
13
|
+
|
|
14
|
+
test('KIRuntime parallel execution waits for all paths to complete', async () => {
|
|
15
|
+
// 3 separate functions, one per parallel path:
|
|
16
|
+
// Path1: Wait 2000ms -> Print "2000 Finished"
|
|
17
|
+
// Path2: Wait 3000ms -> Print "3000 Finished"
|
|
18
|
+
// Path3: Print "Without Time Finished" (instant)
|
|
19
|
+
//
|
|
20
|
+
// Main function calls all 3 in parallel and should wait for all to complete.
|
|
21
|
+
|
|
22
|
+
const path1 = new KIRuntime(
|
|
23
|
+
FunctionDefinition.from(
|
|
24
|
+
JSON.parse(`{
|
|
25
|
+
"name": "Path1",
|
|
26
|
+
"namespace": "Internal",
|
|
27
|
+
"events": {
|
|
28
|
+
"output": { "name": "output", "parameters": {} }
|
|
29
|
+
},
|
|
30
|
+
"steps": {
|
|
31
|
+
"wait": {
|
|
32
|
+
"statementName": "wait",
|
|
33
|
+
"namespace": "System",
|
|
34
|
+
"name": "Wait",
|
|
35
|
+
"parameterMap": {
|
|
36
|
+
"millis": { "one": { "key": "one", "type": "VALUE", "value": 2000 } }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"print": {
|
|
40
|
+
"statementName": "print",
|
|
41
|
+
"namespace": "System",
|
|
42
|
+
"name": "Print",
|
|
43
|
+
"parameterMap": {
|
|
44
|
+
"values": { "one": { "key": "one", "type": "VALUE", "value": "2000 Finished" } }
|
|
45
|
+
},
|
|
46
|
+
"dependentStatements": { "Steps.wait.output": true }
|
|
47
|
+
},
|
|
48
|
+
"genOutput": {
|
|
49
|
+
"statementName": "genOutput",
|
|
50
|
+
"namespace": "System",
|
|
51
|
+
"name": "GenerateEvent",
|
|
52
|
+
"dependentStatements": { "Steps.print.output": true },
|
|
53
|
+
"parameterMap": {
|
|
54
|
+
"eventName": { "one": { "key": "one", "type": "VALUE", "value": "output" } }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}`),
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const path2 = new KIRuntime(
|
|
63
|
+
FunctionDefinition.from(
|
|
64
|
+
JSON.parse(`{
|
|
65
|
+
"name": "Path2",
|
|
66
|
+
"namespace": "Internal",
|
|
67
|
+
"events": {
|
|
68
|
+
"output": { "name": "output", "parameters": {} }
|
|
69
|
+
},
|
|
70
|
+
"steps": {
|
|
71
|
+
"wait": {
|
|
72
|
+
"statementName": "wait",
|
|
73
|
+
"namespace": "System",
|
|
74
|
+
"name": "Wait",
|
|
75
|
+
"parameterMap": {
|
|
76
|
+
"millis": { "one": { "key": "one", "type": "VALUE", "value": 3000 } }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"print": {
|
|
80
|
+
"statementName": "print",
|
|
81
|
+
"namespace": "System",
|
|
82
|
+
"name": "Print",
|
|
83
|
+
"parameterMap": {
|
|
84
|
+
"values": { "one": { "key": "one", "type": "VALUE", "value": "3000 Finished" } }
|
|
85
|
+
},
|
|
86
|
+
"dependentStatements": { "Steps.wait.output": true }
|
|
87
|
+
},
|
|
88
|
+
"genOutput": {
|
|
89
|
+
"statementName": "genOutput",
|
|
90
|
+
"namespace": "System",
|
|
91
|
+
"name": "GenerateEvent",
|
|
92
|
+
"dependentStatements": { "Steps.print.output": true },
|
|
93
|
+
"parameterMap": {
|
|
94
|
+
"eventName": { "one": { "key": "one", "type": "VALUE", "value": "output" } }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}`),
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const path3 = new KIRuntime(
|
|
103
|
+
FunctionDefinition.from(
|
|
104
|
+
JSON.parse(`{
|
|
105
|
+
"name": "Path3",
|
|
106
|
+
"namespace": "Internal",
|
|
107
|
+
"events": {
|
|
108
|
+
"output": { "name": "output", "parameters": {} }
|
|
109
|
+
},
|
|
110
|
+
"steps": {
|
|
111
|
+
"print": {
|
|
112
|
+
"statementName": "print",
|
|
113
|
+
"namespace": "System",
|
|
114
|
+
"name": "Print",
|
|
115
|
+
"parameterMap": {
|
|
116
|
+
"values": { "one": { "key": "one", "type": "VALUE", "value": "Without Time Finished" } }
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"genOutput": {
|
|
120
|
+
"statementName": "genOutput",
|
|
121
|
+
"namespace": "System",
|
|
122
|
+
"name": "GenerateEvent",
|
|
123
|
+
"dependentStatements": { "Steps.print.output": true },
|
|
124
|
+
"parameterMap": {
|
|
125
|
+
"eventName": { "one": { "key": "one", "type": "VALUE", "value": "output" } }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}`),
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Main function calls all 3 paths in parallel
|
|
134
|
+
const mainDef = FunctionDefinition.from({
|
|
135
|
+
name: 'TestParallel',
|
|
136
|
+
namespace: 'UIApp',
|
|
137
|
+
|
|
138
|
+
steps: {
|
|
139
|
+
exPath1: {
|
|
140
|
+
statementName: 'exPath1',
|
|
141
|
+
name: 'Path1',
|
|
142
|
+
namespace: 'Internal',
|
|
143
|
+
parameterMap: {},
|
|
144
|
+
},
|
|
145
|
+
exPath2: {
|
|
146
|
+
statementName: 'exPath2',
|
|
147
|
+
name: 'Path2',
|
|
148
|
+
namespace: 'Internal',
|
|
149
|
+
parameterMap: {},
|
|
150
|
+
},
|
|
151
|
+
exPath3: {
|
|
152
|
+
statementName: 'exPath3',
|
|
153
|
+
name: 'Path3',
|
|
154
|
+
namespace: 'Internal',
|
|
155
|
+
parameterMap: {},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
class InternalRepository implements Repository<Function> {
|
|
161
|
+
async find(namespace: string, name: string): Promise<Function | undefined> {
|
|
162
|
+
if (namespace !== 'Internal') return undefined;
|
|
163
|
+
if (name === 'Path1') return path1;
|
|
164
|
+
if (name === 'Path2') return path2;
|
|
165
|
+
if (name === 'Path3') return path3;
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async filter(name: string): Promise<string[]> {
|
|
170
|
+
return [
|
|
171
|
+
path1.getSignature().getFullName(),
|
|
172
|
+
path2.getSignature().getFullName(),
|
|
173
|
+
path3.getSignature().getFullName(),
|
|
174
|
+
].filter((e) => e.toLowerCase().includes(name.toLowerCase()));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const repo = new HybridRepository(new KIRunFunctionRepository(), new InternalRepository());
|
|
179
|
+
const mock = jest.spyOn(global.console, 'log').mockImplementation(oldLog);
|
|
180
|
+
|
|
181
|
+
const startTime = Date.now();
|
|
182
|
+
|
|
183
|
+
await new KIRuntime(mainDef, false).execute(
|
|
184
|
+
new FunctionExecutionParameters(repo, new KIRunSchemaRepository()),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const elapsed = Date.now() - startTime;
|
|
188
|
+
|
|
189
|
+
// All 3 print statements should have been called
|
|
190
|
+
expect(mock).toHaveBeenCalledTimes(3);
|
|
191
|
+
expect(mock).toHaveBeenCalledWith('Without Time Finished');
|
|
192
|
+
expect(mock).toHaveBeenCalledWith('2000 Finished');
|
|
193
|
+
expect(mock).toHaveBeenCalledWith('3000 Finished');
|
|
194
|
+
|
|
195
|
+
// Execution should have waited for the longest path (3000ms).
|
|
196
|
+
// If parallel execution finishes early (before all paths), elapsed would be < 2000ms.
|
|
197
|
+
expect(elapsed).toBeGreaterThanOrEqual(2000);
|
|
198
|
+
|
|
199
|
+
mock.mockRestore();
|
|
200
|
+
}, 15000);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExpressionEvaluator,
|
|
3
|
+
KIRunSchemaRepository,
|
|
4
|
+
FunctionExecutionParameters,
|
|
5
|
+
KIRunFunctionRepository,
|
|
6
|
+
} from '../../../../src';
|
|
7
|
+
|
|
8
|
+
// Reproduces the sitezump buyTokens status-filter chip label expression.
|
|
9
|
+
//
|
|
10
|
+
// Kirun's equality operator is '=' (Operation.EQUAL = new Operation('=')),
|
|
11
|
+
// NOT '=='. Writing '==' makes the lexer read two consecutive '=' tokens,
|
|
12
|
+
// which leaves a dangling operator and throws "Extra operator ... found."
|
|
13
|
+
// This is exactly the error reported on the chip label.
|
|
14
|
+
|
|
15
|
+
let inMap: Map<string, any> = new Map();
|
|
16
|
+
inMap.set('status', 'PAID'); // Page.invoiceQuery.status equivalent (active)
|
|
17
|
+
inMap.set('emptyStatus', ''); // Page.invoiceQuery.status when "All" (inactive)
|
|
18
|
+
inMap.set('value', 'PAID'); // Parent.value equivalent
|
|
19
|
+
inMap.set('label', 'Paid'); // Parent.label equivalent
|
|
20
|
+
|
|
21
|
+
let output: Map<string, Map<string, Map<string, any>>> = new Map([
|
|
22
|
+
['step1', new Map([['output', inMap]])],
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
let parameters: FunctionExecutionParameters = new FunctionExecutionParameters(
|
|
26
|
+
new KIRunFunctionRepository(),
|
|
27
|
+
new KIRunSchemaRepository(),
|
|
28
|
+
)
|
|
29
|
+
.setArguments(new Map())
|
|
30
|
+
.setSteps(output);
|
|
31
|
+
|
|
32
|
+
test('Double-equals (==) is not a valid Kirun operator and throws', () => {
|
|
33
|
+
const expr = new ExpressionEvaluator(
|
|
34
|
+
"((Steps.step1.output.status ?? '') == Steps.step1.output.value ? '● ' : '') + Steps.step1.output.label",
|
|
35
|
+
);
|
|
36
|
+
expect(() => expr.evaluate(parameters.getValuesMap())).toThrow();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('Single-equals (=) evaluates the chip label correctly', () => {
|
|
40
|
+
// active chip: status = value -> prefixed with the bullet
|
|
41
|
+
let expr = new ExpressionEvaluator(
|
|
42
|
+
"((Steps.step1.output.status ?? '') = Steps.step1.output.value ? '● ' : '') + Steps.step1.output.label",
|
|
43
|
+
);
|
|
44
|
+
expect(expr.evaluate(parameters.getValuesMap())).toBe('● Paid');
|
|
45
|
+
|
|
46
|
+
// inactive chip: emptyStatus (All) != value -> no prefix
|
|
47
|
+
expr = new ExpressionEvaluator(
|
|
48
|
+
"((Steps.step1.output.emptyStatus ?? '') = Steps.step1.output.value ? '● ' : '') + Steps.step1.output.label",
|
|
49
|
+
);
|
|
50
|
+
expect(expr.evaluate(parameters.getValuesMap())).toBe('Paid');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Investigating Kiran's hypothesis: does an expression that ENDS with a string
|
|
54
|
+
// literal (like the original chip label that ended in '') need a trailing space?
|
|
55
|
+
test('Expression ending in a string literal: trailing space should not matter', () => {
|
|
56
|
+
// exact shape Kiran quoted, ending in '' — no trailing space
|
|
57
|
+
let noTrail = new ExpressionEvaluator(
|
|
58
|
+
"(Steps.step1.output.status ?? '') = Steps.step1.output.value ? '● ' : ''",
|
|
59
|
+
);
|
|
60
|
+
expect(noTrail.evaluate(parameters.getValuesMap())).toBe('● ');
|
|
61
|
+
|
|
62
|
+
// same, WITH a trailing space
|
|
63
|
+
let withTrail = new ExpressionEvaluator(
|
|
64
|
+
"(Steps.step1.output.status ?? '') = Steps.step1.output.value ? '● ' : '' ",
|
|
65
|
+
);
|
|
66
|
+
expect(withTrail.evaluate(parameters.getValuesMap())).toBe('● ');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('Bare string literals at end of expression, with/without trailing space', () => {
|
|
70
|
+
expect(new ExpressionEvaluator("'hello'").evaluate(parameters.getValuesMap())).toBe('hello');
|
|
71
|
+
expect(new ExpressionEvaluator("'hello' ").evaluate(parameters.getValuesMap())).toBe('hello');
|
|
72
|
+
expect(new ExpressionEvaluator("''").evaluate(parameters.getValuesMap())).toBe('');
|
|
73
|
+
expect(new ExpressionEvaluator("'' ").evaluate(parameters.getValuesMap())).toBe('');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Kiran's platform example: a {{ }} template that expands to a bare quoted string
|
|
77
|
+
// literal followed by trailing spaces. Before the fix this evaluated to undefined,
|
|
78
|
+
// which would have made e.g. a FetchData url resolve to undefined.
|
|
79
|
+
test('Template expanding to a quoted literal with trailing spaces resolves (not undefined)', () => {
|
|
80
|
+
const expr = new ExpressionEvaluator(
|
|
81
|
+
'"api/ui/personalization/{{Steps.step1.output.label}}/{{Steps.step1.output.value}}" ',
|
|
82
|
+
);
|
|
83
|
+
expect(expr.evaluate(parameters.getValuesMap())).toBe('api/ui/personalization/Paid/PAID');
|
|
84
|
+
});
|