@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.cjs CHANGED
@@ -84,6 +84,7 @@ var REF_BEAM = "range_beam";
84
84
  var REF_TERNARY = "range_ternary";
85
85
  var REF_NAMED = "range_named";
86
86
  var REF_STRUCT = "structured";
87
+ var REF_CELL = "cell";
87
88
  var FX_PREFIX = "fx_prefix";
88
89
  var UNKNOWN = "unknown";
89
90
  var UNARY = "UnaryExpression";
@@ -103,24 +104,26 @@ var MAX_ROWS = 2 ** 20 - 1;
103
104
  // lib/mergeRefTokens.ts
104
105
  var END = "$";
105
106
  var validRunsMerge = [
106
- [REF_RANGE, ":", REF_RANGE],
107
- [REF_RANGE, ".:", REF_RANGE],
108
- [REF_RANGE, ":.", REF_RANGE],
109
- [REF_RANGE, ".:.", REF_RANGE],
107
+ [REF_CELL, ":", REF_CELL],
108
+ [REF_CELL, ".:", REF_CELL],
109
+ [REF_CELL, ":.", REF_CELL],
110
+ [REF_CELL, ".:.", REF_CELL],
110
111
  [REF_RANGE],
111
112
  [REF_BEAM],
112
113
  [REF_TERNARY],
113
- [CONTEXT, "!", REF_RANGE, ":", REF_RANGE],
114
- [CONTEXT, "!", REF_RANGE, ".:", REF_RANGE],
115
- [CONTEXT, "!", REF_RANGE, ":.", REF_RANGE],
116
- [CONTEXT, "!", REF_RANGE, ".:.", REF_RANGE],
114
+ [CONTEXT, "!", REF_CELL, ":", REF_CELL],
115
+ [CONTEXT, "!", REF_CELL, ".:", REF_CELL],
116
+ [CONTEXT, "!", REF_CELL, ":.", REF_CELL],
117
+ [CONTEXT, "!", REF_CELL, ".:.", REF_CELL],
118
+ [CONTEXT, "!", REF_CELL],
117
119
  [CONTEXT, "!", REF_RANGE],
118
120
  [CONTEXT, "!", REF_BEAM],
119
121
  [CONTEXT, "!", REF_TERNARY],
120
- [CONTEXT_QUOTE, "!", REF_RANGE, ":", REF_RANGE],
121
- [CONTEXT_QUOTE, "!", REF_RANGE, ".:", REF_RANGE],
122
- [CONTEXT_QUOTE, "!", REF_RANGE, ":.", REF_RANGE],
123
- [CONTEXT_QUOTE, "!", REF_RANGE, ".:.", REF_RANGE],
122
+ [CONTEXT_QUOTE, "!", REF_CELL, ":", REF_CELL],
123
+ [CONTEXT_QUOTE, "!", REF_CELL, ".:", REF_CELL],
124
+ [CONTEXT_QUOTE, "!", REF_CELL, ":.", REF_CELL],
125
+ [CONTEXT_QUOTE, "!", REF_CELL, ".:.", REF_CELL],
126
+ [CONTEXT_QUOTE, "!", REF_CELL],
124
127
  [CONTEXT_QUOTE, "!", REF_RANGE],
125
128
  [CONTEXT_QUOTE, "!", REF_BEAM],
126
129
  [CONTEXT_QUOTE, "!", REF_TERNARY],
@@ -152,7 +155,11 @@ var matcher = (tokens2, currNode, anchorIndex, index = 0) => {
152
155
  while (i <= max) {
153
156
  const token = tokens2[anchorIndex - i];
154
157
  if (token) {
155
- const key = token.type === OPERATOR ? token.value : token.type;
158
+ const value = token.value;
159
+ let key = token.type === OPERATOR ? value : token.type;
160
+ if (key === REF_RANGE && !value.includes(":")) {
161
+ key = REF_CELL;
162
+ }
156
163
  if (key in node) {
157
164
  node = node[key];
158
165
  i += 1;
@@ -542,7 +549,7 @@ function lexRangeA1(str, pos, options) {
542
549
  }
543
550
  }
544
551
  }
545
- if (top && canEndRange(str, preOp)) {
552
+ if (top && canEndRange(str, preOp) && str.charCodeAt(preOp) !== 33) {
546
553
  return { type: REF_RANGE, value: str.slice(pos, preOp) };
547
554
  }
548
555
  } else {
@@ -582,6 +589,7 @@ var UC_C = 67;
582
589
  var LC_C = 99;
583
590
  var PLUS = 43;
584
591
  var MINUS = 45;
592
+ var EXCL2 = 33;
585
593
  function lexR1C1Part(str, pos, isRow = false) {
586
594
  const start = pos;
587
595
  const c0 = str.charCodeAt(pos);
@@ -636,7 +644,7 @@ function lexRangeR1C1(str, pos, options) {
636
644
  p += r1;
637
645
  const c1 = lexR1C1Part(str, p);
638
646
  p += c1;
639
- if (c1 || r1) {
647
+ if ((c1 || r1) && str.charCodeAt(p) !== EXCL2) {
640
648
  const op = advRangeOp(str, p);
641
649
  const preOp = p;
642
650
  if (op) {
@@ -853,7 +861,7 @@ function parseSRange(str, pos = 0) {
853
861
  }
854
862
 
855
863
  // lib/lexers/lexStructured.ts
856
- var EXCL2 = 33;
864
+ var EXCL3 = 33;
857
865
  function lexStructured(str, pos) {
858
866
  const structData = parseSRange(str, pos);
859
867
  if (structData && structData.length) {
@@ -861,7 +869,7 @@ function lexStructured(str, pos) {
861
869
  while (isWS(str.charCodeAt(pos + i))) {
862
870
  i++;
863
871
  }
864
- if (str.charCodeAt(pos + i) !== EXCL2) {
872
+ if (str.charCodeAt(pos + i) !== EXCL3) {
865
873
  return {
866
874
  type: REF_STRUCT,
867
875
  value: structData.token
@@ -956,9 +964,9 @@ function lexNamed(str, pos) {
956
964
  }
957
965
 
958
966
  // lib/lexers/lexRefOp.ts
959
- var EXCL3 = 33;
967
+ var EXCL4 = 33;
960
968
  function lexRefOp(str, pos, opts) {
961
- if (str.charCodeAt(pos) === EXCL3) {
969
+ if (str.charCodeAt(pos) === EXCL4) {
962
970
  return { type: OPERATOR, value: str[pos] };
963
971
  }
964
972
  if (!opts.r1c1) {
@@ -972,7 +980,7 @@ function lexRefOp(str, pos, opts) {
972
980
  // lib/lexers/lexNameFuncCntx.ts
973
981
  var BR_OPEN4 = 91;
974
982
  var PAREN_OPEN = 40;
975
- var EXCL4 = 33;
983
+ var EXCL5 = 33;
976
984
  var OFFS = 32;
977
985
  var ALLOWED = new Uint8Array(180 - OFFS);
978
986
  var OK_NAME_0 = 1;
@@ -1037,7 +1045,7 @@ function lexNameFuncCntx(str, pos, opts) {
1037
1045
  } else {
1038
1046
  if (c === PAREN_OPEN && func) {
1039
1047
  return { type: FUNCTION, value: str.slice(start, pos) };
1040
- } else if (c === EXCL4 && cntx) {
1048
+ } else if (c === EXCL5 && cntx) {
1041
1049
  return { type: CONTEXT, value: str.slice(start, pos) };
1042
1050
  }
1043
1051
  return nameOrUnknown(str, s, start, pos, name);
@@ -1073,6 +1081,11 @@ var lexersRefs = [
1073
1081
  lexNamed
1074
1082
  ];
1075
1083
 
1084
+ // lib/isRCTokenValue.ts
1085
+ function isRCTokenValue(value) {
1086
+ return value === "r" || value === "R" || value === "c" || value === "C";
1087
+ }
1088
+
1076
1089
  // lib/tokenize.ts
1077
1090
  var reLetLambda = /^l(?:ambda|et)$/i;
1078
1091
  var isType = (t, type) => t && t.type === type;
@@ -1080,12 +1093,13 @@ var isTextTokenType = (tokenType) => tokenType === REF_NAMED || tokenType === FU
1080
1093
  var causesBinaryMinus = (token) => {
1081
1094
  return !isType(token, OPERATOR) || (token.value === "%" || token.value === "}" || token.value === ")" || token.value === "#");
1082
1095
  };
1083
- function fixRCNames(tokens2) {
1096
+ function fixRCNames(tokens2, r1c1Mode) {
1084
1097
  let withinCall = 0;
1085
1098
  let parenDepth = 0;
1086
1099
  let lastToken;
1087
1100
  for (const token of tokens2) {
1088
- if (token.type === OPERATOR) {
1101
+ const tokenType = token.type;
1102
+ if (tokenType === OPERATOR) {
1089
1103
  if (token.value === "(") {
1090
1104
  parenDepth++;
1091
1105
  if (lastToken.type === FUNCTION) {
@@ -1099,7 +1113,9 @@ function fixRCNames(tokens2) {
1099
1113
  withinCall = 0;
1100
1114
  }
1101
1115
  }
1102
- } else if (withinCall && token.type === UNKNOWN && /^[rc]$/.test(token.value)) {
1116
+ } else if (withinCall && tokenType === UNKNOWN && isRCTokenValue(token.value)) {
1117
+ token.type = REF_NAMED;
1118
+ } else if (withinCall && r1c1Mode && tokenType === REF_BEAM && isRCTokenValue(token.value)) {
1103
1119
  token.type = REF_NAMED;
1104
1120
  }
1105
1121
  lastToken = token;
@@ -1186,9 +1202,8 @@ function getTokens(fx, tokenHandlers, options = {}) {
1186
1202
  letOrLambda++;
1187
1203
  }
1188
1204
  }
1189
- if (token.type === UNKNOWN && token.value.length === 1) {
1190
- const valLC = token.value.toLowerCase();
1191
- unknownRC += valLC === "r" || valLC === "c" ? 1 : 0;
1205
+ if (token.value.length === 1 && (token.type === UNKNOWN || opts.r1c1 && token.type === REF_BEAM)) {
1206
+ unknownRC += isRCTokenValue(token.value) ? 1 : 0;
1192
1207
  }
1193
1208
  if (negativeNumbers && token.type === NUMBER) {
1194
1209
  const last1 = lastToken;
@@ -1207,7 +1222,7 @@ function getTokens(fx, tokenHandlers, options = {}) {
1207
1222
  pushToken(token);
1208
1223
  }
1209
1224
  if (unknownRC && letOrLambda) {
1210
- fixRCNames(tokens2);
1225
+ fixRCNames(tokens2, opts.r1c1);
1211
1226
  }
1212
1227
  for (const index of trimOps) {
1213
1228
  const before = tokens2[index - 1];
@@ -1813,6 +1828,24 @@ function parse(tokenlist, options = {}) {
1813
1828
 
1814
1829
  // lib/stringifyPrefix.ts
1815
1830
  var reBannedChars = /[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;
1831
+ var reIsRangelike = /^(R|C|RC|[A-Z]{1,3}\d{1,7})$/i;
1832
+ function needQuotes(scope, yesItDoes = 0) {
1833
+ if (yesItDoes) {
1834
+ return 1;
1835
+ }
1836
+ if (scope) {
1837
+ if (reBannedChars.test(scope)) {
1838
+ return 1;
1839
+ }
1840
+ if (reIsRangelike.test(scope)) {
1841
+ return 1;
1842
+ }
1843
+ }
1844
+ return 0;
1845
+ }
1846
+ function quotePrefix(prefix2) {
1847
+ return "'" + prefix2.replace(/'/g, "''") + "'";
1848
+ }
1816
1849
  function stringifyPrefix(ref) {
1817
1850
  let pre = "";
1818
1851
  let quote = 0;
@@ -1823,12 +1856,12 @@ function stringifyPrefix(ref) {
1823
1856
  if (scope) {
1824
1857
  const part = nth % 2 ? "[" + scope + "]" : scope;
1825
1858
  pre = part + pre;
1826
- quote += +reBannedChars.test(scope);
1859
+ quote += needQuotes(scope, quote);
1827
1860
  nth++;
1828
1861
  }
1829
1862
  }
1830
1863
  if (quote) {
1831
- pre = "'" + pre.replace(/'/g, "''") + "'";
1864
+ pre = quotePrefix(pre);
1832
1865
  }
1833
1866
  return pre ? pre + "!" : pre;
1834
1867
  }
@@ -1838,14 +1871,14 @@ function stringifyPrefixXlsx(ref) {
1838
1871
  const { workbookName, sheetName } = ref;
1839
1872
  if (workbookName) {
1840
1873
  pre += "[" + workbookName + "]";
1841
- quote += +reBannedChars.test(workbookName);
1874
+ quote += needQuotes(workbookName);
1842
1875
  }
1843
1876
  if (sheetName) {
1844
1877
  pre += sheetName;
1845
- quote += +reBannedChars.test(sheetName);
1878
+ quote += needQuotes(sheetName);
1846
1879
  }
1847
1880
  if (quote) {
1848
- pre = "'" + pre.replace(/'/g, "''") + "'";
1881
+ pre = quotePrefix(pre);
1849
1882
  }
1850
1883
  return pre ? pre + "!" : pre;
1851
1884
  }
@@ -2297,6 +2330,7 @@ function parseRefXlsx(ref, opts = {}) {
2297
2330
  }
2298
2331
 
2299
2332
  // lib/translateToR1C1.ts
2333
+ var reLetLambda2 = /^l(?:ambda|et)$/i;
2300
2334
  var calc = (abs, vX, aX) => {
2301
2335
  if (vX == null) {
2302
2336
  return null;
@@ -2325,29 +2359,53 @@ function translateTokensToR1C1(tokens2, anchorCell) {
2325
2359
  throw new Error("translateTokensToR1C1 got an invalid anchorCell: " + anchorCell);
2326
2360
  }
2327
2361
  const { top, left } = anchorRange;
2362
+ let withinCall = 0;
2363
+ let parenDepth = 0;
2328
2364
  let offsetSkew = 0;
2329
2365
  const outTokens = [];
2330
2366
  for (let token of tokens2) {
2331
2367
  const tokenType = token?.type;
2368
+ if (tokenType === OPERATOR) {
2369
+ if (token.value === "(") {
2370
+ parenDepth++;
2371
+ const lastToken = outTokens[outTokens.length - 1];
2372
+ if (lastToken && lastToken.type === FUNCTION) {
2373
+ if (reLetLambda2.test(lastToken.value)) {
2374
+ withinCall = parenDepth;
2375
+ }
2376
+ }
2377
+ } else if (token.value === ")") {
2378
+ parenDepth--;
2379
+ if (parenDepth < withinCall) {
2380
+ withinCall = 0;
2381
+ }
2382
+ }
2383
+ }
2332
2384
  if (tokenType === REF_RANGE || tokenType === REF_BEAM || tokenType === REF_TERNARY) {
2333
2385
  token = cloneToken(token);
2334
2386
  const tokenValue = token.value;
2335
2387
  const ref = quickParseA1(tokenValue);
2336
- const d = ref.range;
2337
- const range = {};
2338
- range.r0 = calc(d.$top, d.top, top);
2339
- range.r1 = calc(d.$bottom, d.bottom, top);
2340
- range.c0 = calc(d.$left, d.left, left);
2341
- range.c1 = calc(d.$right, d.right, left);
2342
- range.$r0 = d.$top;
2343
- range.$r1 = d.$bottom;
2344
- range.$c0 = d.$left;
2345
- range.$c1 = d.$right;
2346
- if (d.trim) {
2347
- range.trim = d.trim;
2388
+ if (ref) {
2389
+ const d = ref.range;
2390
+ const range = {};
2391
+ range.r0 = calc(d.$top, d.top, top);
2392
+ range.r1 = calc(d.$bottom, d.bottom, top);
2393
+ range.c0 = calc(d.$left, d.left, left);
2394
+ range.c1 = calc(d.$right, d.right, left);
2395
+ range.$r0 = d.$top;
2396
+ range.$r1 = d.$bottom;
2397
+ range.$c0 = d.$left;
2398
+ range.$c1 = d.$right;
2399
+ if (d.trim) {
2400
+ range.trim = d.trim;
2401
+ }
2402
+ ref.range = range;
2403
+ let val = stringifyR1C1RefXlsx(ref);
2404
+ if (isRCTokenValue(val) && withinCall) {
2405
+ val += "[0]";
2406
+ }
2407
+ token.value = val;
2348
2408
  }
2349
- ref.range = range;
2350
- token.value = stringifyR1C1RefXlsx(ref);
2351
2409
  if (token.loc) {
2352
2410
  token.loc[0] += offsetSkew;
2353
2411
  offsetSkew += token.value.length - tokenValue.length;
@@ -2661,44 +2719,46 @@ function translateTokensToA1(tokens2, anchorCell, options = {}) {
2661
2719
  token = cloneToken(token);
2662
2720
  const tokenValue = token.value;
2663
2721
  const ref = parseR1C1RefXlsx(tokenValue, REF_OPTS);
2664
- const d = ref.range;
2665
- const range = { top: 0, left: 0 };
2666
- const r0 = toFixed(d.r0, d.$r0, top, MAX_ROWS, wrapEdges);
2667
- const r1 = toFixed(d.r1, d.$r1, top, MAX_ROWS, wrapEdges);
2668
- if (r0 > r1) {
2669
- range.top = r1;
2670
- range.$top = d.$r1;
2671
- range.bottom = r0;
2672
- range.$bottom = d.$r0;
2673
- } else {
2674
- range.top = r0;
2675
- range.$top = d.$r0;
2676
- range.bottom = r1;
2677
- range.$bottom = d.$r1;
2678
- }
2679
- const c0 = toFixed(d.c0, d.$c0, left, MAX_COLS, wrapEdges);
2680
- const c1 = toFixed(d.c1, d.$c1, left, MAX_COLS, wrapEdges);
2681
- if (c0 > c1) {
2682
- range.left = c1;
2683
- range.$left = d.$c1;
2684
- range.right = c0;
2685
- range.$right = d.$c0;
2686
- } else {
2687
- range.left = c0;
2688
- range.$left = d.$c0;
2689
- range.right = c1;
2690
- range.$right = d.$c1;
2691
- }
2692
- if (d.trim) {
2693
- range.trim = d.trim;
2694
- }
2695
- if (isNaN(r0) || isNaN(r1) || isNaN(c0) || isNaN(c1)) {
2696
- token.type = ERROR;
2697
- token.value = "#REF!";
2698
- delete token.groupId;
2699
- } else {
2700
- ref.range = range;
2701
- token.value = stringifyA1RefXlsx(ref);
2722
+ if (ref) {
2723
+ const d = ref.range;
2724
+ const range = { top: 0, left: 0 };
2725
+ const r0 = toFixed(d.r0, d.$r0, top, MAX_ROWS, wrapEdges);
2726
+ const r1 = toFixed(d.r1, d.$r1, top, MAX_ROWS, wrapEdges);
2727
+ if (r0 > r1) {
2728
+ range.top = r1;
2729
+ range.$top = d.$r1;
2730
+ range.bottom = r0;
2731
+ range.$bottom = d.$r0;
2732
+ } else {
2733
+ range.top = r0;
2734
+ range.$top = d.$r0;
2735
+ range.bottom = r1;
2736
+ range.$bottom = d.$r1;
2737
+ }
2738
+ const c0 = toFixed(d.c0, d.$c0, left, MAX_COLS, wrapEdges);
2739
+ const c1 = toFixed(d.c1, d.$c1, left, MAX_COLS, wrapEdges);
2740
+ if (c0 > c1) {
2741
+ range.left = c1;
2742
+ range.$left = d.$c1;
2743
+ range.right = c0;
2744
+ range.$right = d.$c0;
2745
+ } else {
2746
+ range.left = c0;
2747
+ range.$left = d.$c0;
2748
+ range.right = c1;
2749
+ range.$right = d.$c1;
2750
+ }
2751
+ if (d.trim) {
2752
+ range.trim = d.trim;
2753
+ }
2754
+ if (isNaN(r0) || isNaN(r1) || isNaN(c0) || isNaN(c1)) {
2755
+ token.type = ERROR;
2756
+ token.value = "#REF!";
2757
+ delete token.groupId;
2758
+ } else {
2759
+ ref.range = range;
2760
+ token.value = stringifyA1RefXlsx(ref);
2761
+ }
2702
2762
  }
2703
2763
  if (token.loc) {
2704
2764
  token.loc[0] += offsetSkew;