@borgar/fx 5.0.0 → 5.0.2

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/dist/index.js CHANGED
@@ -15,6 +15,7 @@ var REF_BEAM = "range_beam";
15
15
  var REF_TERNARY = "range_ternary";
16
16
  var REF_NAMED = "range_named";
17
17
  var REF_STRUCT = "structured";
18
+ var REF_CELL = "cell";
18
19
  var FX_PREFIX = "fx_prefix";
19
20
  var UNKNOWN = "unknown";
20
21
  var UNARY = "UnaryExpression";
@@ -34,24 +35,26 @@ var MAX_ROWS = 2 ** 20 - 1;
34
35
  // lib/mergeRefTokens.ts
35
36
  var END = "$";
36
37
  var validRunsMerge = [
37
- [REF_RANGE, ":", REF_RANGE],
38
- [REF_RANGE, ".:", REF_RANGE],
39
- [REF_RANGE, ":.", REF_RANGE],
40
- [REF_RANGE, ".:.", REF_RANGE],
38
+ [REF_CELL, ":", REF_CELL],
39
+ [REF_CELL, ".:", REF_CELL],
40
+ [REF_CELL, ":.", REF_CELL],
41
+ [REF_CELL, ".:.", REF_CELL],
41
42
  [REF_RANGE],
42
43
  [REF_BEAM],
43
44
  [REF_TERNARY],
44
- [CONTEXT, "!", REF_RANGE, ":", REF_RANGE],
45
- [CONTEXT, "!", REF_RANGE, ".:", REF_RANGE],
46
- [CONTEXT, "!", REF_RANGE, ":.", REF_RANGE],
47
- [CONTEXT, "!", REF_RANGE, ".:.", REF_RANGE],
45
+ [CONTEXT, "!", REF_CELL, ":", REF_CELL],
46
+ [CONTEXT, "!", REF_CELL, ".:", REF_CELL],
47
+ [CONTEXT, "!", REF_CELL, ":.", REF_CELL],
48
+ [CONTEXT, "!", REF_CELL, ".:.", REF_CELL],
49
+ [CONTEXT, "!", REF_CELL],
48
50
  [CONTEXT, "!", REF_RANGE],
49
51
  [CONTEXT, "!", REF_BEAM],
50
52
  [CONTEXT, "!", REF_TERNARY],
51
- [CONTEXT_QUOTE, "!", REF_RANGE, ":", REF_RANGE],
52
- [CONTEXT_QUOTE, "!", REF_RANGE, ".:", REF_RANGE],
53
- [CONTEXT_QUOTE, "!", REF_RANGE, ":.", REF_RANGE],
54
- [CONTEXT_QUOTE, "!", REF_RANGE, ".:.", REF_RANGE],
53
+ [CONTEXT_QUOTE, "!", REF_CELL, ":", REF_CELL],
54
+ [CONTEXT_QUOTE, "!", REF_CELL, ".:", REF_CELL],
55
+ [CONTEXT_QUOTE, "!", REF_CELL, ":.", REF_CELL],
56
+ [CONTEXT_QUOTE, "!", REF_CELL, ".:.", REF_CELL],
57
+ [CONTEXT_QUOTE, "!", REF_CELL],
55
58
  [CONTEXT_QUOTE, "!", REF_RANGE],
56
59
  [CONTEXT_QUOTE, "!", REF_BEAM],
57
60
  [CONTEXT_QUOTE, "!", REF_TERNARY],
@@ -83,7 +86,11 @@ var matcher = (tokens2, currNode, anchorIndex, index = 0) => {
83
86
  while (i <= max) {
84
87
  const token = tokens2[anchorIndex - i];
85
88
  if (token) {
86
- const key = token.type === OPERATOR ? token.value : token.type;
89
+ const value = token.value;
90
+ let key = token.type === OPERATOR ? value : token.type;
91
+ if (key === REF_RANGE && !value.includes(":")) {
92
+ key = REF_CELL;
93
+ }
87
94
  if (key in node) {
88
95
  node = node[key];
89
96
  i += 1;
@@ -473,7 +480,7 @@ function lexRangeA1(str, pos, options) {
473
480
  }
474
481
  }
475
482
  }
476
- if (top && canEndRange(str, preOp)) {
483
+ if (top && canEndRange(str, preOp) && str.charCodeAt(preOp) !== 33) {
477
484
  return { type: REF_RANGE, value: str.slice(pos, preOp) };
478
485
  }
479
486
  } else {
@@ -513,6 +520,7 @@ var UC_C = 67;
513
520
  var LC_C = 99;
514
521
  var PLUS = 43;
515
522
  var MINUS = 45;
523
+ var EXCL2 = 33;
516
524
  function lexR1C1Part(str, pos, isRow = false) {
517
525
  const start = pos;
518
526
  const c0 = str.charCodeAt(pos);
@@ -567,7 +575,7 @@ function lexRangeR1C1(str, pos, options) {
567
575
  p += r1;
568
576
  const c1 = lexR1C1Part(str, p);
569
577
  p += c1;
570
- if (c1 || r1) {
578
+ if ((c1 || r1) && str.charCodeAt(p) !== EXCL2) {
571
579
  const op = advRangeOp(str, p);
572
580
  const preOp = p;
573
581
  if (op) {
@@ -784,7 +792,7 @@ function parseSRange(str, pos = 0) {
784
792
  }
785
793
 
786
794
  // lib/lexers/lexStructured.ts
787
- var EXCL2 = 33;
795
+ var EXCL3 = 33;
788
796
  function lexStructured(str, pos) {
789
797
  const structData = parseSRange(str, pos);
790
798
  if (structData && structData.length) {
@@ -792,7 +800,7 @@ function lexStructured(str, pos) {
792
800
  while (isWS(str.charCodeAt(pos + i))) {
793
801
  i++;
794
802
  }
795
- if (str.charCodeAt(pos + i) !== EXCL2) {
803
+ if (str.charCodeAt(pos + i) !== EXCL3) {
796
804
  return {
797
805
  type: REF_STRUCT,
798
806
  value: structData.token
@@ -887,9 +895,9 @@ function lexNamed(str, pos) {
887
895
  }
888
896
 
889
897
  // lib/lexers/lexRefOp.ts
890
- var EXCL3 = 33;
898
+ var EXCL4 = 33;
891
899
  function lexRefOp(str, pos, opts) {
892
- if (str.charCodeAt(pos) === EXCL3) {
900
+ if (str.charCodeAt(pos) === EXCL4) {
893
901
  return { type: OPERATOR, value: str[pos] };
894
902
  }
895
903
  if (!opts.r1c1) {
@@ -903,7 +911,7 @@ function lexRefOp(str, pos, opts) {
903
911
  // lib/lexers/lexNameFuncCntx.ts
904
912
  var BR_OPEN4 = 91;
905
913
  var PAREN_OPEN = 40;
906
- var EXCL4 = 33;
914
+ var EXCL5 = 33;
907
915
  var OFFS = 32;
908
916
  var ALLOWED = new Uint8Array(180 - OFFS);
909
917
  var OK_NAME_0 = 1;
@@ -968,7 +976,7 @@ function lexNameFuncCntx(str, pos, opts) {
968
976
  } else {
969
977
  if (c === PAREN_OPEN && func) {
970
978
  return { type: FUNCTION, value: str.slice(start, pos) };
971
- } else if (c === EXCL4 && cntx) {
979
+ } else if (c === EXCL5 && cntx) {
972
980
  return { type: CONTEXT, value: str.slice(start, pos) };
973
981
  }
974
982
  return nameOrUnknown(str, s, start, pos, name);
@@ -1004,6 +1012,11 @@ var lexersRefs = [
1004
1012
  lexNamed
1005
1013
  ];
1006
1014
 
1015
+ // lib/isRCTokenValue.ts
1016
+ function isRCTokenValue(value) {
1017
+ return value === "r" || value === "R" || value === "c" || value === "C";
1018
+ }
1019
+
1007
1020
  // lib/tokenize.ts
1008
1021
  var reLetLambda = /^l(?:ambda|et)$/i;
1009
1022
  var isType = (t, type) => t && t.type === type;
@@ -1011,12 +1024,13 @@ var isTextTokenType = (tokenType) => tokenType === REF_NAMED || tokenType === FU
1011
1024
  var causesBinaryMinus = (token) => {
1012
1025
  return !isType(token, OPERATOR) || (token.value === "%" || token.value === "}" || token.value === ")" || token.value === "#");
1013
1026
  };
1014
- function fixRCNames(tokens2) {
1027
+ function fixRCNames(tokens2, r1c1Mode) {
1015
1028
  let withinCall = 0;
1016
1029
  let parenDepth = 0;
1017
1030
  let lastToken;
1018
1031
  for (const token of tokens2) {
1019
- if (token.type === OPERATOR) {
1032
+ const tokenType = token.type;
1033
+ if (tokenType === OPERATOR) {
1020
1034
  if (token.value === "(") {
1021
1035
  parenDepth++;
1022
1036
  if (lastToken.type === FUNCTION) {
@@ -1030,7 +1044,9 @@ function fixRCNames(tokens2) {
1030
1044
  withinCall = 0;
1031
1045
  }
1032
1046
  }
1033
- } else if (withinCall && token.type === UNKNOWN && /^[rc]$/.test(token.value)) {
1047
+ } else if (withinCall && tokenType === UNKNOWN && isRCTokenValue(token.value)) {
1048
+ token.type = REF_NAMED;
1049
+ } else if (withinCall && r1c1Mode && tokenType === REF_BEAM && isRCTokenValue(token.value)) {
1034
1050
  token.type = REF_NAMED;
1035
1051
  }
1036
1052
  lastToken = token;
@@ -1117,9 +1133,8 @@ function getTokens(fx, tokenHandlers, options = {}) {
1117
1133
  letOrLambda++;
1118
1134
  }
1119
1135
  }
1120
- if (token.type === UNKNOWN && token.value.length === 1) {
1121
- const valLC = token.value.toLowerCase();
1122
- unknownRC += valLC === "r" || valLC === "c" ? 1 : 0;
1136
+ if (token.value.length === 1 && (token.type === UNKNOWN || opts.r1c1 && token.type === REF_BEAM)) {
1137
+ unknownRC += isRCTokenValue(token.value) ? 1 : 0;
1123
1138
  }
1124
1139
  if (negativeNumbers && token.type === NUMBER) {
1125
1140
  const last1 = lastToken;
@@ -1138,7 +1153,7 @@ function getTokens(fx, tokenHandlers, options = {}) {
1138
1153
  pushToken(token);
1139
1154
  }
1140
1155
  if (unknownRC && letOrLambda) {
1141
- fixRCNames(tokens2);
1156
+ fixRCNames(tokens2, opts.r1c1);
1142
1157
  }
1143
1158
  for (const index of trimOps) {
1144
1159
  const before = tokens2[index - 1];
@@ -1744,6 +1759,24 @@ function parse(tokenlist, options = {}) {
1744
1759
 
1745
1760
  // lib/stringifyPrefix.ts
1746
1761
  var reBannedChars = /[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;
1762
+ var reIsRangelike = /^(R|C|RC|[A-Z]{1,3}\d{1,7})$/i;
1763
+ function needQuotes(scope, yesItDoes = 0) {
1764
+ if (yesItDoes) {
1765
+ return 1;
1766
+ }
1767
+ if (scope) {
1768
+ if (reBannedChars.test(scope)) {
1769
+ return 1;
1770
+ }
1771
+ if (reIsRangelike.test(scope)) {
1772
+ return 1;
1773
+ }
1774
+ }
1775
+ return 0;
1776
+ }
1777
+ function quotePrefix(prefix2) {
1778
+ return "'" + prefix2.replace(/'/g, "''") + "'";
1779
+ }
1747
1780
  function stringifyPrefix(ref) {
1748
1781
  let pre = "";
1749
1782
  let quote = 0;
@@ -1754,12 +1787,12 @@ function stringifyPrefix(ref) {
1754
1787
  if (scope) {
1755
1788
  const part = nth % 2 ? "[" + scope + "]" : scope;
1756
1789
  pre = part + pre;
1757
- quote += +reBannedChars.test(scope);
1790
+ quote += needQuotes(scope, quote);
1758
1791
  nth++;
1759
1792
  }
1760
1793
  }
1761
1794
  if (quote) {
1762
- pre = "'" + pre.replace(/'/g, "''") + "'";
1795
+ pre = quotePrefix(pre);
1763
1796
  }
1764
1797
  return pre ? pre + "!" : pre;
1765
1798
  }
@@ -1769,14 +1802,14 @@ function stringifyPrefixXlsx(ref) {
1769
1802
  const { workbookName, sheetName } = ref;
1770
1803
  if (workbookName) {
1771
1804
  pre += "[" + workbookName + "]";
1772
- quote += +reBannedChars.test(workbookName);
1805
+ quote += needQuotes(workbookName);
1773
1806
  }
1774
1807
  if (sheetName) {
1775
1808
  pre += sheetName;
1776
- quote += +reBannedChars.test(sheetName);
1809
+ quote += needQuotes(sheetName);
1777
1810
  }
1778
1811
  if (quote) {
1779
- pre = "'" + pre.replace(/'/g, "''") + "'";
1812
+ pre = quotePrefix(pre);
1780
1813
  }
1781
1814
  return pre ? pre + "!" : pre;
1782
1815
  }
@@ -2228,6 +2261,7 @@ function parseRefXlsx(ref, opts = {}) {
2228
2261
  }
2229
2262
 
2230
2263
  // lib/translateToR1C1.ts
2264
+ var reLetLambda2 = /^l(?:ambda|et)$/i;
2231
2265
  var calc = (abs, vX, aX) => {
2232
2266
  if (vX == null) {
2233
2267
  return null;
@@ -2256,29 +2290,53 @@ function translateTokensToR1C1(tokens2, anchorCell) {
2256
2290
  throw new Error("translateTokensToR1C1 got an invalid anchorCell: " + anchorCell);
2257
2291
  }
2258
2292
  const { top, left } = anchorRange;
2293
+ let withinCall = 0;
2294
+ let parenDepth = 0;
2259
2295
  let offsetSkew = 0;
2260
2296
  const outTokens = [];
2261
2297
  for (let token of tokens2) {
2262
2298
  const tokenType = token?.type;
2299
+ if (tokenType === OPERATOR) {
2300
+ if (token.value === "(") {
2301
+ parenDepth++;
2302
+ const lastToken = outTokens[outTokens.length - 1];
2303
+ if (lastToken && lastToken.type === FUNCTION) {
2304
+ if (reLetLambda2.test(lastToken.value)) {
2305
+ withinCall = parenDepth;
2306
+ }
2307
+ }
2308
+ } else if (token.value === ")") {
2309
+ parenDepth--;
2310
+ if (parenDepth < withinCall) {
2311
+ withinCall = 0;
2312
+ }
2313
+ }
2314
+ }
2263
2315
  if (tokenType === REF_RANGE || tokenType === REF_BEAM || tokenType === REF_TERNARY) {
2264
2316
  token = cloneToken(token);
2265
2317
  const tokenValue = token.value;
2266
2318
  const ref = quickParseA1(tokenValue);
2267
- const d = ref.range;
2268
- const range = {};
2269
- range.r0 = calc(d.$top, d.top, top);
2270
- range.r1 = calc(d.$bottom, d.bottom, top);
2271
- range.c0 = calc(d.$left, d.left, left);
2272
- range.c1 = calc(d.$right, d.right, left);
2273
- range.$r0 = d.$top;
2274
- range.$r1 = d.$bottom;
2275
- range.$c0 = d.$left;
2276
- range.$c1 = d.$right;
2277
- if (d.trim) {
2278
- range.trim = d.trim;
2319
+ if (ref) {
2320
+ const d = ref.range;
2321
+ const range = {};
2322
+ range.r0 = calc(d.$top, d.top, top);
2323
+ range.r1 = calc(d.$bottom, d.bottom, top);
2324
+ range.c0 = calc(d.$left, d.left, left);
2325
+ range.c1 = calc(d.$right, d.right, left);
2326
+ range.$r0 = d.$top;
2327
+ range.$r1 = d.$bottom;
2328
+ range.$c0 = d.$left;
2329
+ range.$c1 = d.$right;
2330
+ if (d.trim) {
2331
+ range.trim = d.trim;
2332
+ }
2333
+ ref.range = range;
2334
+ let val = stringifyR1C1RefXlsx(ref);
2335
+ if (isRCTokenValue(val) && withinCall) {
2336
+ val += "[0]";
2337
+ }
2338
+ token.value = val;
2279
2339
  }
2280
- ref.range = range;
2281
- token.value = stringifyR1C1RefXlsx(ref);
2282
2340
  if (token.loc) {
2283
2341
  token.loc[0] += offsetSkew;
2284
2342
  offsetSkew += token.value.length - tokenValue.length;
@@ -2592,44 +2650,46 @@ function translateTokensToA1(tokens2, anchorCell, options = {}) {
2592
2650
  token = cloneToken(token);
2593
2651
  const tokenValue = token.value;
2594
2652
  const ref = parseR1C1RefXlsx(tokenValue, REF_OPTS);
2595
- const d = ref.range;
2596
- const range = { top: 0, left: 0 };
2597
- const r0 = toFixed(d.r0, d.$r0, top, MAX_ROWS, wrapEdges);
2598
- const r1 = toFixed(d.r1, d.$r1, top, MAX_ROWS, wrapEdges);
2599
- if (r0 > r1) {
2600
- range.top = r1;
2601
- range.$top = d.$r1;
2602
- range.bottom = r0;
2603
- range.$bottom = d.$r0;
2604
- } else {
2605
- range.top = r0;
2606
- range.$top = d.$r0;
2607
- range.bottom = r1;
2608
- range.$bottom = d.$r1;
2609
- }
2610
- const c0 = toFixed(d.c0, d.$c0, left, MAX_COLS, wrapEdges);
2611
- const c1 = toFixed(d.c1, d.$c1, left, MAX_COLS, wrapEdges);
2612
- if (c0 > c1) {
2613
- range.left = c1;
2614
- range.$left = d.$c1;
2615
- range.right = c0;
2616
- range.$right = d.$c0;
2617
- } else {
2618
- range.left = c0;
2619
- range.$left = d.$c0;
2620
- range.right = c1;
2621
- range.$right = d.$c1;
2622
- }
2623
- if (d.trim) {
2624
- range.trim = d.trim;
2625
- }
2626
- if (isNaN(r0) || isNaN(r1) || isNaN(c0) || isNaN(c1)) {
2627
- token.type = ERROR;
2628
- token.value = "#REF!";
2629
- delete token.groupId;
2630
- } else {
2631
- ref.range = range;
2632
- token.value = stringifyA1RefXlsx(ref);
2653
+ if (ref) {
2654
+ const d = ref.range;
2655
+ const range = { top: 0, left: 0 };
2656
+ const r0 = toFixed(d.r0, d.$r0, top, MAX_ROWS, wrapEdges);
2657
+ const r1 = toFixed(d.r1, d.$r1, top, MAX_ROWS, wrapEdges);
2658
+ if (r0 > r1) {
2659
+ range.top = r1;
2660
+ range.$top = d.$r1;
2661
+ range.bottom = r0;
2662
+ range.$bottom = d.$r0;
2663
+ } else {
2664
+ range.top = r0;
2665
+ range.$top = d.$r0;
2666
+ range.bottom = r1;
2667
+ range.$bottom = d.$r1;
2668
+ }
2669
+ const c0 = toFixed(d.c0, d.$c0, left, MAX_COLS, wrapEdges);
2670
+ const c1 = toFixed(d.c1, d.$c1, left, MAX_COLS, wrapEdges);
2671
+ if (c0 > c1) {
2672
+ range.left = c1;
2673
+ range.$left = d.$c1;
2674
+ range.right = c0;
2675
+ range.$right = d.$c0;
2676
+ } else {
2677
+ range.left = c0;
2678
+ range.$left = d.$c0;
2679
+ range.right = c1;
2680
+ range.$right = d.$c1;
2681
+ }
2682
+ if (d.trim) {
2683
+ range.trim = d.trim;
2684
+ }
2685
+ if (isNaN(r0) || isNaN(r1) || isNaN(c0) || isNaN(c1)) {
2686
+ token.type = ERROR;
2687
+ token.value = "#REF!";
2688
+ delete token.groupId;
2689
+ } else {
2690
+ ref.range = range;
2691
+ token.value = stringifyA1RefXlsx(ref);
2692
+ }
2633
2693
  }
2634
2694
  if (token.loc) {
2635
2695
  token.loc[0] += offsetSkew;