@cj-tech-master/excelts 9.3.1 → 9.4.0

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.
Files changed (109) hide show
  1. package/dist/browser/index.d.ts +1 -0
  2. package/dist/browser/index.js +2 -0
  3. package/dist/browser/modules/excel/cell.d.ts +18 -0
  4. package/dist/browser/modules/excel/cell.js +21 -0
  5. package/dist/browser/modules/excel/utils/cell-format.js +85 -13
  6. package/dist/browser/modules/excel/workbook.browser.d.ts +57 -0
  7. package/dist/browser/modules/excel/workbook.browser.js +49 -0
  8. package/dist/browser/modules/excel/xlsx/defaultnumformats.js +3 -3
  9. package/dist/browser/modules/formula/compile/binder.js +48 -6
  10. package/dist/browser/modules/formula/compile/bound-ast.d.ts +16 -2
  11. package/dist/browser/modules/formula/compile/bound-ast.js +1 -0
  12. package/dist/browser/modules/formula/compile/compiled-formula.js +41 -8
  13. package/dist/browser/modules/formula/functions/_shared.d.ts +19 -0
  14. package/dist/browser/modules/formula/functions/_shared.js +47 -0
  15. package/dist/browser/modules/formula/functions/conditional.js +103 -22
  16. package/dist/browser/modules/formula/functions/date.js +105 -23
  17. package/dist/browser/modules/formula/functions/dynamic-array.js +173 -69
  18. package/dist/browser/modules/formula/functions/engineering.d.ts +2 -2
  19. package/dist/browser/modules/formula/functions/engineering.js +103 -151
  20. package/dist/browser/modules/formula/functions/financial.js +210 -184
  21. package/dist/browser/modules/formula/functions/lookup.js +224 -157
  22. package/dist/browser/modules/formula/functions/math.d.ts +26 -0
  23. package/dist/browser/modules/formula/functions/math.js +249 -69
  24. package/dist/browser/modules/formula/functions/statistical.js +221 -171
  25. package/dist/browser/modules/formula/functions/text.js +112 -52
  26. package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +20 -1
  27. package/dist/browser/modules/formula/materialize/build-writeback-plan.js +10 -6
  28. package/dist/browser/modules/formula/materialize/types.d.ts +15 -0
  29. package/dist/browser/modules/formula/runtime/evaluator.d.ts +8 -0
  30. package/dist/browser/modules/formula/runtime/evaluator.js +582 -162
  31. package/dist/browser/modules/formula/runtime/function-registry.d.ts +5 -0
  32. package/dist/browser/modules/formula/runtime/function-registry.js +59 -13
  33. package/dist/browser/modules/formula/runtime/values.d.ts +13 -0
  34. package/dist/browser/modules/formula/runtime/values.js +20 -2
  35. package/dist/browser/modules/formula/syntax/ast.d.ts +14 -2
  36. package/dist/browser/modules/formula/syntax/ast.js +1 -0
  37. package/dist/browser/modules/formula/syntax/parser.js +29 -7
  38. package/dist/browser/modules/formula/syntax/token-types.d.ts +4 -0
  39. package/dist/browser/modules/formula/syntax/token-types.js +9 -0
  40. package/dist/browser/modules/formula/syntax/tokenizer.js +76 -19
  41. package/dist/cjs/index.js +7 -2
  42. package/dist/cjs/modules/excel/cell.js +21 -0
  43. package/dist/cjs/modules/excel/utils/cell-format.js +85 -13
  44. package/dist/cjs/modules/excel/workbook.browser.js +49 -0
  45. package/dist/cjs/modules/excel/xlsx/defaultnumformats.js +3 -3
  46. package/dist/cjs/modules/formula/compile/binder.js +48 -6
  47. package/dist/cjs/modules/formula/compile/compiled-formula.js +41 -8
  48. package/dist/cjs/modules/formula/functions/_shared.js +48 -0
  49. package/dist/cjs/modules/formula/functions/conditional.js +103 -22
  50. package/dist/cjs/modules/formula/functions/date.js +104 -22
  51. package/dist/cjs/modules/formula/functions/dynamic-array.js +173 -69
  52. package/dist/cjs/modules/formula/functions/engineering.js +109 -157
  53. package/dist/cjs/modules/formula/functions/financial.js +209 -183
  54. package/dist/cjs/modules/formula/functions/lookup.js +224 -157
  55. package/dist/cjs/modules/formula/functions/math.js +254 -70
  56. package/dist/cjs/modules/formula/functions/statistical.js +222 -172
  57. package/dist/cjs/modules/formula/functions/text.js +112 -52
  58. package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +20 -1
  59. package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +10 -6
  60. package/dist/cjs/modules/formula/runtime/evaluator.js +581 -161
  61. package/dist/cjs/modules/formula/runtime/function-registry.js +57 -11
  62. package/dist/cjs/modules/formula/runtime/values.js +21 -2
  63. package/dist/cjs/modules/formula/syntax/parser.js +29 -7
  64. package/dist/cjs/modules/formula/syntax/token-types.js +9 -0
  65. package/dist/cjs/modules/formula/syntax/tokenizer.js +76 -19
  66. package/dist/esm/index.js +2 -0
  67. package/dist/esm/modules/excel/cell.js +21 -0
  68. package/dist/esm/modules/excel/utils/cell-format.js +85 -13
  69. package/dist/esm/modules/excel/workbook.browser.js +49 -0
  70. package/dist/esm/modules/excel/xlsx/defaultnumformats.js +3 -3
  71. package/dist/esm/modules/formula/compile/binder.js +48 -6
  72. package/dist/esm/modules/formula/compile/bound-ast.js +1 -0
  73. package/dist/esm/modules/formula/compile/compiled-formula.js +41 -8
  74. package/dist/esm/modules/formula/functions/_shared.js +47 -0
  75. package/dist/esm/modules/formula/functions/conditional.js +103 -22
  76. package/dist/esm/modules/formula/functions/date.js +105 -23
  77. package/dist/esm/modules/formula/functions/dynamic-array.js +173 -69
  78. package/dist/esm/modules/formula/functions/engineering.js +103 -151
  79. package/dist/esm/modules/formula/functions/financial.js +210 -184
  80. package/dist/esm/modules/formula/functions/lookup.js +224 -157
  81. package/dist/esm/modules/formula/functions/math.js +249 -69
  82. package/dist/esm/modules/formula/functions/statistical.js +221 -171
  83. package/dist/esm/modules/formula/functions/text.js +112 -52
  84. package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +20 -1
  85. package/dist/esm/modules/formula/materialize/build-writeback-plan.js +10 -6
  86. package/dist/esm/modules/formula/runtime/evaluator.js +582 -162
  87. package/dist/esm/modules/formula/runtime/function-registry.js +59 -13
  88. package/dist/esm/modules/formula/runtime/values.js +20 -2
  89. package/dist/esm/modules/formula/syntax/ast.js +1 -0
  90. package/dist/esm/modules/formula/syntax/parser.js +29 -7
  91. package/dist/esm/modules/formula/syntax/token-types.js +9 -0
  92. package/dist/esm/modules/formula/syntax/tokenizer.js +76 -19
  93. package/dist/iife/excelts.iife.js +1502 -1379
  94. package/dist/iife/excelts.iife.js.map +1 -1
  95. package/dist/iife/excelts.iife.min.js +26 -26
  96. package/dist/types/index.d.ts +1 -0
  97. package/dist/types/modules/excel/cell.d.ts +18 -0
  98. package/dist/types/modules/excel/workbook.browser.d.ts +57 -0
  99. package/dist/types/modules/formula/compile/bound-ast.d.ts +16 -2
  100. package/dist/types/modules/formula/functions/_shared.d.ts +19 -0
  101. package/dist/types/modules/formula/functions/engineering.d.ts +2 -2
  102. package/dist/types/modules/formula/functions/math.d.ts +26 -0
  103. package/dist/types/modules/formula/materialize/types.d.ts +15 -0
  104. package/dist/types/modules/formula/runtime/evaluator.d.ts +8 -0
  105. package/dist/types/modules/formula/runtime/function-registry.d.ts +5 -0
  106. package/dist/types/modules/formula/runtime/values.d.ts +13 -0
  107. package/dist/types/modules/formula/syntax/ast.d.ts +14 -2
  108. package/dist/types/modules/formula/syntax/token-types.d.ts +4 -0
  109. package/package.json +1 -1
