@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 +145 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +145 -85
- package/dist/index.js.map +1 -1
- package/dist/xlsx/index.cjs +144 -84
- package/dist/xlsx/index.cjs.map +1 -1
- package/dist/xlsx/index.js +144 -84
- package/dist/xlsx/index.js.map +1 -1
- package/lib/constants.ts +3 -0
- package/lib/fixRanges.spec.ts +14 -0
- package/lib/isRCTokenValue.ts +3 -0
- package/lib/lexers/lexRangeA1.ts +1 -1
- package/lib/lexers/lexRangeR1C1.ts +2 -1
- package/lib/mergeRefTokens.ts +23 -14
- package/lib/parseA1Ref.spec.ts +7 -0
- package/lib/stringifyA1Ref.spec.ts +18 -0
- package/lib/stringifyPrefix.ts +26 -5
- package/lib/tokenize.spec.ts +99 -0
- package/lib/tokenize.ts +17 -9
- package/lib/translateToA1.spec.ts +84 -0
- package/lib/translateToA1.ts +45 -43
- package/lib/translateToR1C1.spec.ts +68 -4
- package/lib/translateToR1C1.ts +46 -19
- package/package.json +7 -7
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
|
-
[
|
|
38
|
-
[
|
|
39
|
-
[
|
|
40
|
-
[
|
|
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, "!",
|
|
45
|
-
[CONTEXT, "!",
|
|
46
|
-
[CONTEXT, "!",
|
|
47
|
-
[CONTEXT, "!",
|
|
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, "!",
|
|
52
|
-
[CONTEXT_QUOTE, "!",
|
|
53
|
-
[CONTEXT_QUOTE, "!",
|
|
54
|
-
[CONTEXT_QUOTE, "!",
|
|
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
|
|
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
|
|
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) !==
|
|
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
|
|
898
|
+
var EXCL4 = 33;
|
|
891
899
|
function lexRefOp(str, pos, opts) {
|
|
892
|
-
if (str.charCodeAt(pos) ===
|
|
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
|
|
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 ===
|
|
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
|
-
|
|
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 &&
|
|
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.
|
|
1121
|
-
|
|
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 +=
|
|
1790
|
+
quote += needQuotes(scope, quote);
|
|
1758
1791
|
nth++;
|
|
1759
1792
|
}
|
|
1760
1793
|
}
|
|
1761
1794
|
if (quote) {
|
|
1762
|
-
pre =
|
|
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 +=
|
|
1805
|
+
quote += needQuotes(workbookName);
|
|
1773
1806
|
}
|
|
1774
1807
|
if (sheetName) {
|
|
1775
1808
|
pre += sheetName;
|
|
1776
|
-
quote +=
|
|
1809
|
+
quote += needQuotes(sheetName);
|
|
1777
1810
|
}
|
|
1778
1811
|
if (quote) {
|
|
1779
|
-
pre =
|
|
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
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
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
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
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;
|