@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.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
|
-
[
|
|
107
|
-
[
|
|
108
|
-
[
|
|
109
|
-
[
|
|
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, "!",
|
|
114
|
-
[CONTEXT, "!",
|
|
115
|
-
[CONTEXT, "!",
|
|
116
|
-
[CONTEXT, "!",
|
|
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, "!",
|
|
121
|
-
[CONTEXT_QUOTE, "!",
|
|
122
|
-
[CONTEXT_QUOTE, "!",
|
|
123
|
-
[CONTEXT_QUOTE, "!",
|
|
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
|
|
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
|
|
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) !==
|
|
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
|
|
967
|
+
var EXCL4 = 33;
|
|
960
968
|
function lexRefOp(str, pos, opts) {
|
|
961
|
-
if (str.charCodeAt(pos) ===
|
|
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
|
|
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 ===
|
|
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
|
-
|
|
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 &&
|
|
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.
|
|
1190
|
-
|
|
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 +=
|
|
1859
|
+
quote += needQuotes(scope, quote);
|
|
1827
1860
|
nth++;
|
|
1828
1861
|
}
|
|
1829
1862
|
}
|
|
1830
1863
|
if (quote) {
|
|
1831
|
-
pre =
|
|
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 +=
|
|
1874
|
+
quote += needQuotes(workbookName);
|
|
1842
1875
|
}
|
|
1843
1876
|
if (sheetName) {
|
|
1844
1877
|
pre += sheetName;
|
|
1845
|
-
quote +=
|
|
1878
|
+
quote += needQuotes(sheetName);
|
|
1846
1879
|
}
|
|
1847
1880
|
if (quote) {
|
|
1848
|
-
pre =
|
|
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
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
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
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
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;
|