@@ -78,32 +78,73 @@ function fnFILTER(args) {
78
78
  if (!dataArr || !includeArr) {
79
79
  return values_1.ERRORS.VALUE;
80
80
  }
81
- // Excel requires `include` to be a 1-column vector matching data's
82
- // height (the common row-filter shape). A mismatched shape previously
83
- // let rows slip through silently because `getCell` out-of-bounds
84
- // returns BLANK, which reads as FALSE.
85
- if (includeArr.width !== 1 || includeArr.height !== dataArr.height) {
81
+ const ifEmpty = args.length > 2 && args[2].kind !== 0 /* RVKind.Blank */ ? (0, values_1.topLeft)(args[2]) : null;
82
+ // Decide filter orientation from the include vector's shape:
83
+ // - N×1 vector matching data.height ROW filter (classic).
84
+ // - 1×N vector matching data.width → COL filter (Excel supports
85
+ // both; previously we hard-required the row shape and silently
86
+ // rejected column filters with #VALUE!).
87
+ // A 1×1 include vector is treated as a row filter over 1 row.
88
+ const isRowFilter = includeArr.width === 1 && includeArr.height === dataArr.height;
89
+ const isColFilter = !isRowFilter && includeArr.height === 1 && includeArr.width === dataArr.width;
90
+ if (!isRowFilter && !isColFilter) {
86
91
  return values_1.ERRORS.VALUE;
87
92
  }
88
- const ifEmpty = args.length > 2 ? (0, values_1.topLeft)(args[2]) : null;
89
- const resultRows = [];
90
- for (let r = 0; r < dataArr.height; r++) {
91
- const inc = (0, _shared_1.getCell)(includeArr, r, 0);
92
- if (inc.kind === 4 /* RVKind.Error */) {
93
- return inc;
94
- }
95
- if ((inc.kind === 3 /* RVKind.Boolean */ && inc.value) ||
96
- (inc.kind === 1 /* RVKind.Number */ && inc.value !== 0)) {
97
- const row = [];
98
- for (let c = 0; c < dataArr.width; c++) {
99
- row.push((0, _shared_1.getCell)(dataArr, r, c));
93
+ const cellIsTruthy = (cell) => {
94
+ if (cell.kind === 4 /* RVKind.Error */) {
95
+ return cell;
96
+ }
97
+ if (cell.kind === 3 /* RVKind.Boolean */) {
98
+ return cell.value;
99
+ }
100
+ if (cell.kind === 1 /* RVKind.Number */) {
101
+ return cell.value !== 0;
102
+ }
103
+ // Blank / String / anything else treated as FALSE.
104
+ return false;
105
+ };
106
+ if (isRowFilter) {
107
+ const resultRows = [];
108
+ for (let r = 0; r < dataArr.height; r++) {
109
+ const truthy = cellIsTruthy((0, _shared_1.getCell)(includeArr, r, 0));
110
+ if (typeof truthy !== "boolean") {
111
+ return truthy;
100
112
  }
101
- resultRows.push(row);
113
+ if (truthy) {
114
+ const row = [];
115
+ for (let c = 0; c < dataArr.width; c++) {
116
+ row.push((0, _shared_1.getCell)(dataArr, r, c));
117
+ }
118
+ resultRows.push(row);
119
+ }
120
+ }
121
+ if (resultRows.length === 0) {
122
+ return ifEmpty !== null ? (0, values_1.rvArray)([[ifEmpty]]) : values_1.ERRORS.CALC;
123
+ }
124
+ return (0, values_1.rvArray)(resultRows);
125
+ }
126
+ // Column filter — pick a subset of columns across every row.
127
+ const keepCols = [];
128
+ for (let c = 0; c < dataArr.width; c++) {
129
+ const truthy = cellIsTruthy((0, _shared_1.getCell)(includeArr, 0, c));
130
+ if (typeof truthy !== "boolean") {
131
+ return truthy;
132
+ }
133
+ if (truthy) {
134
+ keepCols.push(c);
102
135
  }
103
136
  }
104
- if (resultRows.length === 0) {
137
+ if (keepCols.length === 0) {
105
138
  return ifEmpty !== null ? (0, values_1.rvArray)([[ifEmpty]]) : values_1.ERRORS.CALC;
106
139
  }
140
+ const resultRows = [];
141
+ for (let r = 0; r < dataArr.height; r++) {
142
+ const row = new Array(keepCols.length);
143
+ for (let i = 0; i < keepCols.length; i++) {
144
+ row[i] = (0, _shared_1.getCell)(dataArr, r, keepCols[i]);
145
+ }
146
+ resultRows.push(row);
147
+ }
107
148
  return (0, values_1.rvArray)(resultRows);
108
149
  }
109
150
  function fnSORT(args) {
@@ -119,15 +160,26 @@ function fnSORT(args) {
119
160
  }
120
161
  rows.push(row);
121
162
  }
122
- const sortIndexV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(1);
163
+ const sortIndexV = args.length > 1 && args[1].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(1);
123
164
  if ((0, values_1.isError)(sortIndexV)) {
124
165
  return sortIndexV;
125
166
  }
126
- const sortOrderV = args.length > 2 ? (0, values_1.toNumberRV)(args[2]) : (0, values_1.rvNumber)(1);
167
+ // Blank `sort_order` Excel's default 1 (ascending). Without this
168
+ // guard the blank coerces through `toNumberRV` to 0, which multiplies
169
+ // the comparator output and produces a no-op sort — every pair is
170
+ // treated as equal and the output order is engine-defined noise.
171
+ const sortOrderV = args.length > 2 && args[2].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(1);
127
172
  if ((0, values_1.isError)(sortOrderV)) {
128
173
  return sortOrderV;
129
174
  }
130
- const byColV = args.length > 3 ? (0, values_1.toBooleanRV)(args[3]) : { kind: 3 /* RVKind.Boolean */, value: false };
175
+ // Excel restricts `sort_order` to exactly 1 or -1; any other integer
176
+ // (0, 2, 3, …) is #VALUE!. Previously zero silently disabled the sort.
177
+ if (sortOrderV.value !== 1 && sortOrderV.value !== -1) {
178
+ return values_1.ERRORS.VALUE;
179
+ }
180
+ const byColV = args.length > 3
181
+ ? (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[3]))
182
+ : { kind: 3 /* RVKind.Boolean */, value: false };
131
183
  if ((0, values_1.isError)(byColV)) {
132
184
  return byColV;
133
185
  }
@@ -161,11 +213,15 @@ function fnUNIQUE(args) {
161
213
  if (!dataArr) {
162
214
  return values_1.ERRORS.VALUE;
163
215
  }
164
- const byColV = args.length > 1 ? (0, values_1.toBooleanRV)(args[1]) : { kind: 3 /* RVKind.Boolean */, value: false };
216
+ const byColV = args.length > 1
217
+ ? (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[1]))
218
+ : { kind: 3 /* RVKind.Boolean */, value: false };
165
219
  if ((0, values_1.isError)(byColV)) {
166
220
  return byColV;
167
221
  }
168
- const exactlyOnceV = args.length > 2 ? (0, values_1.toBooleanRV)(args[2]) : { kind: 3 /* RVKind.Boolean */, value: false };
222
+ const exactlyOnceV = args.length > 2
223
+ ? (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[2]))
224
+ : { kind: 3 /* RVKind.Boolean */, value: false };
169
225
  if ((0, values_1.isError)(exactlyOnceV)) {
170
226
  return exactlyOnceV;
171
227
  }
@@ -266,10 +322,18 @@ function fnSORTBY(args) {
266
322
  if (!keyArr) {
267
323
  return values_1.ERRORS.VALUE;
268
324
  }
269
- const orderV = i + 1 < args.length ? (0, values_1.toNumberRV)(args[i + 1]) : (0, values_1.rvNumber)(1);
325
+ // Blank order default 1 (ascending); anything other than ±1 is
326
+ // #VALUE!. Mirrors the SORT validation — a blank used to produce
327
+ // 0 via `toNumberRV`, silently disabling the sort key.
328
+ const orderV = i + 1 < args.length && args[i + 1].kind !== 0 /* RVKind.Blank */
329
+ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[i + 1]))
330
+ : (0, values_1.rvNumber)(1);
270
331
  if ((0, values_1.isError)(orderV)) {
271
332
  return orderV;
272
333
  }
334
+ if (orderV.value !== 1 && orderV.value !== -1) {
335
+ return values_1.ERRORS.VALUE;
336
+ }
273
337
  sortKeys.push({ arr: keyArr, order: orderV.value });
274
338
  }
275
339
  data.sort((a, b) => {
@@ -286,7 +350,7 @@ function fnSORTBY(args) {
286
350
  return (0, values_1.rvArray)(data.map(d => d.row));
287
351
  }
288
352
  function fnSUBTOTAL(args) {
289
- const funcNumV = (0, values_1.toNumberRV)(args[0]);
353
+ const funcNumV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[0]));
290
354
  if ((0, values_1.isError)(funcNumV)) {
291
355
  return funcNumV;
292
356
  }
@@ -338,7 +402,7 @@ function fnSUBTOTAL(args) {
338
402
  }
339
403
  }
340
404
  function fnAGGREGATE(args) {
341
- const funcNumV = (0, values_1.toNumberRV)(args[0]);
405
+ const funcNumV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[0]));
342
406
  if ((0, values_1.isError)(funcNumV)) {
343
407
  return funcNumV;
344
408
  }
