@borgar/fx 4.7.1 → 4.9.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.
@@ -64,21 +64,21 @@ test('parse errors', t => {
64
64
  });
65
65
 
66
66
  test('parse ranges', t => {
67
- t.isParsed('A1', { type: 'ReferenceIdentifier', value: 'A1' });
68
- t.isParsed('A1:B2', { type: 'ReferenceIdentifier', value: 'A1:B2' });
69
- t.isParsed('A:B', { type: 'ReferenceIdentifier', value: 'A:B' });
70
- t.isParsed('1:2', { type: 'ReferenceIdentifier', value: '1:2' });
71
- t.isParsed('A1:2', { type: 'ReferenceIdentifier', value: 'A1:2' });
72
- t.isParsed('1:A2', { type: 'ReferenceIdentifier', value: '1:A2' });
73
- t.isParsed('Sheet!A1', { type: 'ReferenceIdentifier', value: 'Sheet!A1' });
74
- t.isParsed('[Workbook]Sheet!A1', { type: 'ReferenceIdentifier', value: '[Workbook]Sheet!A1' });
75
- t.isParsed('\'Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'Sheet\'!A1' });
76
- t.isParsed('\'[Workbook]Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'[Workbook]Sheet\'!A1' });
77
- t.isParsed('foo', { type: 'ReferenceIdentifier', value: 'foo' });
78
- t.isParsed('Workbook!foo', { type: 'ReferenceIdentifier', value: 'Workbook!foo' });
79
- t.isParsed('[Workbook]Sheet!foo', { type: 'ReferenceIdentifier', value: '[Workbook]Sheet!foo' });
80
- t.isParsed('\'Workbook\'!A1', { type: 'ReferenceIdentifier', value: '\'Workbook\'!A1' });
81
- t.isParsed('\'[Workbook]Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'[Workbook]Sheet\'!A1' });
67
+ t.isParsed('A1', { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' });
68
+ t.isParsed('A1:B2', { type: 'ReferenceIdentifier', value: 'A1:B2', kind: 'range' });
69
+ t.isParsed('A:B', { type: 'ReferenceIdentifier', value: 'A:B', kind: 'beam' });
70
+ t.isParsed('1:2', { type: 'ReferenceIdentifier', value: '1:2', kind: 'beam' });
71
+ t.isParsed('A1:2', { type: 'ReferenceIdentifier', value: 'A1:2', kind: 'range' });
72
+ t.isParsed('1:A2', { type: 'ReferenceIdentifier', value: '1:A2', kind: 'range' });
73
+ t.isParsed('Sheet!A1', { type: 'ReferenceIdentifier', value: 'Sheet!A1', kind: 'range' });
74
+ t.isParsed('[Workbook]Sheet!A1', { type: 'ReferenceIdentifier', value: '[Workbook]Sheet!A1', kind: 'range' });
75
+ t.isParsed('\'Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'Sheet\'!A1', kind: 'range' });
76
+ t.isParsed('\'[Workbook]Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'[Workbook]Sheet\'!A1', kind: 'range' });
77
+ t.isParsed('foo', { type: 'ReferenceIdentifier', value: 'foo', kind: 'name' });
78
+ t.isParsed('Workbook!foo', { type: 'ReferenceIdentifier', value: 'Workbook!foo', kind: 'name' });
79
+ t.isParsed('[Workbook]Sheet!foo', { type: 'ReferenceIdentifier', value: '[Workbook]Sheet!foo', kind: 'name' });
80
+ t.isParsed('\'Workbook\'!A1', { type: 'ReferenceIdentifier', value: '\'Workbook\'!A1', kind: 'range' });
81
+ t.isParsed('\'[Workbook]Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'[Workbook]Sheet\'!A1', kind: 'range' });
82
82
  t.end();
83
83
  });
84
84
 
