@sheetxl/primitives 0.8.0-beta.12 → 0.8.0-beta.13

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license @sheetxl/primitives - Primitives - Base types for SheetXL functions. - v0.8.0-beta.12
2
+ * @license @sheetxl/primitives - Primitives - Base types for SheetXL functions. - v0.8.0-beta.13
3
3
  *
4
4
  * (C) 2026-present SheetXL Inc. & Michael T. Ford
5
5
  * License: The license can be found at https://www.sheetxl.com/license.
@@ -21,6 +21,39 @@ var e;
21
21
  }
22
22
  return i === null ? e : i.join("");
23
23
  };
24
+ let n = e.MIN_NUMBER = 22250738585072014e-324;
25
+ e.flushSubnormal = function(e) {
26
+ return e > -n && e < n ? 0 : e;
27
+ }, e.isNumberTextInRange = function(e, t = ".") {
28
+ let n = e.length;
29
+ if (n < 309 && e.indexOf("E") < 0 && e.indexOf("e") < 0) return !0;
30
+ let r = t.charCodeAt(0), i = !1, a = !1, o = !1, s = 0, c = 0, l = 0, u = 0;
31
+ for (; u < n; u++) {
32
+ let t = e.charCodeAt(u);
33
+ if (t >= 48 && t <= 57) i = !0, a ? (l++, o || (t === 48 ? c++ : o = !0)) : (o || t !== 48) && (o = !0, s++);
34
+ else if (t === r) a = !0;
35
+ else if ((t === 69 || t === 101) && i) break;
36
+ }
37
+ let d = 0;
38
+ if (u < n) {
39
+ let t = u + 1, r = !1, i = e.charCodeAt(t);
40
+ i === 45 ? (r = !0, t++) : i === 43 && t++;
41
+ let a = 0;
42
+ for (; t < n; t++) {
43
+ let n = e.charCodeAt(t);
44
+ if (n < 48 || n > 57) break;
45
+ d = 10 * d + (n - 48), a++;
46
+ }
47
+ if (a === 0) return !0;
48
+ r && (d = -d);
49
+ }
50
+ if (o) {
51
+ let e = (s > 0 ? s - 1 : -(c + 1)) + d;
52
+ return e >= -309 && e <= 307;
53
+ }
54
+ let f = d - l;
55
+ return f >= -308 && f <= 308;
56
+ };
24
57
  })(e ||= {});