@@ -352,7 +416,7 @@ function fnAGGREGATE(args) {
352
416
  // 5 → ignore hidden rows (keep nested)
353
417
  // 6 → ignore errors (keep nested)
354
418
  // 7 → ignore hidden rows + errors (keep nested)
355
- const optV = args[1] !== undefined ? (0, values_1.toNumberRV)(args[1]) : undefined;
419
+ const optV = args[1] !== undefined ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : undefined;
356
420
  if (optV && (0, values_1.isError)(optV)) {
357
421
  return optV;
358
422
  }
@@ -417,19 +481,22 @@ function fnAGGREGATE(args) {
417
481
  }
418
482
  }
419
483
  function fnSEQUENCE(args) {
420
- const rowsV = (0, values_1.toNumberRV)(args[0]);
484
+ const rowsV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[0]));
421
485
  if ((0, values_1.isError)(rowsV)) {
422
486
  return rowsV;
423
487
  }
424
- const colsV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(1);
488
+ // Blank `cols` / `start` / `step` Excel defaults 1 / 1 / 1. Without
489
+ // the blank guards, `SEQUENCE(5, )` coerces blank → 0 → `colCount < 1`
490
+ // → #NUM! instead of Excel's single-column sequence.
491
+ const colsV = args.length > 1 && args[1].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(1);
425
492
  if ((0, values_1.isError)(colsV)) {
426
493
  return colsV;
427
494
  }