@@ -168,10 +168,10 @@ test('parse array literals', t => {
168
168
  t.isParsed('{A1,A1:B2;A:A}', {
169
169
  type: 'ArrayExpression',
170
170
  elements: [ [
171
- { type: 'ReferenceIdentifier', value: 'A1' },
172
- { type: 'ReferenceIdentifier', value: 'A1:B2' }
171
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
172
+ { type: 'ReferenceIdentifier', value: 'A1:B2', kind: 'range' }
173
173
  ], [
174
- { type: 'ReferenceIdentifier', value: 'A:A' }
174
+ { type: 'ReferenceIdentifier', value: 'A:A', kind: 'beam' }
175
175
  ] ]
176
176
  }, { permitArrayRanges: true });
177
177
  t.isParsed('{-0.1,"foo";#NAME?,false}', {
@@ -202,8 +202,6 @@ test('parse array literals', t => {
202
202
  // ] ]
203
203
  // }, { negativeNumbers: false });
204
204
  t.isInvalidExpr('{A1}', { permitArrayRanges: false });
205
- // TODO: WHY???
206
- // t.isInvalidExpr('{-1}', { negativeNumbers: true });
207
205
  t.isInvalidExpr('{--1}', { negativeNumbers: true });
208
206
  t.isInvalidExpr('{--1}', { negativeNumbers: false });
209
207
  t.isInvalidExpr('{---1}', { negativeNumbers: true });
@@ -226,7 +224,7 @@ test('parse array literals', t => {
226
224
  { type: 'ArrayExpression', elements: [
227
225
  [ { type: 'Literal', value: 1234, raw: '1234' } ],
228
226
  [ { type: 'CallExpression', callee: { type: 'Identifier', name: 'UNIQUE' }, arguments: [
229
- { type: 'ReferenceIdentifier', value: 'A:A' }
227
+ { type: 'ReferenceIdentifier', value: 'A:A', kind: 'beam' }
230
228
  ] } ]
231
229
  ] },
232
230
  { permitArrayCalls: true });
@@ -273,16 +271,16 @@ test('parse function calls', t => {
273
271
  t.isParsed('=FOO(A1,B2)', {
274
272
  type: 'CallExpression', callee: { type: 'Identifier', name: 'FOO' },
275
273
  arguments: [
276
- { type: 'ReferenceIdentifier', value: 'A1' },
277
- { type: 'ReferenceIdentifier', value: 'B2' }
274
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
275
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
278
276
  ]
279
277
  });
280
278
  t.isParsed('=FOO((A1,B2))', {
281
279
  type: 'CallExpression', callee: { type: 'Identifier', name: 'FOO' },
282
280
  arguments: [
283
281
  { type: 'BinaryExpression', operator: ',', arguments: [
284
- { type: 'ReferenceIdentifier', value: 'A1' },
285
- { type: 'ReferenceIdentifier', value: 'B2' }
282
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
283
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
286
284
  ] }
287
285
  ]
288
286
  });
@@ -326,7 +324,7 @@ test('parse function calls', t => {
326
324
  test('parse unary operator %', t => {
327
325
  t.isParsed('A1%', {
328
326
  type: 'UnaryExpression', operator: '%',
329
- arguments: [ { type: 'ReferenceIdentifier', value: 'A1' } ]
327
+ arguments: [ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' } ]
330
328
  });
331
329
  t.isParsed('1%', {
332
330
  type: 'UnaryExpression', operator: '%',
@@ -352,7 +350,7 @@ test('parse unary operator -', t => {
352
350
  });
353
351
  t.isParsed('-A1:B2', {
354
352
  type: 'UnaryExpression', operator: '-',
355
- arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2' } ]
353
+ arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2', kind: 'range' } ]
356
354
  });
357
355
  t.isParsed('--1', {
358
356
  type: 'UnaryExpression', operator: '-',
@@ -385,7 +383,7 @@ test('parse unary operator +', t => {
385
383
  });
386
384
  t.isParsed('+A1:B2', {
387
385
  type: 'UnaryExpression', operator: '+',
388
- arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2' } ]
386
+ arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2', kind: 'range' } ]
389
387
  });
390
388
  t.isInvalidExpr('++');
391
389
  t.isInvalidExpr('+');
@@ -395,19 +393,19 @@ test('parse unary operator +', t => {
395
393
  test('parse unary operator #', t => {
396
394
  t.isParsed('D9#', {
397
395
  type: 'UnaryExpression', operator: '#',
398
- arguments: [ { type: 'ReferenceIdentifier', value: 'D9' } ]
396
+ arguments: [ { type: 'ReferenceIdentifier', value: 'D9', kind: 'range' } ]
399
397
  });
400
398
  t.isParsed('A1:B2#', { // this parses but is a runtime error in Excel
401
399
  type: 'UnaryExpression', operator: '#',
402
- arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2' } ]
400
+ arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2', kind: 'range' } ]
403
401
  });
404
402
  t.isParsed('(A1):(B2)#', { // this parses but is a runtime error in Excel
405
403
  type: 'UnaryExpression', operator: '#',
406
404
  arguments: [ {
407
405
  type: 'BinaryExpression', operator: ':',
408
406
  arguments: [
409
- { type: 'ReferenceIdentifier', value: 'A1' },
410
- { type: 'ReferenceIdentifier', value: 'B2' }
407
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
408
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
411
409
  ] } ]
412
410
  });
413
411
  t.isParsed('(A1,B2)#', {
@@ -415,8 +413,8 @@ test('parse unary operator #', t => {
415
413
  arguments: [ {
416
414
  type: 'BinaryExpression', operator: ',',
417
415
  arguments: [
418
- { type: 'ReferenceIdentifier', value: 'A1' },
419
- { type: 'ReferenceIdentifier', value: 'B2' }
416
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
417
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
420
418
  ] } ]
421
419
  });
422
420
  t.isParsed('(A1 B2)#', {
@@ -424,8 +422,8 @@ test('parse unary operator #', t => {
424
422
  arguments: [ {
425
423
  type: 'BinaryExpression', operator: ' ',
426
424
  arguments: [
427
- { type: 'ReferenceIdentifier', value: 'A1' },
428
- { type: 'ReferenceIdentifier', value: 'B2' }
425
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
426
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
429
427
  ] } ]
430
428
  });
431
429
  t.isParsed('#REF!#', {
@@ -461,11 +459,11 @@ test('parse unary operator @', t => {
461
459
  });
462
460
  t.isParsed('@D9', {
463
461
  type: 'UnaryExpression', operator: '@',
464
- arguments: [ { type: 'ReferenceIdentifier', value: 'D9' } ]
462
+ arguments: [ { type: 'ReferenceIdentifier', value: 'D9', kind: 'range' } ]
465
463
  });
466
464
  t.isParsed('@A1:B2', {
467
465
  type: 'UnaryExpression', operator: '@',
468
- arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2' } ]
466
+ arguments: [ { type: 'ReferenceIdentifier', value: 'A1:B2', kind: 'range' } ]
469
467
  });
470
468
  t.isParsed('@#REF!', {
471
469
  type: 'UnaryExpression', operator: '@',
@@ -573,26 +571,26 @@ test('parse unary operator @', t => {
573
571
  t.isParsed(`named1${op}named2`, {
574
572
  type: 'BinaryExpression', operator: op,
575
573
  arguments: [
576
- { type: 'ReferenceIdentifier', value: 'named1' },
577
- { type: 'ReferenceIdentifier', value: 'named2' }
574
+ { type: 'ReferenceIdentifier', value: 'named1', kind: 'name' },
575
+ { type: 'ReferenceIdentifier', value: 'named2', kind: 'name' }
578
576
  ] });
579
577
  t.isParsed(`A1${op}named2`, {
580
578
  type: 'BinaryExpression', operator: op,
581
579
  arguments: [
582
- { type: 'ReferenceIdentifier', value: 'A1' },
583
- { type: 'ReferenceIdentifier', value: 'named2' }
580
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
581
+ { type: 'ReferenceIdentifier', value: 'named2', kind: 'name' }
584
582
  ] });
585
583
  t.isParsed(`named1${op}B2`, {
586
584
  type: 'BinaryExpression', operator: op,
587
585
  arguments: [
588
- { type: 'ReferenceIdentifier', value: 'named1' },
589
- { type: 'ReferenceIdentifier', value: 'B2' }
586
+ { type: 'ReferenceIdentifier', value: 'named1', kind: 'name' },
587
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
590
588
  ] });
591
589
  t.isParsed(`(A1)${op}(B2)`, {
592
590
  type: 'BinaryExpression', operator: op,
593
591
  arguments: [
594
- { type: 'ReferenceIdentifier', value: 'A1' },
595
- { type: 'ReferenceIdentifier', value: 'B2' }
592
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
593
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
596
594
  ] });
597
595
  t.isInvalidExpr(`A1${op}0`);
598
596
  t.isInvalidExpr(`0${op}A1`);
@@ -603,14 +601,14 @@ test('parse unary operator @', t => {
603
601
  t.isParsed(`A1${op}#REF!`, {
604
602
  type: 'BinaryExpression', operator: op,
605
603
  arguments: [
606
- { type: 'ReferenceIdentifier', value: 'A1' },
604
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
607
605
  { type: 'ErrorLiteral', value: '#REF!', raw: '#REF!' }
608
606
  ] });
609
607
  t.isParsed(`#REF!${op}B2`, {
610
608
  type: 'BinaryExpression', operator: op,
611
609
  arguments: [
612
610
  { type: 'ErrorLiteral', value: '#REF!', raw: '#REF!' },
613
- { type: 'ReferenceIdentifier', value: 'B2' }
611
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
614
612
  ] });
615
613
  t.isInvalidExpr(`A1${op}#NAME?`);
616
614
  t.isInvalidExpr(`A1${op}#VALUE!`);
@@ -622,19 +620,19 @@ test('parse unary operator @', t => {
622
620
  arguments: [
623
621
  { type: 'BinaryExpression', operator: ',',
624
622
  arguments: [
625
- { type: 'ReferenceIdentifier', value: 'A1' },
626
- { type: 'ReferenceIdentifier', value: 'B2' }
623
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
624
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
627
625
  ] },
628
- { type: 'ReferenceIdentifier', value: 'C3' }
626
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' }
629
627
  ] });
630
628
  t.isParsed(`C3${op}(A1,B2)`, {
631
629
  type: 'BinaryExpression', operator: op,
632
630
  arguments: [
633
- { type: 'ReferenceIdentifier', value: 'C3' },
631
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' },
634
632
  { type: 'BinaryExpression', operator: ',',
635
633
  arguments: [
636
- { type: 'ReferenceIdentifier', value: 'A1' },
637
- { type: 'ReferenceIdentifier', value: 'B2' }
634
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
635
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
638
636
  ] }
639
637
  ] });
640
638
  // intersection ops
@@ -643,19 +641,19 @@ test('parse unary operator @', t => {
643
641
  arguments: [
644
642
  { type: 'BinaryExpression', operator: ' ',
645
643
  arguments: [
646
- { type: 'ReferenceIdentifier', value: 'A1' },
647
- { type: 'ReferenceIdentifier', value: 'B2' }
644
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
645
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
648
646
  ] },
649
- { type: 'ReferenceIdentifier', value: 'C3' }
647
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' }
650
648
  ] });
651
649
  t.isParsed(`C3${op}(A1 B2)`, {
652
650
  type: 'BinaryExpression', operator: op,
653
651
  arguments: [
654
- { type: 'ReferenceIdentifier', value: 'C3' },
652
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' },
655
653
  { type: 'BinaryExpression', operator: ' ',
656
654
  arguments: [
657
- { type: 'ReferenceIdentifier', value: 'A1' },
658
- { type: 'ReferenceIdentifier', value: 'B2' }
655
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
656
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
659
657
  ] }
660
658
  ] });
661
659
  // join ops
@@ -664,21 +662,27 @@ test('parse unary operator @', t => {
664
662
  arguments: [
665
663
  { type: 'BinaryExpression', operator: ':',
666
664
  arguments: [
667
- { type: 'ReferenceIdentifier', value: 'A1' },
668
- { type: 'ReferenceIdentifier', value: 'B2' }
665
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
666
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
669
667
  ] },
670
- { type: 'ReferenceIdentifier', value: 'C3' }
668
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' }
671
669
  ] });
672
670
  t.isParsed(`C3${op}(A1:(B2))`, {
673
671
  type: 'BinaryExpression', operator: op,
674
672
  arguments: [
675
- { type: 'ReferenceIdentifier', value: 'C3' },
673
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' },
676
674
  { type: 'BinaryExpression', operator: ':',
677
675
  arguments: [
678
- { type: 'ReferenceIdentifier', value: 'A1' },
679
- { type: 'ReferenceIdentifier', value: 'B2' }
676
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
677
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
680
678
  ] }
681
679
  ] });
680
+ t.isParsed(`A1 ${op} B2`, {
681
+ type: 'BinaryExpression', operator: op,
682
+ arguments: [
683
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
684
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
685
+ ] });
682
686
  // ref calls
683
687
  ([
684
688
  [ 'ANCHORARRAY', true ],
@@ -688,8 +692,8 @@ test('parse unary operator @', t => {
688
692
  [ 'IFS', true ],
689
693
  [ 'INDEX', true ],
690
694
  [ 'INDIRECT', true ],
691
- [ 'LAMBDA', true ],
692
- [ 'LET', true ],
695
+ // [ 'LAMBDA', true ],
696
+ // [ 'LET', true ],
693
697
  [ 'OFFSET', true ],
694
698
  [ 'REDUCE', true ],
695
699
  [ 'SINGLE', true ],
@@ -708,12 +712,12 @@ test('parse unary operator @', t => {
708
712
  type: 'BinaryExpression', operator: op,
709
713
  arguments: [
710
714
  { type: 'CallExpression', callee: { type: 'Identifier', name: funcName }, arguments: [] },
711
- { type: 'ReferenceIdentifier', value: 'C3' }
715
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' }
712
716
  ] });
713
717
  t.isParsed(`C3${op}${funcName}()`, {
714
718
  type: 'BinaryExpression', operator: op,
715
719
  arguments: [
716
- { type: 'ReferenceIdentifier', value: 'C3' },
720
+ { type: 'ReferenceIdentifier', value: 'C3', kind: 'range' },
717
721
  { type: 'CallExpression', callee: { type: 'Identifier', name: funcName }, arguments: [] }
718
722
  ] });
719
723
  }
@@ -731,15 +735,15 @@ test('union operators are normalized', t => {
731
735
  t.isParsed('A1 B2', {
732
736
  type: 'BinaryExpression', operator: ' ',
733
737
  arguments: [
734
- { type: 'ReferenceIdentifier', value: 'A1' },
735
- { type: 'ReferenceIdentifier', value: 'B2' }
738
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
739
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
736
740
  ]
737
741
  });
738
742
  t.isParsed('A1 B2', {
739
743
  type: 'BinaryExpression', operator: ' ',
740
744
  arguments: [
741
- { type: 'ReferenceIdentifier', value: 'A1' },
742
- { type: 'ReferenceIdentifier', value: 'B2' }
745
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
746
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
743
747
  ]
744
748
  });
745
749
  t.end();
@@ -768,7 +772,7 @@ test('position information is correct', t => {
768
772
  );
769
773
  t.isParsed(
770
774
  '=Sheet1!A1:B2',
771
- { type: 'ReferenceIdentifier', value: 'Sheet1!A1:B2', loc: [ 1, 13 ] },
775
+ { type: 'ReferenceIdentifier', value: 'Sheet1!A1:B2', kind: 'range', loc: [ 1, 13 ] },
772
776
  { withLocation: true }
773
777
  );
774
778
  t.isParsed(
@@ -780,7 +784,7 @@ test('position information is correct', t => {
780
784
  t.isParsed(
781
785
  '=-A1',
782
786
  { type: 'UnaryExpression', loc: [ 1, 4 ], operator: '-', arguments: [
783
- { type: 'ReferenceIdentifier', value: 'A1', loc: [ 2, 4 ] }
787
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range', loc: [ 2, 4 ] }
784
788
  ] },
785
789
  { withLocation: true }
786
790
  );
@@ -809,8 +813,8 @@ test('position information is correct', t => {
809
813
  t.isParsed(
810
814
  '=(A1 B2)',
811
815
  { type: 'BinaryExpression', loc: [ 2, 7 ], operator: ' ', arguments: [
812
- { type: 'ReferenceIdentifier', value: 'A1', loc: [ 2, 4 ] },
813
- { type: 'ReferenceIdentifier', value: 'B2', loc: [ 5, 7 ] }
816
+ { type: 'ReferenceIdentifier', value: 'A1', kind: 'range', loc: [ 2, 4 ] },
817
+ { type: 'ReferenceIdentifier', value: 'B2', kind: 'range', loc: [ 5, 7 ] }
814
818
  ] },
815
819
  { withLocation: true }
816
820
  );
@@ -844,20 +848,20 @@ test('does not tolerate unterminated tokens', t => {
844
848
  { type: 'CallExpression', callee: { type: 'Identifier', name: 'SORT' },
845
849
  arguments: [
846
850
  { type: 'ArrayExpression', elements: [
847
- [ { type: 'ReferenceIdentifier', value: 'A:A' },
848
- { type: 'ReferenceIdentifier', value: 'B:B' } ]
851
+ [ { type: 'ReferenceIdentifier', value: 'A:A', kind: 'beam' },
852
+ { type: 'ReferenceIdentifier', value: 'B:B', kind: 'beam' } ]
849
853
  ] }
850
854
  ] },
851
855
  { permitArrayRanges: true });
852
856
  // whitespace in arguments
853
857
  t.isParsed('=A2:A5=XLOOKUP(B1,C:C, D:D)',
854
858
  { type: 'BinaryExpression', operator: '=', arguments: [
855
- { type: 'ReferenceIdentifier', value: 'A2:A5' },
859
+ { type: 'ReferenceIdentifier', value: 'A2:A5', kind: 'range' },
856
860
  { type: 'CallExpression', callee: { type: 'Identifier', name: 'XLOOKUP' },
857
861
  arguments: [
858
- { type: 'ReferenceIdentifier', value: 'B1' },
859
- { type: 'ReferenceIdentifier', value: 'C:C' },
860
- { type: 'ReferenceIdentifier', value: 'D:D' }
862
+ { type: 'ReferenceIdentifier', value: 'B1', kind: 'range' },
863
+ { type: 'ReferenceIdentifier', value: 'C:C', kind: 'beam' },
864
+ { type: 'ReferenceIdentifier', value: 'D:D', kind: 'beam' }
861
865
  ] }
862
866
  ] },
863
867
  { permitArrayRanges: true });
@@ -865,14 +869,14 @@ test('does not tolerate unterminated tokens', t => {
865
869
  t.isParsed('=SUM(12 , B:B)',
866
870
  { type: 'CallExpression', callee: { type: 'Identifier', name: 'SUM' }, arguments: [
867
871
  { type: 'Literal', value: 12, raw: '12' },
868
- { type: 'ReferenceIdentifier', value: 'B:B' }
872
+ { type: 'ReferenceIdentifier', value: 'B:B', kind: 'beam' }
869
873
  ] },
870
874
  { permitArrayCalls: true });
871
875
  // whitespace tailing operator
872
876
  t.isParsed('=A:A= C1',
873
877
  { type: 'BinaryExpression', operator: '=', arguments: [
874
- { type: 'ReferenceIdentifier', value: 'A:A' },
875
- { type: 'ReferenceIdentifier', value: 'C1' }
878
+ { type: 'ReferenceIdentifier', value: 'A:A', kind: 'beam' },
879
+ { type: 'ReferenceIdentifier', value: 'C1', kind: 'range' }
876
880
  ] },
877
881
  { permitArrayCalls: true });
878
882
  t.end();
@@ -883,10 +887,297 @@ test('parser can permit xlsx mode references', t => {
883
887
  t.isParsed('=SUM([Workbook.xlsx]!A1+[Workbook.xlsx]!Table1[#Data])',
884
888
  { type: 'CallExpression', callee: { type: 'Identifier', name: 'SUM' }, arguments: [
885
889
  { type: 'BinaryExpression', operator: '+', arguments: [
886
- { type: 'ReferenceIdentifier', value: '[Workbook.xlsx]!A1' },
887
- { type: 'ReferenceIdentifier', value: '[Workbook.xlsx]!Table1[#Data]' }
890
+ { type: 'ReferenceIdentifier', value: '[Workbook.xlsx]!A1', kind: 'range' },
891
+ { type: 'ReferenceIdentifier', value: '[Workbook.xlsx]!Table1[#Data]', kind: 'table' }
888
892
  ] }
889
893
  ] },
890
894
  { xlsx: true });
891
895
  t.end();
892
896
  });
897
+
898
+ test('parser supports LAMBDA expressions', t => {
899
+ t.isInvalidExpr('LAMBDA(,)');
900
+ t.isInvalidExpr('LAMBDA(a,)');
901
+ t.isInvalidExpr('LAMBDA(a,,)');
902
+ t.isInvalidExpr('=LAMBDA(1,1)');
903
+ t.isInvalidExpr('=LAMBDA(a,1,a)');
904
+ t.isInvalidExpr('=LAMBDA(a,A,1)');
905
+ t.isInvalidExpr('=LAMBDA(a,a,1)');
906
+ t.isInvalidExpr('=LAMBDA(A1,B1,1)');
907
+ t.isParsed('=LAMBDA()', {
908
+ type: 'LambdaExpression',
909
+ params: [],
910
+ body: null
911
+ });
912
+ t.isParsed('=LAMBDA(1)', {
913
+ type: 'LambdaExpression',
914
+ params: [],
915
+ body: {
916
+ type: 'Literal',
917
+ value: 1,
918
+ raw: '1'
919
+ }
920
+ });
921
+ t.isParsed('=LAMBDA(1+1)', {
922
+ type: 'LambdaExpression',
923
+ params: [],
924
+ body: {
925
+ type: 'BinaryExpression',
926
+ operator: '+',
927
+ arguments: [
928
+ { type: 'Literal', value: 1, raw: '1' },
929
+ { type: 'Literal', value: 1, raw: '1' }
930
+ ]
931
+ }
932
+ });
933
+ t.isParsed('=LAMBDA(a,1)', {
934
+ type: 'LambdaExpression',
935
+ body: { type: 'Literal', value: 1, raw: '1' },
936
+ params: [
937
+ { type: 'Identifier', name: 'a' }
938
+ ]
939
+ });
940
+ t.isParsed('=LAMBDA(a,b,1)', {
941
+ type: 'LambdaExpression',
942
+ body: { type: 'Literal', value: 1, raw: '1' },
943
+ params: [
944
+ { type: 'Identifier', name: 'a' },
945
+ { type: 'Identifier', name: 'b' }
946
+ ]
947
+ });
948
+ t.isParsed('=LAMBDA(a,b,1)', {
949
+ type: 'LambdaExpression',
950
+ body: { type: 'Literal', value: 1, raw: '1' },
951
+ params: [
952
+ { type: 'Identifier', name: 'a' },
953
+ { type: 'Identifier', name: 'b' }
954
+ ]
955
+ });
956
+ t.isParsed('=lambda(a,b,a*b)', {
957
+ type: 'LambdaExpression',
958
+ body: {
959
+ type: 'BinaryExpression',
960
+ operator: '*',
961
+ arguments: [
962
+ { type: 'ReferenceIdentifier', value: 'a', kind: 'name' },
963
+ { type: 'ReferenceIdentifier', value: 'b', kind: 'name' }
964
+ ]
965
+ },
966
+ params: [
967
+ { type: 'Identifier', name: 'a' },
968
+ { type: 'Identifier', name: 'b' }
969
+ ]
970
+ });
971
+ t.isParsed('=lambda(a,b,a*b)', {
972
+ type: 'LambdaExpression',
973
+ body: {
974
+ type: 'BinaryExpression',
975
+ operator: '*',
976
+ arguments: [
977
+ { type: 'ReferenceIdentifier', value: 'a', kind: 'name' },
978
+ { type: 'ReferenceIdentifier', value: 'b', kind: 'name' }
979
+ ]
980
+ },
981
+ params: [
982
+ { type: 'Identifier', name: 'a' },
983
+ { type: 'Identifier', name: 'b' }
984
+ ]
985
+ });
986
+ t.isParsed('=lambda( a , b , a b )', {
987
+ type: 'LambdaExpression',
988
+ body: {
989
+ type: 'BinaryExpression',
990
+ operator: ' ',
991
+ arguments: [
992
+ { type: 'ReferenceIdentifier', value: 'a', kind: 'name' },
993
+ { type: 'ReferenceIdentifier', value: 'b', kind: 'name' }
994
+ ]
995
+ },
996
+ params: [
997
+ { type: 'Identifier', name: 'a' },
998
+ { type: 'Identifier', name: 'b' }
999
+ ]
1000
+ });
1001
+ // r and c are forbidden as names, but should work here
1002
+ t.isParsed('=LAMBDA(r,c,r*c)', {
1003
+ type: 'LambdaExpression',
1004
+ body: {
1005
+ type: 'BinaryExpression',
1006
+ operator: '*',
1007
+ arguments: [
1008
+ { type: 'ReferenceIdentifier', value: 'r', kind: 'name' },
1009
+ { type: 'ReferenceIdentifier', value: 'c', kind: 'name' }
1010
+ ]
1011
+ },
1012
+ params: [
1013
+ { type: 'Identifier', name: 'r' },
1014
+ { type: 'Identifier', name: 'c' }
1015
+ ]
1016
+ });
1017
+ t.end();
1018
+ });
1019
+
1020
+ test('parser allows calling refs, lambda, let, and call expressions', t => {
1021
+ t.isInvalidExpr('1()');
1022
+ t.isInvalidExpr('"str"()');
1023
+ t.isInvalidExpr('#VALUE!()');
1024
+ t.isInvalidExpr('foo%()');
1025
+ t.isInvalidExpr('foo ()');
1026
+
1027
+ t.isParsed('=lambda()()', {
1028
+ type: 'CallExpression',
1029
+ callee: {
1030
+ type: 'LambdaExpression',
1031
+ params: [],
1032
+ body: null
1033
+ },
1034
+ arguments: []
1035
+ });
1036
+ t.isParsed('=lambda(1)(1)', {
1037
+ type: 'CallExpression',
1038
+ callee: {
1039
+ type: 'LambdaExpression',
1040
+ params: [],
1041
+ body: { type: 'Literal', value: 1, raw: '1' }
1042
+ },
1043
+ arguments: [
1044
+ { type: 'Literal', value: 1, raw: '1' }
1045
+ ]
1046
+ });
1047
+ t.isParsed('=FOO()()', {
1048
+ type: 'CallExpression',
1049
+ callee: {
1050
+ type: 'CallExpression',
1051
+ callee: { type: 'Identifier', name: 'FOO' },
1052
+ arguments: []
1053
+ },
1054
+ arguments: []
1055
+ });
1056
+ t.isParsed('=(A1)()', {
1057
+ type: 'CallExpression',
1058
+ callee: { type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
1059
+ arguments: []
1060
+ });
1061
+ t.isParsed('=LET(a,1,a)()', {
1062
+ type: 'CallExpression',
1063
+ callee: {
1064
+ type: 'LetExpression',
1065
+ declarations: [
1066
+ { type: 'LetDeclarator',
1067
+ id: { type: 'Identifier', name: 'a' },
1068
+ init: { type: 'Literal', value: 1, raw: '1' }
1069
+ }
1070
+ ],
1071
+ body: { type: 'ReferenceIdentifier', value: 'a', kind: 'name' }
1072
+ },
1073
+ arguments: []
1074
+ });
1075
+ t.isParsed('=#REF!()', {
1076
+ type: 'CallExpression',
1077
+ callee: {
1078
+ type: 'ErrorLiteral',
1079
+ value: '#REF!',
1080
+ raw: '#REF!'
1081
+ },
1082
+ arguments: []
1083
+ });
1084
+ // this is allowed because in Excel: `foo#()` is really `ANCHORARRAY(foo)()`
1085
+ t.isParsed('foo#()', {
1086
+ type: 'CallExpression',
1087
+ callee: {
1088
+ type: 'UnaryExpression', operator: '#', arguments: [
1089
+ { type: 'ReferenceIdentifier', value: 'foo', kind: 'name' }
1090
+ ]
1091
+ },
1092
+ arguments: []
1093
+ });
1094
+ // `@1()` works in Excel because it is really `SINGLE(foo)()`
1095
+ t.end();
1096
+ });
1097
+
1098
+ test('parser supports LET expressions', t => {
1099
+ // Argument is not a name
1100
+ t.isInvalidExpr('LET(,)');
1101
+ t.isInvalidExpr('LET(1,a,1)');
1102
+ // Unexpected end of arguments
1103
+ t.isInvalidExpr('LET()');
1104
+ t.isInvalidExpr('LET(a,b)');
1105
+ t.isInvalidExpr('LET(a,)');
1106
+ // Unexpected argument following calculation
1107
+ t.isInvalidExpr('LET(a,a,1,1)');
1108
+ t.isInvalidExpr('LET(a,a,1,a)');
1109
+ t.isInvalidExpr('LET(a,1,b,1,c,1,a1+b,1)');
1110
+ // Duplicate name: a
1111
+ t.isInvalidExpr('LET(a,1,a,1,1)');
1112
+ t.isInvalidExpr('LET(a,1,A,1,1)');
1113
+
1114
+ t.isParsed('=LET(a,1,)', {
1115
+ type: 'LetExpression',
1116
+ declarations: [
1117
+ {
1118
+ type: 'LetDeclarator',
1119
+ id: { type: 'Identifier', name: 'a' },
1120
+ init: { type: 'Literal', value: 1, raw: '1' }
1121
+ }
1122
+ ],
1123
+ body: null
1124
+ });
1125
+ t.isParsed('=LET(a,1,a)', {
1126
+ type: 'LetExpression',
1127
+ declarations: [
1128
+ {
1129
+ type: 'LetDeclarator',
1130
+ id: { type: 'Identifier', name: 'a' },
1131
+ init: { type: 'Literal', value: 1, raw: '1' }
1132
+ }
1133
+ ],
1134
+ body: { type: 'ReferenceIdentifier', value: 'a', kind: 'name' }
1135
+ });
1136
+ t.isParsed('=LET(a,1,b,1,c,1,a+b*c)', {
1137
+ type: 'LetExpression',
1138
+ declarations: [
1139
+ { type: 'LetDeclarator',
1140
+ id: { type: 'Identifier', name: 'a' },
1141
+ init: { type: 'Literal', value: 1, raw: '1' } },
1142
+ { type: 'LetDeclarator',
1143
+ id: { type: 'Identifier', name: 'b' },
1144
+ init: { type: 'Literal', value: 1, raw: '1' } },
1145
+ { type: 'LetDeclarator',
1146
+ id: { type: 'Identifier', name: 'c' },
1147
+ init: { type: 'Literal', value: 1, raw: '1' } }
1148
+ ],
1149
+ body: {
1150
+ type: 'BinaryExpression', operator: '+', arguments: [
1151
+ { type: 'ReferenceIdentifier', value: 'a', kind: 'name' },
1152
+ { type: 'BinaryExpression', operator: '*', arguments: [
1153
+ { type: 'ReferenceIdentifier', value: 'b', kind: 'name' },
1154
+ { type: 'ReferenceIdentifier', value: 'c', kind: 'name' }
1155
+ ] }
1156
+ ]
1157
+ }
1158
+ });
1159
+ // r and c are forbidden as names, but should work here
1160
+ t.isParsed('LET(r,1,c,1,r*c)', {
1161
+ type: 'LetExpression',
1162
+ declarations: [
1163
+ { type: 'LetDeclarator',
1164
+ id: { type: 'Identifier', name: 'r' },
1165
+ init: { type: 'Literal', value: 1, raw: '1' }
1166
+ },
1167
+ {
1168
+ type: 'LetDeclarator',
1169
+ id: { type: 'Identifier', name: 'c' },
1170
+ init: { type: 'Literal', value: 1, raw: '1' }
1171
+ }
1172
+ ],
1173
+ body: {
1174
+ type: 'BinaryExpression',
1175
+ operator: '*',
1176
+ arguments: [
1177
+ { type: 'ReferenceIdentifier', value: 'r', kind: 'name' },
1178
+ { type: 'ReferenceIdentifier', value: 'c', kind: 'name' }
1179
+ ]
1180
+ }
1181
+ });
1182
+ t.end();
1183
+ });