@devmm/puredocs-excel-formula 1.0.9 → 1.1.1

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
@@ -31,6 +31,13 @@ var FormulaError = /* @__PURE__ */ ((FormulaError2) => {
31
31
  FormulaError2[FormulaError2["Spill"] = 9] = "Spill";
32
32
  return FormulaError2;
33
33
  })(FormulaError || {});
34
+ var DECIMAL = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;
35
+ function numericText(text) {
36
+ const trimmed = text.trim();
37
+ if (!DECIMAL.test(trimmed)) return null;
38
+ const n = Number(trimmed);
39
+ return Number.isFinite(n) ? n : null;
40
+ }
34
41
  var TailCall = class {
35
42
  constructor(lambda, args) {
36
43
  this.lambda = lambda;
@@ -275,7 +282,7 @@ var _FormulaValue = class _FormulaValue {
275
282
  if (value2 === null || value2 === void 0) return _FormulaValue.blank;
276
283
  if (typeof value2 === "number") return isNaN(value2) ? _FormulaValue.errorValue : _FormulaValue.number(value2);
277
284
  if (typeof value2 === "boolean") return _FormulaValue.boolean(value2);
278
- if (typeof value2 === "string") return value2 === "" ? _FormulaValue.blank : _FormulaValue.text(value2);
285
+ if (typeof value2 === "string") return _FormulaValue.text(value2);
279
286
  if (value2 instanceof Date) {
280
287
  return _FormulaValue.number(puredocsExcel.toOADate(value2));
281
288
  }
@@ -1443,6 +1450,7 @@ var indexes = /* @__PURE__ */ new WeakMap();
1443
1450
  function build(arr) {
1444
1451
  const byText = /* @__PURE__ */ new Map();
1445
1452
  const byNumber = /* @__PURE__ */ new Map();
1453
+ const byTextNumber = /* @__PURE__ */ new Map();
1446
1454
  const classes = /* @__PURE__ */ new Map();
1447
1455
  const addToClass = (kind, v, i2) => {
1448
1456
  const group = classes.get(kind);
@@ -1462,6 +1470,14 @@ function build(arr) {
1462
1470
  else byNumber.set(n, [i]);
1463
1471
  } else {
1464
1472
  addToClass(v.kind, v, i);
1473
+ if (v.isText) {
1474
+ const n = numericText(v.textValue);
1475
+ if (n !== null) {
1476
+ const atText2 = byTextNumber.get(n);
1477
+ if (atText2) atText2.push(i);
1478
+ else byTextNumber.set(n, [i]);
1479
+ }
1480
+ }
1465
1481
  }
1466
1482
  i++;
1467
1483
  }
@@ -1470,7 +1486,15 @@ function build(arr) {
1470
1486
  for (let k = 0; k < sortedNumbers.length; k++) {
1471
1487
  cumulative[k + 1] = cumulative[k] + byNumber.get(sortedNumbers[k]).length;
1472
1488
  }
1473
- return { byText, byNumber, sortedNumbers, cumulative, classes: [...classes.values()] };
1489
+ return {
1490
+ byText,
1491
+ byNumber,
1492
+ sortedNumbers,
1493
+ cumulative,
1494
+ byTextNumber,
1495
+ sortedTextNumbers: Float64Array.from(byTextNumber.keys()).sort(),
1496
+ classes: [...classes.values()]
1497
+ };
1474
1498
  }
1475
1499
  function indexOf(arr) {
1476
1500
  let idx = indexes.get(arr);
@@ -1508,19 +1532,25 @@ function matchingPositions(criteriaRange, criteria, minSize) {
1508
1532
  if (criteria.kind === "equalsNumber") {
1509
1533
  const target = criteria.number;
1510
1534
  const idx = indexOf(arr);
1511
- const exact2 = idx.byNumber.get(target);
1512
- let near;
1513
- const { sortedNumbers } = idx;
1514
- for (let k = lowerBound(sortedNumbers, target - EPSILON); k < sortedNumbers.length; k++) {
1515
- const value2 = sortedNumbers[k];
1516
- if (value2 > target + EPSILON) break;
1517
- if (value2 === target) continue;
1518
- if (!criteria.test(FormulaValue.number(value2))) continue;
1519
- (near ?? (near = [])).push(...idx.byNumber.get(value2));
1520
- }
1535
+ const groups = [];
1536
+ const collect = (byValue, sorted) => {
1537
+ const exact2 = byValue.get(target);
1538
+ if (exact2) groups.push(exact2);
1539
+ for (let k = lowerBound(sorted, target - EPSILON); k < sorted.length; k++) {
1540
+ const value2 = sorted[k];
1541
+ if (value2 > target + EPSILON) break;
1542
+ if (value2 === target) continue;
1543
+ if (!criteria.test(FormulaValue.number(value2))) continue;
1544
+ groups.push(byValue.get(value2));
1545
+ }
1546
+ };
1547
+ collect(idx.byNumber, idx.sortedNumbers);
1548
+ collect(idx.byTextNumber, idx.sortedTextNumbers);
1521
1549
  const blanks = criteria.test(FormulaValue.blank) ? blankPositions(idx) : void 0;
1522
- if (!near && !blanks?.length) return exact2 ?? EMPTY;
1523
- const merged = [...exact2 ?? EMPTY, ...near ?? EMPTY, ...blanks ?? EMPTY];
1550
+ if (blanks?.length) groups.push(blanks);
1551
+ if (groups.length === 0) return EMPTY;
1552
+ if (groups.length === 1) return groups[0];
1553
+ const merged = groups.flat();
1524
1554
  merged.sort((a, b) => a - b);
1525
1555
  return merged;
1526
1556
  }
@@ -1790,11 +1820,14 @@ function count(a, c) {
1790
1820
  function countA(a, c) {
1791
1821
  return FormulaValue.number(exports.FormulaHelper.flattenArgs(a, c).filter((v) => !v.isBlank).length);
1792
1822
  }
1823
+ function isCountBlank(v) {
1824
+ return v.isBlank || v.isText && v.textValue === "";
1825
+ }
1793
1826
  function countBlank(a, c) {
1794
1827
  const v = a[0].evaluate(c);
1795
- if (!v.isArray) return FormulaValue.number(v.isBlank ? 1 : 0);
1828
+ if (!v.isArray) return FormulaValue.number(isCountBlank(v) ? 1 : 0);
1796
1829
  let n = 0;
1797
- for (const item of v.arrayVal.values()) if (item.isBlank) n++;
1830
+ for (const item of v.arrayVal.values()) if (isCountBlank(item)) n++;
1798
1831
  return FormulaValue.number(n);
1799
1832
  }
1800
1833
  function countIf(a, c) {
@@ -1802,11 +1835,12 @@ function countIf(a, c) {
1802
1835
  if (range.isError) return range;
1803
1836
  const crit = a[1].evaluate(c);
1804
1837
  if (crit.isError) return crit;
1805
- const criteria = crit.asText();
1806
- if (!range.isArray) return FormulaValue.number(exports.FormulaHelper.matchesCriteria(range, criteria) ? 1 : 0);
1838
+ const compiled = exports.FormulaHelper.compileCriteria(crit.asText());
1839
+ if (!range.isArray) return FormulaValue.number(compiled.test(range) ? 1 : 0);
1840
+ const countBlanks = compiled.kind === "blankness";
1807
1841
  let n = 0;
1808
1842
  for (const item of range.arrayVal.values()) {
1809
- if (!item.isBlank && exports.FormulaHelper.matchesCriteria(item, criteria)) n++;
1843
+ if ((countBlanks || !item.isBlank) && compiled.test(item)) n++;
1810
1844
  }
1811
1845
  return FormulaValue.number(n);
1812
1846
  }
@@ -4698,11 +4732,14 @@ exports.FormulaHelper = void 0;
4698
4732
  const rhsVal = parseFloat(rhs);
4699
4733
  const rhsNum = isNaN(rhsVal) ? null : rhsVal;
4700
4734
  const rhsValue = rhsNum !== null ? FormulaValue.number(rhsNum) : FormulaValue.text(rhs);
4735
+ if (rhs === "" && op === "=") return { kind: "blankness", test: (v) => v.isBlank };
4736
+ if (rhs === "" && op === "<>") return { kind: "other", test: (v) => !v.isBlank };
4701
4737
  if (op === "=") {
4702
4738
  return rhsNum !== null ? numberEquality(rhsNum) : textEquality(rhs);
4703
4739
  }
4704
4740
  if (op === "<>") {
4705
- return { kind: "other", test: (v) => !FormulaValue.areEqual(v, rhsValue) };
4741
+ const equals = rhsNum !== null ? numberEquality(rhsNum) : textEquality(rhs);
4742
+ return { kind: "other", test: (v) => !equals.test(v) };
4706
4743
  }
4707
4744
  const wanted = op === ">" ? (c) => c > 0 : op === ">=" ? (c) => c >= 0 : op === "<" ? (c) => c < 0 : (c) => c <= 0;
4708
4745
  const test = (v) => wanted(FormulaValue.compare(v, rhsValue));
@@ -4712,13 +4749,25 @@ exports.FormulaHelper = void 0;
4712
4749
  const pattern = wildcardToRegex(trimmed);
4713
4750
  return { kind: "other", test: (v) => pattern.test(v.asText()) };
4714
4751
  }
4752
+ if (trimmed === "") {
4753
+ return { kind: "blankness", test: (v) => v.isBlank || v.isText && v.textValue === "" };
4754
+ }
4715
4755
  const num5 = parseFloat(trimmed);
4716
4756
  return isNaN(num5) ? textEquality(trimmed) : numberEquality(num5);
4717
4757
  }
4718
4758
  FormulaHelper2.compileCriteria = compileCriteria;
4719
4759
  function numberEquality(n) {
4720
4760
  const target = FormulaValue.number(n);
4721
- return { kind: "equalsNumber", number: n, test: (v) => FormulaValue.areEqual(v, target) };
4761
+ return {
4762
+ kind: "equalsNumber",
4763
+ number: n,
4764
+ test: (v) => {
4765
+ if (FormulaValue.areEqual(v, target)) return true;
4766
+ if (!v.isText) return false;
4767
+ const asNumber = numericText(v.textValue);
4768
+ return asNumber !== null && Math.abs(asNumber - n) < 1e-10;
4769
+ }
4770
+ };
4722
4771
  }
4723
4772
  function textEquality(s) {
4724
4773
  const upper2 = s.toUpperCase();