428
- const startV = args.length > 2 ? (0, values_1.toNumberRV)(args[2]) : (0, values_1.rvNumber)(1);
495
+ const startV = args.length > 2 && args[2].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(1);
429
496
  if ((0, values_1.isError)(startV)) {
430
497
  return startV;
431
498
  }
432
- const stepV = args.length > 3 ? (0, values_1.toNumberRV)(args[3]) : (0, values_1.rvNumber)(1);
499
+ const stepV = args.length > 3 && args[3].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[3])) : (0, values_1.rvNumber)(1);
433
500
  if ((0, values_1.isError)(stepV)) {
434
501
  return stepV;
435
502
  }
@@ -461,23 +528,29 @@ function fnSEQUENCE(args) {
461
528
  return (0, values_1.rvArray)(result);
462
529
  }
463
530
  function fnRANDARRAY(args) {
464
- const rowsV = args.length > 0 ? (0, values_1.toNumberRV)(args[0]) : (0, values_1.rvNumber)(1);
531
+ // Each arg has a distinct Excel default; blank must be distinguished
532
+ // from an explicit 0, which would cause rows/cols validation to
533
+ // reject the call. Blanks → engine defaults (rows=1, cols=1, min=0,
534
+ // max=1, whole=FALSE).
535
+ const rowsV = args.length > 0 && args[0].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[0])) : (0, values_1.rvNumber)(1);
465
536
  if ((0, values_1.isError)(rowsV)) {
466
537
  return rowsV;
467
538
  }
