@devmm/puredocs-excel-formula 1.0.7 → 1.0.9

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
@@ -1,4 +1,4 @@
1
- import { toOADate, fromOADate, columnLetter, parseCellRef, cellRefFromRowCol, shiftIndex, shiftFormulaRefs, shiftSpan, EXCEL_MAX_ROWS, EXCEL_MAX_COLUMNS, columnNumber } from '@devmm/puredocs-excel';
1
+ import { toOADate, fromOADate, columnLetter, parseCellRef, cellRefFromRowCol, parseRangeRef, shiftIndex, shiftFormulaRefs, shiftSpan, EXCEL_MAX_ROWS, EXCEL_MAX_COLUMNS, columnNumber } from '@devmm/puredocs-excel';
2
2
 
3
3
  var __typeError = (msg) => {
4
4
  throw TypeError(msg);
@@ -446,8 +446,11 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
446
446
  TokenType2[TokenType2["SpillReference"] = 24] = "SpillReference";
447
447
  TokenType2[TokenType2["Exclamation"] = 25] = "Exclamation";
448
448
  TokenType2[TokenType2["AtSign"] = 26] = "AtSign";
449
- TokenType2[TokenType2["ErrorLiteral"] = 27] = "ErrorLiteral";
450
- TokenType2[TokenType2["EOF"] = 28] = "EOF";
449
+ TokenType2[TokenType2["LeftBrace"] = 27] = "LeftBrace";
450
+ TokenType2[TokenType2["RightBrace"] = 28] = "RightBrace";
451
+ TokenType2[TokenType2["Semicolon"] = 29] = "Semicolon";
452
+ TokenType2[TokenType2["ErrorLiteral"] = 30] = "ErrorLiteral";
453
+ TokenType2[TokenType2["EOF"] = 31] = "EOF";
451
454
  return TokenType2;
452
455
  })(TokenType || {});
453
456
  function makeToken(type, value2, position) {
@@ -461,6 +464,8 @@ var FormulaException = class extends Error {
461
464
  this.name = "FormulaException";
462
465
  }
463
466
  };