25
58
  var t, n, r, i, a = {
26
59
  Number: "number",
@@ -370,34 +403,34 @@ var v = class {
370
403
  }
371
404
  }, y = class {
372
405
  createRange(e, t, n) {
373
- throw new C();
406
+ throw x("createRange");
374
407
  }
375
408
  flattenAreas(e) {
376
- throw new C();
409
+ throw x("flattenAreas");
377
410
  }
378
411
  getReference(e, t) {
379
- throw new C();
412
+ throw x("getReference");
380
413
  }
381
414
  getResizedReference(e, t, n) {
382
- throw new C();
415
+ throw x("getResizedReference");
383
416
  }
384
417
  getNumberFormat(e, t) {
385
- throw new C();
418
+ throw x("getNumberFormat");
386
419
  }
387
420
  fromSerialDate(e, t) {
388
- throw new C();
421
+ throw x("fromSerialDate");
389
422
  }
390
423
  toSerialDate(e, t) {
391
- throw new C();
424
+ throw x("toSerialDate");
392
425
  }
393
426
  getDateParts(e, t) {
394
- throw new C();
427
+ throw x("getDateParts");
395
428
  }
396
429
  getSerialDate(e, t, n, r, i, a, o) {
397
- throw new C();
430
+ throw x("getSerialDate");
398
431
  }
399
432
  getNow() {
400
- throw new C();
433
+ throw x("getNow");
401
434
  }
402
435
  getRandom() {
403
436
  return Math.random();
@@ -406,10 +439,10 @@ var v = class {
406
439
  return null;
407
440
  }
408
441
  getEntireCoords() {
409
- return w;
442
+ return T;
410
443
  }
411
444
  isValidDate(e, t) {
412
- return e instanceof Date || Object.prototype.toString.call(e) === "[object Date]" ? !isNaN(e.getTime()) : !t && typeof e == "number" && !(e < 0 || e > E);
445
+ return e instanceof Date || Object.prototype.toString.call(e) === "[object Date]" ? !isNaN(e.getTime()) : !t && typeof e == "number" && !(e < 0 || e > D);
413
446
  }
414
447
  getRow() {
415
448
  return 0;
@@ -445,22 +478,22 @@ var v = class {
445
478
  return null;
446
479
  }
447
480
  getAddress(e, t) {
448
- throw new C();
481
+ throw x("getAddress");
449
482
  }
450
483
  parseAsSerialDate(e, t) {
451
- throw new C();
484
+ throw x("parseAsSerialDate");
452
485
  }
453
486
  parseAsDate(e, t) {
454
- throw new C();
487
+ throw x("parseAsDate");
455
488
  }
456
489
  parseAsNumber(e, t) {
457
- throw new C();
490
+ throw x("parseAsNumber");
458
491
  }
459
492
  createCriteria(e, t) {
460
- throw new C();
493
+ throw x("createCriteria");
461
494
  }
462
495
  createGrouping(e, t) {
463
- throw new C();
496
+ throw x("createGrouping");
464
497
  }
465
498
  parseAsLiteral(e) {
466
499
  let t = e.toUpperCase();
@@ -475,13 +508,13 @@ var v = class {
475
508
  return r === i ? e < t ? -1 : +(e > t) : r < i ? -1 : 1;
476
509
  }
477
510
  getRuntime() {
478
- return T;
511
+ return E;
479
512
  }
480
513
  getArgs() {
481
- throw new C(x);
514
+ throw new w(S);
482
515
  }
483
516
  createRichData(e, t) {
484
- throw new C(S);
517
+ throw new w(C);
485
518
  }
486
519
  }, b = (e) => {
487
520
  if (e == null) return 0;
@@ -491,19 +524,19 @@ var v = class {
491
524
  case "boolean": return 3;
492
525
  default: return 4;
493
526
  }
494
- }, x = "FormulaContext.getArgs() is only valid while a function body is running", S = "FormulaContext.createRichData() needs a workbook being calculated", C = class extends Error {
527
+ }, x = (e) => new w(`FormulaContext.${e}() is only valid while a function body is running. A deferred executor reads its workbook through ctx.getFormulaContext().`), S = "FormulaContext.getArgs() is only valid while a function body is running", C = "FormulaContext.createRichData() needs a workbook being calculated", w = class extends Error {
495
528
  constructor(e = "Not implemented in StubbedFormulaContext") {
496
529
  super(e), this.name = "NotImplementedError";
497
530
  }
498
- }, w = Object.freeze({
531
+ }, T = Object.freeze({
499
532
  colStart: 0,
500
533
  rowStart: 0,
501
534
  colEnd: 2 ** 14 - 1,
502
535
  rowEnd: 2 ** 20 - 1
503
- }), T = {
536
+ }), E = {
504
537
  isDate1904: () => !1,
505
- getLocale: () => k.tag,
506
- getLocaleProfile: () => k,
538
+ getLocale: () => A.tag,
539
+ getLocaleProfile: () => A,
507
540
  isR1C1: () => !1,
508
541
  getNow: () => 0,
509
542
  getRandom: () => Math.random(),
@@ -512,12 +545,12 @@ var v = class {
512
545
  getOS: () => "unknown",
513
546
  getUser: () => "unidentified",
514
547
  getDescription: () => "Stubbed Formula Context"
515
- }, E = 2958465, D = new y(), O = class {
548
+ }, D = 2958465, O = new y(), k = class {
516
549
  constructor() {
517
- this._scope = D, this._argsFn = null;
550
+ this._scope = O, this._argsFn = null;
518
551
  }
519
552
  _setScope(e) {
520
- this._scope = e ?? D;
553
+ this._scope = e ?? O;
521
554
  }
522
555
  _getScope() {
523
556
  return this._scope;
@@ -529,7 +562,7 @@ var v = class {
529
562
  return this._getScope().getNumberFormat(e, t);
530
563
  }
531
564
  getEntireCoords() {
532
- return this._getScope().getEntireCoords() ?? w;
565
+ return this._getScope().getEntireCoords() ?? T;
533
566
  }
534
567
  parseAsSerialDate(e, t) {
535
568
  return this._getScope().parseAsSerialDate(e, t);
@@ -548,7 +581,7 @@ var v = class {
548
581
  }
549
582
  parseAsLiteral(e) {
550
583
  let t = this._getScope();
551
- return t.parseAsLiteral ? t.parseAsLiteral(e) : D.parseAsLiteral(e);
584
+ return t.parseAsLiteral ? t.parseAsLiteral(e) : O.parseAsLiteral(e);
552
585
  }
553
586
  toText(e) {
554
587
  return this._getScope().toText(e);
@@ -638,18 +671,18 @@ var v = class {
638
671
  return this._getScope().getAddress(e, t);
639
672
  }
640
673
  compare(e, t, n) {
641
- return this._getScope().compare?.(e, t, n) ?? D.compare(e, t, n);
674
+ return this._getScope().compare?.(e, t, n) ?? O.compare(e, t, n);
642
675
  }
643
676
  getRuntime() {
644
677
  return this._getScope().getRuntime();
645
678
  }
646
679
  createRichData(e, t) {
647
680
  let n = this._getScope();
648
- return n.createRichData ? n.createRichData(e, t) : D.createRichData(e, t);
681
+ return n.createRichData ? n.createRichData(e, t) : O.createRichData(e, t);
649
682
  }
650
683
  getArgs() {
651
684
  let e = this._argsFn, t = e ? e() : null;
652
- if (!t) throw new C(x);
685
+ if (!t) throw new w(S);
653
686
  return t;
654
687
  }
655
688
  get [Symbol.toStringTag]() {
@@ -658,7 +691,7 @@ var v = class {
658
691
  toString() {
659
692
  return this._getScope()?.toString?.() ?? "{STUB SCOPE}";
660
693
  }
661
- }, k = Object.freeze({
694
+ }, A = Object.freeze({
662
695
  tag: "en-US",
663
696
  numberingSystem: "latn",
664
697
  decimal: ".",
@@ -738,5 +771,5 @@ var v = class {
738
771
  sensitivity: "base",
739
772
  numeric: !0
740
773
  })
741
- }), A = new O();
742
- export { k as DEFAULT_LOCALE_PROFILE, A as FormulaContext, i as FormulaError, t as IRange, r as IRangeStats, o as InteropScalarType, v as Observable, e as Scalar, a as ScalarType, O as ScopedFormulaContext, y as StubbedFormulaContext, s as ValueKind, u as WildCard, d as isLazyValue };
774
+ }), j = new k();
775
+ export { A as DEFAULT_LOCALE_PROFILE, j as FormulaContext, i as FormulaError, t as IRange, r as IRangeStats, o as InteropScalarType, v as Observable, e as Scalar, a as ScalarType, k as ScopedFormulaContext, y as StubbedFormulaContext, s as ValueKind, u as WildCard, d as isLazyValue };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license @sheetxl/primitives - Primitives - Base types for SheetXL functions. - v0.8.0-beta.12
2
+ * @license @sheetxl/primitives - Primitives - Base types for SheetXL functions. - v0.8.0-beta.13
3
3
  *
4
4
  * (C) 2026-present SheetXL Inc. & Michael T. Ford
5
5
  * License: The license can be found at https://www.sheetxl.com/license.
@@ -21,6 +21,41 @@ var e;
21
21
  }
22
22
  return null === n ? e : n.join("");
23
23
  };
24
+ const r = e.MIN_NUMBER = 22250738585072014e-324;
25
+ e.flushSubnormal = function(e) {
26
+ return e > -r && e < r ? 0 : e;
27
+ }, e.isNumberTextInRange = function(e, t = ".") {
28
+ const r = e.length;
29
+ if (r < 309 && e.indexOf("E") < 0 && e.indexOf("e") < 0) return !0;
30
+ const o = t.charCodeAt(0);
31
+ let n = !1, s = !1, a = !1, i = 0, c = 0, u = 0, l = 0;
32
+ for (; l < r; l++) {
33
+ const t = e.charCodeAt(l);
34
+ if (t >= 48 && t <= 57) n = !0, s ? (u++, a || (48 === t ? c++ : a = !0)) : (a || 48 !== t) && (a = !0, i++);
35
+ else if (t === o) s = !0;
36
+ else if ((69 === t || 101 === t) && n) break;
37
+ }
38
+ let d = 0;
39
+ if (l < r) {
40
+ let t = l + 1, o = !1;
41
+ const n = e.charCodeAt(t);
42
+ 45 === n ? (o = !0, t++) : 43 === n && t++;
43
+ let s = 0;
44
+ for (; t < r; t++) {
45
+ const r = e.charCodeAt(t);
46
+ if (r < 48 || r > 57) break;
47
+ d = 10 * d + (r - 48), s++;
48
+ }
49
+ if (0 === s) return !0;
50
+ o && (d = -d);
51
+ }
52
+ if (a) {
53
+ const e = (i > 0 ? i - 1 : -(c + 1)) + d;
54
+ return e >= -309 && e <= 307;
55
+ }
56
+ const g = d - u;
57
+ return g >= -308 && g <= 308;
58
+ };
24
59
  })(e || (e = {}));
25
60
  var t, r, o, n, s = {
26
61
  Number: "number",
@@ -270,7 +305,7 @@ var t, r, o, n, s = {
270
305
  }
271
306
  }
272
307
  e.Unknown = C;
273
- class w extends o {
308
+ class f extends o {
274
309
  constructor(e, o) {
275
310
  super(t.Field, r.Field, e, o);
276
311
  }
@@ -278,8 +313,8 @@ var t, r, o, n, s = {
278
313
  this.code = n.Code.Field;
279
314
  }
280
315
  }
281
- e.Field = w;
282
- class f extends o {
316
+ e.Field = f;
317
+ class b extends o {
283
318
  constructor(e, o) {
284
319
  super(t.Calc, r.Calc, e, o);
285
320
  }
@@ -287,8 +322,8 @@ var t, r, o, n, s = {
287
322
  this.code = n.Code.Calc;
288
323
  }
289
324
  }
290
- e.Calc = f;
291
- class y extends o {
325
+ e.Calc = b;
326
+ class A extends o {
292
327
  constructor(e, o) {
293
328
  super(t.Busy, r.Busy, e, o);
294
329
  }
@@ -296,7 +331,7 @@ var t, r, o, n, s = {
296
331
  this.code = n.Code.Busy;
297
332
  }
298
333
  }
299
- e.Busy = y;
334
+ e.Busy = A;
300
335
  class N extends o {
301
336
  constructor(e, o) {
302
337
  super(t.Python, r.Python, e, o);
@@ -306,7 +341,7 @@ var t, r, o, n, s = {
306
341
  }
307
342
  }
308
343
  e.Python = N;
309
- class b extends o {
344
+ class D extends o {
310
345
  constructor(e, o) {
311
346
  super(t.Timeout, r.Timeout, e, o);
312
347
  }
@@ -314,7 +349,7 @@ var t, r, o, n, s = {
314
349
  this.code = n.Code.Timeout;
315
350
  }
316
351
  }
317
- e.Timeout = b;
352
+ e.Timeout = D;
318
353
  }(n || (n = {}));
319
354
  var g = {};
320
355
  g[n.Code.Parse] = n.Parse, g[n.Code.Null] = n.Null, g[n.Code.Div0] = n.Div0, g[n.Code.Value] = n.Value, g[n.Code.Ref] = n.Ref, g[n.Code.Name] = n.Name, g[n.Code.Num] = n.Num, g[n.Code.NA] = n.NA, g[n.Code.GettingData] = n.GettingData, g[n.Code.Spill] = n.Spill, g[n.Code.Connect] = n.Connect, g[n.Code.Blocked] = n.Blocked, g[n.Code.Unknown] = n.Unknown, g[n.Code.Field] = n.Field, g[n.Code.Calc] = n.Calc, g[n.Code.Busy] = n.Busy, g[n.Code.Python] = n.Python, g[n.Code.Timeout] = n.Timeout;
@@ -351,7 +386,7 @@ for (let e = 0; e < C.length; e++) {
351
386
  return !!e && !0 === e.isFormulaError && (void 0 === t || e.getCode() === t);
352
387
  };
353
388
  })(n || (n = {}));
354
- var w = class {
389
+ var f = class {
355
390
  constructor(e) {
356
391
  this._subscribeFn = e;
357
392
  }
@@ -371,36 +406,36 @@ var w = class {
371
406
  "function" == typeof n && n();
372
407
  }, o;
373
408
  }
374
- }, f = class {
409
+ }, b = class {
375
410
  createRange(e, t, r) {
376
- throw new D();
411
+ throw N("createRange");
377
412
  }
378
413
  flattenAreas(e) {
379
- throw new D();
414
+ throw N("flattenAreas");
380
415
  }
381
416
  getReference(e, t) {
382
- throw new D();
417
+ throw N("getReference");
383
418
  }
384
419
  getResizedReference(e, t, r) {
385
- throw new D();
420
+ throw N("getResizedReference");
386
421
  }
387
422
  getNumberFormat(e, t) {
388
- throw new D();
423
+ throw N("getNumberFormat");
389
424
  }
390
425
  fromSerialDate(e, t) {
391
- throw new D();
426
+ throw N("fromSerialDate");
392
427
  }
393
428
  toSerialDate(e, t) {
394
- throw new D();
429
+ throw N("toSerialDate");
395
430
  }
396
431
  getDateParts(e, t) {
397
- throw new D();
432
+ throw N("getDateParts");
398
433
  }
399
434
  getSerialDate(e, t, r, o, n, s, a) {
400
- throw new D();
435
+ throw N("getSerialDate");
401
436
  }
402
437
  getNow() {
403
- throw new D();
438
+ throw N("getNow");
404
439
  }
405
440
  getRandom() {
406
441
  return Math.random();
@@ -409,10 +444,10 @@ var w = class {
409
444
  return null;
410
445
  }
411
446
  getEntireCoords() {
412
- return A;
447
+ return _;
413
448
  }
414
449
  isValidDate(e, t) {
415
- return e instanceof Date || "[object Date]" === Object.prototype.toString.call(e) ? !isNaN(e.getTime()) : !t && "number" == typeof e && !(e < 0 || e > R);
450
+ return e instanceof Date || "[object Date]" === Object.prototype.toString.call(e) ? !isNaN(e.getTime()) : !t && "number" == typeof e && !(e < 0 || e > x);
416
451
  }
417
452
  getRow() {
418
453
  return 0;
@@ -448,22 +483,22 @@ var w = class {
448
483
  return null;
449
484
  }
450
485
  getAddress(e, t) {
451
- throw new D();
486
+ throw N("getAddress");
452
487
  }
453
488
  parseAsSerialDate(e, t) {
454
- throw new D();
489
+ throw N("parseAsSerialDate");
455
490
  }
456
491
  parseAsDate(e, t) {
457
- throw new D();
492
+ throw N("parseAsDate");
458
493
  }
459
494
  parseAsNumber(e, t) {
460
- throw new D();
495
+ throw N("parseAsNumber");
461
496
  }
462
497
  createCriteria(e, t) {
463
- throw new D();
498
+ throw N("createCriteria");
464
499
  }
465
500
  createGrouping(e, t) {
466
- throw new D();
501
+ throw N("createGrouping");
467
502
  }
468
503
  parseAsLiteral(e) {
469
504
  const t = e.toUpperCase();
@@ -474,19 +509,19 @@ var w = class {
474
509
  }
475
510
  compare(e, t, r) {
476
511
  if (e === t) return 0;
477
- const o = y(e), n = y(t);
512
+ const o = A(e), n = A(t);
478
513
  return o !== n ? o < n ? -1 : 1 : e < t ? -1 : e > t ? 1 : 0;
479
514
  }
480
515
  getRuntime() {
481
- return _;
516
+ return R;
482
517
  }
483
518
  getArgs() {
484
- throw new D(N);
519
+ throw new w(D);
485
520
  }
486
521
  createRichData(e, t) {
487
- throw new D(b);
522
+ throw new w(y);
488
523
  }
489
- }, y = (e) => {
524
+ }, A = (e) => {
490
525
  if (null == e) return 0;
491
526
  switch (typeof e) {
492
527
  case "number": return 1;
@@ -494,19 +529,19 @@ var w = class {
494
529
  case "boolean": return 3;
495
530
  default: return 4;
496
531
  }
497
- }, N = "FormulaContext.getArgs() is only valid while a function body is running", b = "FormulaContext.createRichData() needs a workbook being calculated", D = class extends Error {
532
+ }, N = (e) => new w(`FormulaContext.${e}() is only valid while a function body is running. A deferred executor reads its workbook through ctx.getFormulaContext().`), D = "FormulaContext.getArgs() is only valid while a function body is running", y = "FormulaContext.createRichData() needs a workbook being calculated", w = class extends Error {
498
533
  constructor(e = "Not implemented in StubbedFormulaContext") {
499
534
  super(e), this.name = "NotImplementedError";
500
535
  }
501
- }, A = Object.freeze({
536
+ }, _ = Object.freeze({
502
537
  colStart: 0,
503
538
  rowStart: 0,
504
539
  colEnd: Math.pow(2, 14) - 1,
505
540
  rowEnd: Math.pow(2, 20) - 1
506
- }), _ = {
541
+ }), R = {
507
542
  isDate1904: () => !1,
508
- getLocale: () => T.tag,
509
- getLocaleProfile: () => T,
543
+ getLocale: () => k.tag,
544
+ getLocaleProfile: () => k,
510
545
  isR1C1: () => !1,
511
546
  getNow: () => 0,
512
547
  getRandom: () => Math.random(),
@@ -515,12 +550,12 @@ var w = class {
515
550
  getOS: () => "unknown",
516
551
  getUser: () => "unidentified",
517
552
  getDescription: () => "Stubbed Formula Context"
518
- }, R = 2958465, x = new f(), F = class {
553
+ }, x = 2958465, F = new b(), T = class {
519
554
  constructor() {
520
- this._scope = x, this._argsFn = null;
555
+ this._scope = F, this._argsFn = null;
521
556
  }
522
557
  _setScope(e) {
523
- this._scope = e ?? x;
558
+ this._scope = e ?? F;
524
559
  }
525
560
  _getScope() {
526
561
  return this._scope;
@@ -532,7 +567,7 @@ var w = class {
532
567
  return this._getScope().getNumberFormat(e, t);
533
568
  }
534
569
  getEntireCoords() {
535
- return this._getScope().getEntireCoords() ?? A;
570
+ return this._getScope().getEntireCoords() ?? _;
536
571
  }
537
572
  parseAsSerialDate(e, t) {
538
573
  return this._getScope().parseAsSerialDate(e, t);
@@ -551,7 +586,7 @@ var w = class {
551
586
  }
552
587
  parseAsLiteral(e) {
553
588
  const t = this._getScope();
554
- return t.parseAsLiteral ? t.parseAsLiteral(e) : x.parseAsLiteral(e);
589
+ return t.parseAsLiteral ? t.parseAsLiteral(e) : F.parseAsLiteral(e);
555
590
  }
556
591
  toText(e) {
557
592
  return this._getScope().toText(e);
@@ -641,18 +676,18 @@ var w = class {
641
676
  return this._getScope().getAddress(e, t);
642
677
  }
643
678
  compare(e, t, r) {
644
- return this._getScope().compare?.(e, t, r) ?? x.compare(e, t, r);
679
+ return this._getScope().compare?.(e, t, r) ?? F.compare(e, t, r);
645
680
  }
646
681
  getRuntime() {
647
682
  return this._getScope().getRuntime();
648
683
  }
649
684
  createRichData(e, t) {
650
685
  const r = this._getScope();
651
- return r.createRichData ? r.createRichData(e, t) : x.createRichData(e, t);
686
+ return r.createRichData ? r.createRichData(e, t) : F.createRichData(e, t);
652
687
  }
653
688
  getArgs() {
654
689
  const e = this._argsFn, t = e ? e() : null;
655
- if (!t) throw new D(N);
690
+ if (!t) throw new w(D);
656
691
  return t;
657
692
  }
658
693
  get [Symbol.toStringTag]() {
@@ -661,7 +696,7 @@ var w = class {
661
696
  toString() {
662
697
  return this._getScope()?.toString?.() ?? "{STUB SCOPE}";
663
698
  }
664
- }, T = Object.freeze({
699
+ }, k = Object.freeze({
665
700
  tag: "en-US",
666
701
  numberingSystem: "latn",
667
702
  decimal: ".",
@@ -741,5 +776,5 @@ var w = class {
741
776
  sensitivity: "base",
742
777
  numeric: !0
743
778
  })
744
- }), P = new F();
745
- export { T as DEFAULT_LOCALE_PROFILE, P as FormulaContext, n as FormulaError, t as IRange, o as IRangeStats, a as InteropScalarType, w as Observable, e as Scalar, s as ScalarType, F as ScopedFormulaContext, f as StubbedFormulaContext, i as ValueKind, l as WildCard, d as isLazyValue };
779
+ }), P = new T();
780
+ export { k as DEFAULT_LOCALE_PROFILE, P as FormulaContext, n as FormulaError, t as IRange, o as IRangeStats, a as InteropScalarType, f as Observable, e as Scalar, s as ScalarType, T as ScopedFormulaContext, b as StubbedFormulaContext, i as ValueKind, l as WildCard, d as isLazyValue };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sheetxl/primitives",
3
3
  "description": "Primitives - Base types for SheetXL functions.",
4
- "version": "0.8.0-beta.12",
4
+ "version": "0.8.0-beta.13",
5
5
  "license": "SEE LICENSE IN <LICENSE>",
6
6
  "type": "module",
7
7
  "exports": {
@@ -24,11 +24,11 @@
24
24
  * if (range.hasError()) return range.firstError();
25
25
  * ```
26
26
  *
27
- * placed before its own validation where Excel's error outranks it (`LARGE(range-with-#N/A, 0)`
27
+ * placed before its own validation where the member's error outranks it (`LARGE(range-with-#N/A, 0)`
28
28
  * is `#N/A`, not `#NUM!`). Aggregators and consumers say it; reshapers and lookups, whose members
29
29
  * pass through or are never read, need no line at all. Where a function takes several ranges the
30
30
  * lines run in ARGUMENT order — the whole of argument N before N+1, row-major within — which is
31
- * Excel's which-error-wins order, and a function that pairs its ranges (the paired
31
+ * the which-error-wins order, and a function that pairs its ranges (the paired
32
32
  * statistics) orders its own scan the way it pairs.
33
33
  *
34
34
  * > *A bare error propagates unless your function opts in to seeing it; the members of a range
@@ -19,8 +19,8 @@
19
19
  * Both are the same mechanism at different granularity — the marshaller picks the unit from the
20
20
  * element type — and a blank drops out of either. The scalar case is the common one; the range case
21
21
  * exists because a reference UNION is a single argument holding several areas: a parameter that does
22
- * not declare `Flatten` refuses one outright (`#VALUE!` — `TRANSPOSE((A1:A3,C1:C3))` in Excel), and a
23
- * body that declares it answers for the union itself, in one line, the way Excel's own do:
22
+ * not declare `Flatten` refuses one outright (`#VALUE!` — `TRANSPOSE((A1:A3,C1:C3))`), and a
23
+ * body that declares it answers for the union itself, in one line, the way the built-ins do:
24
24
  * `AREAS` counts the areas, `SUM` adds them, `ROWS` answers `#REF!` to more than one, the lookups
25
25
  * `#N/A`.
26
26
  *
@@ -97,7 +97,7 @@ export declare class StubbedFormulaContext implements IFormulaContext {
97
97
  * Unimplemented. See {@link IFormulaContext.createGrouping}.
98
98
  *
99
99
  * @remarks
100
- * Grouping needs Excel's key equality, which this stub does not have.
100
+ * Grouping needs the engine's key equality, which this stub does not have.
101
101
  */
102
102
  createGrouping(keys: IRange, options?: IFormulaContext.GroupingOptions): IFormulaContext.Grouping;
103
103
  /**
@@ -115,15 +115,15 @@ export declare class StubbedFormulaContext implements IFormulaContext {
115
115
  * Renders a scalar as text. See {@link IFormulaContext.toText}.
116
116
  *
117
117
  * @remarks
118
- * A BASIC rendering, deliberately NOT Excel's. Excel's rule -- coercion General (15
118
+ * A BASIC rendering, deliberately NOT the engine's. The engine's rule -- coercion General (15
119
119
  * significant digits, plain decimal while the rendering fits 20 characters, else
120
120
  * scientific) written with the workbook LOCALE's decimal separator -- is
121
121
  * `formatNumberGeneral` in `@sheetxl/sdk`, and every evaluation path reaches it through
122
122
  * the calculation context rather than through this stub. Numbers here get the plain JS
123
- * rendering, which diverges from Excel on both precision and separator.
123
+ * rendering, which diverges from the engine on both precision and separator.
124
124
  *
125
125
  * This exists so authoring, type defs and other non-runtime access get usable text
126
- * instead of throwing. Anything that needs Excel parity is running in the engine, and
126
+ * instead of throwing. Anything that needs the full rule is running in the engine, and
127
127
  * the engine never lands here.
128
128
  */
129
129
  toText(value: Scalar | undefined): string;
@@ -131,14 +131,14 @@ export declare class StubbedFormulaContext implements IFormulaContext {
131
131
  * Orders two scalars. See {@link IFormulaContext.compare}.
132
132
  *
133
133
  * @remarks
134
- * A BASIC total order, deliberately NOT Excel's. Excel's rule -- locale collation, the word
134
+ * A BASIC total order, deliberately NOT the engine's. The engine's rule -- locale collation, the word
135
135
  * sort, a blank taking the other operand's type, 11-decimal numeric normalization -- is
136
136
  * `ScalarCollation` in `@sheetxl/sdk`, and every evaluation path reaches it through the
137
137
  * calculation context rather than through this stub. `options` is ignored: strength is a
138
138
  * collation concept and nothing here collates.
139
139
  *
140
140
  * This exists so authoring, type defs and other non-runtime access get a usable ordering
141
- * instead of throwing. Anything that needs Excel parity is running in the engine, and the
141
+ * instead of throwing. Anything that needs the full rule is running in the engine, and the
142
142
  * engine never lands here.
143
143
  */
144
144
  compare(a: Scalar, b: Scalar, options?: Intl.CollatorOptions): number;
@@ -20,7 +20,7 @@ import { IReferenceRange } from './IReferenceRange';
20
20
  *
21
21
  * SpillErrorScalarSubType | "Unknown" | "Collision" | "IndeterminateSize" | "WorksheetEdge" | "OutOfMemoryWhileCalc" | "Table" | "MergedCell"
22
22
  * # Office 2023
23
- * 10. #CONNECT! This occurs when a data type is used that is not currently supported in this version of Excel.
23
+ * 10. #CONNECT! This occurs when a data type is used that is not currently supported.
24
24
  * 11. #BLOCKED! Indicates that an action or feature is blocked, possibly due to security settings, protected view, or other restrictions. Often related to online features, external links, or macros.
25
25
  * 12. #UNKNOWN! May be returned in the case of a protected workbook.
26
26
  * 13. #FIELD! Invalid field name for a data type.
@@ -67,8 +67,8 @@ export interface IFormulaContext {
67
67
  * A union `(A1:A5,B1:B2)` reaches a {@link IFunction.ParameterTypeJSON.reportType} slot as one
68
68
  * `IRange` per area. Functions that answer over it do so because they walk MEMBERS and a union
69
69
  * simply has more of them — `LARGE((DA1:DA5,DK1:DK2),2)` is the second largest of all seven
70
- * cells. This is that walk, and it is a helper rather than a marshalling step on purpose: Excel
71
- * flattens in exactly the same place, a shared reducer its bodies opt into, which is why the
70
+ * cells. This is that walk, and it is a helper rather than a marshalling step on purpose:
71
+ * flattening is a shared reducer the bodies opt into, which is why the
72
72
  * same union is flattened by `LARGE`, refused by `SUMPRODUCT` and answered `#REF!` by `ROWS`.
73
73
  *
74
74
  * The result is a single column in area order, row-major within each area. SHAPE IS NOT
@@ -117,7 +117,7 @@ export interface IFormulaContext {
117
117
  */
118
118
  getColumn(): number;
119
119
  /**
120
- * Whether the call being evaluated is in Excel's VALUE mode, where a multi-cell reference at a
120
+ * Whether the call being evaluated is in VALUE mode, where a multi-cell reference at a
121
121
  * slot that reads ONE value is implicitly intersected with the formula's cell (the `@` rule);
122
122
  * `false` is ARRAY mode, where such a slot reads the reference's first cell.
123
123
  *
@@ -156,7 +156,7 @@ export interface IFormulaContext {
156
156
  * A few arguments honor only their top-left corner and are re-sized to the shape of the range
157
157
  * that drives them — `SUMIF`'s `sum_range`, `LOOKUP`'s `result_vector`. The window can therefore
158
158
  * run off the bottom or right of the grid: `SUMIF(A1:A5,">0",A1048574)` asks for five rows
159
- * starting three from the end. Excel reads the part that fits and treats the rest as blank, which
159
+ * starting three from the end. The part that fits is read and the rest is blank, which
160
160
  * is what this returns; positions past the clamp read as `undefined` from `getValueAt`.
161
161
  *
162
162
  * @param anchor The coords of the argument as written; only its top-left corner is honored.
@@ -560,12 +560,11 @@ export interface IFormulaContext {
560
560
  * want the raw carry above — `DATEDIF("2020-01-31","2020-03-01","md")` is `-1`
561
561
  * because Jan 31 rolls into March. `EDATE`/`EOMONTH` want the opposite and CLAMP to
562
562
  * the target month's length, so they pre-clamp before calling here. One conversion,
563
- * two opposite rules, both matching Excel. Baking either one in breaks the other.
563
+ * two opposite rules. Baking either one in breaks the other.
564
564
  * * **Results may legitimately leave the calendar.** `YEARFRAC` basis 1 anchors a year
565
565
  * length on January 1 of `laterYear + 1`, which at the top of the calendar is
566
- * `10000-01-01`; Excel answers `1.9972602739726026` for
567
- * `YEARFRAC(DATE(9998,1,1),DATE(9999,12,31),1)` rather than `#NUM!`. A range check
568
- * here would break it.
566
+ * `10000-01-01`; `YEARFRAC(DATE(9998,1,1),DATE(9999,12,31),1)` is
567
+ * `1.9972602739726026`, not `#NUM!`. A range check here would break it.
569
568
  * * **The 16-bit argument limits are per-function.** `DATE`'s month errors outside
570
569
  * `[-32767, 32766]` while its day saturates to `32767`, and `TIME` errors outside
571
570
  * `[0, 32767]` on every argument — same magic number, three different rules.
@@ -573,8 +572,8 @@ export interface IFormulaContext {
573
572
  * Note the asymmetry with {@link getDateParts}, which DOES throw `#NUM!` outside the
574
573
  * calendar because it answers a user-facing question. An internal intermediate that
575
574
  * steps one day past the end must therefore not be round-tripped through it; compute
576
- * on the fields instead. That mistake made `YEARFRAC(DATE(9999,1,1),DATE(9999,12,31),0)`
577
- * `#NUM!` where Excel says `1`.
575
+ * on the fields instead, or `YEARFRAC(DATE(9999,1,1),DATE(9999,12,31),0)` becomes `#NUM!`
576
+ * rather than `1`.
578
577
  */
579
578
  getSerialDate(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millis?: number): number;
580
579
  /**
@@ -590,8 +589,8 @@ export interface IFormulaContext {
590
589
  *
591
590
  * @remarks
592
591
  * Argument REFLECTION, for the one thing a declaration cannot say: what happened at *this* call.
593
- * It exists to serve Excel's declared `any`, which means "no contract, the body decides" — every
594
- * other Excel type maps onto a type we already have and the marshaller handles it.
592
+ * It exists to serve a declared `any`, which means "no contract, the body decides" — every
593
+ * other declared type maps onto a type we already have and the marshaller handles it.
595
594
  *
596
595
  * The returned view is valid ONLY while the body that asked for it is running. Views are pooled
597
596
  * by dispatch depth, so retaining one across an `await`, a callback, or a nested evaluation hands
@@ -610,7 +609,7 @@ export interface IFormulaContext {
610
609
  * recognizes it: while the call is still waiting, a recalculation with
611
610
  * an equal payload leaves it be rather than asking again. Once it has stopped, a recalculation
612
611
  * calls the function again; what it fetched is answered from the workbook's cache
613
- * (`IBatchContext.fetch`).
612
+ * (`IDeferContext.fetch`).
614
613
  * @returns The last answer this call gave for the same question, when the function is being
615
614
  * called again (a recalculation); `undefined` on a first call or a changed question. Return it
616
615
  * to keep showing it until the new answer arrives, or return something else to show that the
@@ -622,14 +621,15 @@ export interface IFormulaContext {
622
621
  * from meanwhile: return `#BUSY!` when they should wait as an error, or text such as
623
622
  * `'Fetching…'` when that is what they should show.
624
623
  *
625
- * The executor runs after the recalculation, outside any cell; read nothing from the formula
626
- * context there. Whatever the body knows goes in the payload.
624
+ * The executor runs after the recalculation, outside any cell, so the ambient `FormulaContext`
625
+ * is not its own: it reads the workbook through `ctx.getFormulaContext()`. Whatever the body
626
+ * knows about its cell goes in the payload.
627
627
  *
628
628
  * @example
629
629
  * ```typescript
630
630
  * function fetchAll(
631
631
  * calls: readonly IFormulaContext.DeferredCall<string>[],
632
- * ctx: IFormulaContext.IBatchContext
632
+ * ctx: IFormulaContext.IDeferContext
633
633
  * ): void {
634
634
  * for (const call of calls) {
635
635
  * ctx.fetch(call.payload as string)
@@ -683,7 +683,7 @@ export declare namespace IFormulaContext {
683
683
  * then `range` is returned as it is, hidden rows included.
684
684
  *
685
685
  * @remarks
686
- * This is `SUBTOTAL` 1-11 (Excel: they "include manually hidden rows", which is what an
686
+ * This is `SUBTOTAL` 1-11 (they include manually hidden rows, which is what an
687
687
  * unfiltered sheet reads as). `SUBTOTAL` 101-111 and `AGGREGATE` leave it off and skip
688
688
  * always.
689
689
  * @defaultValue false
@@ -812,7 +812,7 @@ export declare namespace IFormulaContext {
812
812
  * Answers the calls made by {@link IFormulaContext.defer} against it. Invoked once at the end of
813
813
  * a recalculation with every such call; how many requests that becomes is the executor's choice.
814
814
  */
815
- type DeferExecutor<T = any> = (calls: readonly DeferredCall<T>[], ctx: IBatchContext) => void | Promise<void>;
815
+ type DeferExecutor<T = any> = (calls: readonly DeferredCall<T>[], ctx: IDeferContext) => void | Promise<void>;
816
816
  /**
817
817
  * One call made by {@link IFormulaContext.defer}, as its executor receives it.
818
818
  *
@@ -824,7 +824,7 @@ export declare namespace IFormulaContext {
824
824
  /** What the function passed to `defer`. */
825
825
  readonly payload: unknown;
826
826
  /** Settles the call with its result. */
827
- resolve(value: T): void;
827
+ resolve(value: T, options?: DeferredCall.ResolveOptions): void;
828
828
  /** Settles the call with an error: a `FormulaError` as itself, anything else as `#VALUE!`. */
829
829
  reject(error: unknown): void;
830
830
  /** Runs `fn` when the result is no longer wanted. */
@@ -835,10 +835,29 @@ export declare namespace IFormulaContext {
835
835
  */
836
836
  readonly cancelled: boolean;
837
837
  }
838
+ namespace DeferredCall {
839
+ /**
840
+ * Options for {@link DeferredCall.resolve}.
841
+ */
842
+ interface ResolveOptions {
843
+ /**
844
+ * Whether the blanks of an array result stay blank when it spills. Omitted, they read as
845
+ * `0`, as any spilled array's blanks do.
846
+ *
847
+ * @remarks
848
+ * For data whose empty fields mean "nothing here", such as an imported file. The result
849
+ * keeps them while a formula passes it on as it is (`IF(c, result, …)`). A function that
850
+ * answers element by element builds a new array, whose blanks read as `0`
851
+ * (`IFERROR(result, …)`, `result & ""`).
852
+ * @defaultValue false
853
+ */
854
+ keepBlanks?: boolean;
855
+ }
856
+ }
838
857
  /**
839
858
  * What an executor is given beside its calls.
840
859
  */
841
- interface IBatchContext {
860
+ interface IDeferContext {
842
861
  /** A random number in `[0, 1)` from the calculation's source, which a test can seed. */
843
862
  getRandom(): number;
844
863
  /**
@@ -846,6 +865,35 @@ export declare namespace IFormulaContext {
846
865
  * here (maps, numbers, strings, buffers), not connections or sockets.
847
866
  */
848
867
  getState<S>(init: () => S): S;
868
+ /**
869
+ * Groups `calls` by payload and runs `answer` once per distinct payload with every call that
870
+ * asked it: one request per question, however many cells asked.
871
+ *
872
+ * @param calls The calls to group, usually every call the executor was handed.
873
+ * @param answer Settles one group. When it throws, or the promise it returns rejects, the
874
+ * group's calls it has not settled fail with that error; the other groups are not affected.
875
+ * @returns Resolves once every group has been answered. It never rejects.
876
+ *
877
+ * @remarks
878
+ * Payloads are equal as `defer` compares them: the same primitive, or plain objects or arrays
879
+ * whose own values are the same one level deep. Groups are answered concurrently, in the
880
+ * order their first call appears.
881
+ *
882
+ * @example
883
+ * ```typescript
884
+ * async function fetchQuotes(
885
+ * calls: readonly IFormulaContext.DeferredCall<number>[],
886
+ * ctx: IFormulaContext.IDeferContext
887
+ * ): Promise<void> {
888
+ * await ctx.byPayload(calls, async (ticker: string, group) => {
889
+ * const response = await ctx.fetch(`https://api.example.com/quote/${ticker}`);
890
+ * const price: number = (await response.json()).price;
891
+ * for (const call of group) call.resolve(price);
892
+ * });
893
+ * }
894
+ * ```
895
+ */
896
+ byPayload<T = any, P = unknown>(calls: readonly DeferredCall<T>[], answer: (payload: P, group: readonly DeferredCall<T>[]) => void | Promise<void>): Promise<void>;
849
897
  /**
850
898
  * A rich value of a registered type, for the workbook being calculated: what
851
899
  * {@link IFormulaContext.createRichData} makes inside a cell, made here for a call's result.
@@ -866,8 +914,44 @@ export declare namespace IFormulaContext {
866
914
  * answer the workbook already has for the URL (a picture it keeps, or anything fetched while
867
915
  * it is open) answers from the workbook, and two calls for one URL share one request. In an
868
916
  * external calculation (*Refresh All*) it goes to the source.
917
+ *
918
+ * Rejects when the URL cannot be reached, with a `FormulaError.Blocked` when the site responded
919
+ * but the browser would not let the page read it.
869
920
  */
870
921
  fetch(input: string, init?: RequestInit): Promise<Response>;
922
+ /**
923
+ * The formula context of the workbook being calculated, with no cell: its parsing, text,
924
+ * comparison and dates, read with the workbook's locale and date system.
925
+ *
926
+ * @remarks
927
+ * Valid for as long as the executor runs, across every `await`. The ambient `FormulaContext`
928
+ * is not: it belongs to the cell being evaluated, and an executor runs after that evaluation
929
+ * ends. What needs a cell (`getRow`, `getReference`, `getValueAt`, `defer`, `markVolatile`,
930
+ * `formatResults`, `getRandom`) throws here; {@link getRandom} is the executor's own.
931
+ */
932
+ getFormulaContext(): IFormulaContext;
933
+ /**
934
+ * Reads delimited text (CSV, TSV) into rows of values, each field read the way the workbook
935
+ * reads typed entry: numbers, dates, booleans and error labels become values, anything else
936
+ * stays text, and an empty field is blank.
937
+ *
938
+ * @param text The delimited text.
939
+ * @param options How the text is split.
940
+ * @returns The rows, padded with blanks to the widest row.
941
+ */
942
+ parseText(text: string, options?: IDeferContext.ParseTextOptions): Promise<Scalar[][]>;
943
+ }
944
+ namespace IDeferContext {
945
+ /**
946
+ * Options for {@link IDeferContext.parseText}.
947
+ */
948
+ interface ParseTextOptions {
949
+ /**
950
+ * The character between fields.
951
+ * @defaultValue `','`
952
+ */
953
+ delimiter?: string;
954
+ }
871
955
  }
872
956
  }
873
957
  //# sourceMappingURL=IFormulaContext.d.ts.map
@@ -304,7 +304,7 @@ export declare namespace IFunction {
304
304
  *
305
305
  * @remarks
306
306
  * STATIC, and read from the formula text at compile time: it is true of the call whether or
307
- * not the call runs, which is what a lazy argument (and Excel) requires.
307
+ * not the call runs, which is what a lazy argument requires.
308
308
  *
309
309
  * @see {@link ReturnTypeJSON.volatile}
310
310
  */
@@ -343,7 +343,7 @@ export declare namespace IFunction {
343
343
  * @remarks
344
344
  * Only meaningful for a VARIADIC function; a fixed parameter list is already its own maximum.
345
345
  * The number is the whole CALL's argument count, prefix and optional suffix included, and it
346
- * is refused where Excel refuses it — at entry, before evaluation.
346
+ * is refused at entry, before evaluation.
347
347
  *
348
348
  * @see {@link Repeating}
349
349
  */
@@ -645,8 +645,8 @@ export declare namespace IFunction {
645
645
  * Generated from the `NoLift<T>` marker.
646
646
  *
647
647
  * @remarks
648
- * Per parameter, because Excel is: `NETWORKDAYS.INTL` refuses a reference at its date slots
649
- * and lifts one at `weekend`. An ARRAY at the slot still lifts, a one-cell reference is an
648
+ * Per parameter, because Excel's built-ins differ by slot: `NETWORKDAYS.INTL` refuses a
649
+ * reference at its date slots and lifts one at `weekend`. An ARRAY at the slot still lifts, a one-cell reference is an
650
650
  * ordinary argument, and a repeating slot absorbs a container as members, so the marker only
651
651
  * ever applies to a non-repeating scalar parameter.
652
652
  */
@@ -686,7 +686,7 @@ export declare namespace IFunction {
686
686
  * union is the range arm, handed over whole. The slot never lifts.
687
687
  *
688
688
  * @remarks
689
- * Excel reads a one-cell argument at some array slots as THE ARGUMENT rather than as a
689
+ * Some array slots read a one-cell argument as THE ARGUMENT rather than as a
690
690
  * one-cell container: `SORT(<#N/A cell>,1,1,<#DIV/0! cell>)` is `#N/A` where
691
691
  * `TAKE(<#N/A cell>,<#DIV/0! cell>)` is `#DIV/0!`. The engine's default
692
692
  * for a range slot is TAKE's; this flag is SORT's. {@link scalar} and {@link range} each carry
@@ -753,7 +753,7 @@ export declare namespace IFunction {
753
753
  *
754
754
  * @remarks
755
755
  * Collected at COMPILE time from the formula text (`CompiledFormula.hasVolatile`), because
756
- * that is where Excel decides it: `=IF(TRUE,1,RAND())` recalculates on every idle pass though
756
+ * that is where volatility is decided: `=IF(TRUE,1,RAND())` recalculates on every idle pass though
757
757
  * no branch selects the arm, and with lazy arguments the call never happens for the engine to
758
758
  * observe.
759
759
  *
@@ -776,11 +776,10 @@ export declare namespace IFunction {
776
776
  * parameter. Omitted at the default of 255.
777
777
  *
778
778
  * @remarks
779
- * Excel keeps one such number per NAME and compares it against the whole call's argument
780
- * count in its front end, so a call past it is refused AT ENTRY rather than answered — which
781
- * is why the cap lives on the declaration and not in a body. It is not derivable from the
782
- * shape: `STDEV` takes 255 arguments and `STDEV.S`, the same function under its dotted name,
783
- * takes 254.
779
+ * The cap is one number per NAME, compared against the whole call's argument count, so a call
780
+ * past it is refused AT ENTRY rather than answered — which is why the cap lives on the
781
+ * declaration and not in a body. It is not derivable from the shape: in Excel `STDEV` takes 255
782
+ * arguments and `STDEV.S`, the same function under its dotted name, takes 254.
784
783
  *
785
784
  * @defaultValue 255
786
785
  */
@@ -15,9 +15,8 @@ import { IFunction } from './IFunction';
15
15
  * - What was the value BEFORE the parameter's type coerced it?
16
16
  * - Was that empty slot an omission, or a blank cell the caller pointed at?
17
17
  *
18
- * Excel has behaviors that turn on exactly those questions, and they cluster at the
19
- * parameters Excel declares `any` — where there is nothing to express as a type, because Excel
20
- * declined to express one. `CUMIPMT` refuses a boolean at every slot while `FV` coerces one at
18
+ * Some functions have behaviors that turn on exactly those questions, and they cluster at
19
+ * parameters declared `any` — where there is nothing to express as a type. `CUMIPMT` refuses a boolean at every slot while `FV` coerces one at
21
20
  * every slot; the difference is not the values, it is that `CUMIPMT`'s slots are `any` and its
22
21
  * body decides.
23
22
  *
@@ -142,7 +141,7 @@ export interface IFunctionArguments {
142
141
  */
143
142
  getKindAt(index: number): ValueKind;
144
143
  /**
145
- * True when the argument at `index` is DIRECT — Excel's "typed into the list of arguments":
144
+ * True when the argument at `index` is DIRECT — typed into the list of arguments:
146
145
  * the evaluated value IS a value, not a container or a callable.
147
146
  *
148
147
  * @param index The PARAMETER index — the position in the body's own signature.
@@ -255,7 +255,7 @@ export interface IRange<T extends Scalar = Scalar> {
255
255
  * @remarks
256
256
  * Errors INSIDE a range are the body's to judge: the engine hands a valid range over whole and
257
257
  * never looks inside, so a function whose answer depends on every member says so with this
258
- * line, placed before its own validation where Excel's error outranks it. A reshaper or a
258
+ * line, placed before its own validation where the member's error outranks it. A reshaper or a
259
259
  * lookup, whose members pass through or are never read, needs no line at all.
260
260
  */
261
261
  firstError(): FormulaError.Known | null;
@@ -268,7 +268,7 @@ export interface IRange<T extends Scalar = Scalar> {
268
268
  * @remarks
269
269
  * `options.axis` is the TRAVERSAL order feeding the ordinal, not the orientation of the result:
270
270
  * the result is always Nx1, and a row is `flatten().transpose()`. The default is row-major,
271
- * which is the order Excel pairs two range operands in.
271
+ * which is the order two range operands pair in.
272
272
  *
273
273
  * `options.type` carries a read type onto the result, so a member the type filters out becomes
274
274
  * a HOLE at its ordinal rather than compacting the column. That is what lets two operands be
@@ -916,7 +916,7 @@ export declare namespace IRange {
916
916
  *
917
917
  * - By default, `broadcast()` follows strict alignment rules like NumPy and will
918
918
  * throw an error if the input ranges cannot be broadcasted together.
919
- * - When `misalignValue` is provided, `broadcast()` will instead mimic Excel behavior:
919
+ * - When `misalignValue` is provided, `broadcast()` will instead follow Excel's behavior:
920
920
  * - It finds the **largest valid intersection** of the ranges.
921
921
  * - It expands the result to the **union of both range sizes**.
922
922
  * - Any cells that do not have valid corresponding values from the inputs
@@ -974,7 +974,7 @@ export declare namespace IRange {
974
974
  *
975
975
  * @remarks
976
976
  * Off, a dimension of 1 is a short dimension like any other and pads `misalignValue` past
977
- * its one position: Excel's `MAP` rule, where a 1-row array is not stretched.
977
+ * its one position: the `MAP` rule, where a 1-row array is not stretched.
978
978
  */
979
979
  tile?: boolean;
980
980
  /**
@@ -71,7 +71,7 @@ export interface IRangeStats {
71
71
  */
72
72
  getAggregates(options?: IRange.IteratorOptions): Readonly<IRangeStats.Aggregates>;
73
73
  /**
74
- * Returns the sum as Excel's `SUM` reports it — {@link getAggregates}'s `sum` with Excel's
74
+ * Returns the sum as `SUM` reports it — {@link getAggregates}'s `sum` with Excel's
75
75
  * cancellation-to-zero rule applied.
76
76
  *
77
77
  * @param total A total the caller accumulated across SEVERAL stats instances. Omit for a
@@ -82,7 +82,7 @@ export interface IRangeStats {
82
82
  * @remarks
83
83
  * Collapses a total to exactly zero when it lands at least 50 binary exponents below the
84
84
  * operands that produced it, so `SUM(0.1,0.2,-0.3)` is `0` rather than `5.55111512312578E-17`.
85
- * Use this wherever you mean "the number Excel's SUM would show" — a status bar, a report
85
+ * Use this wherever you mean "the number SUM shows" — a status bar, a report
86
86
  * total, a formula. Use `getAggregates().sum` where you mean the true total of the data.
87
87
  *
88
88
  * The two genuinely differ, and neither is a rounding of the other:
@@ -92,12 +92,12 @@ export interface IRangeStats {
92
92
  * and `PERCENTOF`, and to NOTHING else — `SUMIF`, `SUMPRODUCT`, `SERIESSUM`, `DSUM`, the
93
93
  * `SUMX2MY2` family and every binary operator all keep the residue over the same values.
94
94
  * That is why this is a method you call and not a change to `getAggregates`.
95
- * - `AVERAGE` divides THIS, not the raw sum: snapping the mean instead is measurably wrong.
95
+ * - `AVERAGE` divides THIS, not the raw sum: snapping the mean instead is wrong.
96
96
  *
97
97
  * It is also cheap when it does not fire: a bound derived from `min`/`max` rejects any
98
98
  * ordinary total without re-reading the range.
99
99
  *
100
- * **Multiple ranges.** Excel evaluates the rule on the *final* accumulation step, so a total
100
+ * **Multiple ranges.** The rule applies on the *final* accumulation step, so a total
101
101
  * spanning several ranges must be judged against the range holding the LAST value — pass the
102
102
  * running total as `total` and call this on that range. (Snapping each range separately gets
103
103
  * `SUM(A1:A3,0)` and `SUM(A1:A1,A2:A2,A3:A3)` wrong in opposite directions.) A composite
@@ -245,7 +245,7 @@ export declare namespace IRangeStats {
245
245
  * Sorting requires materializing the full numeric population (O(n log n), one allocation).
246
246
  * Unlike `Aggregates`, sorted views are **not composable across sub-ranges**.
247
247
  *
248
- * Covers the following Excel functions (all share one sort per coords per calc cycle):
248
+ * Covers the following functions (all share one sort per coords per calc cycle):
249
249
  * - `LARGE`, `SMALL`
250
250
  * - `MEDIAN`, `PERCENTILE`, `PERCENTILE.INC`, `PERCENTILE.EXC`
251
251
  * - `QUARTILE`, `QUARTILE.INC`, `QUARTILE.EXC` (q1 = k=0.25, q3 = k=0.75)
@@ -310,7 +310,7 @@ export declare namespace IRangeStats {
310
310
  * one outside the population is not found.
311
311
  * @param exclusive If true, uses exclusive formula (0 and 1 are excluded).
312
312
  * @param significance Number of DECIMAL PLACES to TRUNCATE the result to — despite what
313
- * Excel's own help calls the argument, it is not significant digits and it does not round.
313
+ * Excel's help calls the argument, it is not significant digits and it does not round.
314
314
  * Truncated toward zero first (1.9 places means 1), and must be at least 1. Omit it for the
315
315
  * exact untruncated rank, which is also the only form that cannot fail.
316
316
  * @returns The percent rank of x; `null` if x is not found or there are no numbers in range.
@@ -46,12 +46,12 @@
46
46
  * omitted when there is a single repetition. `SORTBY`'s legal arities are 2 and 1+2n and nothing
47
47
  * else — `SORTBY(array, by1)` is legal, `SORTBY(array, by1, o1, by2)` is not. It is not a general
48
48
  * "the final element of the final group may be omitted" rule; that rule would accept a formula
49
- * Excel refuses. An optional slot anywhere else in the group is a compiler error.
49
+ * that must be refused. An optional slot anywhere else in the group is a compiler error.
50
50
  *
51
51
  * ### The maximum, `Max`
52
52
  *
53
- * The second type argument is the largest number of arguments the WHOLE CALL accepts, which is
54
- * how Excel states it: one number per NAME, compared against the call's total argument count and
53
+ * The second type argument is the largest number of arguments the WHOLE CALL accepts: one
54
+ * number per NAME, compared against the call's total argument count and
55
55
  * refused at entry (`Excess_function_arguments`), never a count of this parameter's own share.
56
56
  * `SWITCH`'s 254 therefore covers its `expression` and its trailing `default` as well as the
57
57
  * pairs, and `CHOOSEROWS`' covers its `array`.
@@ -27,8 +27,8 @@
27
27
  * what can arrive and {@link IFunctionArguments.getAreaCountAt} answers the union question the
28
28
  * kind cannot — a plain reference is one area, a union is more.
29
29
  *
30
- * Its use is meant to stay countable: a slot earns it with a rule Excel actually shows, never
31
- * with a guess.
30
+ * Its use is meant to stay countable: a slot earns it with a concrete behavior that needs it,
31
+ * never speculatively.
32
32
  *
33
33
  * @example
34
34
  * ```ts
@@ -31,8 +31,8 @@ export declare namespace Scalar {
31
31
  */
32
32
  const MAX_SIGNIFICANT_DIGITS = 15;
33
33
  /**
34
- * Applies Excel's entry rule to numeric text: every significand digit past the
35
- * 15th becomes `0`, so the text parses to the double Excel would store.
34
+ * Applies the 15-digit entry rule to numeric text: every significand digit past the
35
+ * 15th becomes `0`, so the text parses to the double a cell stores.
36
36
  *
37
37
  * @param text Numeric text in any accepted form — signed, grouped, percent,
38
38
  * currency-affixed, or scientific. The scan is locale-blind: only digit
@@ -46,6 +46,30 @@ export declare namespace Scalar {
46
46
  * truncation, not rounding: `1234567890.123456789` stores `…345`, never `…346`.
47
47
  */
48
48
  function truncateNumberText(text: string): string;
49
+ /**
50
+ * The smallest magnitude a stored number can have: the smallest normal double. A smaller one is
51
+ * stored as `0`.
52
+ */
53
+ const MIN_NUMBER = 2.2250738585072014e-308;
54
+ /**
55
+ * Applies the stored-number floor to a number entering a workbook — typed, parsed from text, written
56
+ * through the API or loaded from a file: a magnitude below {@link MIN_NUMBER} becomes `0`.
57
+ */
58
+ function flushSubnormal(value: number): number;
59
+ /**
60
+ * Whether numeric text is inside the range accepted as a number, judged from the text as
61
+ * written rather than the double it parses to.
62
+ *
63
+ * @param text Numeric text in any accepted form, as {@link truncateNumberText} takes it. Only
64
+ * digits, `decimal` and an exponent marker are read.
65
+ * @param decimal The decimal separator `text` is written with.
66
+ * @returns `false` when the leading significant digit sits outside `1E-309` … `1E+307`
67
+ * (`1E-310`, `0.00001E-305`, `1E+308`); for a zero mantissa, when its scale — exponent less
68
+ * fraction digits — is outside ±308 (`0E-309`, `0.0E-308` and `0E+309`, but not `0E-308`,
69
+ * `000E-308` or `0.0E+309`). Text out of range is not a number: a formula literal will not
70
+ * commit, `VALUE` is `#VALUE!` and typed entry stays text.
71
+ */
72
+ function isNumberTextInRange(text: string, decimal?: string): boolean;
49
73
  /**
50
74
  * Encodings of `ScalarType` for persistence.
51
75
  */
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * @remarks
6
6
  * A value's kind and its extent are different axes: `{10}`, `A1` and a bare `10` all reach a
7
- * range-typed parameter as a 1x1 container, yet Excel separates them:
7
+ * range-typed parameter as a 1x1 container, yet they are distinct:
8
8
  * `VLOOKUP(10,10,1,TRUE)` is `#N/A` while `VLOOKUP(10,{10},1,TRUE)` is 10, and `TYPE` answers
9
9
  * 1 vs 64. The kind is what the CALLER supplied; the extent is merely its size.
10
10
  *
@@ -13,7 +13,7 @@
13
13
  * argument can be: a reference, a non-reference array, a callable, and no argument at all. As an
14
14
  * argument kind, {@link ScalarType.Null} means a BLANK value.
15
15
  *
16
- * The names and values are ours. The numeric codes Excel's `TYPE` function answers are a
16
+ * The names and values are ours. The numeric codes the `TYPE` function answers are a
17
17
  * PROJECTION of this kind (see `TYPE`'s implementation), not the kind itself.
18
18
  *
19
19
  * @see {@link IFunctionArguments.getKindAt}
@@ -11,7 +11,7 @@ export declare const WildCard: {
11
11
  * Compiles Excel wildcard text into a regex.
12
12
  *
13
13
  * @param anchor Where the pattern has to line up: `true` for the WHOLE string, `'start'` for a
14
- * PREFIX, `false` for anywhere in it. Excel matches a whole cell, so every lookup and criteria
14
+ * PREFIX, `false` for anywhere in it. A criterion matches a whole cell, so every lookup and criteria
15
15
  * caller anchors; `SEARCH`, which looks for a substring, does not; and a `D` function's criteria
16
16
  * table is the prefix form — `DSUM` with the criterion `appl` takes the row whose value is
17
17
  * `Apple`, where `COUNTIF` with the same criterion takes none.