468
- const colsV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(1);
539
+ const colsV = args.length > 1 && args[1].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(1);
469
540
  if ((0, values_1.isError)(colsV)) {
470
541
  return colsV;
471
542
  }
472
- const minV = args.length > 2 ? (0, values_1.toNumberRV)(args[2]) : (0, values_1.rvNumber)(0);
543
+ const minV = args.length > 2 && args[2].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(0);
473
544
  if ((0, values_1.isError)(minV)) {
474
545
  return minV;
475
546
  }
476
- const maxV = args.length > 3 ? (0, values_1.toNumberRV)(args[3]) : (0, values_1.rvNumber)(1);
547
+ const maxV = args.length > 3 && args[3].kind !== 0 /* RVKind.Blank */ ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[3])) : (0, values_1.rvNumber)(1);
477
548
  if ((0, values_1.isError)(maxV)) {
478
549
  return maxV;
479
550
  }
480
- const wholeV = args.length > 4 ? (0, values_1.toBooleanRV)(args[4]) : { kind: 3 /* RVKind.Boolean */, value: false };
551
+ const wholeV = args.length > 4 && args[4].kind !== 0 /* RVKind.Blank */
552
+ ? (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[4]))
553
+ : { kind: 3 /* RVKind.Boolean */, value: false };
481
554
  if ((0, values_1.isError)(wholeV)) {
482
555
  return wholeV;
483
556
  }
