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