@devmm/puredocs-excel-formula 1.0.2 → 1.0.4
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 +218 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +218 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
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
|
-
|
|
3723
|
-
const
|
|
3724
|
-
const
|
|
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
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
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
|
|
4692
|
-
if (__privateMethod(this, _RecalcEngine_instances, isOccupied_fn).call(this,
|
|
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
|
|
4714
|
-
newSpill.add(
|
|
4715
|
-
__privateGet(this, _spillOwner).set(
|
|
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(
|
|
4736
|
-
if (__privateGet(this, _formulas).has(
|
|
4737
|
-
const owner = __privateGet(this, _spillOwner).get(
|
|
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(
|
|
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
|
|
4748
|
-
const cell = parseKey(
|
|
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(
|
|
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);
|