@@ -524,11 +597,13 @@ function fnTOCOL(args) {
524
597
  return (0, values_1.rvArray)([[(0, values_1.topLeft)(args[0])]]);
525
598
  }
526
599
  const arr = args[0];
527
- const ignoreV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(0);
600
+ const ignoreV = args.length > 1 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(0);
528
601
  if ((0, values_1.isError)(ignoreV)) {
529
602
  return ignoreV;
530
603
  }
531
- const scanV = args.length > 2 ? (0, values_1.toBooleanRV)(args[2]) : { kind: 3 /* RVKind.Boolean */, value: false };
604
+ const scanV = args.length > 2
605
+ ? (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[2]))
606
+ : { kind: 3 /* RVKind.Boolean */, value: false };
532
607
  if ((0, values_1.isError)(scanV)) {
533
608
  return scanV;
534
609
  }
@@ -566,11 +641,13 @@ function fnTOROW(args) {
566
641
  return (0, values_1.rvArray)([[(0, values_1.topLeft)(args[0])]]);
567
642
  }
568
643
  const arr = args[0];
569
- const ignoreV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(0);
644
+ const ignoreV = args.length > 1 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(0);
570
645
  if ((0, values_1.isError)(ignoreV)) {
571
646
  return ignoreV;
572
647
  }
573
- const scanV = args.length > 2 ? (0, values_1.toBooleanRV)(args[2]) : { kind: 3 /* RVKind.Boolean */, value: false };
648
+ const scanV = args.length > 2
649
+ ? (0, values_1.toBooleanRV)((0, values_1.topLeft)(args[2]))
650
+ : { kind: 3 /* RVKind.Boolean */, value: false };
574
651
  if ((0, values_1.isError)(scanV)) {
575
652
  return scanV;
576
653
  }
@@ -610,11 +687,18 @@ function fnCHOOSEROWS(args) {
610
687
  }
611
688
  const result = [];
612
689
  for (let i = 1; i < args.length; i++) {
613
- const nV = (0, values_1.toNumberRV)(args[i]);
690
+ const nV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[i]));
614
691
  if ((0, values_1.isError)(nV)) {
615
692
  return nV;
616
693
  }
617
- const idx = nV.value > 0 ? nV.value - 1 : d.height + nV.value;
694
+ // Excel truncates toward zero before the bounds check; without this,
695
+ // `CHOOSEROWS(A1:A5, 2.5)` would compute `idx = 1.5` and end up
696
+ // reading `d.rows[1.5]` (= undefined), throwing on the next index.
697
+ const raw = Math.trunc(nV.value);
698
+ if (raw === 0) {
699
+ return values_1.ERRORS.VALUE;
700
+ }
701
+ const idx = raw > 0 ? raw - 1 : d.height + raw;
618
702
  if (idx < 0 || idx >= d.height) {
619
703
  return values_1.ERRORS.VALUE;
620
704
  }
