@devmm/puredocs-excel-formula 1.0.2 → 1.0.3

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
@@ -2362,6 +2362,7 @@ function registerLookup(r) {
2362
2362
  r.register("LOOKUP", lookup, 2, 3);
2363
2363
  r.register("INDEX", index_, 2, 3);
2364
2364
  r.register("MATCH", match, 2, 3);
2365
+ r.register("XMATCH", xmatch, 2, 4);
2365
2366
  r.register("CHOOSE", choose, 2);
2366
2367
  r.register("ADDRESS", address, 2, 5);
2367
2368
  r.register("ROW", row, 0, 1);
@@ -2533,6 +2534,23 @@ function xlookup(a, c) {
2533
2534
  for (let r = 0; r < ret.rows; r++) out.set(r, 0, ret.get(r, idx));
2534
2535
  return FormulaValue.array(out);
2535
2536
  }
2537
+ function xmatch(a, c) {
2538
+ const lookupVal = a[0].evaluate(c);
2539
+ if (lookupVal.isError) return lookupVal;
2540
+ const lookupRaw = a[1].evaluate(c);
2541
+ if (lookupRaw.isError) return lookupRaw;
2542
+ const matchMode = a.length > 2 ? num2(a, c, 2) : { ok: true, n: 0 };
2543
+ if (!matchMode.ok) return matchMode.e;
2544
+ const searchMode = a.length > 3 ? num2(a, c, 3) : { ok: true, n: 1 };
2545
+ if (!searchMode.ok) return searchMode.e;
2546
+ const la = lookupRaw.isArray ? lookupRaw.arrayVal : ArrayValue.fromScalar(lookupRaw);
2547
+ if (la.rows > 1 && la.columns > 1) return FormulaValue.errorValue;
2548
+ const vertical = !(la.rows === 1 && la.columns > 1);
2549
+ const n = vertical ? la.rows : la.columns;
2550
+ const get = vertical ? (i) => la.get(i, 0) : (i) => la.get(0, i);
2551
+ const idx = findMatch(n, get, lookupVal, Math.trunc(matchMode.n), Math.trunc(searchMode.n));
2552
+ return idx < 0 ? FormulaValue.errorNA : FormulaValue.number(idx + 1);
2553
+ }
2536
2554
  function index_(a, c) {
2537
2555
  const arrVal = a[0].evaluate(c);
2538
2556
  if (arrVal.isError) return arrVal;
@@ -3070,6 +3088,20 @@ function registerFinance(r) {
3070
3088
  r.register("NPER", nper, 3, 5);
3071
3089
  r.register("XNPV", xnpv, 3, 3);
3072
3090
  r.register("XIRR", xirr, 2, 3);
3091
+ r.register("IPMT", ipmt, 4, 6);
3092
+ r.register("PPMT", ppmt, 4, 6);
3093
+ }
3094
+ function pmtValue(r, n, pv2, fv2, type) {
3095
+ if (r === 0) return -(pv2 + fv2) / n;
3096
+ const pow = Math.pow(1 + r, n);
3097
+ let payment = (-fv2 - pv2 * pow) * r / (pow - 1);
3098
+ if (type === 1) payment /= 1 + r;
3099
+ return payment;
3100
+ }
3101
+ function fvValue(r, n, pmt2, pv2, type) {
3102
+ if (r === 0) return -(pv2 + pmt2 * n);
3103
+ const pow = Math.pow(1 + r, n);
3104
+ return -(pv2 * pow + pmt2 * (1 + r * type) * (pow - 1) / r);
3073
3105
  }
3074
3106
  function arg(a, c, idx, dflt) {
3075
3107
  if (idx >= a.length) return { ok: true, n: dflt };
@@ -3089,11 +3121,7 @@ function pmt(a, c) {
3089
3121
  if (!type.ok) return type.e;
3090
3122
  const r = rate2.n, n = nper2.n, present = pvv.n, future = fvv.n, t = type.n;
3091
3123
  if (n === 0) return FormulaValue.errorNum;
3092
- if (r === 0) return FormulaValue.number(-(present + future) / n);
3093
- const pow = Math.pow(1 + r, n);
3094
- let payment = (-future - present * pow) * r / (pow - 1);
3095
- if (t === 1) payment /= 1 + r;
3096
- return FormulaValue.number(payment);
3124
+ return FormulaValue.number(pmtValue(r, n, present, future, t));
3097
3125
  }
3098
3126
  function fv(a, c) {
3099
3127
  const rate2 = arg(a, c, 0, 0);
@@ -3107,9 +3135,7 @@ function fv(a, c) {
3107
3135
  const type = arg(a, c, 4, 0);
3108
3136
  if (!type.ok) return type.e;
3109
3137
  const r = rate2.n, n = nper2.n, payment = pmtv.n, present = pvv.n, t = type.n;
3110
- if (r === 0) return FormulaValue.number(-(present + payment * n));
3111
- const pow = Math.pow(1 + r, n);
3112
- return FormulaValue.number(-(present * pow + payment * (1 + r * t) * (pow - 1) / r));
3138
+ return FormulaValue.number(fvValue(r, n, payment, present, t));
3113
3139
  }
3114
3140
  function pv(a, c) {
3115
3141
  const rate2 = arg(a, c, 0, 0);
@@ -3235,6 +3261,49 @@ function nper(a, c) {
3235
3261
  if (!isFinite(result)) return FormulaValue.errorNum;
3236
3262
  return FormulaValue.number(result);
3237
3263
  }
3264
+ function interestForPeriod(r, per, n, pv2, fv2, t) {
3265
+ const pay = pmtValue(r, n, pv2, fv2, t);
3266
+ if (t === 1) {
3267
+ if (per === 1) return 0;
3268
+ return fvValue(r, per - 2, pay, pv2, 1) * r / (1 + r);
3269
+ }
3270
+ return fvValue(r, per - 1, pay, pv2, 0) * r;
3271
+ }
3272
+ function ipmt(a, c) {
3273
+ const rate2 = arg(a, c, 0, 0);
3274
+ if (!rate2.ok) return rate2.e;
3275
+ const perv = arg(a, c, 1, 0);
3276
+ if (!perv.ok) return perv.e;
3277
+ const nper2 = arg(a, c, 2, 0);
3278
+ if (!nper2.ok) return nper2.e;
3279
+ const pvv = arg(a, c, 3, 0);
3280
+ if (!pvv.ok) return pvv.e;
3281
+ const fvv = arg(a, c, 4, 0);
3282
+ if (!fvv.ok) return fvv.e;
3283
+ const type = arg(a, c, 5, 0);
3284
+ if (!type.ok) return type.e;
3285
+ const r = rate2.n, per = perv.n, n = nper2.n, pv2 = pvv.n, fv2 = fvv.n, t = type.n;
3286
+ if (n === 0 || per < 1 || per > n) return FormulaValue.errorNum;
3287
+ return FormulaValue.number(interestForPeriod(r, per, n, pv2, fv2, t));
3288
+ }
3289
+ function ppmt(a, c) {
3290
+ const rate2 = arg(a, c, 0, 0);
3291
+ if (!rate2.ok) return rate2.e;
3292
+ const perv = arg(a, c, 1, 0);
3293
+ if (!perv.ok) return perv.e;
3294
+ const nper2 = arg(a, c, 2, 0);
3295
+ if (!nper2.ok) return nper2.e;
3296
+ const pvv = arg(a, c, 3, 0);
3297
+ if (!pvv.ok) return pvv.e;
3298
+ const fvv = arg(a, c, 4, 0);
3299
+ if (!fvv.ok) return fvv.e;
3300
+ const type = arg(a, c, 5, 0);
3301
+ if (!type.ok) return type.e;
3302
+ const r = rate2.n, per = perv.n, n = nper2.n, pv2 = pvv.n, fv2 = fvv.n, t = type.n;
3303
+ if (n === 0 || per < 1 || per > n) return FormulaValue.errorNum;
3304
+ const pay = pmtValue(r, n, pv2, fv2, t);
3305
+ return FormulaValue.number(pay - interestForPeriod(r, per, n, pv2, fv2, t));
3306
+ }
3238
3307
  function flatNumbers(node, c) {
3239
3308
  const v = node.evaluate(c);
3240
3309
  if (v.isError) return { ok: false, e: v };
@@ -3662,7 +3731,13 @@ function registerArray(r) {
3662
3731
  r.register("FILTER", filter, 2, 3);
3663
3732
  r.register("MMULT", mmult, 2, 2);
3664
3733
  r.register("TEXTSPLIT", textSplit, 2, 6);
3734
+ r.register("VSTACK", vstack, 1);
3735
+ r.register("HSTACK", hstack, 1);
3736
+ r.register("TOCOL", toCol, 1, 3);
3737
+ r.register("TOROW", toRow, 1, 3);
3665
3738
  }
3739
+ var MAX_ROWS = 1048576;
3740
+ var MAX_COLS = 16384;
3666
3741
  var asArray2 = (v) => v.isArray ? v.arrayVal : ArrayValue.fromScalar(v);
3667
3742
  function fromRows(rows2) {
3668
3743
  const nr = rows2.length;
@@ -3709,26 +3784,53 @@ function sequence(a, c) {
3709
3784
  }
3710
3785
  return FormulaValue.array(arr);
3711
3786
  }
3712
- function rowsEqual(x, y) {
3713
- if (x.length !== y.length) return false;
3714
- for (let i = 0; i < x.length; i++) if (!FormulaValue.areEqual(x[i], y[i])) return false;
3715
- return true;
3787
+ function cellKey(v) {
3788
+ switch (v.kind) {
3789
+ case "number":
3790
+ return "n" + (v.numberValue === 0 ? "0" : String(v.numberValue));
3791
+ case "text":
3792
+ return "t" + v.textValue.toUpperCase();
3793
+ // case-insensitive
3794
+ case "boolean":
3795
+ return v.booleanValue ? "b1" : "b0";
3796
+ case "blank":
3797
+ return "B";
3798
+ case "error":
3799
+ return "e" + v.errorCode;
3800
+ default:
3801
+ return "x";
3802
+ }
3716
3803
  }
3717
3804
  function unique(a, c) {
3718
3805
  const v = a[0].evaluate(c);
3719
3806
  if (v.isError) return v;
3720
3807
  const byCol2 = a.length > 1 ? a[1].evaluate(c).coerceToBool().booleanValue : false;
3721
3808
  const exactlyOnce = a.length > 2 ? a[2].evaluate(c).coerceToBool().booleanValue : false;
3722
- let rows2 = toRows(byCol2 ? asArray2(v).transpose() : asArray2(v));
3723
- const counts = rows2.map((r) => rows2.filter((o) => rowsEqual(o, r)).length);
3724
- const seen = [];
3809
+ const base = byCol2 ? asArray2(v).transpose() : asArray2(v);
3810
+ const map = /* @__PURE__ */ new Map();
3811
+ const order = [];
3812
+ for (let r = 0; r < base.rows; r++) {
3813
+ const cells = new Array(base.columns);
3814
+ let key = "";
3815
+ for (let col = 0; col < base.columns; col++) {
3816
+ const cell = base.get(r, col);
3817
+ cells[col] = cell;
3818
+ const k = cellKey(cell);
3819
+ key += k.length + ":" + k;
3820
+ }
3821
+ const hit = map.get(key);
3822
+ if (hit) hit.count++;
3823
+ else {
3824
+ map.set(key, { cells, count: 1 });
3825
+ order.push(key);
3826
+ }
3827
+ }
3725
3828
  const result = [];
3726
- rows2.forEach((r, i) => {
3727
- if (seen.some((o) => rowsEqual(o, r))) return;
3728
- seen.push(r);
3729
- if (exactlyOnce && counts[i] > 1) return;
3730
- result.push(r);
3731
- });
3829
+ for (const key of order) {
3830
+ const e = map.get(key);
3831
+ if (exactlyOnce && e.count > 1) continue;
3832
+ result.push(e.cells);
3833
+ }
3732
3834
  if (result.length === 0) return FormulaValue.error(8 /* Calc */);
3733
3835
  const out = fromRows(result);
3734
3836
  return byCol2 ? FormulaValue.array(out.arrayVal.transpose()) : out;
@@ -3886,6 +3988,89 @@ function textSplit(a, c) {
3886
3988
  });
3887
3989
  return fromRows(rows2);
3888
3990
  }
3991
+ function vstack(a, c) {
3992
+ const parts = [];
3993
+ let totalRows = 0, maxCols = 0;
3994
+ for (const node of a) {
3995
+ const arr = asArray2(node.evaluate(c));
3996
+ parts.push(arr);
3997
+ totalRows += arr.rows;
3998
+ if (arr.columns > maxCols) maxCols = arr.columns;
3999
+ }
4000
+ if (totalRows > MAX_ROWS || maxCols > MAX_COLS) return FormulaValue.errorNum;
4001
+ const out = new ArrayValue(totalRows, maxCols);
4002
+ let rowOff = 0;
4003
+ for (const arr of parts) {
4004
+ for (let r = 0; r < arr.rows; r++) {
4005
+ for (let col = 0; col < maxCols; col++) {
4006
+ out.set(rowOff + r, col, col < arr.columns ? arr.get(r, col) : FormulaValue.errorNA);
4007
+ }
4008
+ }
4009
+ rowOff += arr.rows;
4010
+ }
4011
+ return FormulaValue.array(out);
4012
+ }
4013
+ function hstack(a, c) {
4014
+ const parts = [];
4015
+ let totalCols = 0, maxRows = 0;
4016
+ for (const node of a) {
4017
+ const arr = asArray2(node.evaluate(c));
4018
+ parts.push(arr);
4019
+ totalCols += arr.columns;
4020
+ if (arr.rows > maxRows) maxRows = arr.rows;
4021
+ }
4022
+ if (maxRows > MAX_ROWS || totalCols > MAX_COLS) return FormulaValue.errorNum;
4023
+ const out = new ArrayValue(maxRows, totalCols);
4024
+ let colOff = 0;
4025
+ for (const arr of parts) {
4026
+ for (let col = 0; col < arr.columns; col++) {
4027
+ for (let r = 0; r < maxRows; r++) {
4028
+ out.set(r, colOff + col, r < arr.rows ? arr.get(r, col) : FormulaValue.errorNA);
4029
+ }
4030
+ }
4031
+ colOff += arr.columns;
4032
+ }
4033
+ return FormulaValue.array(out);
4034
+ }
4035
+ function flatten(a, c) {
4036
+ const arr = asArray2(a[0].evaluate(c));
4037
+ const ig = num4(a, c, 1, 0);
4038
+ if (!ig.ok) return { ok: false, e: ig.e };
4039
+ const ignore = Math.trunc(ig.n);
4040
+ const byCol2 = a.length > 2 ? a[2].evaluate(c).coerceToBool().booleanValue : false;
4041
+ const skip = (x) => (ignore & 1) !== 0 && x.isBlank || (ignore & 2) !== 0 && x.isError;
4042
+ const values = [];
4043
+ if (byCol2) {
4044
+ for (let col = 0; col < arr.columns; col++)
4045
+ for (let r = 0; r < arr.rows; r++) {
4046
+ const x = arr.get(r, col);
4047
+ if (!skip(x)) values.push(x);
4048
+ }
4049
+ } else {
4050
+ for (let r = 0; r < arr.rows; r++)
4051
+ for (let col = 0; col < arr.columns; col++) {
4052
+ const x = arr.get(r, col);
4053
+ if (!skip(x)) values.push(x);
4054
+ }
4055
+ }
4056
+ return { ok: true, values };
4057
+ }
4058
+ function toCol(a, c) {
4059
+ const f = flatten(a, c);
4060
+ if (!f.ok) return f.e;
4061
+ if (f.values.length === 0) return FormulaValue.errorNA;
4062
+ const out = new ArrayValue(f.values.length, 1);
4063
+ for (let i = 0; i < f.values.length; i++) out.set(i, 0, f.values[i]);
4064
+ return FormulaValue.array(out);
4065
+ }
4066
+ function toRow(a, c) {
4067
+ const f = flatten(a, c);
4068
+ if (!f.ok) return f.e;
4069
+ if (f.values.length === 0) return FormulaValue.errorNA;
4070
+ const out = new ArrayValue(1, f.values.length);
4071
+ for (let i = 0; i < f.values.length; i++) out.set(0, i, f.values[i]);
4072
+ return FormulaValue.array(out);
4073
+ }
3889
4074
 
3890
4075
  // src/function-registry.ts
3891
4076
  var _default, _functions, _FunctionRegistry_instances, registerBuiltIns_fn;
@@ -4688,8 +4873,8 @@ writeResult_fn = function(e) {
4688
4873
  for (let dc = 0; dc < cols && !collides; dc++) {
4689
4874
  if (dr === 0 && dc === 0) continue;
4690
4875
  const r = e.row + dr, c = e.col + dc;
4691
- const cellKey = keyOf(e.sheet, puredocsExcel.cellRefFromRowCol(r, c));
4692
- if (__privateMethod(this, _RecalcEngine_instances, isOccupied_fn).call(this, cellKey, e.sheetName, puredocsExcel.cellRefFromRowCol(r, c), anchorKey, prevSpill)) {
4876
+ const cellKey2 = keyOf(e.sheet, puredocsExcel.cellRefFromRowCol(r, c));
4877
+ if (__privateMethod(this, _RecalcEngine_instances, isOccupied_fn).call(this, cellKey2, e.sheetName, puredocsExcel.cellRefFromRowCol(r, c), anchorKey, prevSpill)) {
4693
4878
  collides = true;
4694
4879
  }
4695
4880
  }
@@ -4710,9 +4895,9 @@ writeResult_fn = function(e) {
4710
4895
  __privateGet(this, _model).setCellValue(e.sheetName, ref, arr.get(dr, dc).toObject());
4711
4896
  changed.push({ sheet: e.sheet, row: r, col: c });
4712
4897
  if (dr !== 0 || dc !== 0) {
4713
- const cellKey = keyOf(e.sheet, ref);
4714
- newSpill.add(cellKey);
4715
- __privateGet(this, _spillOwner).set(cellKey, anchorKey);
4898
+ const cellKey2 = keyOf(e.sheet, ref);
4899
+ newSpill.add(cellKey2);
4900
+ __privateGet(this, _spillOwner).set(cellKey2, anchorKey);
4716
4901
  }
4717
4902
  }
4718
4903
  }
@@ -4732,11 +4917,11 @@ writeResult_fn = function(e) {
4732
4917
  };
4733
4918
  };
4734
4919
  /** Whether a target cell already holds content that blocks a spill. */
4735
- isOccupied_fn = function(cellKey, sheetName, ref, anchorKey, prevSpill) {
4736
- if (__privateGet(this, _formulas).has(cellKey) && cellKey !== anchorKey) return true;
4737
- const owner = __privateGet(this, _spillOwner).get(cellKey);
4920
+ isOccupied_fn = function(cellKey2, sheetName, ref, anchorKey, prevSpill) {
4921
+ if (__privateGet(this, _formulas).has(cellKey2) && cellKey2 !== anchorKey) return true;
4922
+ const owner = __privateGet(this, _spillOwner).get(cellKey2);
4738
4923
  if (owner && owner !== anchorKey) return true;
4739
- if (prevSpill.has(cellKey)) return false;
4924
+ if (prevSpill.has(cellKey2)) return false;
4740
4925
  const v = __privateGet(this, _model).getCellValue(sheetName, ref);
4741
4926
  return v !== null && v !== void 0 && v !== "";
4742
4927
  };
@@ -4744,10 +4929,10 @@ isOccupied_fn = function(cellKey, sheetName, ref, anchorKey, prevSpill) {
4744
4929
  clearSpill_fn = function(anchorKey, changed) {
4745
4930
  const spill = __privateGet(this, _spills).get(anchorKey);
4746
4931
  if (!spill) return;
4747
- for (const cellKey of spill) {
4748
- const cell = parseKey(cellKey);
4932
+ for (const cellKey2 of spill) {
4933
+ const cell = parseKey(cellKey2);
4749
4934
  __privateGet(this, _model).setCellValue(__privateGet(this, _sheetNames).get(cell.sheet) ?? cell.sheet, cell.ref, null);
4750
- __privateGet(this, _spillOwner).delete(cellKey);
4935
+ __privateGet(this, _spillOwner).delete(cellKey2);
4751
4936
  changed.push({ sheet: cell.sheet, row: cell.row, col: cell.col });
4752
4937
  }
4753
4938
  __privateGet(this, _spills).delete(anchorKey);