@fincity/kirun-js 3.8.0 → 3.14.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.
@@ -256,6 +256,133 @@ describe('ExpressionEvaluator with Bracket Notation', () => {
256
256
  });
257
257
  });
258
258
 
259
+ // Keys whose characters collide with operators. `http-equiv` is the real
260
+ // case: it is one of the four attributes a `properties.metas.<uid>` entry
261
+ // can carry in an app definition, and a hyphen is also subtraction.
262
+ describe('Keys containing operator characters', () => {
263
+ beforeEach(() => {
264
+ testData.obj['key-with-hyphen'] = 'hyphenValue';
265
+ testData.obj['key with space'] = 'spaceValue';
266
+ testData.obj['key+plus'] = 'plusValue';
267
+ testData.obj['key:colon'] = 'colonValue';
268
+ testData.obj['key/slash'] = 'slashValue';
269
+ testData.obj['a-b'] = 'literalAMinusB';
270
+ testData.obj.a = 10;
271
+ testData.obj.b = 3;
272
+ testData.metas = { m1: { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' } };
273
+ testData.k = 'm1';
274
+ });
275
+
276
+ test('hyphen in a double-quoted key', () => {
277
+ expect(
278
+ new ExpressionEvaluator('Context.obj["key-with-hyphen"]').evaluate(evaluatorMap),
279
+ ).toBe('hyphenValue');
280
+ });
281
+
282
+ test('hyphen in a single-quoted key', () => {
283
+ expect(
284
+ new ExpressionEvaluator("Context.obj['key-with-hyphen']").evaluate(evaluatorMap),
285
+ ).toBe('hyphenValue');
286
+ });
287
+
288
+ test('http-equiv, the app definition meta attribute', () => {
289
+ expect(
290
+ new ExpressionEvaluator('Context.metas.m1["http-equiv"]').evaluate(evaluatorMap),
291
+ ).toBe('X-UA-Compatible');
292
+ });
293
+
294
+ test('space, plus, colon and slash in a key', () => {
295
+ expect(
296
+ new ExpressionEvaluator('Context.obj["key with space"]').evaluate(evaluatorMap),
297
+ ).toBe('spaceValue');
298
+ expect(new ExpressionEvaluator('Context.obj["key+plus"]').evaluate(evaluatorMap)).toBe(
299
+ 'plusValue',
300
+ );
301
+ expect(new ExpressionEvaluator('Context.obj["key:colon"]').evaluate(evaluatorMap)).toBe(
302
+ 'colonValue',
303
+ );
304
+ expect(new ExpressionEvaluator('Context.obj["key/slash"]').evaluate(evaluatorMap)).toBe(
305
+ 'slashValue',
306
+ );
307
+ });
308
+
309
+ test('a quoted key wins over the arithmetic it looks like', () => {
310
+ expect(new ExpressionEvaluator('Context.obj["a-b"]').evaluate(evaluatorMap)).toBe(
311
+ 'literalAMinusB',
312
+ );
313
+ });
314
+
315
+ test('the SAME key unquoted is arithmetic, and throws', () => {
316
+ expect(() =>
317
+ new ExpressionEvaluator('Context.obj.key-with-hyphen').evaluate(evaluatorMap),
318
+ ).toThrow();
319
+ expect(() =>
320
+ new ExpressionEvaluator('Context.metas.m1.http-equiv').evaluate(evaluatorMap),
321
+ ).toThrow();
322
+ });
323
+
324
+ test('chained brackets, both keys hyphenated or dotted', () => {
325
+ expect(
326
+ new ExpressionEvaluator("Context.metas['m1']['http-equiv']").evaluate(evaluatorMap),
327
+ ).toBe('X-UA-Compatible');
328
+ });
329
+
330
+ test('a variable key resolves, including into a hyphenated leaf', () => {
331
+ expect(
332
+ new ExpressionEvaluator('Context.metas[Context.k].content').evaluate(evaluatorMap),
333
+ ).toBe('IE=edge');
334
+ expect(
335
+ new ExpressionEvaluator("Context.metas[Context.k]['http-equiv']").evaluate(
336
+ evaluatorMap,
337
+ ),
338
+ ).toBe('X-UA-Compatible');
339
+ });
340
+
341
+ // LIMITATION, asserted so a fix shows up as a failing test rather than
342
+ // going unnoticed: a bracket segment is a literal or a token path, never
343
+ // an expression. A concatenation inside brackets is taken as the key
344
+ // text itself and silently misses, with no error.
345
+ test('an expression inside brackets is NOT evaluated (documented gap)', () => {
346
+ expect(
347
+ new ExpressionEvaluator("Context.metas['m' + '1'].content").evaluate(evaluatorMap),
348
+ ).toBeUndefined();
349
+ });
350
+ });
351
+
352
+ // A token whose FIRST separator is a bracket used to match no extractor at
353
+ // all: the prefix is taken as the text up to the first dot, so `Context[0]`
354
+ // produced an empty prefix and fell through to the literal extractor, which
355
+ // throws. In the UI that throw reached the root error boundary and replaced
356
+ // the whole page with an error card. `Parent[0]` was the case that surfaced
357
+ // it, from a repeater bound to ObjectEntries output ([key, value] pairs),
358
+ // but it was never Parent-specific.
359
+ describe('Root level bracket access', () => {
360
+ test('numeric index directly on the extractor root', () => {
361
+ const arr: any = ['zero', 'one', 'two'];
362
+ const map = new Map([['Context.', new TestExtractor(arr)]]);
363
+ expect(new ExpressionEvaluator('Context[0]').evaluate(map)).toBe('zero');
364
+ expect(new ExpressionEvaluator('Context[2]').evaluate(map)).toBe('two');
365
+ });
366
+
367
+ test('the dotted form keeps working', () => {
368
+ const arr: any = ['zero', 'one', 'two'];
369
+ const map = new Map([['Context.', new TestExtractor(arr)]]);
370
+ expect(new ExpressionEvaluator('Context.0').evaluate(map)).toBe('zero');
371
+ });
372
+
373
+ test('quoted key directly on the extractor root', () => {
374
+ const map = new Map([['Context.', new TestExtractor({ 'a.b': 'dotted', plain: 'p' })]]);
375
+ expect(new ExpressionEvaluator('Context["a.b"]').evaluate(map)).toBe('dotted');
376
+ expect(new ExpressionEvaluator('Context["plain"]').evaluate(map)).toBe('p');
377
+ expect(new ExpressionEvaluator("Context['plain']").evaluate(map)).toBe('p');
378
+ });
379
+
380
+ test('a bracket after a dotted path is untouched', () => {
381
+ const map = new Map([['Context.', new TestExtractor({ arr: [1, 2, 3] })]]);
382
+ expect(new ExpressionEvaluator('Context.arr[1]').evaluate(map)).toBe(2);
383
+ });
384
+ });
385
+
259
386
  describe('Edge cases', () => {
260
387
  test('should handle property with multiple dots', () => {
261
388
  testData.obj['a.b.c.d'] = 'deepValue';