@@ -633,11 +717,17 @@ function fnCHOOSECOLS(args) {
633
717
  }
634
718
  const ci = [];
635
719
  for (let i = 1; i < args.length; i++) {
636
- const nV = (0, values_1.toNumberRV)(args[i]);
720
+ const nV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[i]));
637
721
  if ((0, values_1.isError)(nV)) {
638
722
  return nV;
639
723
  }
640
- const idx = nV.value > 0 ? nV.value - 1 : d.width + nV.value;
724
+ // Truncate fractional indices before the bounds check see CHOOSEROWS
725
+ // for the rationale (fractional indices silently crash getCell).
726
+ const raw = Math.trunc(nV.value);
727
+ if (raw === 0) {
728
+ return values_1.ERRORS.VALUE;
729
+ }
730
+ const idx = raw > 0 ? raw - 1 : d.width + raw;
641
731
  if (idx < 0 || idx >= d.width) {
642
732
  return values_1.ERRORS.VALUE;
643
733
  }
@@ -727,18 +817,24 @@ function fnTAKE(args) {
727
817
  if (!d) {
728
818
  return values_1.ERRORS.VALUE;
729
819
  }
730
- const rowsV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(d.height);
820
+ const rowsV = args.length > 1 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(d.height);
731
821
  if ((0, values_1.isError)(rowsV)) {
732
822
  return rowsV;
733
823
  }
734
- const colsV = args.length > 2 ? (0, values_1.toNumberRV)(args[2]) : (0, values_1.rvNumber)(d.width);
824
+ const colsV = args.length > 2 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(d.width);
735
825
  if ((0, values_1.isError)(colsV)) {
736
826
  return colsV;
737
827
  }
738
- const rS = rowsV.value >= 0 ? 0 : Math.max(0, d.height + rowsV.value);
739
- const rE = rowsV.value >= 0 ? Math.min(rowsV.value, d.height) : d.height;
740
- const cS = colsV.value >= 0 ? 0 : Math.max(0, d.width + colsV.value);
741
- const cE = colsV.value >= 0 ? Math.min(colsV.value, d.width) : d.width;
828
+ // Truncate toward zero before using these as array indices. Without
829
+ // it, `TAKE(A1:A5, 2.7)` lands `rE = 2.7` in the slice bounds; V8
830
+ // silently walks the integer range `0..2` but a misuse of the value
831
+ // elsewhere (`d.rows[r]` with `r` fractional) would return undefined.
832
+ const rows = Math.trunc(rowsV.value);
833
+ const cols = Math.trunc(colsV.value);
834
+ const rS = rows >= 0 ? 0 : Math.max(0, d.height + rows);
835
+ const rE = rows >= 0 ? Math.min(rows, d.height) : d.height;
836
+ const cS = cols >= 0 ? 0 : Math.max(0, d.width + cols);
837
+ const cE = cols >= 0 ? Math.min(cols, d.width) : d.width;
742
838
  const result = [];
743
839
  for (let r = rS; r < rE; r++) {
744
840
  const row = [];
@@ -754,18 +850,21 @@ function fnDROP(args) {
754
850
  if (!d) {
755
851
  return values_1.ERRORS.VALUE;
756
852
  }
757
- const rowsV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(0);
853
+ const rowsV = args.length > 1 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(0);
758
854
  if ((0, values_1.isError)(rowsV)) {
759
855
  return rowsV;
760
856
  }
761
- const colsV = args.length > 2 ? (0, values_1.toNumberRV)(args[2]) : (0, values_1.rvNumber)(0);
857
+ const colsV = args.length > 2 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(0);
762
858
  if ((0, values_1.isError)(colsV)) {
763
859
  return colsV;
764
860
  }
765
- const rS = rowsV.value >= 0 ? rowsV.value : 0;
766
- const rE = rowsV.value >= 0 ? d.height : d.height + rowsV.value;
767
- const cS = colsV.value >= 0 ? colsV.value : 0;
768
- const cE = colsV.value >= 0 ? d.width : d.width + colsV.value;
861
+ // Truncate see TAKE for rationale.
862
+ const rows = Math.trunc(rowsV.value);
863
+ const cols = Math.trunc(colsV.value);
864
+ const rS = rows >= 0 ? rows : 0;
865
+ const rE = rows >= 0 ? d.height : d.height + rows;
866
+ const cS = cols >= 0 ? cols : 0;
867
+ const cE = cols >= 0 ? d.width : d.width + cols;
769
868
  const result = [];
770
869
  for (let r = rS; r < rE; r++) {
771
870
  const row = [];
@@ -789,18 +888,22 @@ function fnWRAPROWS(args) {
789
888
  flat.push((0, _shared_1.getCell)(arr, r, c));
790
889
  }
791
890
  }
792
- const wcV = (0, values_1.toNumberRV)(args[1]);
891
+ const wcV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1]));
793
892
  if ((0, values_1.isError)(wcV)) {
794
893
  return wcV;
795
894
  }