467
+ var UNDERSCORE = 95;
468
+ var RESERVED_PREFIXES = ["_XLFN.", "_XLWS.", "_XLPM."];
464
469
  var KNOWN_ERRORS = /* @__PURE__ */ new Set([
465
470
  "#NULL!",
466
471
  "#DIV/0!",
@@ -472,7 +477,7 @@ var KNOWN_ERRORS = /* @__PURE__ */ new Set([
472
477
  "#CALC!",
473
478
  "#SPILL!"
474
479
  ]);
475
- var _formula, _pos, _FormulaLexer_instances, readNextToken_fn, readString_fn, readErrorLiteral_fn, readQuotedSheetRef_fn, readNumber_fn, readIdentifier_fn, readCellRefChars_fn, readOperator_fn, skipWhitespace_fn;
480
+ var _formula, _pos, _FormulaLexer_instances, readNextToken_fn, readString_fn, readErrorLiteral_fn, readQuotedSheetRef_fn, readNumber_fn, readIdentifier_fn, stripReservedPrefixes_fn, readCellRefChars_fn, readOperator_fn, skipWhitespace_fn;
476
481
  var FormulaLexer = class {
477
482
  constructor(formula) {
478
483
  __privateAdd(this, _FormulaLexer_instances);
@@ -490,7 +495,7 @@ var FormulaLexer = class {
490
495
  const token = __privateMethod(this, _FormulaLexer_instances, readNextToken_fn).call(this);
491
496
  if (token) tokens.push(token);
492
497
  }
493
- tokens.push(makeToken(28 /* EOF */, "", __privateGet(this, _pos)));
498
+ tokens.push(makeToken(31 /* EOF */, "", __privateGet(this, _pos)));
494
499
  return tokens;
495
500
  }
496
501
  };
@@ -544,7 +549,7 @@ readErrorLiteral_fn = function() {
544
549
  if (!KNOWN_ERRORS.has(upper2)) {
545
550
  throw new FormulaException(`Unknown error literal "${raw}" at position ${start}.`);
546
551
  }
547
- return makeToken(27 /* ErrorLiteral */, upper2, start);
552
+ return makeToken(30 /* ErrorLiteral */, upper2, start);
548
553
  };
549
554
  readQuotedSheetRef_fn = function() {
550
555
  const start = __privateWrapper(this, _pos)._++;
@@ -607,10 +612,8 @@ readIdentifier_fn = function() {
607
612
  } else break;
608
613
  }
609
614
  let upper2 = raw.toUpperCase();
610
- if (upper2.startsWith("_XLFN.")) {
611
- raw = raw.slice(6);
612
- upper2 = upper2.slice(6);
613
- }
615
+ raw = __privateMethod(this, _FormulaLexer_instances, stripReservedPrefixes_fn).call(this, raw, upper2);
616
+ if (raw.length !== upper2.length) upper2 = upper2.slice(upper2.length - raw.length);
614
617
  if (upper2 === "TRUE") return makeToken(2 /* Boolean */, "TRUE", start);
615
618
  if (upper2 === "FALSE") return makeToken(2 /* Boolean */, "FALSE", start);
616
619
  if (__privateGet(this, _formula)[__privateGet(this, _pos)] === "!") {
@@ -632,6 +635,30 @@ readIdentifier_fn = function() {
632
635
  }
633
636
  return makeToken(23 /* NamedRange */, raw, start);
634
637
  };
638
+ /**
639
+ * Drops Excel's storage-level name decorations. They carry no semantics — the
640
+ * writer stamps them so an older reader fails loudly instead of silently
641
+ * mis-evaluating — and they *stack*: `_xlfn._xlws.FILTER` wears two. Stripping
642
+ * one prefix once, as this used to, leaves `_XLWS.FILTER` unresolvable.
643
+ *
644
+ * Every identifier in every formula passes through here, so the common case is
645
+ * gated on a single char-code test: a name not starting with '_' returns
646
+ * untouched without so much as a comparison against the prefix table.
647
+ */
648
+ stripReservedPrefixes_fn = function(raw, upper2) {
649
+ if (raw.charCodeAt(0) !== UNDERSCORE) return raw;
650
+ let cut = 0;
651
+ outer: for (; ; ) {
652
+ for (const prefix of RESERVED_PREFIXES) {
653
+ if (upper2.startsWith(prefix, cut)) {
654
+ cut += prefix.length;
655
+ continue outer;
656
+ }
657
+ }
658
+ break;
659
+ }
660
+ return cut > 0 && cut < raw.length ? raw.slice(cut) : raw;
661
+ };
635
662
  readCellRefChars_fn = function() {
636
663
  let ref = "";
637
664
  while (__privateGet(this, _pos) < __privateGet(this, _formula).length) {
@@ -675,6 +702,14 @@ readOperator_fn = function() {
675
702
  return makeToken(26 /* AtSign */, "@", start);
676
703
  case "!":
677
704
  return makeToken(25 /* Exclamation */, "!", start);
705
+ case "{":
706
+ return makeToken(27 /* LeftBrace */, "{", start);
707
+ case "}":
708
+ return makeToken(28 /* RightBrace */, "}", start);
709
+ // Inside an array constant ';' separates rows. Excel always stores ',' as
710
+ // the argument separator regardless of locale, so ';' has no other role.
711
+ case ";":
712
+ return makeToken(29 /* Semicolon */, ";", start);
678
713
  case "<":
679
714
  if (__privateGet(this, _formula)[__privateGet(this, _pos)] === ">") {
680
715
  __privateWrapper(this, _pos)._++;
@@ -757,6 +792,29 @@ var ErrorNode = class extends FormulaNode {
757
792
  return this.errorValue;
758
793
  }
759
794
  };
795
+ var _value;
796
+ var ArrayLiteralNode = class extends FormulaNode {
797
+ constructor(array) {
798
+ super();
799
+ this.array = array;
800
+ __privateAdd(this, _value);
801
+ __privateSet(this, _value, FormulaValue.array(array));
802
+ }
803
+ evaluate() {
804
+ return __privateGet(this, _value);
805
+ }
806
+ };
807
+ _value = new WeakMap();
808
+ var ValueNode = class extends FormulaNode {
809
+ /** Mutable so one wrapper can be re-pointed across a lifted call's cells. */
810
+ constructor(value2) {
811
+ super();
812
+ this.value = value2;
813
+ }
814
+ evaluate() {
815
+ return this.value;
816
+ }
817
+ };
760
818
  var BlankNode = class extends FormulaNode {
761
819
  evaluate() {
762
820
  return FormulaValue.blank;
@@ -1034,7 +1092,7 @@ var CallNode = class extends FormulaNode {
1034
1092
  };
1035
1093
 
1036
1094
  // src/formula-parser.ts
1037
- var _tokens, _pos2, _FormulaParser_instances, current_get, advance_fn, expect_fn, parseComparison_fn, parseConcatenation_fn, parseAddSub_fn, parseMulDiv_fn, parseUnary_fn, parsePower_fn, parsePercent_fn, parsePostfix_fn, parsePrimary_fn, tryParseFullRange_fn, parseFunction_fn, parseArgList_fn;
1095
+ var _tokens, _pos2, _FormulaParser_instances, current_get, advance_fn, expect_fn, parseComparison_fn, parseConcatenation_fn, parseAddSub_fn, parseMulDiv_fn, parseUnary_fn, parsePower_fn, parsePercent_fn, parsePostfix_fn, parsePrimary_fn, tryParseFullRange_fn, parseArrayLiteral_fn, parseArrayElement_fn, parseFunction_fn, parseArgList_fn;
1038
1096
  var FormulaParser = class {
1039
1097
  constructor(tokens) {
1040
1098
  __privateAdd(this, _FormulaParser_instances);
@@ -1045,7 +1103,7 @@ var FormulaParser = class {
1045
1103
  parse() {
1046
1104
  __privateSet(this, _pos2, 0);
1047
1105
  const node = __privateMethod(this, _FormulaParser_instances, parseComparison_fn).call(this);
1048
- if (__privateGet(this, _FormulaParser_instances, current_get).type !== 28 /* EOF */) {
1106
+ if (__privateGet(this, _FormulaParser_instances, current_get).type !== 31 /* EOF */) {
1049
1107
  throw new FormulaException(
1050
1108
  `Unexpected token '${__privateGet(this, _FormulaParser_instances, current_get).value}' at position ${__privateGet(this, _FormulaParser_instances, current_get).position}.`
1051
1109
  );
@@ -1057,7 +1115,7 @@ _tokens = new WeakMap();
1057
1115
  _pos2 = new WeakMap();
1058
1116
  _FormulaParser_instances = new WeakSet();
1059
1117
  current_get = function() {
1060
- return __privateGet(this, _tokens)[__privateGet(this, _pos2)] ?? { type: 28 /* EOF */, value: "", position: -1 };
1118
+ return __privateGet(this, _tokens)[__privateGet(this, _pos2)] ?? { type: 31 /* EOF */, value: "", position: -1 };
1061
1119
  };
1062
1120
  advance_fn = function() {
1063
1121
  const t = __privateGet(this, _FormulaParser_instances, current_get);
@@ -1172,7 +1230,7 @@ parsePrimary_fn = function() {
1172
1230
  case 2 /* Boolean */:
1173
1231
  __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1174
1232
  return new BooleanNode(token.value === "TRUE");
1175
- case 27 /* ErrorLiteral */:
1233
+ case 30 /* ErrorLiteral */:
1176
1234
  __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1177
1235
  return new ErrorNode(FormulaValue.error(FormulaValue.errorFromString(token.value)));
1178
1236
  case 3 /* CellReference */: {
@@ -1211,6 +1269,8 @@ parsePrimary_fn = function() {
1211
1269
  return new SpillReferenceNode(token.value);
1212
1270
  case 5 /* Function */:
1213
1271
  return __privateMethod(this, _FormulaParser_instances, parseFunction_fn).call(this);
1272
+ case 27 /* LeftBrace */:
1273
+ return __privateMethod(this, _FormulaParser_instances, parseArrayLiteral_fn).call(this);
1214
1274
  case 6 /* LeftParen */: {
1215
1275
  __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1216
1276
  const expr = __privateMethod(this, _FormulaParser_instances, parseComparison_fn).call(this);
@@ -1245,6 +1305,79 @@ tryParseFullRange_fn = function(startText, sheetName) {
1245
1305
  const hi = Math.max(start.index, end.index);
1246
1306
  return start.kind === "col" ? new FullRangeReferenceNode(lo, hi, null, null, sheetName) : new FullRangeReferenceNode(null, null, lo, hi, sheetName);
1247
1307
  };
1308
+ /**
1309
+ * Parses an array constant: `{1,2;3,4}` — ',' separates columns, ';' rows.
1310
+ *
1311
+ * Excel permits only literals inside one (no references, no calls, not even
1312
+ * arithmetic beyond a leading sign), so the value is fully determined here and
1313
+ * is materialised once into the node instead of being rebuilt on every eval.
1314
+ *
1315
+ * A ragged constant is rejected rather than padded: Excel refuses to accept
1316
+ * one at entry, so a file cannot legitimately contain it, and silently filling
1317
+ * the gaps would invent data the author never wrote.
1318
+ */
1319
+ parseArrayLiteral_fn = function() {
1320
+ const open = __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1321
+ const rows2 = [];
1322
+ let row2 = [];
1323
+ for (; ; ) {
1324
+ row2.push(__privateMethod(this, _FormulaParser_instances, parseArrayElement_fn).call(this));
1325
+ if (__privateGet(this, _FormulaParser_instances, current_get).type === 8 /* Comma */) {
1326
+ __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1327
+ continue;
1328
+ }
1329
+ if (__privateGet(this, _FormulaParser_instances, current_get).type === 29 /* Semicolon */) {
1330
+ __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1331
+ rows2.push(row2);
1332
+ row2 = [];
1333
+ continue;
1334
+ }
1335
+ break;
1336
+ }
1337
+ rows2.push(row2);
1338
+ __privateMethod(this, _FormulaParser_instances, expect_fn).call(this, 28 /* RightBrace */);
1339
+ const cols = rows2[0].length;
1340
+ if (rows2.some((r) => r.length !== cols)) {
1341
+ throw new FormulaException(
1342
+ `Array constant at position ${open.position} has rows of differing lengths.`
1343
+ );
1344
+ }
1345
+ const array = new ArrayValue(rows2.length, cols);
1346
+ for (let r = 0; r < rows2.length; r++) {
1347
+ for (let c = 0; c < cols; c++) array.set(r, c, rows2[r][c]);
1348
+ }
1349
+ return new ArrayLiteralNode(array);
1350
+ };
1351
+ /** One element of an array constant: a literal, optionally signed. */
1352
+ parseArrayElement_fn = function() {
1353
+ let negate = false;
1354
+ let signed = false;
1355
+ while (__privateGet(this, _FormulaParser_instances, current_get).type === 10 /* Minus */ || __privateGet(this, _FormulaParser_instances, current_get).type === 9 /* Plus */) {
1356
+ if (__privateGet(this, _FormulaParser_instances, current_get).type === 10 /* Minus */) negate = !negate;
1357
+ signed = true;
1358
+ __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1359
+ }
1360
+ const token = __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1361
+ switch (token.type) {
1362
+ case 0 /* Number */: {
1363
+ const n = parseFloat(token.value);
1364
+ if (isNaN(n)) throw new FormulaException(`Invalid number: ${token.value}`);
1365
+ return FormulaValue.number(negate ? -n : n);
1366
+ }
1367
+ case 1 /* String */:
1368
+ if (signed) break;
1369
+ return FormulaValue.text(token.value);
1370
+ case 2 /* Boolean */:
1371
+ if (signed) break;
1372
+ return FormulaValue.boolean(token.value === "TRUE");
1373
+ case 30 /* ErrorLiteral */:
1374
+ if (signed) break;
1375
+ return FormulaValue.error(FormulaValue.errorFromString(token.value));
1376
+ }
1377
+ throw new FormulaException(
1378
+ `Array constants accept only literal values; got '${token.value}' at position ${token.position}.`
1379
+ );
1380
+ };
1248
1381
  parseFunction_fn = function() {
1249
1382
  const nameToken = __privateMethod(this, _FormulaParser_instances, advance_fn).call(this);
1250
1383
  __privateMethod(this, _FormulaParser_instances, expect_fn).call(this, 6 /* LeftParen */);
@@ -1451,42 +1584,42 @@ function registerMath(r) {
1451
1584
  r.register("PRODUCT", product, 1);
1452
1585
  r.register("SUMPRODUCT", sumProduct, 1);
1453
1586
  r.register("SUMSQ", sumSq, 1);
1454
- r.register("ABS", abs, 1, 1);
1455
- r.register("ROUND", round, 2, 2);
1456
- r.register("ROUNDUP", roundUp, 2, 2);
1457
- r.register("ROUNDDOWN", roundDown, 2, 2);
1458
- r.register("CEILING", ceiling, 2, 2);
1459
- r.register("CEILING.MATH", ceiling, 2, 2);
1460
- r.register("FLOOR", floor, 2, 2);
1461
- r.register("FLOOR.MATH", floor, 2, 2);
1462
- r.register("INT", int_, 1, 1);
1463
- r.register("TRUNC", trunc, 1, 2);
1464
- r.register("MOD", mod, 2, 2);
1465
- r.register("QUOTIENT", quotient, 2, 2);
1466
- r.register("POWER", power, 2, 2);
1467
- r.register("SQRT", sqrt, 1, 1);
1468
- r.register("SIGN", sign, 1, 1);
1587
+ r.registerElementwise("ABS", abs, 1, 1);
1588
+ r.registerElementwise("ROUND", round, 2, 2);
1589
+ r.registerElementwise("ROUNDUP", roundUp, 2, 2);
1590
+ r.registerElementwise("ROUNDDOWN", roundDown, 2, 2);
1591
+ r.registerElementwise("CEILING", ceiling, 2, 2);
1592
+ r.registerElementwise("CEILING.MATH", ceiling, 2, 2);
1593
+ r.registerElementwise("FLOOR", floor, 2, 2);
1594
+ r.registerElementwise("FLOOR.MATH", floor, 2, 2);
1595
+ r.registerElementwise("INT", int_, 1, 1);
1596
+ r.registerElementwise("TRUNC", trunc, 1, 2);
1597
+ r.registerElementwise("MOD", mod, 2, 2);
1598
+ r.registerElementwise("QUOTIENT", quotient, 2, 2);
1599
+ r.registerElementwise("POWER", power, 2, 2);
1600
+ r.registerElementwise("SQRT", sqrt, 1, 1);
1601
+ r.registerElementwise("SIGN", sign, 1, 1);
1469
1602
  r.register("PI", pi, 0, 0);
1470
1603
  r.register("RAND", rand, 0, 0, true);
1471
1604
  r.register("RANDBETWEEN", randBetween, 2, 2, true);
1472
- r.register("LOG", log, 1, 2);
1473
- r.register("LOG10", log10, 1, 1);
1474
- r.register("LN", ln, 1, 1);
1475
- r.register("EXP", exp, 1, 1);
1476
- r.register("FACT", fact, 1, 1);
1477
- r.register("COMBIN", combin, 2, 2);
1478
- r.register("SIN", unary(Math.sin), 1, 1);
1479
- r.register("COS", unary(Math.cos), 1, 1);
1480
- r.register("TAN", unary(Math.tan), 1, 1);
1481
- r.register("ASIN", asin, 1, 1);
1482
- r.register("ACOS", acos, 1, 1);
1483
- r.register("ATAN", unary(Math.atan), 1, 1);
1484
- r.register("ATAN2", atan2, 2, 2);
1485
- r.register("SINH", unary(Math.sinh), 1, 1);
1486
- r.register("COSH", unary(Math.cosh), 1, 1);
1487
- r.register("TANH", unary(Math.tanh), 1, 1);
1488
- r.register("DEGREES", unary((r2d) => r2d * 180 / Math.PI), 1, 1);
1489
- r.register("RADIANS", unary((d) => d * Math.PI / 180), 1, 1);
1605
+ r.registerElementwise("LOG", log, 1, 2);
1606
+ r.registerElementwise("LOG10", log10, 1, 1);
1607
+ r.registerElementwise("LN", ln, 1, 1);
1608
+ r.registerElementwise("EXP", exp, 1, 1);
1609
+ r.registerElementwise("FACT", fact, 1, 1);
1610
+ r.registerElementwise("COMBIN", combin, 2, 2);
1611
+ r.registerElementwise("SIN", unary(Math.sin), 1, 1);
1612
+ r.registerElementwise("COS", unary(Math.cos), 1, 1);
1613
+ r.registerElementwise("TAN", unary(Math.tan), 1, 1);
1614
+ r.registerElementwise("ASIN", asin, 1, 1);
1615
+ r.registerElementwise("ACOS", acos, 1, 1);
1616
+ r.registerElementwise("ATAN", unary(Math.atan), 1, 1);
1617
+ r.registerElementwise("ATAN2", atan2, 2, 2);
1618
+ r.registerElementwise("SINH", unary(Math.sinh), 1, 1);
1619
+ r.registerElementwise("COSH", unary(Math.cosh), 1, 1);
1620
+ r.registerElementwise("TANH", unary(Math.tanh), 1, 1);
1621
+ r.registerElementwise("DEGREES", unary((r2d) => r2d * 180 / Math.PI), 1, 1);
1622
+ r.registerElementwise("RADIANS", unary((d) => d * Math.PI / 180), 1, 1);
1490
1623
  }
1491
1624
  function valueAt(v, i) {
1492
1625
  return v.isArray ? v.arrayVal.getFlat(i) : v;
@@ -1918,31 +2051,31 @@ function combin(a, c) {
1918
2051
  return FormulaValue.number(Math.round(result));
1919
2052
  }
1920
2053
  function registerText(r) {
1921
- r.register("LEFT", left, 1, 2);
1922
- r.register("RIGHT", right, 1, 2);
1923
- r.register("MID", mid, 3, 3);
1924
- r.register("LEN", len, 1, 1);
1925
- r.register("UPPER", upper, 1, 1);
1926
- r.register("LOWER", lower, 1, 1);
1927
- r.register("PROPER", proper, 1, 1);
1928
- r.register("TRIM", trim, 1, 1);
1929
- r.register("CLEAN", clean, 1, 1);
1930
- r.register("SUBSTITUTE", substitute, 3, 4);
1931
- r.register("REPLACE", replace, 4, 4);
2054
+ r.registerElementwise("LEFT", left, 1, 2);
2055
+ r.registerElementwise("RIGHT", right, 1, 2);
2056
+ r.registerElementwise("MID", mid, 3, 3);
2057
+ r.registerElementwise("LEN", len, 1, 1);
2058
+ r.registerElementwise("UPPER", upper, 1, 1);
2059
+ r.registerElementwise("LOWER", lower, 1, 1);
2060
+ r.registerElementwise("PROPER", proper, 1, 1);
2061
+ r.registerElementwise("TRIM", trim, 1, 1);
2062
+ r.registerElementwise("CLEAN", clean, 1, 1);
2063
+ r.registerElementwise("SUBSTITUTE", substitute, 3, 4);
2064
+ r.registerElementwise("REPLACE", replace, 4, 4);
1932
2065
  r.register("CONCATENATE", concatenate, 1);
1933
2066
  r.register("CONCAT", concatenate, 1);
1934
2067
  r.register("TEXTJOIN", textJoin, 3);
1935
- r.register("TEXT", text_, 2, 2);
1936
- r.register("VALUE", value, 1, 1);
1937
- r.register("FIND", find, 2, 3);
1938
- r.register("SEARCH", search, 2, 3);
1939
- r.register("REPT", rept, 2, 2);
1940
- r.register("EXACT", exact, 2, 2);
1941
- r.register("CHAR", char_, 1, 1);
1942
- r.register("CODE", code, 1, 1);
1943
- r.register("T", t_, 1, 1);
1944
- r.register("TEXTBEFORE", textBefore, 2, 3);
1945
- r.register("TEXTAFTER", textAfter, 2, 3);
2068
+ r.registerElementwise("TEXT", text_, 2, 2);
2069
+ r.registerElementwise("VALUE", value, 1, 1);
2070
+ r.registerElementwise("FIND", find, 2, 3);
2071
+ r.registerElementwise("SEARCH", search, 2, 3);
2072
+ r.registerElementwise("REPT", rept, 2, 2);
2073
+ r.registerElementwise("EXACT", exact, 2, 2);
2074
+ r.registerElementwise("CHAR", char_, 1, 1);
2075
+ r.registerElementwise("CODE", code, 1, 1);
2076
+ r.registerElementwise("T", t_, 1, 1);
2077
+ r.registerElementwise("TEXTBEFORE", textBefore, 2, 3);
2078
+ r.registerElementwise("TEXTAFTER", textAfter, 2, 3);
1946
2079
  }
1947
2080
  function str(a, c, idx) {
1948
2081
  const r = FormulaHelper.evalString(a[idx], c);
@@ -2256,6 +2389,7 @@ function registerLogical(r) {
2256
2389
  function if_(a, c) {
2257
2390
  const cond = a[0].evaluate(c);
2258
2391
  if (cond.isError) return cond;
2392
+ if (cond.isArray) return ifArray(cond.arrayVal, a, c);
2259
2393
  const b = cond.coerceToBool();
2260
2394
  if (b.isError) return b;
2261
2395
  return b.booleanValue ? a[1].evaluate(c) : a.length > 2 ? a[2].evaluate(c) : FormulaValue.false_;
@@ -2332,13 +2466,63 @@ function xor(a, c) {
2332
2466
  }
2333
2467
  return FormulaValue.boolean(trueCount % 2 === 1);
2334
2468
  }
2335
- function ifError(a, c) {
2469
+ function ifArray(mask, a, c) {
2470
+ let wantTrue = false, wantFalse = false;
2471
+ for (const item of mask.values()) {
2472
+ const b = item.coerceToBool();
2473
+ if (b.isError) return b;
2474
+ if (b.booleanValue) wantTrue = true;
2475
+ else wantFalse = true;
2476
+ if (wantTrue && wantFalse) break;
2477
+ }
2478
+ const yes = wantTrue ? a[1].evaluate(c) : FormulaValue.blank;
2479
+ const no = wantFalse ? a.length > 2 ? a[2].evaluate(c) : FormulaValue.false_ : FormulaValue.blank;
2480
+ const pick = (v, r, col) => {
2481
+ if (!v.isArray) return v;
2482
+ const arr = v.arrayVal;
2483
+ return r < arr.rows && col < arr.columns ? arr.get(r, col) : FormulaValue.errorNA;
2484
+ };
2485
+ const out = new ArrayValue(mask.rows, mask.columns);
2486
+ for (let r = 0; r < mask.rows; r++) {
2487
+ for (let col = 0; col < mask.columns; col++) {
2488
+ const b = mask.get(r, col).coerceToBool();
2489
+ out.set(r, col, b.booleanValue ? pick(yes, r, col) : pick(no, r, col));
2490
+ }
2491
+ }
2492
+ return FormulaValue.array(out);
2493
+ }
2494
+ function ifCaught(a, c, caught) {
2336
2495
  const v = a[0].evaluate(c);
2337
- return v.isError ? a[1].evaluate(c) : v;
2496
+ if (!v.isArray) return caught(v) ? a[1].evaluate(c) : v;
2497
+ const arr = v.arrayVal;
2498
+ let any = false;
2499
+ for (const item of arr.values()) {
2500
+ if (caught(item)) {
2501
+ any = true;
2502
+ break;
2503
+ }
2504
+ }
2505
+ if (!any) return v;
2506
+ const fb = a[1].evaluate(c);
2507
+ const fbArr = fb.isArray ? fb.arrayVal : null;
2508
+ const out = new ArrayValue(arr.rows, arr.columns);
2509
+ for (let r = 0; r < arr.rows; r++) {
2510
+ for (let col = 0; col < arr.columns; col++) {
2511
+ const item = arr.get(r, col);
2512
+ if (!caught(item)) {
2513
+ out.set(r, col, item);
2514
+ continue;
2515
+ }
2516
+ out.set(r, col, fbArr ? r < fbArr.rows && col < fbArr.columns ? fbArr.get(r, col) : FormulaValue.errorNA : fb);
2517
+ }
2518
+ }
2519
+ return FormulaValue.array(out);
2520
+ }
2521
+ function ifError(a, c) {
2522
+ return ifCaught(a, c, (v) => v.isError);
2338
2523
  }
2339
2524
  function ifNa(a, c) {
2340
- const v = a[0].evaluate(c);
2341
- return v.isError && v.errorCode === 7 /* NA */ ? a[1].evaluate(c) : v;
2525
+ return ifCaught(a, c, (v) => v.isError && v.errorCode === 7 /* NA */);
2342
2526
  }
2343
2527
  function ifs(a, c) {
2344
2528
  for (let i = 0; i + 1 < a.length; i += 2) {
@@ -2395,21 +2579,21 @@ function fromOA(oa) {
2395
2579
  function registerDate(r) {
2396
2580
  r.register("NOW", now, 0, 0, true);
2397
2581
  r.register("TODAY", today, 0, 0, true);
2398
- r.register("DATE", date_, 3, 3);
2399
- r.register("YEAR", year, 1, 1);
2400
- r.register("MONTH", month, 1, 1);
2401
- r.register("DAY", day, 1, 1);
2402
- r.register("HOUR", hour, 1, 1);
2403
- r.register("MINUTE", minute, 1, 1);
2404
- r.register("SECOND", second, 1, 1);
2405
- r.register("DATEVALUE", dateValue, 1, 1);
2406
- r.register("DAYS", days, 2, 2);
2407
- r.register("EDATE", edate, 2, 2);
2408
- r.register("EOMONTH", eomonth, 2, 2);
2409
- r.register("WEEKDAY", weekday, 1, 2);
2410
- r.register("WEEKNUM", weeknum, 1, 2);
2582
+ r.registerElementwise("DATE", date_, 3, 3);
2583
+ r.registerElementwise("YEAR", year, 1, 1);
2584
+ r.registerElementwise("MONTH", month, 1, 1);
2585
+ r.registerElementwise("DAY", day, 1, 1);
2586
+ r.registerElementwise("HOUR", hour, 1, 1);
2587
+ r.registerElementwise("MINUTE", minute, 1, 1);
2588
+ r.registerElementwise("SECOND", second, 1, 1);
2589
+ r.registerElementwise("DATEVALUE", dateValue, 1, 1);
2590
+ r.registerElementwise("DAYS", days, 2, 2);
2591
+ r.registerElementwise("EDATE", edate, 2, 2);
2592
+ r.registerElementwise("EOMONTH", eomonth, 2, 2);
2593
+ r.registerElementwise("WEEKDAY", weekday, 1, 2);
2594
+ r.registerElementwise("WEEKNUM", weeknum, 1, 2);
2411
2595
  r.register("NETWORKDAYS", networkdays, 2, 3);
2412
- r.register("DATEDIF", datedif, 3, 3);
2596
+ r.registerElementwise("DATEDIF", datedif, 3, 3);
2413
2597
  }
2414
2598
  function evalDate(a, c, idx) {
2415
2599
  const r = FormulaHelper.evalDouble(a[idx], c);
@@ -3222,20 +3406,20 @@ function ifsAggregate(a, c, mode2) {
3222
3406
 
3223
3407
  // src/functions/info-functions.ts
3224
3408
  function registerInfo(r) {
3225
- r.register("ISBLANK", isBlank, 1, 1);
3226
- r.register("ISNUMBER", isNumber, 1, 1);
3227
- r.register("ISTEXT", isText, 1, 1);
3228
- r.register("ISERROR", isError, 1, 1);
3229
- r.register("ISERR", isErr, 1, 1);
3230
- r.register("ISLOGICAL", isLogical, 1, 1);
3231
- r.register("ISNA", isNa, 1, 1);
3232
- r.register("ISNONTEXT", isNonText, 1, 1);
3409
+ r.registerElementwise("ISBLANK", isBlank, 1, 1);
3410
+ r.registerElementwise("ISNUMBER", isNumber, 1, 1);
3411
+ r.registerElementwise("ISTEXT", isText, 1, 1);
3412
+ r.registerElementwise("ISERROR", isError, 1, 1);
3413
+ r.registerElementwise("ISERR", isErr, 1, 1);
3414
+ r.registerElementwise("ISLOGICAL", isLogical, 1, 1);
3415
+ r.registerElementwise("ISNA", isNa, 1, 1);
3416
+ r.registerElementwise("ISNONTEXT", isNonText, 1, 1);
3233
3417
  r.register("NA", na, 0, 0);
3234
- r.register("TYPE", type_, 1, 1);
3235
- r.register("N", n_, 1, 1);
3236
- r.register("ISODD", isOdd, 1, 1);
3237
- r.register("ISEVEN", isEven, 1, 1);
3238
- r.register("ERROR.TYPE", errorType, 1, 1);
3418
+ r.registerElementwise("TYPE", type_, 1, 1);
3419
+ r.registerElementwise("N", n_, 1, 1);
3420
+ r.registerElementwise("ISODD", isOdd, 1, 1);
3421
+ r.registerElementwise("ISEVEN", isEven, 1, 1);
3422
+ r.registerElementwise("ERROR.TYPE", errorType, 1, 1);
3239
3423
  }
3240
3424
  function isBlank(a, c) {
3241
3425
  return FormulaValue.boolean(a[0].evaluate(c).isBlank);
@@ -4061,22 +4245,46 @@ function unique(a, c) {
4061
4245
  const out = fromRows(result);
4062
4246
  return byCol2 ? FormulaValue.array(out.arrayVal.transpose()) : out;
4063
4247
  }
4248
+ var numVector = (a, c, i, dflt) => {
4249
+ if (i >= a.length) return { ok: true, v: [dflt] };
4250
+ const val = a[i].evaluate(c);
4251
+ if (val.isError) return { ok: false, e: val };
4252
+ const out = [];
4253
+ for (const item of val.isArray ? val.arrayVal.values() : [val]) {
4254
+ if (item.isBlank) continue;
4255
+ const d = item.tryAsDouble();
4256
+ if (!d.ok) return { ok: false, e: FormulaValue.errorValue };
4257
+ out.push(d.value);
4258
+ }
4259
+ return out.length > 0 ? { ok: true, v: out } : { ok: true, v: [dflt] };
4260
+ };
4064
4261
  function sort(a, c) {
4065
4262
  const v = a[0].evaluate(c);
4066
4263
  if (v.isError) return v;
4067
- const sortIndex = num4(a, c, 1, 1);
4068
- if (!sortIndex.ok) return sortIndex.e;
4069
- const sortOrder = num4(a, c, 2, 1);
4070
- if (!sortOrder.ok) return sortOrder.e;
4264
+ const indices = numVector(a, c, 1, 1);
4265
+ if (!indices.ok) return indices.e;
4266
+ const orders = numVector(a, c, 2, 1);
4267
+ if (!orders.ok) return orders.e;
4071
4268
  const byCol2 = a.length > 3 ? a[3].evaluate(c).coerceToBool().booleanValue : false;
4269
+ if (orders.v.length !== 1 && orders.v.length !== indices.v.length) {
4270
+ return FormulaValue.errorValue;
4271
+ }
4072
4272
  const base = byCol2 ? asArray2(v).transpose() : asArray2(v);
4073
4273
  const rows2 = toRows(base);
4074
- const idx = Math.trunc(sortIndex.n) - 1;
4075
- const dir = sortOrder.n < 0 ? -1 : 1;
4076
- if (rows2.length > 0 && (idx < 0 || idx >= rows2[0].length)) return FormulaValue.errorValue;
4274
+ const keys = indices.v.map((n, i) => ({
4275
+ col: Math.trunc(n) - 1,
4276
+ dir: (orders.v.length === 1 ? orders.v[0] : orders.v[i]) < 0 ? -1 : 1
4277
+ }));
4278
+ const width = rows2.length > 0 ? rows2[0].length : 0;
4279
+ if (rows2.length > 0 && keys.some((k) => k.col < 0 || k.col >= width)) {
4280
+ return FormulaValue.errorValue;
4281
+ }
4077
4282
  const sorted = rows2.map((r, i) => ({ r, i })).sort((x, y) => {
4078
- const cmp = FormulaValue.compare(x.r[idx], y.r[idx]) * dir;
4079
- return cmp !== 0 ? cmp : x.i - y.i;
4283
+ for (const k of keys) {
4284
+ const cmp = FormulaValue.compare(x.r[k.col], y.r[k.col]) * k.dir;
4285
+ if (cmp !== 0) return cmp;
4286
+ }
4287
+ return x.i - y.i;
4080
4288
  }).map((o) => o.r);
4081
4289
  const out = fromRows(sorted);
4082
4290
  return byCol2 ? FormulaValue.array(out.arrayVal.transpose()) : out;
@@ -4299,7 +4507,8 @@ function toRow(a, c) {
4299
4507
  }
4300
4508
 
4301
4509
  // src/function-registry.ts
4302
- var _default, _functions, _FunctionRegistry_instances, registerBuiltIns_fn;
4510
+ var MAX_LIFTED_CELLS = 1048576;
4511
+ var _default, _functions, _FunctionRegistry_static, executeElementwise_fn, _FunctionRegistry_instances, registerBuiltIns_fn;
4303
4512
  var _FunctionRegistry = class _FunctionRegistry {
4304
4513
  constructor() {
4305
4514
  __privateAdd(this, _FunctionRegistry_instances);
@@ -4321,17 +4530,45 @@ var _FunctionRegistry = class _FunctionRegistry {
4321
4530
  minArgs,
4322
4531
  maxArgs,
4323
4532
  isVolatile,
4324
- handler
4533
+ handler,
4534
+ elementwise: false
4535
+ });
4536
+ }
4537
+ /**
4538
+ * Registers a **scalar** function — one whose arguments are single values —
4539
+ * and lifts it over arrays automatically.
4540
+ *
4541
+ * `LEFT(A2:A100, 3)` is not a special form in Excel: LEFT takes one string, and
4542
+ * the grid maps it over the range, giving a 99-row array. Without that lifting
4543
+ * the range collapses to one value, so the dynamic array built on top of it —
4544
+ * `FILTER(IFERROR(LEFT(A2:A100,3),""), …)` — filters a 1×1 input and returns
4545
+ * `#CALC!`. Lifting belongs here rather than in each handler: the ~40 scalar
4546
+ * text/math/date functions then get it for free and cannot each get it subtly
4547
+ * wrong.
4548
+ *
4549
+ * Only mark functions that are genuinely per-cell. Anything that *consumes* an
4550
+ * array (SUM, COUNTIF, FILTER, SORT, the lazy branch functions) must keep
4551
+ * `register`, or lifting would map it over the array it is meant to reduce.
4552
+ */
4553
+ registerElementwise(name, handler, minArgs = 0, maxArgs = -1) {
4554
+ __privateGet(this, _functions).set(name.toUpperCase(), {
4555
+ name: name.toUpperCase(),
4556
+ minArgs,
4557
+ maxArgs,
4558
+ isVolatile: false,
4559
+ handler,
4560
+ elementwise: true
4325
4561
  });
4326
4562
  }
4327
4563
  /** Executes a function by name with argument validation. */
4328
4564
  execute(name, args, ctx) {
4565
+ var _a;
4329
4566
  const def = __privateGet(this, _functions).get(name.toUpperCase());
4330
4567
  if (!def) return FormulaValue.errorName;
4331
4568
  if (args.length < def.minArgs) return FormulaValue.errorValue;
4332
4569
  if (def.maxArgs >= 0 && args.length > def.maxArgs) return FormulaValue.errorValue;
4333
4570
  try {
4334
- return def.handler(args, ctx);
4571
+ return def.elementwise ? __privateMethod(_a = _FunctionRegistry, _FunctionRegistry_static, executeElementwise_fn).call(_a, def, args, ctx) : def.handler(args, ctx);
4335
4572
  } catch {
4336
4573
  return FormulaValue.errorValue;
4337
4574
  }
@@ -4347,6 +4584,42 @@ var _FunctionRegistry = class _FunctionRegistry {
4347
4584
  };
4348
4585
  _default = new WeakMap();
4349
4586
  _functions = new WeakMap();
4587
+ _FunctionRegistry_static = new WeakSet();
4588
+ executeElementwise_fn = function(def, args, ctx) {
4589
+ const values = args.map((a) => a.evaluate(ctx));
4590
+ let rows2 = 1, cols = 1;
4591
+ for (const v of values) {
4592
+ if (!v.isArray) continue;
4593
+ const a = v.arrayVal;
4594
+ if (a.rows > rows2) rows2 = a.rows;
4595
+ if (a.columns > cols) cols = a.columns;
4596
+ }
4597
+ if (rows2 === 1 && cols === 1) {
4598
+ return def.handler(values.map((v) => new ValueNode(v.isArray ? v.arrayVal.get(0, 0) : v)), ctx);
4599
+ }
4600
+ if (rows2 * cols > MAX_LIFTED_CELLS) return FormulaValue.errorValue;
4601
+ for (const v of values) {
4602
+ if (!v.isArray) continue;
4603
+ const a = v.arrayVal;
4604
+ if (a.rows !== 1 && a.rows !== rows2 || a.columns !== 1 && a.columns !== cols) {
4605
+ return FormulaValue.errorValue;
4606
+ }
4607
+ }
4608
+ const nodes = values.map((v) => new ValueNode(v));
4609
+ const out = new ArrayValue(rows2, cols);
4610
+ for (let r = 0; r < rows2; r++) {
4611
+ for (let c = 0; c < cols; c++) {
4612
+ for (let i = 0; i < values.length; i++) {
4613
+ const v = values[i];
4614
+ if (!v.isArray) continue;
4615
+ const a = v.arrayVal;
4616
+ nodes[i].value = a.get(a.rows === 1 ? 0 : r, a.columns === 1 ? 0 : c);
4617
+ }
4618
+ out.set(r, c, def.handler(nodes, ctx));
4619
+ }
4620
+ }
4621
+ return FormulaValue.array(out);
4622
+ };
4350
4623
  _FunctionRegistry_instances = new WeakSet();
4351
4624
  registerBuiltIns_fn = function() {
4352
4625
  registerMath(this);
@@ -4361,6 +4634,7 @@ registerBuiltIns_fn = function() {
4361
4634
  registerAggregate(this);
4362
4635
  registerArray(this);
4363
4636
  };
4637
+ __privateAdd(_FunctionRegistry, _FunctionRegistry_static);
4364
4638
  __privateAdd(_FunctionRegistry, _default);
4365
4639
  var FunctionRegistry = _FunctionRegistry;
4366
4640
  var FormulaHelper;
@@ -5222,6 +5496,7 @@ function createWorkbookRecalcModel(workbook) {
5222
5496
  getDefinedName: (name, sheet) => workbook.getDefinedName(name, sheet)
5223
5497
  };
5224
5498
  }
5499
+ var MAX_ADOPTED_SPILL_CELLS = 262144;
5225
5500
  var normSheet = (s) => s.toUpperCase();
5226
5501
  var normRef = (r) => r.replace(/\$/g, "").toUpperCase();
5227
5502
  var keyOf = (sheet, ref) => `${normSheet(sheet)}!${normRef(ref)}`;
@@ -5232,7 +5507,7 @@ function parseKey(key) {
5232
5507
  const { row: row2, column: column2 } = parseCellRef(ref);
5233
5508
  return { sheet, ref, row: row2, col: column2 };
5234
5509
  }
5235
- var _model, _registry, _formulas, _sheetNames, _spills, _spillOwner, _dependents, _volatiles, _sheetLikes, _workbookLike, _rangeCache, _RecalcEngine_instances, writeCell_fn, register_fn, unregister_fn, rememberSheet_fn, recalcInOrder_fn, applyShift_fn, shiftPrecedents_fn, shiftSpillBookkeeping_fn, recalcFrom_fn, runFixpoint_fn, addVolatiles_fn, dependentClosure_fn, forEachDirectDependent_fn, evaluatePass_fn, writeResult_fn, isOccupied_fn, clearSpill_fn, evaluateFormulaValue_fn, sheetLike_fn, buildSheetLike_fn, buildWorkbookLike_fn;
5510
+ var _model, _registry, _formulas, _sheetNames, _spills, _spillOwner, _dependents, _volatiles, _sheetLikes, _workbookLike, _rangeCache, _RecalcEngine_instances, writeCell_fn, register_fn, unregister_fn, rememberSheet_fn, adoptDeclaredSpill_fn, recalcInOrder_fn, applyShift_fn, shiftPrecedents_fn, shiftSpillBookkeeping_fn, recalcFrom_fn, runFixpoint_fn, addVolatiles_fn, dependentClosure_fn, forEachDirectDependent_fn, evaluatePass_fn, writeResult_fn, isOccupied_fn, clearSpill_fn, evaluateFormulaValue_fn, sheetLike_fn, buildSheetLike_fn, buildWorkbookLike_fn;
5236
5511
  var RecalcEngine = class {
5237
5512
  constructor(model, registry = FunctionRegistry.default) {
5238
5513
  __privateAdd(this, _RecalcEngine_instances);
@@ -5340,11 +5615,12 @@ var RecalcEngine = class {
5340
5615
  const ast = parseFormulaUncached(text);
5341
5616
  const { refs, volatile } = extractReferences(ast, s, __privateGet(this, _registry), resolveName2);
5342
5617
  __privateMethod(this, _RecalcEngine_instances, rememberSheet_fn).call(this, sheet);
5618
+ const key = keyOf(s, r);
5343
5619
  __privateMethod(this, _RecalcEngine_instances, register_fn).call(this, {
5344
5620
  sheet: s,
5345
5621
  sheetName: sheet,
5346
5622
  ref: r,
5347
- key: keyOf(s, r),
5623
+ key,
5348
5624
  row: row2,
5349
5625
  col: column2,
5350
5626
  formula: text,
@@ -5352,6 +5628,7 @@ var RecalcEngine = class {
5352
5628
  refs,
5353
5629
  volatile
5354
5630
  });
5631
+ __privateMethod(this, _RecalcEngine_instances, adoptDeclaredSpill_fn).call(this, s, sheet, r, key, row2, column2);
5355
5632
  registered++;
5356
5633
  } catch (err) {
5357
5634
  failed.push({ sheet, ref, error: err instanceof Error ? err.message : String(err) });
@@ -5519,6 +5796,51 @@ unregister_fn = function(key) {
5519
5796
  rememberSheet_fn = function(name) {
5520
5797
  __privateGet(this, _sheetNames).set(normSheet(name), name);
5521
5798
  };
5799
+ /**
5800
+ * Takes ownership of the spill block a *file* already declared for an anchor.
5801
+ *
5802
+ * Excel stores a dynamic array as one formula on the anchor plus the spilled
5803
+ * results written as plain cached values in the cells below/right, and records
5804
+ * the extent in the anchor's `<f t="array" ref="…">`. Without this step the
5805
+ * engine meets those cached values on the first recalculation, sees literal
5806
+ * content inside the block it wants to spill into, and reports `#SPILL!` for
5807
+ * every dynamic array in every real file. Registering the declared block as
5808
+ * this anchor's existing spill makes them what they actually are — the anchor's
5809
+ * own territory, free to overwrite — and reuses the ordinary shrink path, so a
5810
+ * result smaller than the declared block clears the leftovers.
5811
+ *
5812
+ * Cost is one Set entry per already-spilled cell, paid once at load. A declared
5813
+ * block far larger than any real spill (a corrupt or hand-written `ref`) is
5814
+ * skipped rather than materialised.
5815
+ */
5816
+ adoptDeclaredSpill_fn = function(s, sheetName, ref, anchorKey, row2, col) {
5817
+ const declared = __privateGet(this, _model).getSpillRange?.(sheetName, ref);
5818
+ if (!declared || !declared.includes(":")) return;
5819
+ let rect;
5820
+ try {
5821
+ rect = parseRangeRef(declared);
5822
+ } catch {
5823
+ return;
5824
+ }
5825
+ if (rect.startRow !== row2 || rect.startColumn !== col) return;
5826
+ const height = rect.endRow - rect.startRow + 1;
5827
+ const width = rect.endColumn - rect.startColumn + 1;
5828
+ if (height < 1 || width < 1) return;
5829
+ if (height * width > MAX_ADOPTED_SPILL_CELLS) return;
5830
+ if (height === 1 && width === 1) return;
5831
+ const members = /* @__PURE__ */ new Set();
5832
+ for (let r = rect.startRow; r <= rect.endRow; r++) {
5833
+ for (let c = rect.startColumn; c <= rect.endColumn; c++) {
5834
+ if (r === row2 && c === col) continue;
5835
+ const key = keyOf(s, cellRefFromRowCol(r, c));
5836
+ if (__privateGet(this, _formulas).has(key)) continue;
5837
+ if (__privateGet(this, _spillOwner).has(key)) continue;
5838
+ members.add(key);
5839
+ __privateGet(this, _spillOwner).set(key, anchorKey);
5840
+ }
5841
+ }
5842
+ if (members.size > 0) __privateGet(this, _spills).set(anchorKey, members);
5843
+ };
5522
5844
  /**
5523
5845
  * One pass in a caller-supplied order, watching for inversions.
5524
5846
  *