@devmm/puredocs-excel-formula 1.0.8 → 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.cjs CHANGED
@@ -807,6 +807,16 @@ var ArrayLiteralNode = class extends FormulaNode {
807
807
  }
808
808
  };
809
809
  _value = new WeakMap();
810
+ var ValueNode = class extends FormulaNode {
811
+ /** Mutable so one wrapper can be re-pointed across a lifted call's cells. */
812
+ constructor(value2) {
813
+ super();
814
+ this.value = value2;
815
+ }
816
+ evaluate() {
817
+ return this.value;
818
+ }
819
+ };
810
820
  var BlankNode = class extends FormulaNode {
811
821
  evaluate() {
812
822
  return FormulaValue.blank;
@@ -1576,42 +1586,42 @@ function registerMath(r) {
1576
1586
  r.register("PRODUCT", product, 1);
1577
1587
  r.register("SUMPRODUCT", sumProduct, 1);
1578
1588
  r.register("SUMSQ", sumSq, 1);
1579
- r.register("ABS", abs, 1, 1);
1580
- r.register("ROUND", round, 2, 2);
1581
- r.register("ROUNDUP", roundUp, 2, 2);
1582
- r.register("ROUNDDOWN", roundDown, 2, 2);
1583
- r.register("CEILING", ceiling, 2, 2);
1584
- r.register("CEILING.MATH", ceiling, 2, 2);
1585
- r.register("FLOOR", floor, 2, 2);
1586
- r.register("FLOOR.MATH", floor, 2, 2);
1587
- r.register("INT", int_, 1, 1);
1588
- r.register("TRUNC", trunc, 1, 2);
1589
- r.register("MOD", mod, 2, 2);
1590
- r.register("QUOTIENT", quotient, 2, 2);
1591
- r.register("POWER", power, 2, 2);
1592
- r.register("SQRT", sqrt, 1, 1);
1593
- r.register("SIGN", sign, 1, 1);
1589
+ r.registerElementwise("ABS", abs, 1, 1);
1590
+ r.registerElementwise("ROUND", round, 2, 2);
1591
+ r.registerElementwise("ROUNDUP", roundUp, 2, 2);
1592
+ r.registerElementwise("ROUNDDOWN", roundDown, 2, 2);
1593
+ r.registerElementwise("CEILING", ceiling, 2, 2);
1594
+ r.registerElementwise("CEILING.MATH", ceiling, 2, 2);
1595
+ r.registerElementwise("FLOOR", floor, 2, 2);
1596
+ r.registerElementwise("FLOOR.MATH", floor, 2, 2);
1597
+ r.registerElementwise("INT", int_, 1, 1);
1598
+ r.registerElementwise("TRUNC", trunc, 1, 2);
1599
+ r.registerElementwise("MOD", mod, 2, 2);
1600
+ r.registerElementwise("QUOTIENT", quotient, 2, 2);
1601
+ r.registerElementwise("POWER", power, 2, 2);
1602
+ r.registerElementwise("SQRT", sqrt, 1, 1);
1603
+ r.registerElementwise("SIGN", sign, 1, 1);
1594
1604
  r.register("PI", pi, 0, 0);
1595
1605
  r.register("RAND", rand, 0, 0, true);
1596
1606
  r.register("RANDBETWEEN", randBetween, 2, 2, true);
1597
- r.register("LOG", log, 1, 2);
1598
- r.register("LOG10", log10, 1, 1);
1599
- r.register("LN", ln, 1, 1);
1600
- r.register("EXP", exp, 1, 1);
1601
- r.register("FACT", fact, 1, 1);
1602
- r.register("COMBIN", combin, 2, 2);
1603
- r.register("SIN", unary(Math.sin), 1, 1);
1604
- r.register("COS", unary(Math.cos), 1, 1);
1605
- r.register("TAN", unary(Math.tan), 1, 1);
1606
- r.register("ASIN", asin, 1, 1);
1607
- r.register("ACOS", acos, 1, 1);
1608
- r.register("ATAN", unary(Math.atan), 1, 1);
1609
- r.register("ATAN2", atan2, 2, 2);
1610
- r.register("SINH", unary(Math.sinh), 1, 1);
1611
- r.register("COSH", unary(Math.cosh), 1, 1);
1612
- r.register("TANH", unary(Math.tanh), 1, 1);
1613
- r.register("DEGREES", unary((r2d) => r2d * 180 / Math.PI), 1, 1);
1614
- r.register("RADIANS", unary((d) => d * Math.PI / 180), 1, 1);
1607
+ r.registerElementwise("LOG", log, 1, 2);
1608
+ r.registerElementwise("LOG10", log10, 1, 1);
1609
+ r.registerElementwise("LN", ln, 1, 1);
1610
+ r.registerElementwise("EXP", exp, 1, 1);
1611
+ r.registerElementwise("FACT", fact, 1, 1);
1612
+ r.registerElementwise("COMBIN", combin, 2, 2);
1613
+ r.registerElementwise("SIN", unary(Math.sin), 1, 1);
1614
+ r.registerElementwise("COS", unary(Math.cos), 1, 1);
1615
+ r.registerElementwise("TAN", unary(Math.tan), 1, 1);
1616
+ r.registerElementwise("ASIN", asin, 1, 1);
1617
+ r.registerElementwise("ACOS", acos, 1, 1);
1618
+ r.registerElementwise("ATAN", unary(Math.atan), 1, 1);
1619
+ r.registerElementwise("ATAN2", atan2, 2, 2);
1620
+ r.registerElementwise("SINH", unary(Math.sinh), 1, 1);
1621
+ r.registerElementwise("COSH", unary(Math.cosh), 1, 1);
1622
+ r.registerElementwise("TANH", unary(Math.tanh), 1, 1);
1623
+ r.registerElementwise("DEGREES", unary((r2d) => r2d * 180 / Math.PI), 1, 1);
1624
+ r.registerElementwise("RADIANS", unary((d) => d * Math.PI / 180), 1, 1);
1615
1625
  }
1616
1626
  function valueAt(v, i) {
1617
1627
  return v.isArray ? v.arrayVal.getFlat(i) : v;
@@ -2043,31 +2053,31 @@ function combin(a, c) {
2043
2053
  return FormulaValue.number(Math.round(result));
2044
2054
  }
2045
2055
  function registerText(r) {
2046
- r.register("LEFT", left, 1, 2);
2047
- r.register("RIGHT", right, 1, 2);
2048
- r.register("MID", mid, 3, 3);
2049
- r.register("LEN", len, 1, 1);
2050
- r.register("UPPER", upper, 1, 1);
2051
- r.register("LOWER", lower, 1, 1);
2052
- r.register("PROPER", proper, 1, 1);
2053
- r.register("TRIM", trim, 1, 1);
2054
- r.register("CLEAN", clean, 1, 1);
2055
- r.register("SUBSTITUTE", substitute, 3, 4);
2056
- r.register("REPLACE", replace, 4, 4);
2056
+ r.registerElementwise("LEFT", left, 1, 2);
2057
+ r.registerElementwise("RIGHT", right, 1, 2);
2058
+ r.registerElementwise("MID", mid, 3, 3);
2059
+ r.registerElementwise("LEN", len, 1, 1);
2060
+ r.registerElementwise("UPPER", upper, 1, 1);
2061
+ r.registerElementwise("LOWER", lower, 1, 1);
2062
+ r.registerElementwise("PROPER", proper, 1, 1);
2063
+ r.registerElementwise("TRIM", trim, 1, 1);
2064
+ r.registerElementwise("CLEAN", clean, 1, 1);
2065
+ r.registerElementwise("SUBSTITUTE", substitute, 3, 4);
2066
+ r.registerElementwise("REPLACE", replace, 4, 4);
2057
2067
  r.register("CONCATENATE", concatenate, 1);
2058
2068
  r.register("CONCAT", concatenate, 1);
2059
2069
  r.register("TEXTJOIN", textJoin, 3);
2060
- r.register("TEXT", text_, 2, 2);
2061
- r.register("VALUE", value, 1, 1);
2062
- r.register("FIND", find, 2, 3);
2063
- r.register("SEARCH", search, 2, 3);
2064
- r.register("REPT", rept, 2, 2);
2065
- r.register("EXACT", exact, 2, 2);
2066
- r.register("CHAR", char_, 1, 1);
2067
- r.register("CODE", code, 1, 1);
2068
- r.register("T", t_, 1, 1);
2069
- r.register("TEXTBEFORE", textBefore, 2, 3);
2070
- r.register("TEXTAFTER", textAfter, 2, 3);
2070
+ r.registerElementwise("TEXT", text_, 2, 2);
2071
+ r.registerElementwise("VALUE", value, 1, 1);
2072
+ r.registerElementwise("FIND", find, 2, 3);
2073
+ r.registerElementwise("SEARCH", search, 2, 3);
2074
+ r.registerElementwise("REPT", rept, 2, 2);
2075
+ r.registerElementwise("EXACT", exact, 2, 2);
2076
+ r.registerElementwise("CHAR", char_, 1, 1);
2077
+ r.registerElementwise("CODE", code, 1, 1);
2078
+ r.registerElementwise("T", t_, 1, 1);
2079
+ r.registerElementwise("TEXTBEFORE", textBefore, 2, 3);
2080
+ r.registerElementwise("TEXTAFTER", textAfter, 2, 3);
2071
2081
  }
2072
2082
  function str(a, c, idx) {
2073
2083
  const r = exports.FormulaHelper.evalString(a[idx], c);
@@ -2381,6 +2391,7 @@ function registerLogical(r) {
2381
2391
  function if_(a, c) {
2382
2392
  const cond = a[0].evaluate(c);
2383
2393
  if (cond.isError) return cond;
2394
+ if (cond.isArray) return ifArray(cond.arrayVal, a, c);
2384
2395
  const b = cond.coerceToBool();
2385
2396
  if (b.isError) return b;
2386
2397
  return b.booleanValue ? a[1].evaluate(c) : a.length > 2 ? a[2].evaluate(c) : FormulaValue.false_;
@@ -2457,13 +2468,63 @@ function xor(a, c) {
2457
2468
  }
2458
2469
  return FormulaValue.boolean(trueCount % 2 === 1);
2459
2470
  }
2460
- function ifError(a, c) {
2471
+ function ifArray(mask, a, c) {
2472
+ let wantTrue = false, wantFalse = false;
2473
+ for (const item of mask.values()) {
2474
+ const b = item.coerceToBool();
2475
+ if (b.isError) return b;
2476
+ if (b.booleanValue) wantTrue = true;
2477
+ else wantFalse = true;
2478
+ if (wantTrue && wantFalse) break;
2479
+ }
2480
+ const yes = wantTrue ? a[1].evaluate(c) : FormulaValue.blank;
2481
+ const no = wantFalse ? a.length > 2 ? a[2].evaluate(c) : FormulaValue.false_ : FormulaValue.blank;
2482
+ const pick = (v, r, col) => {
2483
+ if (!v.isArray) return v;
2484
+ const arr = v.arrayVal;
2485
+ return r < arr.rows && col < arr.columns ? arr.get(r, col) : FormulaValue.errorNA;
2486
+ };
2487
+ const out = new ArrayValue(mask.rows, mask.columns);
2488
+ for (let r = 0; r < mask.rows; r++) {
2489
+ for (let col = 0; col < mask.columns; col++) {
2490
+ const b = mask.get(r, col).coerceToBool();
2491
+ out.set(r, col, b.booleanValue ? pick(yes, r, col) : pick(no, r, col));
2492
+ }
2493
+ }
2494
+ return FormulaValue.array(out);
2495
+ }
2496
+ function ifCaught(a, c, caught) {
2461
2497
  const v = a[0].evaluate(c);
2462
- return v.isError ? a[1].evaluate(c) : v;
2498
+ if (!v.isArray) return caught(v) ? a[1].evaluate(c) : v;
2499
+ const arr = v.arrayVal;
2500
+ let any = false;
2501
+ for (const item of arr.values()) {
2502
+ if (caught(item)) {
2503
+ any = true;
2504
+ break;
2505
+ }
2506
+ }
2507
+ if (!any) return v;
2508
+ const fb = a[1].evaluate(c);
2509
+ const fbArr = fb.isArray ? fb.arrayVal : null;
2510
+ const out = new ArrayValue(arr.rows, arr.columns);
2511
+ for (let r = 0; r < arr.rows; r++) {
2512
+ for (let col = 0; col < arr.columns; col++) {
2513
+ const item = arr.get(r, col);
2514
+ if (!caught(item)) {
2515
+ out.set(r, col, item);
2516
+ continue;
2517
+ }
2518
+ out.set(r, col, fbArr ? r < fbArr.rows && col < fbArr.columns ? fbArr.get(r, col) : FormulaValue.errorNA : fb);
2519
+ }
2520
+ }
2521
+ return FormulaValue.array(out);
2522
+ }
2523
+ function ifError(a, c) {
2524
+ return ifCaught(a, c, (v) => v.isError);
2463
2525
  }
2464
2526
  function ifNa(a, c) {
2465
- const v = a[0].evaluate(c);
2466
- return v.isError && v.errorCode === 7 /* NA */ ? a[1].evaluate(c) : v;
2527
+ return ifCaught(a, c, (v) => v.isError && v.errorCode === 7 /* NA */);
2467
2528
  }
2468
2529
  function ifs(a, c) {
2469
2530
  for (let i = 0; i + 1 < a.length; i += 2) {
@@ -2520,21 +2581,21 @@ function fromOA(oa) {
2520
2581
  function registerDate(r) {
2521
2582
  r.register("NOW", now, 0, 0, true);
2522
2583
  r.register("TODAY", today, 0, 0, true);
2523
- r.register("DATE", date_, 3, 3);
2524
- r.register("YEAR", year, 1, 1);
2525
- r.register("MONTH", month, 1, 1);
2526
- r.register("DAY", day, 1, 1);
2527
- r.register("HOUR", hour, 1, 1);
2528
- r.register("MINUTE", minute, 1, 1);
2529
- r.register("SECOND", second, 1, 1);
2530
- r.register("DATEVALUE", dateValue, 1, 1);
2531
- r.register("DAYS", days, 2, 2);
2532
- r.register("EDATE", edate, 2, 2);
2533
- r.register("EOMONTH", eomonth, 2, 2);
2534
- r.register("WEEKDAY", weekday, 1, 2);
2535
- r.register("WEEKNUM", weeknum, 1, 2);
2584
+ r.registerElementwise("DATE", date_, 3, 3);
2585
+ r.registerElementwise("YEAR", year, 1, 1);
2586
+ r.registerElementwise("MONTH", month, 1, 1);
2587
+ r.registerElementwise("DAY", day, 1, 1);
2588
+ r.registerElementwise("HOUR", hour, 1, 1);
2589
+ r.registerElementwise("MINUTE", minute, 1, 1);
2590
+ r.registerElementwise("SECOND", second, 1, 1);
2591
+ r.registerElementwise("DATEVALUE", dateValue, 1, 1);
2592
+ r.registerElementwise("DAYS", days, 2, 2);
2593
+ r.registerElementwise("EDATE", edate, 2, 2);
2594
+ r.registerElementwise("EOMONTH", eomonth, 2, 2);
2595
+ r.registerElementwise("WEEKDAY", weekday, 1, 2);
2596
+ r.registerElementwise("WEEKNUM", weeknum, 1, 2);
2536
2597
  r.register("NETWORKDAYS", networkdays, 2, 3);
2537
- r.register("DATEDIF", datedif, 3, 3);
2598
+ r.registerElementwise("DATEDIF", datedif, 3, 3);
2538
2599
  }
2539
2600
  function evalDate(a, c, idx) {
2540
2601
  const r = exports.FormulaHelper.evalDouble(a[idx], c);
@@ -3347,20 +3408,20 @@ function ifsAggregate(a, c, mode2) {
3347
3408
 
3348
3409
  // src/functions/info-functions.ts
3349
3410
  function registerInfo(r) {
3350
- r.register("ISBLANK", isBlank, 1, 1);
3351
- r.register("ISNUMBER", isNumber, 1, 1);
3352
- r.register("ISTEXT", isText, 1, 1);
3353
- r.register("ISERROR", isError, 1, 1);
3354
- r.register("ISERR", isErr, 1, 1);
3355
- r.register("ISLOGICAL", isLogical, 1, 1);
3356
- r.register("ISNA", isNa, 1, 1);
3357
- r.register("ISNONTEXT", isNonText, 1, 1);
3411
+ r.registerElementwise("ISBLANK", isBlank, 1, 1);
3412
+ r.registerElementwise("ISNUMBER", isNumber, 1, 1);
3413
+ r.registerElementwise("ISTEXT", isText, 1, 1);
3414
+ r.registerElementwise("ISERROR", isError, 1, 1);
3415
+ r.registerElementwise("ISERR", isErr, 1, 1);
3416
+ r.registerElementwise("ISLOGICAL", isLogical, 1, 1);
3417
+ r.registerElementwise("ISNA", isNa, 1, 1);
3418
+ r.registerElementwise("ISNONTEXT", isNonText, 1, 1);
3358
3419
  r.register("NA", na, 0, 0);
3359
- r.register("TYPE", type_, 1, 1);
3360
- r.register("N", n_, 1, 1);
3361
- r.register("ISODD", isOdd, 1, 1);
3362
- r.register("ISEVEN", isEven, 1, 1);
3363
- r.register("ERROR.TYPE", errorType, 1, 1);
3420
+ r.registerElementwise("TYPE", type_, 1, 1);
3421
+ r.registerElementwise("N", n_, 1, 1);
3422
+ r.registerElementwise("ISODD", isOdd, 1, 1);
3423
+ r.registerElementwise("ISEVEN", isEven, 1, 1);
3424
+ r.registerElementwise("ERROR.TYPE", errorType, 1, 1);
3364
3425
  }
3365
3426
  function isBlank(a, c) {
3366
3427
  return FormulaValue.boolean(a[0].evaluate(c).isBlank);
@@ -4448,7 +4509,8 @@ function toRow(a, c) {
4448
4509
  }
4449
4510
 
4450
4511
  // src/function-registry.ts
4451
- var _default, _functions, _FunctionRegistry_instances, registerBuiltIns_fn;
4512
+ var MAX_LIFTED_CELLS = 1048576;
4513
+ var _default, _functions, _FunctionRegistry_static, executeElementwise_fn, _FunctionRegistry_instances, registerBuiltIns_fn;
4452
4514
  var _FunctionRegistry = class _FunctionRegistry {
4453
4515
  constructor() {
4454
4516
  __privateAdd(this, _FunctionRegistry_instances);
@@ -4470,17 +4532,45 @@ var _FunctionRegistry = class _FunctionRegistry {
4470
4532
  minArgs,
4471
4533
  maxArgs,
4472
4534
  isVolatile,
4473
- handler
4535
+ handler,
4536
+ elementwise: false
4537
+ });
4538
+ }
4539
+ /**
4540
+ * Registers a **scalar** function — one whose arguments are single values —
4541
+ * and lifts it over arrays automatically.
4542
+ *
4543
+ * `LEFT(A2:A100, 3)` is not a special form in Excel: LEFT takes one string, and
4544
+ * the grid maps it over the range, giving a 99-row array. Without that lifting
4545
+ * the range collapses to one value, so the dynamic array built on top of it —
4546
+ * `FILTER(IFERROR(LEFT(A2:A100,3),""), …)` — filters a 1×1 input and returns
4547
+ * `#CALC!`. Lifting belongs here rather than in each handler: the ~40 scalar
4548
+ * text/math/date functions then get it for free and cannot each get it subtly
4549
+ * wrong.
4550
+ *
4551
+ * Only mark functions that are genuinely per-cell. Anything that *consumes* an
4552
+ * array (SUM, COUNTIF, FILTER, SORT, the lazy branch functions) must keep
4553
+ * `register`, or lifting would map it over the array it is meant to reduce.
4554
+ */
4555
+ registerElementwise(name, handler, minArgs = 0, maxArgs = -1) {
4556
+ __privateGet(this, _functions).set(name.toUpperCase(), {
4557
+ name: name.toUpperCase(),
4558
+ minArgs,
4559
+ maxArgs,
4560
+ isVolatile: false,
4561
+ handler,
4562
+ elementwise: true
4474
4563
  });
4475
4564
  }
4476
4565
  /** Executes a function by name with argument validation. */
4477
4566
  execute(name, args, ctx) {
4567
+ var _a;
4478
4568
  const def = __privateGet(this, _functions).get(name.toUpperCase());
4479
4569
  if (!def) return FormulaValue.errorName;
4480
4570
  if (args.length < def.minArgs) return FormulaValue.errorValue;
4481
4571
  if (def.maxArgs >= 0 && args.length > def.maxArgs) return FormulaValue.errorValue;
4482
4572
  try {
4483
- return def.handler(args, ctx);
4573
+ return def.elementwise ? __privateMethod(_a = _FunctionRegistry, _FunctionRegistry_static, executeElementwise_fn).call(_a, def, args, ctx) : def.handler(args, ctx);
4484
4574
  } catch {
4485
4575
  return FormulaValue.errorValue;
4486
4576
  }
@@ -4496,6 +4586,42 @@ var _FunctionRegistry = class _FunctionRegistry {
4496
4586
  };
4497
4587
  _default = new WeakMap();
4498
4588
  _functions = new WeakMap();
4589
+ _FunctionRegistry_static = new WeakSet();
4590
+ executeElementwise_fn = function(def, args, ctx) {
4591
+ const values = args.map((a) => a.evaluate(ctx));
4592
+ let rows2 = 1, cols = 1;
4593
+ for (const v of values) {
4594
+ if (!v.isArray) continue;
4595
+ const a = v.arrayVal;
4596
+ if (a.rows > rows2) rows2 = a.rows;
4597
+ if (a.columns > cols) cols = a.columns;
4598
+ }
4599
+ if (rows2 === 1 && cols === 1) {
4600
+ return def.handler(values.map((v) => new ValueNode(v.isArray ? v.arrayVal.get(0, 0) : v)), ctx);
4601
+ }
4602
+ if (rows2 * cols > MAX_LIFTED_CELLS) return FormulaValue.errorValue;
4603
+ for (const v of values) {
4604
+ if (!v.isArray) continue;
4605
+ const a = v.arrayVal;
4606
+ if (a.rows !== 1 && a.rows !== rows2 || a.columns !== 1 && a.columns !== cols) {
4607
+ return FormulaValue.errorValue;
4608
+ }
4609
+ }
4610
+ const nodes = values.map((v) => new ValueNode(v));
4611
+ const out = new ArrayValue(rows2, cols);
4612
+ for (let r = 0; r < rows2; r++) {
4613
+ for (let c = 0; c < cols; c++) {
4614
+ for (let i = 0; i < values.length; i++) {
4615
+ const v = values[i];
4616
+ if (!v.isArray) continue;
4617
+ const a = v.arrayVal;
4618
+ nodes[i].value = a.get(a.rows === 1 ? 0 : r, a.columns === 1 ? 0 : c);
4619
+ }
4620
+ out.set(r, c, def.handler(nodes, ctx));
4621
+ }
4622
+ }
4623
+ return FormulaValue.array(out);
4624
+ };
4499
4625
  _FunctionRegistry_instances = new WeakSet();
4500
4626
  registerBuiltIns_fn = function() {
4501
4627
  registerMath(this);
@@ -4510,6 +4636,7 @@ registerBuiltIns_fn = function() {
4510
4636
  registerAggregate(this);
4511
4637
  registerArray(this);
4512
4638
  };
4639
+ __privateAdd(_FunctionRegistry, _FunctionRegistry_static);
4513
4640
  __privateAdd(_FunctionRegistry, _default);
4514
4641
  var FunctionRegistry = _FunctionRegistry;
4515
4642
  exports.FormulaHelper = void 0;
@@ -5371,6 +5498,7 @@ function createWorkbookRecalcModel(workbook) {
5371
5498
  getDefinedName: (name, sheet) => workbook.getDefinedName(name, sheet)
5372
5499
  };
5373
5500
  }
5501
+ var MAX_ADOPTED_SPILL_CELLS = 262144;
5374
5502
  var normSheet = (s) => s.toUpperCase();
5375
5503
  var normRef = (r) => r.replace(/\$/g, "").toUpperCase();
5376
5504
  var keyOf = (sheet, ref) => `${normSheet(sheet)}!${normRef(ref)}`;
@@ -5381,7 +5509,7 @@ function parseKey(key) {
5381
5509
  const { row: row2, column: column2 } = puredocsExcel.parseCellRef(ref);
5382
5510
  return { sheet, ref, row: row2, col: column2 };
5383
5511
  }
5384
- 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;
5512
+ 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;
5385
5513
  var RecalcEngine = class {
5386
5514
  constructor(model, registry = FunctionRegistry.default) {
5387
5515
  __privateAdd(this, _RecalcEngine_instances);
@@ -5489,11 +5617,12 @@ var RecalcEngine = class {
5489
5617
  const ast = parseFormulaUncached(text);
5490
5618
  const { refs, volatile } = extractReferences(ast, s, __privateGet(this, _registry), resolveName2);
5491
5619
  __privateMethod(this, _RecalcEngine_instances, rememberSheet_fn).call(this, sheet);
5620
+ const key = keyOf(s, r);
5492
5621
  __privateMethod(this, _RecalcEngine_instances, register_fn).call(this, {
5493
5622
  sheet: s,
5494
5623
  sheetName: sheet,
5495
5624
  ref: r,
5496
- key: keyOf(s, r),
5625
+ key,
5497
5626
  row: row2,
5498
5627
  col: column2,
5499
5628
  formula: text,
@@ -5501,6 +5630,7 @@ var RecalcEngine = class {
5501
5630
  refs,
5502
5631
  volatile
5503
5632
  });
5633
+ __privateMethod(this, _RecalcEngine_instances, adoptDeclaredSpill_fn).call(this, s, sheet, r, key, row2, column2);
5504
5634
  registered++;
5505
5635
  } catch (err) {
5506
5636
  failed.push({ sheet, ref, error: err instanceof Error ? err.message : String(err) });
@@ -5668,6 +5798,51 @@ unregister_fn = function(key) {
5668
5798
  rememberSheet_fn = function(name) {
5669
5799
  __privateGet(this, _sheetNames).set(normSheet(name), name);
5670
5800
  };
5801
+ /**
5802
+ * Takes ownership of the spill block a *file* already declared for an anchor.
5803
+ *
5804
+ * Excel stores a dynamic array as one formula on the anchor plus the spilled
5805
+ * results written as plain cached values in the cells below/right, and records
5806
+ * the extent in the anchor's `<f t="array" ref="…">`. Without this step the
5807
+ * engine meets those cached values on the first recalculation, sees literal
5808
+ * content inside the block it wants to spill into, and reports `#SPILL!` for
5809
+ * every dynamic array in every real file. Registering the declared block as
5810
+ * this anchor's existing spill makes them what they actually are — the anchor's
5811
+ * own territory, free to overwrite — and reuses the ordinary shrink path, so a
5812
+ * result smaller than the declared block clears the leftovers.
5813
+ *
5814
+ * Cost is one Set entry per already-spilled cell, paid once at load. A declared
5815
+ * block far larger than any real spill (a corrupt or hand-written `ref`) is
5816
+ * skipped rather than materialised.
5817
+ */
5818
+ adoptDeclaredSpill_fn = function(s, sheetName, ref, anchorKey, row2, col) {
5819
+ const declared = __privateGet(this, _model).getSpillRange?.(sheetName, ref);
5820
+ if (!declared || !declared.includes(":")) return;
5821
+ let rect;
5822
+ try {
5823
+ rect = puredocsExcel.parseRangeRef(declared);
5824
+ } catch {
5825
+ return;
5826
+ }
5827
+ if (rect.startRow !== row2 || rect.startColumn !== col) return;
5828
+ const height = rect.endRow - rect.startRow + 1;
5829
+ const width = rect.endColumn - rect.startColumn + 1;
5830
+ if (height < 1 || width < 1) return;
5831
+ if (height * width > MAX_ADOPTED_SPILL_CELLS) return;
5832
+ if (height === 1 && width === 1) return;
5833
+ const members = /* @__PURE__ */ new Set();
5834
+ for (let r = rect.startRow; r <= rect.endRow; r++) {
5835
+ for (let c = rect.startColumn; c <= rect.endColumn; c++) {
5836
+ if (r === row2 && c === col) continue;
5837
+ const key = keyOf(s, puredocsExcel.cellRefFromRowCol(r, c));
5838
+ if (__privateGet(this, _formulas).has(key)) continue;
5839
+ if (__privateGet(this, _spillOwner).has(key)) continue;
5840
+ members.add(key);
5841
+ __privateGet(this, _spillOwner).set(key, anchorKey);
5842
+ }
5843
+ }
5844
+ if (members.size > 0) __privateGet(this, _spills).set(anchorKey, members);
5845
+ };
5671
5846
  /**
5672
5847
  * One pass in a caller-supplied order, watching for inversions.
5673
5848
  *