796
- if (wcV.value < 1) {
895
+ // Truncate toward zero before using as a stride — `i += 2.5` and
896
+ // `row.length < 2.5` work by accidental float coercion in V8, but the
897
+ // intent is an integer wrap width; encode it explicitly.
898
+ const wc = Math.trunc(wcV.value);
899
+ if (wc < 1) {
797
900
  return values_1.ERRORS.VALUE;
798
901
  }
799
902
  const pad = args.length > 2 ? (0, values_1.topLeft)(args[2]) : values_1.ERRORS.NA;
800
903
  const result = [];
801
- for (let i = 0; i < flat.length; i += wcV.value) {
802
- const row = flat.slice(i, i + wcV.value);
803
- while (row.length < wcV.value) {
904
+ for (let i = 0; i < flat.length; i += wc) {
905
+ const row = flat.slice(i, i + wc);
906
+ while (row.length < wc) {
804
907
  row.push(pad);
805
908
  }
806
909
  result.push(row);
@@ -818,20 +921,21 @@ function fnWRAPCOLS(args) {
818
921
  flat.push((0, _shared_1.getCell)(arr, r, c));
819
922
  }
820
923
  }
821
- const wcV = (0, values_1.toNumberRV)(args[1]);
924
+ const wcV = (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1]));
822
925
  if ((0, values_1.isError)(wcV)) {
823
926
  return wcV;
824
927
  }
825
- if (wcV.value < 1) {
928
+ const wc = Math.trunc(wcV.value);
929
+ if (wc < 1) {
826
930
  return values_1.ERRORS.VALUE;
827
931
  }
828
932
  const pad = args.length > 2 ? (0, values_1.topLeft)(args[2]) : values_1.ERRORS.NA;
829
- const numCols = Math.ceil(flat.length / wcV.value);
933
+ const numCols = Math.ceil(flat.length / wc);
830
934
  const result = [];
831
- for (let r = 0; r < wcV.value; r++) {
935
+ for (let r = 0; r < wc; r++) {
832
936
  const row = [];
833
937
  for (let c = 0; c < numCols; c++) {
834
- const idx = c * wcV.value + r;
938
+ const idx = c * wc + r;
835
939
  row.push(idx < flat.length ? flat[idx] : pad);
836
940
  }
837
941
  result.push(row);
@@ -843,11 +947,11 @@ function fnEXPAND(args) {
843
947
  if (!d) {
844
948
  return values_1.ERRORS.VALUE;
845
949
  }
846
- const rowsV = args.length > 1 ? (0, values_1.toNumberRV)(args[1]) : (0, values_1.rvNumber)(d.height);
950
+ const rowsV = args.length > 1 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[1])) : (0, values_1.rvNumber)(d.height);
847
951
  if ((0, values_1.isError)(rowsV)) {
848
952
  return rowsV;
849
953
  }
850
- const colsV = args.length > 2 ? (0, values_1.toNumberRV)(args[2]) : (0, values_1.rvNumber)(d.width);
954
+ const colsV = args.length > 2 ? (0, values_1.toNumberRV)((0, values_1.topLeft)(args[2])) : (0, values_1.rvNumber)(d.width);
851
955
  if ((0, values_1.isError)(colsV)) {
852
956
  return colsV;
853
957
  }