@odoo/o-spreadsheet 17.4.0-alpha.2 → 17.4.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.4.0-alpha.2
7
- * @date 2024-06-06T13:31:21.327Z
8
- * @hash e07794d
6
+ * @version 17.4.0-alpha.4
7
+ * @date 2024-06-12T14:00:22.046Z
8
+ * @hash cefb0e4
9
9
  */
10
10
 
11
11
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -309,7 +309,10 @@ function deepCopy(obj) {
309
309
  * Check if the object is a plain old javascript object.
310
310
  */
311
311
  function isPlainObject(obj) {
312
- return typeof obj === "object" && obj?.constructor === Object;
312
+ return (typeof obj === "object" &&
313
+ obj !== null &&
314
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
315
+ (obj?.constructor === Object || obj?.constructor === undefined));
313
316
  }
314
317
  /**
315
318
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -1823,22 +1826,28 @@ function isDateAfter(date, dateAfter) {
1823
1826
  */
1824
1827
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
1825
1828
  decimalSeparator = escapeRegExp(decimalSeparator);
1826
- return new RegExp(`(^-?\\d+(${decimalSeparator}?\\d*(e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1829
+ return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1827
1830
  });
1828
1831
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1829
1832
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1830
1833
  const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1831
- const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1832
- const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1833
- const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
1834
- const pPercentFormat = "(\\s*%)?"; // pattern that match percent symbol between zero and one time
1835
- const pNumber = "(\\s*" + pIntegerAndDecimals + "|" + pOnlyDecimals + ")" + pScientificFormat + pPercentFormat;
1836
- const pMinus = "(\\s*-)?"; // pattern that match negative symbol between zero and one time
1837
- const pCurrencyFormat = "(\\s*[\\$€])?";
1834
+ const pIntegerAndDecimals = `(?:\\d+(?:${thousandsSeparator}\\d{3,})*(?:${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1835
+ const pOnlyDecimals = `(?:${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1836
+ const pScientificFormat = "(?:e(?:\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
1837
+ const pPercentFormat = "(?:\\s*%)?"; // pattern that match percent symbol between zero and one time
1838
+ const pNumber = "(?:\\s*" +
1839
+ pIntegerAndDecimals +
1840
+ "|" +
1841
+ pOnlyDecimals +
1842
+ ")" +
1843
+ pScientificFormat +
1844
+ pPercentFormat;
1845
+ const pMinus = "(?:\\s*-)?"; // pattern that match negative symbol between zero and one time
1846
+ const pCurrencyFormat = "(?:\\s*[\\$€])?";
1838
1847
  const p1 = pMinus + pCurrencyFormat + pNumber;
1839
1848
  const p2 = pMinus + pNumber + pCurrencyFormat;
1840
1849
  const p3 = pCurrencyFormat + pMinus + pNumber;
1841
- const pNumberExp = "^((" + [p1, p2, p3].join(")|(") + "))$";
1850
+ const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
1842
1851
  const numberRegexp = new RegExp(pNumberExp, "i");
1843
1852
  return numberRegexp;
1844
1853
  });
@@ -2776,7 +2785,7 @@ function evaluatePredicate(value, criterion) {
2776
2785
  return false;
2777
2786
  }
2778
2787
  if (typeof operand === "number" && operator === "=") {
2779
- return toString(value) === toString(operand);
2788
+ return value.toString() === operand.toString();
2780
2789
  }
2781
2790
  if (operator === "<>" || operator === "=") {
2782
2791
  let result;
@@ -2836,14 +2845,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2836
2845
  if (countArg % 2 === 1) {
2837
2846
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2838
2847
  }
2839
- const dimRow = args[0].length;
2840
- const dimCol = args[0][0].length;
2848
+ const firstArg = toMatrix(args[0]);
2849
+ const dimRow = firstArg.length;
2850
+ const dimCol = firstArg[0].length;
2841
2851
  let predicates = [];
2842
2852
  for (let i = 0; i < countArg - 1; i += 2) {
2843
- const criteriaRange = args[i];
2844
- if (!isMatrix(criteriaRange) ||
2845
- criteriaRange.length !== dimRow ||
2846
- criteriaRange[0].length !== dimCol) {
2853
+ const criteriaRange = toMatrix(args[i]);
2854
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2847
2855
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2848
2856
  }
2849
2857
  const description = toString(args[i + 1]);
@@ -2857,7 +2865,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2857
2865
  for (let j = 0; j < dimCol; j++) {
2858
2866
  let validatedPredicates = true;
2859
2867
  for (let k = 0; k < countArg - 1; k += 2) {
2860
- const criteriaValue = args[k][i][j].value;
2868
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2861
2869
  const criterion = predicates[k / 2];
2862
2870
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2863
2871
  if (!validatedPredicates) {
@@ -3522,10 +3530,8 @@ function detectDateFormat(content, locale) {
3522
3530
  const internalDate = parseDateTime(content, locale);
3523
3531
  return internalDate.format;
3524
3532
  }
3533
+ /** use this function only if the content corresponds to a number (means that isNumber(content) return true */
3525
3534
  function detectNumberFormat(content) {
3526
- if (!isNumber(content, DEFAULT_LOCALE)) {
3527
- return undefined;
3528
- }
3529
3535
  const digitBase = content.includes(".") ? "0.00" : "0";
3530
3536
  const matchedCurrencies = content.match(/[\$€]/);
3531
3537
  if (matchedCurrencies) {
@@ -4728,21 +4734,16 @@ function unionPositionsToZone(positions) {
4728
4734
  * Check if two zones are contiguous, ie. that they share a border
4729
4735
  */
4730
4736
  function areZoneContiguous(zone1, zone2) {
4731
- const u = union(zone1, zone2);
4732
4737
  if (zone1.right + 1 === zone2.left || zone1.left === zone2.right + 1) {
4733
- return getZoneHeight(u) <= getZoneHeight(zone1) + getZoneHeight(zone2);
4738
+ return ((zone1.top <= zone2.bottom && zone1.top >= zone2.top) ||
4739
+ (zone2.top <= zone1.bottom && zone2.top >= zone1.top));
4734
4740
  }
4735
4741
  if (zone1.bottom + 1 === zone2.top || zone1.top === zone2.bottom + 1) {
4736
- return getZoneWidth(u) <= getZoneWidth(zone1) + getZoneWidth(zone2);
4742
+ return ((zone1.left <= zone2.right && zone1.left >= zone2.left) ||
4743
+ (zone2.left <= zone1.right && zone2.left >= zone1.left));
4737
4744
  }
4738
4745
  return false;
4739
4746
  }
4740
- function getZoneHeight(zone) {
4741
- return zone.bottom - zone.top + 1;
4742
- }
4743
- function getZoneWidth(zone) {
4744
- return zone.right - zone.left + 1;
4745
- }
4746
4747
  /**
4747
4748
  * Merge contiguous and overlapping zones that are in the array into bigger zones
4748
4749
  */
@@ -5498,7 +5499,7 @@ class Registry {
5498
5499
  }
5499
5500
  }
5500
5501
 
5501
- function getClipboardDataPositions(zones) {
5502
+ function getClipboardDataPositions(sheetId, zones) {
5502
5503
  const lefts = new Set(zones.map((z) => z.left));
5503
5504
  const rights = new Set(zones.map((z) => z.right));
5504
5505
  const tops = new Set(zones.map((z) => z.top));
@@ -5512,7 +5513,7 @@ function getClipboardDataPositions(zones) {
5512
5513
  const cellsPosition = clippedZones.map((zone) => positions(zone)).flat();
5513
5514
  const columnsIndexes = [...new Set(cellsPosition.map((p) => p.col))].sort((a, b) => a - b);
5514
5515
  const rowsIndexes = [...new Set(cellsPosition.map((p) => p.row))].sort((a, b) => a - b);
5515
- return { zones, clippedZones, columnsIndexes, rowsIndexes };
5516
+ return { sheetId, zones, clippedZones, columnsIndexes, rowsIndexes };
5516
5517
  }
5517
5518
  /**
5518
5519
  * The clipped zone is copied as many times as it fits in the target.
@@ -5562,8 +5563,8 @@ class ClipboardHandler {
5562
5563
  isCutAllowed(data) {
5563
5564
  return "Success" /* CommandResult.Success */;
5564
5565
  }
5565
- getPasteTarget(target, content, options) {
5566
- return { zones: [] };
5566
+ getPasteTarget(sheetId, target, content, options) {
5567
+ return { zones: [], sheetId };
5567
5568
  }
5568
5569
  convertOSClipboardData(data) {
5569
5570
  return;
@@ -5601,7 +5602,7 @@ class AbstractCellClipboardHandler extends ClipboardHandler {
5601
5602
 
5602
5603
  class BorderClipboardHandler extends AbstractCellClipboardHandler {
5603
5604
  copy(data) {
5604
- const sheetId = this.getters.getActiveSheetId();
5605
+ const sheetId = data.sheetId;
5605
5606
  if (data.zones.length === 0) {
5606
5607
  return;
5607
5608
  }
@@ -5621,7 +5622,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
5621
5622
  if (!content) {
5622
5623
  return;
5623
5624
  }
5624
- const sheetId = this.getters.getActiveSheetId();
5625
+ const sheetId = target.sheetId;
5625
5626
  if (options?.pasteOption === "asValue") {
5626
5627
  return;
5627
5628
  }
@@ -6151,7 +6152,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6151
6152
  if (!("zones" in data) || !data.zones.length) {
6152
6153
  return;
6153
6154
  }
6154
- const sheetId = this.getters.getActiveSheetId();
6155
+ const sheetId = data.sheetId;
6155
6156
  const zones = data.zones;
6156
6157
  if (!zones.length) {
6157
6158
  return {
@@ -6180,6 +6181,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6180
6181
  format: evaluatedCell.format,
6181
6182
  content,
6182
6183
  isFormula: false,
6184
+ parsedValue: evaluatedCell.value,
6183
6185
  };
6184
6186
  }
6185
6187
  cellsInRow.push({
@@ -6194,7 +6196,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6194
6196
  return {
6195
6197
  cells: clippedCells,
6196
6198
  zones: clippedZones,
6197
- sheetId: this.getters.getActiveSheetId(),
6199
+ sheetId: data.sheetId,
6198
6200
  };
6199
6201
  }
6200
6202
  isPasteAllowed(sheetId, target, content, clipboardOptions) {
@@ -6222,7 +6224,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6222
6224
  return;
6223
6225
  }
6224
6226
  const zones = target.zones;
6225
- const sheetId = this.getters.getActiveSheetId();
6227
+ const sheetId = target.sheetId;
6226
6228
  if (!options?.isCutOperation) {
6227
6229
  this.pasteFromCopy(sheetId, zones, content.cells, options);
6228
6230
  }
@@ -6230,11 +6232,12 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6230
6232
  this.pasteFromCut(sheetId, zones, content, options);
6231
6233
  }
6232
6234
  }
6233
- getPasteTarget(target, content, options) {
6235
+ getPasteTarget(sheetId, target, content, options) {
6234
6236
  const width = content.cells[0].length;
6235
6237
  const height = content.cells.length;
6236
6238
  if (options?.isCutOperation) {
6237
6239
  return {
6240
+ sheetId,
6238
6241
  zones: [
6239
6242
  {
6240
6243
  left: target[0].left,
@@ -6246,11 +6249,9 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6246
6249
  };
6247
6250
  }
6248
6251
  if (width === 1 && height === 1) {
6249
- return { zones: [] };
6252
+ return { zones: [], sheetId };
6250
6253
  }
6251
- return {
6252
- zones: getPasteZones(target, content.cells),
6253
- };
6254
+ return { sheetId, zones: getPasteZones(target, content.cells) };
6254
6255
  }
6255
6256
  pasteFromCut(sheetId, target, content, options) {
6256
6257
  this.clearClippedZones(content);
@@ -6373,7 +6374,7 @@ class AbstractFigureClipboardHandler extends ClipboardHandler {
6373
6374
 
6374
6375
  class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6375
6376
  copy(data) {
6376
- const sheetId = this.getters.getActiveSheetId();
6377
+ const sheetId = data.sheetId;
6377
6378
  const figure = this.getters.getFigure(sheetId, data.figureId);
6378
6379
  if (!figure) {
6379
6380
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6393,22 +6394,19 @@ class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6393
6394
  copiedChart,
6394
6395
  };
6395
6396
  }
6396
- getPasteTarget(target, content, options) {
6397
+ getPasteTarget(sheetId, target, content, options) {
6397
6398
  if (!content?.copiedFigure || !content?.copiedChart) {
6398
- return { zones: [] };
6399
+ return { zones: [], sheetId };
6399
6400
  }
6400
6401
  const newId = new UuidGenerator().uuidv4();
6401
- return {
6402
- zones: [],
6403
- figureId: newId,
6404
- };
6402
+ return { zones: [], figureId: newId, sheetId };
6405
6403
  }
6406
6404
  paste(target, clippedContent, options) {
6407
6405
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedChart || !target.figureId) {
6408
6406
  return;
6409
6407
  }
6410
6408
  const { zones, figureId } = target;
6411
- const sheetId = this.getters.getActiveSheetId();
6409
+ const sheetId = target.sheetId;
6412
6410
  const numCols = this.getters.getNumberCols(sheetId);
6413
6411
  const numRows = this.getters.getNumberRows(sheetId);
6414
6412
  const targetX = this.getters.getColDimensions(sheetId, zones[0].left).start;
@@ -6454,7 +6452,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6454
6452
  return;
6455
6453
  }
6456
6454
  const { rowsIndexes, columnsIndexes } = data;
6457
- const sheetId = this.getters.getActiveSheetId();
6455
+ const sheetId = data.sheetId;
6458
6456
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6459
6457
  return {
6460
6458
  cellPositions,
@@ -6468,7 +6466,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6468
6466
  return;
6469
6467
  }
6470
6468
  const zones = target.zones;
6471
- const sheetId = this.getters.getActiveSheetId();
6469
+ const sheetId = target.sheetId;
6472
6470
  if (!options?.isCutOperation) {
6473
6471
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6474
6472
  }
@@ -6549,7 +6547,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6549
6547
  return;
6550
6548
  }
6551
6549
  const { rowsIndexes, columnsIndexes } = data;
6552
- const sheetId = this.getters.getActiveSheetId();
6550
+ const sheetId = data.sheetId;
6553
6551
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6554
6552
  return {
6555
6553
  cellPositions,
@@ -6566,7 +6564,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6566
6564
  return;
6567
6565
  }
6568
6566
  const zones = target.zones;
6569
- const sheetId = this.getters.getActiveSheetId();
6567
+ const sheetId = target.sheetId;
6570
6568
  if (!options?.isCutOperation) {
6571
6569
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6572
6570
  }
@@ -6645,7 +6643,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6645
6643
 
6646
6644
  class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6647
6645
  copy(data) {
6648
- const sheetId = this.getters.getActiveSheetId();
6646
+ const sheetId = data.sheetId;
6649
6647
  const figure = this.getters.getFigure(sheetId, data.figureId);
6650
6648
  if (!figure) {
6651
6649
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6663,15 +6661,12 @@ class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6663
6661
  sheetId,
6664
6662
  };
6665
6663
  }
6666
- getPasteTarget(target, content, options) {
6664
+ getPasteTarget(sheetId, target, content, options) {
6667
6665
  if (!content?.copiedFigure || !content?.copiedImage) {
6668
- return { zones: [] };
6666
+ return { zones: [], sheetId };
6669
6667
  }
6670
6668
  const newId = new UuidGenerator().uuidv4();
6671
- return {
6672
- zones: [],
6673
- figureId: newId,
6674
- };
6669
+ return { sheetId, zones: [], figureId: newId };
6675
6670
  }
6676
6671
  paste(target, clippedContent, options) {
6677
6672
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedImage || !target.figureId) {
@@ -6742,8 +6737,7 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
6742
6737
  if (options?.isCutOperation || !("zones" in target) || !target.zones.length) {
6743
6738
  return;
6744
6739
  }
6745
- const sheetId = this.getters.getActiveSheetId();
6746
- this.pasteFromCopy(sheetId, target.zones, content.cells, options);
6740
+ this.pasteFromCopy(target.sheetId, target.zones, content.cells, options);
6747
6741
  }
6748
6742
  pasteZone(sheetId, col, row, cells) {
6749
6743
  for (const [r, rowCells] of cells.entries()) {
@@ -6803,7 +6797,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
6803
6797
 
6804
6798
  class TableClipboardHandler extends AbstractCellClipboardHandler {
6805
6799
  copy(data) {
6806
- const sheetId = this.getters.getActiveSheetId();
6800
+ const sheetId = data.sheetId;
6807
6801
  const { rowsIndexes, columnsIndexes, zones } = data;
6808
6802
  if (!zones || !rowsIndexes.length || !columnsIndexes.length) {
6809
6803
  return { tableCells: [[]], sheetId };
@@ -6845,7 +6839,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6845
6839
  }
6846
6840
  return {
6847
6841
  tableCells,
6848
- sheetId: this.getters.getActiveSheetId(),
6842
+ sheetId: data.sheetId,
6849
6843
  };
6850
6844
  }
6851
6845
  /**
@@ -6867,7 +6861,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6867
6861
  return;
6868
6862
  }
6869
6863
  const zones = target.zones;
6870
- const sheetId = this.getters.getActiveSheetId();
6864
+ const sheetId = target.sheetId;
6871
6865
  if (!options?.isCutOperation) {
6872
6866
  this.pasteFromCopy(sheetId, zones, content.tableCells, options);
6873
6867
  }
@@ -7629,10 +7623,8 @@ function detectLink(value) {
7629
7623
  return undefined;
7630
7624
  }
7631
7625
 
7632
- function evaluateLiteral(content = "", localeFormat) {
7633
- const value = localeFormat.format === PLAIN_TEXT_FORMAT
7634
- ? content
7635
- : parseLiteral(content, localeFormat.locale);
7626
+ function evaluateLiteral(literalCell, localeFormat) {
7627
+ const value = localeFormat.format === PLAIN_TEXT_FORMAT ? literalCell.content : literalCell.parsedValue;
7636
7628
  const fPayload = { value, format: localeFormat.format };
7637
7629
  return createEvaluatedCell(fPayload, localeFormat.locale);
7638
7630
  }
@@ -7644,10 +7636,11 @@ function parseLiteral(content, locale) {
7644
7636
  return null;
7645
7637
  }
7646
7638
  if (isNumber(content, DEFAULT_LOCALE)) {
7647
- return toNumber(content, DEFAULT_LOCALE);
7639
+ return parseNumber(content, DEFAULT_LOCALE);
7648
7640
  }
7649
- if (isDateTime(content, locale)) {
7650
- return toNumber(content, locale);
7641
+ const internalDate = parseDateTime(content, locale);
7642
+ if (internalDate) {
7643
+ return internalDate.value;
7651
7644
  }
7652
7645
  if (isBoolean(content)) {
7653
7646
  return content.toUpperCase() === "TRUE" ? true : false;
@@ -7659,9 +7652,14 @@ function createEvaluatedCell(fPayload, locale = DEFAULT_LOCALE, cell) {
7659
7652
  if (!link) {
7660
7653
  return _createEvaluatedCell(fPayload, locale, cell);
7661
7654
  }
7655
+ const value = parseLiteral(link.label, locale);
7656
+ const format = fPayload.format ||
7657
+ (typeof value === "number"
7658
+ ? detectDateFormat(link.label, locale) || detectNumberFormat(link.label)
7659
+ : undefined);
7662
7660
  const linkPayload = {
7663
- value: parseLiteral(link.label, locale),
7664
- format: fPayload.format || detectDateFormat(link.label, locale) || detectNumberFormat(link.label),
7661
+ value,
7662
+ format,
7665
7663
  };
7666
7664
  return {
7667
7665
  ..._createEvaluatedCell(linkPayload, locale, cell),
@@ -10985,6 +10983,9 @@ function makeArg(str, description) {
10985
10983
  if (types.some((t) => t.startsWith("RANGE"))) {
10986
10984
  result.acceptMatrix = true;
10987
10985
  }
10986
+ if (types.every((t) => t.startsWith("RANGE"))) {
10987
+ result.acceptMatrixOnly = true;
10988
+ }
10988
10989
  return result;
10989
10990
  }
10990
10991
  /**
@@ -11239,7 +11240,6 @@ const ARRAY_CONSTRAIN = {
11239
11240
  arg("rows (number)", _t("The number of rows in the constrained array.")),
11240
11241
  arg("columns (number)", _t("The number of columns in the constrained array.")),
11241
11242
  ],
11242
- returns: ["RANGE<ANY>"],
11243
11243
  compute: function (array, rows, columns) {
11244
11244
  const _array = toMatrix(array);
11245
11245
  const _rowsArg = toInteger(rows?.value, this.locale);
@@ -11262,15 +11262,19 @@ const CHOOSECOLS = {
11262
11262
  arg("col_num (number, range<number>)", _t("The first column index of the columns to be returned.")),
11263
11263
  arg("col_num2 (number, range<number>, repeating)", _t("The columns indexes of the columns to be returned.")),
11264
11264
  ],
11265
- returns: ["RANGE<ANY>"],
11266
11265
  compute: function (array, ...columns) {
11267
11266
  const _array = toMatrix(array);
11268
11267
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11269
- assert(() => _columns.every((col) => col > 0 && col <= _array.length), _t("The columns arguments must be between 1 and %s (got %s).", _array.length.toString(), (_columns.find((col) => col <= 0 || col > _array.length) || 0).toString()));
11268
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11269
+ assert(() => argOutOfRange.length === 0, _t("The columns arguments must be between -%s and %s (got %s), excluding 0.", _array.length.toString(), _array.length.toString(), argOutOfRange.join(",")));
11270
11270
  const result = Array(_columns.length);
11271
11271
  for (let col = 0; col < _columns.length; col++) {
11272
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11273
- result[col] = _array[colIndex];
11272
+ if (_columns[col] > 0) {
11273
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11274
+ }
11275
+ else {
11276
+ result[col] = _array[_array.length + _columns[col]];
11277
+ }
11274
11278
  }
11275
11279
  return result;
11276
11280
  },
@@ -11286,13 +11290,18 @@ const CHOOSEROWS = {
11286
11290
  arg("row_num (number, range<number>)", _t("The first row index of the rows to be returned.")),
11287
11291
  arg("row_num2 (number, range<number>, repeating)", _t("The rows indexes of the rows to be returned.")),
11288
11292
  ],
11289
- returns: ["RANGE<ANY>"],
11290
11293
  compute: function (array, ...rows) {
11291
11294
  const _array = toMatrix(array);
11292
11295
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11293
11296
  const _nbColumns = _array.length;
11294
- assert(() => _rows.every((row) => row > 0 && row <= _array[0].length), _t("The rows arguments must be between 1 and %s (got %s).", _array[0].length.toString(), (_rows.find((row) => row <= 0 || row > _array[0].length) || 0).toString()));
11295
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11297
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11298
+ assert(() => argOutOfRange.length === 0, _t("The rows arguments must be between -%s and %s (got %s), excluding 0.", _array[0].length.toString(), _array[0].length.toString(), argOutOfRange.join(",")));
11299
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11300
+ if (_rows[row] > 0) {
11301
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11302
+ }
11303
+ return _array[col][_array[col].length + _rows[row]];
11304
+ });
11296
11305
  },
11297
11306
  isExported: true,
11298
11307
  };
@@ -11307,7 +11316,6 @@ const EXPAND = {
11307
11316
  arg("columns (number, optional)", _t("The number of columns in the expanded array. If missing, columns will not be expanded.")),
11308
11317
  arg("pad_with (any, default=0)", _t("The value with which to pad.")), // @compatibility: on Excel, pad with #N/A
11309
11318
  ],
11310
- returns: ["RANGE<ANY>"],
11311
11319
  compute: function (arg, rows, columns, padWith = { value: 0 } // TODO : Replace with #N/A errors once it's supported
11312
11320
  ) {
11313
11321
  const _array = toMatrix(arg);
@@ -11328,7 +11336,6 @@ const FLATTEN = {
11328
11336
  arg("range (any, range<any>)", _t("The first range to flatten.")),
11329
11337
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to flatten.")),
11330
11338
  ],
11331
- returns: ["RANGE<ANY>"],
11332
11339
  compute: function (...ranges) {
11333
11340
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
11334
11341
  },
@@ -11343,7 +11350,6 @@ const FREQUENCY = {
11343
11350
  arg("data (range<number>)", _t("The array of ranges containing the values to be counted.")),
11344
11351
  arg("classes (number, range<number>)", _t("The range containing the set of classes.")),
11345
11352
  ],
11346
- returns: ["RANGE<NUMBER>"],
11347
11353
  compute: function (data, classes) {
11348
11354
  const _data = flattenRowFirst([data], (data) => data.value).filter((val) => typeof val === "number");
11349
11355
  const _classes = flattenRowFirst([classes], (data) => data.value).filter((val) => typeof val === "number");
@@ -11391,7 +11397,6 @@ const HSTACK = {
11391
11397
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11392
11398
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11393
11399
  ],
11394
- returns: ["RANGE<ANY>"],
11395
11400
  compute: function (...ranges) {
11396
11401
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
11397
11402
  const result = [];
@@ -11418,7 +11423,6 @@ const MDETERM = {
11418
11423
  args: [
11419
11424
  arg("square_matrix (number, range<number>)", _t("An range with an equal number of rows and columns representing a matrix whose determinant will be calculated.")),
11420
11425
  ],
11421
- returns: ["NUMBER"],
11422
11426
  compute: function (matrix) {
11423
11427
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11424
11428
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11434,7 +11438,6 @@ const MINVERSE = {
11434
11438
  args: [
11435
11439
  arg("square_matrix (number, range<number>)", _t("An range with an equal number of rows and columns representing a matrix whose multiplicative inverse will be calculated.")),
11436
11440
  ],
11437
- returns: ["RANGE<NUMBER>"],
11438
11441
  compute: function (matrix) {
11439
11442
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11440
11443
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11455,7 +11458,6 @@ const MMULT = {
11455
11458
  arg("matrix1 (number, range<number>)", _t("The first matrix in the matrix multiplication operation.")),
11456
11459
  arg("matrix2 (number, range<number>)", _t("The second matrix in the matrix multiplication operation.")),
11457
11460
  ],
11458
- returns: ["RANGE<NUMBER>"],
11459
11461
  compute: function (matrix1, matrix2) {
11460
11462
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11461
11463
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
@@ -11474,7 +11476,6 @@ const SUMPRODUCT = {
11474
11476
  arg("range1 (number, range<number>)", _t("The first range whose entries will be multiplied with corresponding entries in the other ranges.")),
11475
11477
  arg("range2 (number, range<number>, repeating)", _t("The other range whose entries will be multiplied with corresponding entries in the other ranges.")),
11476
11478
  ],
11477
- returns: ["NUMBER"],
11478
11479
  compute: function (...args) {
11479
11480
  assertSameDimensions(_t("All the ranges must have the same dimensions."), ...args);
11480
11481
  const _args = args.map(toMatrix);
@@ -11531,7 +11532,6 @@ const SUMX2MY2 = {
11531
11532
  arg("array_x (number, range<number>)", _t("The array or range of values whose squares will be reduced by the squares of corresponding entries in array_y and added together.")),
11532
11533
  arg("array_y (number, range<number>)", _t("The array or range of values whose squares will be subtracted from the squares of corresponding entries in array_x and added together.")),
11533
11534
  ],
11534
- returns: ["NUMBER"],
11535
11535
  compute: function (arrayX, arrayY) {
11536
11536
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 - y ** 2);
11537
11537
  },
@@ -11546,7 +11546,6 @@ const SUMX2PY2 = {
11546
11546
  arg("array_x (number, range<number>)", _t("The array or range of values whose squares will be added to the squares of corresponding entries in array_y and added together.")),
11547
11547
  arg("array_y (number, range<number>)", _t("The array or range of values whose squares will be added to the squares of corresponding entries in array_x and added together.")),
11548
11548
  ],
11549
- returns: ["NUMBER"],
11550
11549
  compute: function (arrayX, arrayY) {
11551
11550
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 + y ** 2);
11552
11551
  },
@@ -11561,7 +11560,6 @@ const SUMXMY2 = {
11561
11560
  arg("array_x (number, range<number>)", _t("The array or range of values that will be reduced by corresponding entries in array_y, squared, and added together.")),
11562
11561
  arg("array_y (number, range<number>)", _t("The array or range of values that will be subtracted from corresponding entries in array_x, the result squared, and all such results added together.")),
11563
11562
  ],
11564
- returns: ["NUMBER"],
11565
11563
  compute: function (arrayX, arrayY) {
11566
11564
  return getSumXAndY(arrayX, arrayY, (x, y) => (x - y) ** 2);
11567
11565
  },
@@ -11597,7 +11595,6 @@ function shouldKeepValue(ignore) {
11597
11595
  const TOCOL = {
11598
11596
  description: _t("Transforms a range of cells into a single column."),
11599
11597
  args: TO_COL_ROW_ARGS,
11600
- returns: ["RANGE<ANY>"],
11601
11598
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11602
11599
  const _array = toMatrix(array);
11603
11600
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11618,7 +11615,6 @@ const TOCOL = {
11618
11615
  const TOROW = {
11619
11616
  description: _t("Transforms a range of cells into a single row."),
11620
11617
  args: TO_COL_ROW_ARGS,
11621
- returns: ["RANGE<ANY>"],
11622
11618
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11623
11619
  const _array = toMatrix(array);
11624
11620
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11640,7 +11636,6 @@ const TOROW = {
11640
11636
  const TRANSPOSE = {
11641
11637
  description: _t("Transposes the rows and columns of a range."),
11642
11638
  args: [arg("range (any, range<any>)", _t("The range to be transposed."))],
11643
- returns: ["RANGE"],
11644
11639
  compute: function (arg) {
11645
11640
  const _array = toMatrix(arg);
11646
11641
  const nbColumns = _array[0].length;
@@ -11658,7 +11653,6 @@ const VSTACK = {
11658
11653
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11659
11654
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11660
11655
  ],
11661
- returns: ["RANGE<ANY>"],
11662
11656
  compute: function (...ranges) {
11663
11657
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
11664
11658
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -11690,7 +11684,6 @@ const WRAPCOLS = {
11690
11684
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11691
11685
  _t("The value with which to fill the extra cells in the range.")),
11692
11686
  ],
11693
- returns: ["RANGE<ANY>"],
11694
11687
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11695
11688
  const _array = toMatrix(range);
11696
11689
  const nbRows = toInteger(wrapCount?.value, this.locale);
@@ -11715,7 +11708,6 @@ const WRAPROWS = {
11715
11708
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11716
11709
  _t("The value with which to fill the extra cells in the range.")),
11717
11710
  ],
11718
- returns: ["RANGE<ANY>"],
11719
11711
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11720
11712
  const _array = toMatrix(range);
11721
11713
  const nbColumns = toInteger(wrapCount?.value, this.locale);
@@ -11763,7 +11755,6 @@ const FORMAT_LARGE_NUMBER = {
11763
11755
  arg("value (number)", _t("The number.")),
11764
11756
  arg("unit (string, optional)", _t("The formatting unit. Use 'k', 'm', or 'b' to force the unit")),
11765
11757
  ],
11766
- returns: ["NUMBER"],
11767
11758
  compute: function (value, unite) {
11768
11759
  return {
11769
11760
  value: toNumber(value, this.locale),
@@ -11795,7 +11786,6 @@ const DECIMAL_REPRESENTATION = /^-?[a-z0-9]+$/i;
11795
11786
  const ABS = {
11796
11787
  description: _t("Absolute value of a number."),
11797
11788
  args: [arg("value (number)", _t("The number of which to return the absolute value."))],
11798
- returns: ["NUMBER"],
11799
11789
  compute: function (value) {
11800
11790
  return Math.abs(toNumber(value, this.locale));
11801
11791
  },
@@ -11809,7 +11799,6 @@ const ACOS = {
11809
11799
  args: [
11810
11800
  arg("value (number)", _t("The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.")),
11811
11801
  ],
11812
- returns: ["NUMBER"],
11813
11802
  compute: function (value) {
11814
11803
  const _value = toNumber(value, this.locale);
11815
11804
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11825,7 +11814,6 @@ const ACOSH = {
11825
11814
  args: [
11826
11815
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1.")),
11827
11816
  ],
11828
- returns: ["NUMBER"],
11829
11817
  compute: function (value) {
11830
11818
  const _value = toNumber(value, this.locale);
11831
11819
  assert(() => _value >= 1, _t("The value (%s) must be greater than or equal to 1.", _value.toString()));
@@ -11839,7 +11827,6 @@ const ACOSH = {
11839
11827
  const ACOT = {
11840
11828
  description: _t("Inverse cotangent of a value."),
11841
11829
  args: [arg("value (number)", _t("The value for which to calculate the inverse cotangent."))],
11842
- returns: ["NUMBER"],
11843
11830
  compute: function (value) {
11844
11831
  const _value = toNumber(value, this.locale);
11845
11832
  const sign = Math.sign(_value) || 1;
@@ -11858,7 +11845,6 @@ const ACOTH = {
11858
11845
  args: [
11859
11846
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cotangent. Must not be between -1 and 1, inclusive.")),
11860
11847
  ],
11861
- returns: ["NUMBER"],
11862
11848
  compute: function (value) {
11863
11849
  const _value = toNumber(value, this.locale);
11864
11850
  assert(() => Math.abs(_value) > 1, _t("The value (%s) cannot be between -1 and 1 inclusive.", _value.toString()));
@@ -11874,7 +11860,6 @@ const ASIN = {
11874
11860
  args: [
11875
11861
  arg("value (number)", _t("The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive.")),
11876
11862
  ],
11877
- returns: ["NUMBER"],
11878
11863
  compute: function (value) {
11879
11864
  const _value = toNumber(value, this.locale);
11880
11865
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11890,7 +11875,6 @@ const ASINH = {
11890
11875
  args: [
11891
11876
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic sine.")),
11892
11877
  ],
11893
- returns: ["NUMBER"],
11894
11878
  compute: function (value) {
11895
11879
  return Math.asinh(toNumber(value, this.locale));
11896
11880
  },
@@ -11902,7 +11886,6 @@ const ASINH = {
11902
11886
  const ATAN = {
11903
11887
  description: _t("Inverse tangent of a value, in radians."),
11904
11888
  args: [arg("value (number)", _t("The value for which to calculate the inverse tangent."))],
11905
- returns: ["NUMBER"],
11906
11889
  compute: function (value) {
11907
11890
  return Math.atan(toNumber(value, this.locale));
11908
11891
  },
@@ -11917,7 +11900,6 @@ const ATAN2 = {
11917
11900
  arg("x (number)", _t("The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11918
11901
  arg("y (number)", _t("The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11919
11902
  ],
11920
- returns: ["NUMBER"],
11921
11903
  compute: function (x, y) {
11922
11904
  const _x = toNumber(x, this.locale);
11923
11905
  const _y = toNumber(y, this.locale);
@@ -11934,7 +11916,6 @@ const ATANH = {
11934
11916
  args: [
11935
11917
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive.")),
11936
11918
  ],
11937
- returns: ["NUMBER"],
11938
11919
  compute: function (value) {
11939
11920
  const _value = toNumber(value, this.locale);
11940
11921
  assert(() => Math.abs(_value) < 1, _t("The value (%s) must be between -1 and 1 exclusive.", _value.toString()));
@@ -11951,7 +11932,6 @@ const CEILING = {
11951
11932
  arg("value (number)", _t("The value to round up to the nearest integer multiple of factor.")),
11952
11933
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
11953
11934
  ],
11954
- returns: ["NUMBER"],
11955
11935
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
11956
11936
  const _value = toNumber(value, this.locale);
11957
11937
  const _factor = toNumber(factor, this.locale);
@@ -11986,7 +11966,6 @@ const CEILING_MATH = {
11986
11966
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
11987
11967
  arg(`mode (number, default=${DEFAULT_MODE})`, _t("If number is negative, specifies the rounding direction. If 0 or blank, it is rounded towards zero. Otherwise, it is rounded away from zero.")),
11988
11968
  ],
11989
- returns: ["NUMBER"],
11990
11969
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
11991
11970
  const _significance = toNumber(significance, this.locale);
11992
11971
  const _number = toNumber(number, this.locale);
@@ -12007,7 +11986,6 @@ const CEILING_PRECISE = {
12007
11986
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12008
11987
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12009
11988
  ],
12010
- returns: ["NUMBER"],
12011
11989
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12012
11990
  const _significance = toNumber(significance, this.locale);
12013
11991
  const _number = toNumber(number, this.locale);
@@ -12024,7 +12002,6 @@ const CEILING_PRECISE = {
12024
12002
  const COS = {
12025
12003
  description: _t("Cosine of an angle provided in radians."),
12026
12004
  args: [arg("angle (number)", _t("The angle to find the cosine of, in radians."))],
12027
- returns: ["NUMBER"],
12028
12005
  compute: function (angle) {
12029
12006
  return Math.cos(toNumber(angle, this.locale));
12030
12007
  },
@@ -12036,7 +12013,6 @@ const COS = {
12036
12013
  const COSH = {
12037
12014
  description: _t("Hyperbolic cosine of any real number."),
12038
12015
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosine of."))],
12039
- returns: ["NUMBER"],
12040
12016
  compute: function (value) {
12041
12017
  return Math.cosh(toNumber(value, this.locale));
12042
12018
  },
@@ -12048,7 +12024,6 @@ const COSH = {
12048
12024
  const COT = {
12049
12025
  description: _t("Cotangent of an angle provided in radians."),
12050
12026
  args: [arg("angle (number)", _t("The angle to find the cotangent of, in radians."))],
12051
- returns: ["NUMBER"],
12052
12027
  compute: function (angle) {
12053
12028
  const _angle = toNumber(angle, this.locale);
12054
12029
  assertNotZero(_angle);
@@ -12062,7 +12037,6 @@ const COT = {
12062
12037
  const COTH = {
12063
12038
  description: _t("Hyperbolic cotangent of any real number."),
12064
12039
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cotangent of."))],
12065
- returns: ["NUMBER"],
12066
12040
  compute: function (value) {
12067
12041
  const _value = toNumber(value, this.locale);
12068
12042
  assertNotZero(_value);
@@ -12079,7 +12053,6 @@ const COUNTBLANK = {
12079
12053
  arg("value1 (any, range)", _t("The first value or range in which to count the number of blanks.")),
12080
12054
  arg("value2 (any, range, repeating)", _t("Additional values or ranges in which to count the number of blanks.")),
12081
12055
  ],
12082
- returns: ["NUMBER"],
12083
12056
  compute: function (...args) {
12084
12057
  return reduceAny(args, (acc, a) => {
12085
12058
  if (a === undefined) {
@@ -12105,7 +12078,6 @@ const COUNTIF = {
12105
12078
  arg("range (range)", _t("The range that is tested against criterion.")),
12106
12079
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12107
12080
  ],
12108
- returns: ["NUMBER"],
12109
12081
  compute: function (...args) {
12110
12082
  let count = 0;
12111
12083
  visitMatchingRanges(args, (i, j) => {
@@ -12126,7 +12098,6 @@ const COUNTIFS = {
12126
12098
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
12127
12099
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12128
12100
  ],
12129
- returns: ["NUMBER"],
12130
12101
  compute: function (...args) {
12131
12102
  let count = 0;
12132
12103
  visitMatchingRanges(args, (i, j) => {
@@ -12145,7 +12116,6 @@ const COUNTUNIQUE = {
12145
12116
  arg("value1 (any, range)", _t("The first value or range to consider for uniqueness.")),
12146
12117
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider for uniqueness.")),
12147
12118
  ],
12148
- returns: ["NUMBER"],
12149
12119
  compute: function (...args) {
12150
12120
  return countUnique(args);
12151
12121
  },
@@ -12162,7 +12132,6 @@ const COUNTUNIQUEIFS = {
12162
12132
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
12163
12133
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
12164
12134
  ],
12165
- returns: ["NUMBER"],
12166
12135
  compute: function (range, ...args) {
12167
12136
  let uniqueValues = new Set();
12168
12137
  visitMatchingRanges(args, (i, j) => {
@@ -12180,7 +12149,6 @@ const COUNTUNIQUEIFS = {
12180
12149
  const CSC = {
12181
12150
  description: _t("Cosecant of an angle provided in radians."),
12182
12151
  args: [arg("angle (number)", _t("The angle to find the cosecant of, in radians."))],
12183
- returns: ["NUMBER"],
12184
12152
  compute: function (angle) {
12185
12153
  const _angle = toNumber(angle, this.locale);
12186
12154
  assertNotZero(_angle);
@@ -12194,7 +12162,6 @@ const CSC = {
12194
12162
  const CSCH = {
12195
12163
  description: _t("Hyperbolic cosecant of any real number."),
12196
12164
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosecant of."))],
12197
- returns: ["NUMBER"],
12198
12165
  compute: function (value) {
12199
12166
  const _value = toNumber(value, this.locale);
12200
12167
  assertNotZero(_value);
@@ -12211,7 +12178,6 @@ const DECIMAL = {
12211
12178
  arg("value (string)", _t("The number to convert.")),
12212
12179
  arg("base (number)", _t("The base to convert the value from.")),
12213
12180
  ],
12214
- returns: ["NUMBER"],
12215
12181
  compute: function (value, base) {
12216
12182
  let _base = toNumber(base, this.locale);
12217
12183
  _base = Math.floor(_base);
@@ -12238,7 +12204,6 @@ const DECIMAL = {
12238
12204
  const DEGREES = {
12239
12205
  description: _t("Converts an angle value in radians to degrees."),
12240
12206
  args: [arg("angle (number)", _t("The angle to convert from radians to degrees."))],
12241
- returns: ["NUMBER"],
12242
12207
  compute: function (angle) {
12243
12208
  return (toNumber(angle, this.locale) * 180) / Math.PI;
12244
12209
  },
@@ -12250,7 +12215,6 @@ const DEGREES = {
12250
12215
  const EXP = {
12251
12216
  description: _t("Euler's number, e (~2.718) raised to a power."),
12252
12217
  args: [arg("value (number)", _t("The exponent to raise e."))],
12253
- returns: ["NUMBER"],
12254
12218
  compute: function (value) {
12255
12219
  return Math.exp(toNumber(value, this.locale));
12256
12220
  },
@@ -12265,7 +12229,6 @@ const FLOOR = {
12265
12229
  arg("value (number)", _t("The value to round down to the nearest integer multiple of factor.")),
12266
12230
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
12267
12231
  ],
12268
- returns: ["NUMBER"],
12269
12232
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
12270
12233
  const _value = toNumber(value, this.locale);
12271
12234
  const _factor = toNumber(factor, this.locale);
@@ -12300,7 +12263,6 @@ const FLOOR_MATH = {
12300
12263
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
12301
12264
  arg(`mode (number, default=${DEFAULT_MODE})`, _t("If number is negative, specifies the rounding direction. If 0 or blank, it is rounded away from zero. Otherwise, it is rounded towards zero.")),
12302
12265
  ],
12303
- returns: ["NUMBER"],
12304
12266
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
12305
12267
  const _significance = toNumber(significance, this.locale);
12306
12268
  const _number = toNumber(number, this.locale);
@@ -12321,7 +12283,6 @@ const FLOOR_PRECISE = {
12321
12283
  arg("number (number)", _t("The value to round down to the nearest integer multiple of significance.")),
12322
12284
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12323
12285
  ],
12324
- returns: ["NUMBER"],
12325
12286
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12326
12287
  const _significance = toNumber(significance, this.locale);
12327
12288
  const _number = toNumber(number, this.locale);
@@ -12338,7 +12299,6 @@ const FLOOR_PRECISE = {
12338
12299
  const ISEVEN = {
12339
12300
  description: _t("Whether the provided value is even."),
12340
12301
  args: [arg("value (number)", _t("The value to be verified as even."))],
12341
- returns: ["BOOLEAN"],
12342
12302
  compute: function (value) {
12343
12303
  const _value = strictToNumber(value, this.locale);
12344
12304
  return Math.floor(Math.abs(_value)) & 1 ? false : true;
@@ -12354,7 +12314,6 @@ const ISO_CEILING = {
12354
12314
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12355
12315
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12356
12316
  ],
12357
- returns: ["NUMBER"],
12358
12317
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12359
12318
  const _number = toNumber(number, this.locale);
12360
12319
  const _significance = toNumber(significance, this.locale);
@@ -12371,7 +12330,6 @@ const ISO_CEILING = {
12371
12330
  const ISODD = {
12372
12331
  description: _t("Whether the provided value is even."),
12373
12332
  args: [arg("value (number)", _t("The value to be verified as even."))],
12374
- returns: ["BOOLEAN"],
12375
12333
  compute: function (value) {
12376
12334
  const _value = strictToNumber(value, this.locale);
12377
12335
  return Math.floor(Math.abs(_value)) & 1 ? true : false;
@@ -12384,7 +12342,6 @@ const ISODD = {
12384
12342
  const LN = {
12385
12343
  description: _t("The logarithm of a number, base e (euler's number)."),
12386
12344
  args: [arg("value (number)", _t("The value for which to calculate the logarithm, base e."))],
12387
- returns: ["NUMBER"],
12388
12345
  compute: function (value) {
12389
12346
  const _value = toNumber(value, this.locale);
12390
12347
  assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
@@ -12410,7 +12367,6 @@ const MOD = {
12410
12367
  arg("dividend (number)", _t("The number to be divided to find the remainder.")),
12411
12368
  arg("divisor (number)", _t("The number to divide by.")),
12412
12369
  ],
12413
- returns: ["NUMBER"],
12414
12370
  compute: function (dividend, divisor) {
12415
12371
  const _divisor = toNumber(divisor, this.locale);
12416
12372
  const _dividend = toNumber(dividend, this.locale);
@@ -12429,7 +12385,6 @@ const MUNIT = {
12429
12385
  args: [
12430
12386
  arg("dimension (number)", _t("An integer specifying the dimension size of the unit matrix. It must be positive.")),
12431
12387
  ],
12432
- returns: ["RANGE<NUMBER>"],
12433
12388
  compute: function (n) {
12434
12389
  const _n = toInteger(n, this.locale);
12435
12390
  assertPositive(_t("The argument dimension must be positive"), _n);
@@ -12443,7 +12398,6 @@ const MUNIT = {
12443
12398
  const ODD = {
12444
12399
  description: _t("Rounds a number up to the nearest odd integer."),
12445
12400
  args: [arg("value (number)", _t("The value to round to the next greatest odd number."))],
12446
- returns: ["NUMBER"],
12447
12401
  compute: function (value) {
12448
12402
  const _value = toNumber(value, this.locale);
12449
12403
  let temp = Math.ceil(Math.abs(_value));
@@ -12461,7 +12415,6 @@ const ODD = {
12461
12415
  const PI = {
12462
12416
  description: _t("The number pi."),
12463
12417
  args: [],
12464
- returns: ["NUMBER"],
12465
12418
  compute: function () {
12466
12419
  return Math.PI;
12467
12420
  },
@@ -12476,7 +12429,6 @@ const POWER = {
12476
12429
  arg("base (number)", _t("The number to raise to the exponent power.")),
12477
12430
  arg("exponent (number)", _t("The exponent to raise base to.")),
12478
12431
  ],
12479
- returns: ["NUMBER"],
12480
12432
  compute: function (base, exponent) {
12481
12433
  const _base = toNumber(base, this.locale);
12482
12434
  const _exponent = toNumber(exponent, this.locale);
@@ -12494,7 +12446,6 @@ const PRODUCT = {
12494
12446
  arg("factor1 (number, range<number>)", _t("The first number or range to calculate for the product.")),
12495
12447
  arg("factor2 (number, range<number>, repeating)", _t("More numbers or ranges to calculate for the product.")),
12496
12448
  ],
12497
- returns: ["NUMBER"],
12498
12449
  compute: function (...factors) {
12499
12450
  let count = 0;
12500
12451
  let acc = 1;
@@ -12531,7 +12482,6 @@ const PRODUCT = {
12531
12482
  const RAND = {
12532
12483
  description: _t("A random number between 0 inclusive and 1 exclusive."),
12533
12484
  args: [],
12534
- returns: ["NUMBER"],
12535
12485
  compute: function () {
12536
12486
  return Math.random();
12537
12487
  },
@@ -12549,7 +12499,6 @@ const RANDARRAY = {
12549
12499
  arg("max (number, default=1)", _t("The maximum number you would like returned.")),
12550
12500
  arg("whole_number (number, default=FALSE)", _t("Return a whole number or a decimal value.")),
12551
12501
  ],
12552
- returns: ["RANGE<NUMBER>"],
12553
12502
  compute: function (rows = { value: 1 }, columns = { value: 1 }, min = { value: 0 }, max = { value: 1 }, wholeNumber = { value: false }) {
12554
12503
  const _cols = toInteger(columns, this.locale);
12555
12504
  const _rows = toInteger(rows, this.locale);
@@ -12587,7 +12536,6 @@ const RANDBETWEEN = {
12587
12536
  arg("low (number)", _t("The low end of the random range.")),
12588
12537
  arg("high (number)", _t("The high end of the random range.")),
12589
12538
  ],
12590
- returns: ["NUMBER"],
12591
12539
  compute: function (low, high) {
12592
12540
  let _low = toNumber(low, this.locale);
12593
12541
  if (!Number.isInteger(_low)) {
@@ -12614,7 +12562,6 @@ const ROUND = {
12614
12562
  arg("value (number)", _t("The value to round to places number of places.")),
12615
12563
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12616
12564
  ],
12617
- returns: ["NUMBER"],
12618
12565
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12619
12566
  const _value = toNumber(value, this.locale);
12620
12567
  let _places = toNumber(places, this.locale);
@@ -12645,7 +12592,6 @@ const ROUNDDOWN = {
12645
12592
  arg("value (number)", _t("The value to round to places number of places, always rounding down.")),
12646
12593
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12647
12594
  ],
12648
- returns: ["NUMBER"],
12649
12595
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12650
12596
  const _value = toNumber(value, this.locale);
12651
12597
  let _places = toNumber(places, this.locale);
@@ -12676,7 +12622,6 @@ const ROUNDUP = {
12676
12622
  arg("value (number)", _t("The value to round to places number of places, always rounding up.")),
12677
12623
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12678
12624
  ],
12679
- returns: ["NUMBER"],
12680
12625
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12681
12626
  const _value = toNumber(value, this.locale);
12682
12627
  let _places = toNumber(places, this.locale);
@@ -12704,7 +12649,6 @@ const ROUNDUP = {
12704
12649
  const SEC = {
12705
12650
  description: _t("Secant of an angle provided in radians."),
12706
12651
  args: [arg("angle (number)", _t("The angle to find the secant of, in radians."))],
12707
- returns: ["NUMBER"],
12708
12652
  compute: function (angle) {
12709
12653
  return 1 / Math.cos(toNumber(angle, this.locale));
12710
12654
  },
@@ -12716,7 +12660,6 @@ const SEC = {
12716
12660
  const SECH = {
12717
12661
  description: _t("Hyperbolic secant of any real number."),
12718
12662
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic secant of."))],
12719
- returns: ["NUMBER"],
12720
12663
  compute: function (value) {
12721
12664
  return 1 / Math.cosh(toNumber(value, this.locale));
12722
12665
  },
@@ -12728,7 +12671,6 @@ const SECH = {
12728
12671
  const SIN = {
12729
12672
  description: _t("Sine of an angle provided in radians."),
12730
12673
  args: [arg("angle (number)", _t("The angle to find the sine of, in radians."))],
12731
- returns: ["NUMBER"],
12732
12674
  compute: function (angle) {
12733
12675
  return Math.sin(toNumber(angle, this.locale));
12734
12676
  },
@@ -12740,7 +12682,6 @@ const SIN = {
12740
12682
  const SINH = {
12741
12683
  description: _t("Hyperbolic sine of any real number."),
12742
12684
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic sine of."))],
12743
- returns: ["NUMBER"],
12744
12685
  compute: function (value) {
12745
12686
  return Math.sinh(toNumber(value, this.locale));
12746
12687
  },
@@ -12752,7 +12693,6 @@ const SINH = {
12752
12693
  const SQRT = {
12753
12694
  description: _t("Positive square root of a positive number."),
12754
12695
  args: [arg("value (number)", _t("The number for which to calculate the positive square root."))],
12755
- returns: ["NUMBER"],
12756
12696
  compute: function (value) {
12757
12697
  const _value = toNumber(value, this.locale);
12758
12698
  assert(() => _value >= 0, _t("The value (%s) must be positive or null.", _value.toString()));
@@ -12769,7 +12709,6 @@ const SUM = {
12769
12709
  arg("value1 (number, range<number>)", _t("The first number or range to add together.")),
12770
12710
  arg("value2 (number, range<number>, repeating)", _t("Additional numbers or ranges to add to value1.")),
12771
12711
  ],
12772
- returns: ["NUMBER"],
12773
12712
  compute: function (...values) {
12774
12713
  const v1 = values[0];
12775
12714
  return {
@@ -12789,7 +12728,6 @@ const SUMIF = {
12789
12728
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12790
12729
  arg("sum_range (range, default=criteria_range)", _t("The range to be summed, if different from range.")),
12791
12730
  ],
12792
- returns: ["NUMBER"],
12793
12731
  compute: function (criteriaRange, criterion, sumRange) {
12794
12732
  if (sumRange === undefined) {
12795
12733
  sumRange = criteriaRange;
@@ -12817,7 +12755,6 @@ const SUMIFS = {
12817
12755
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges to check.")),
12818
12756
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12819
12757
  ],
12820
- returns: ["NUMBER"],
12821
12758
  compute: function (sumRange, ...criters) {
12822
12759
  let sum = 0;
12823
12760
  visitMatchingRanges(criters, (i, j) => {
@@ -12836,7 +12773,6 @@ const SUMIFS = {
12836
12773
  const TAN = {
12837
12774
  description: _t("Tangent of an angle provided in radians."),
12838
12775
  args: [arg("angle (number)", _t("The angle to find the tangent of, in radians."))],
12839
- returns: ["NUMBER"],
12840
12776
  compute: function (angle) {
12841
12777
  return Math.tan(toNumber(angle, this.locale));
12842
12778
  },
@@ -12848,7 +12784,6 @@ const TAN = {
12848
12784
  const TANH = {
12849
12785
  description: _t("Hyperbolic tangent of any real number."),
12850
12786
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic tangent of."))],
12851
- returns: ["NUMBER"],
12852
12787
  compute: function (value) {
12853
12788
  return Math.tanh(toNumber(value, this.locale));
12854
12789
  },
@@ -12872,7 +12807,6 @@ const TRUNC = {
12872
12807
  arg("value (number)", _t("The value to be truncated.")),
12873
12808
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of significant digits to the right of the decimal point to retain.")),
12874
12809
  ],
12875
- returns: ["NUMBER"],
12876
12810
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12877
12811
  const _value = toNumber(value, this.locale);
12878
12812
  const _places = toNumber(places, this.locale);
@@ -12886,7 +12820,6 @@ const TRUNC = {
12886
12820
  const INT = {
12887
12821
  description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
12888
12822
  args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
12889
- returns: ["NUMBER"],
12890
12823
  compute: function (value) {
12891
12824
  return Math.floor(toNumber(value, this.locale));
12892
12825
  },
@@ -13245,7 +13178,6 @@ const AVEDEV = {
13245
13178
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
13246
13179
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
13247
13180
  ],
13248
- returns: ["NUMBER"],
13249
13181
  compute: function (...values) {
13250
13182
  let count = 0;
13251
13183
  const sum = reduceNumbers(values, (acc, a) => {
@@ -13267,7 +13199,6 @@ const AVERAGE = {
13267
13199
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13268
13200
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13269
13201
  ],
13270
- returns: ["NUMBER"],
13271
13202
  compute: function (...values) {
13272
13203
  return {
13273
13204
  value: average(values, this.locale),
@@ -13289,7 +13220,6 @@ const AVERAGE_WEIGHTED = {
13289
13220
  arg("additional_values (number, range<number>, repeating)", _t("Additional values to average.")),
13290
13221
  arg("additional_weights (number, range<number>, repeating)", _t("Additional weights.")),
13291
13222
  ],
13292
- returns: ["NUMBER"],
13293
13223
  compute: function (...args) {
13294
13224
  let sum = 0;
13295
13225
  let count = 0;
@@ -13337,7 +13267,6 @@ const AVERAGEA = {
13337
13267
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13338
13268
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13339
13269
  ],
13340
- returns: ["NUMBER"],
13341
13270
  compute: function (...args) {
13342
13271
  let count = 0;
13343
13272
  const sum = reduceNumbersTextAs0(args, (acc, a) => {
@@ -13362,7 +13291,6 @@ const AVERAGEIF = {
13362
13291
  arg("criterion (string)", _t("The pattern or test to apply to criteria_range.")),
13363
13292
  arg("average_range (number, range<number>, default=criteria_range)", _t("The range to average. If not included, criteria_range is used for the average instead.")),
13364
13293
  ],
13365
- returns: ["NUMBER"],
13366
13294
  compute: function (criteriaRange, criterion, averageRange) {
13367
13295
  const _averageRange = averageRange === undefined ? toMatrix(criteriaRange) : toMatrix(averageRange);
13368
13296
  let count = 0;
@@ -13391,7 +13319,6 @@ const AVERAGEIFS = {
13391
13319
  arg("criteria_range2 (any, range, repeating)", _t("Additional criteria_range and criterion to check.")),
13392
13320
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13393
13321
  ],
13394
- returns: ["NUMBER"],
13395
13322
  compute: function (averageRange, ...args) {
13396
13323
  const _averageRange = toMatrix(averageRange);
13397
13324
  let count = 0;
@@ -13417,7 +13344,6 @@ const COUNT = {
13417
13344
  arg("value1 (number, range<number>)", _t("The first value or range to consider when counting.")),
13418
13345
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when counting.")),
13419
13346
  ],
13420
- returns: ["NUMBER"],
13421
13347
  compute: function (...values) {
13422
13348
  return countNumbers(values, this.locale);
13423
13349
  },
@@ -13432,7 +13358,6 @@ const COUNTA = {
13432
13358
  arg("value1 (any, range)", _t("The first value or range to consider when counting.")),
13433
13359
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when counting.")),
13434
13360
  ],
13435
- returns: ["NUMBER"],
13436
13361
  compute: function (...values) {
13437
13362
  return countAny(values);
13438
13363
  },
@@ -13449,7 +13374,6 @@ const COVAR = {
13449
13374
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13450
13375
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13451
13376
  ],
13452
- returns: ["NUMBER"],
13453
13377
  compute: function (dataY, dataX) {
13454
13378
  return covariance(dataY, dataX, false);
13455
13379
  },
@@ -13464,7 +13388,6 @@ const COVARIANCE_P = {
13464
13388
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13465
13389
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13466
13390
  ],
13467
- returns: ["NUMBER"],
13468
13391
  compute: function (dataY, dataX) {
13469
13392
  return covariance(dataY, dataX, false);
13470
13393
  },
@@ -13479,7 +13402,6 @@ const COVARIANCE_S = {
13479
13402
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13480
13403
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13481
13404
  ],
13482
- returns: ["NUMBER"],
13483
13405
  compute: function (dataY, dataX) {
13484
13406
  return covariance(dataY, dataX, true);
13485
13407
  },
@@ -13495,7 +13417,6 @@ const FORECAST = {
13495
13417
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13496
13418
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13497
13419
  ],
13498
- returns: ["NUMBER"],
13499
13420
  compute: function (x, dataY, dataX) {
13500
13421
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13501
13422
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
@@ -13513,7 +13434,6 @@ const GROWTH = {
13513
13434
  arg("new_data_x (any, range, default=known_data_x)", _t("The data points to return the y values for on the ideal curve fit.")),
13514
13435
  arg("b (boolean, default=TRUE)", _t("Given a general exponential form of y = b*m^x for a curve fit, calculates b if TRUE or forces b to be 1 and only calculates the m values if FALSE.")),
13515
13436
  ],
13516
- returns: ["NUMBER"],
13517
13437
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13518
13438
  return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "the first argument (known_data_y)")), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b)));
13519
13439
  },
@@ -13527,7 +13447,6 @@ const INTERCEPT = {
13527
13447
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13528
13448
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13529
13449
  ],
13530
- returns: ["NUMBER"],
13531
13450
  compute: function (dataY, dataX) {
13532
13451
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13533
13452
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -13544,7 +13463,6 @@ const LARGE = {
13544
13463
  arg("data (any, range)", _t("Array or range containing the dataset to consider.")),
13545
13464
  arg("n (number)", _t("The rank from largest to smallest of the element to return.")),
13546
13465
  ],
13547
- returns: ["NUMBER"],
13548
13466
  compute: function (data, n) {
13549
13467
  const _n = Math.trunc(toNumber(n?.value, this.locale));
13550
13468
  let largests = [];
@@ -13579,7 +13497,6 @@ const LINEST = {
13579
13497
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13580
13498
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13581
13499
  ],
13582
- returns: ["NUMBER"],
13583
13500
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13584
13501
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13585
13502
  },
@@ -13596,7 +13513,6 @@ const LOGEST = {
13596
13513
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13597
13514
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13598
13515
  ],
13599
- returns: ["NUMBER"],
13600
13516
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13601
13517
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13602
13518
  for (let i = 0; i < coeffs.length; i++) {
@@ -13615,7 +13531,6 @@ const MATTHEWS = {
13615
13531
  arg("data_x (range)", _t("The range representing the array or matrix of observed data.")),
13616
13532
  arg("data_y (range)", _t("The range representing the array or matrix of predicted data.")),
13617
13533
  ],
13618
- returns: ["NUMBER"],
13619
13534
  compute: function (dataX, dataY) {
13620
13535
  const flatX = dataX.flat();
13621
13536
  const flatY = dataY.flat();
@@ -13659,7 +13574,6 @@ const MAX = {
13659
13574
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the maximum value.")),
13660
13575
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13661
13576
  ],
13662
- returns: ["NUMBER"],
13663
13577
  compute: function (...values) {
13664
13578
  return {
13665
13579
  value: max(values, this.locale),
@@ -13677,7 +13591,6 @@ const MAXA = {
13677
13591
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the maximum value.")),
13678
13592
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13679
13593
  ],
13680
- returns: ["NUMBER"],
13681
13594
  compute: function (...args) {
13682
13595
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
13683
13596
  return Math.max(a, acc);
@@ -13698,7 +13611,6 @@ const MAXIFS = {
13698
13611
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
13699
13612
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13700
13613
  ],
13701
- returns: ["NUMBER"],
13702
13614
  compute: function (range, ...args) {
13703
13615
  let result = -Infinity;
13704
13616
  visitMatchingRanges(args, (i, j) => {
@@ -13720,7 +13632,6 @@ const MEDIAN = {
13720
13632
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the median value.")),
13721
13633
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the median value.")),
13722
13634
  ],
13723
- returns: ["NUMBER"],
13724
13635
  compute: function (...values) {
13725
13636
  let data = [];
13726
13637
  visitNumbers(values, (value) => {
@@ -13742,7 +13653,6 @@ const MIN = {
13742
13653
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13743
13654
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13744
13655
  ],
13745
- returns: ["NUMBER"],
13746
13656
  compute: function (...values) {
13747
13657
  return {
13748
13658
  value: min(values, this.locale),
@@ -13760,7 +13670,6 @@ const MINA = {
13760
13670
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13761
13671
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13762
13672
  ],
13763
- returns: ["NUMBER"],
13764
13673
  compute: function (...args) {
13765
13674
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
13766
13675
  return Math.min(a, acc);
@@ -13781,7 +13690,6 @@ const MINIFS = {
13781
13690
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
13782
13691
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13783
13692
  ],
13784
- returns: ["NUMBER"],
13785
13693
  compute: function (range, ...args) {
13786
13694
  let result = Infinity;
13787
13695
  visitMatchingRanges(args, (i, j) => {
@@ -13824,7 +13732,6 @@ const PEARSON = {
13824
13732
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13825
13733
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13826
13734
  ],
13827
- returns: ["NUMBER"],
13828
13735
  compute: function (dataY, dataX) {
13829
13736
  return pearson(dataY, dataX);
13830
13737
  },
@@ -13841,7 +13748,6 @@ const PERCENTILE = {
13841
13748
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13842
13749
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13843
13750
  ],
13844
- returns: ["NUMBER"],
13845
13751
  compute: function (data, percentile) {
13846
13752
  return PERCENTILE_INC.compute.bind(this)(data, percentile);
13847
13753
  },
@@ -13856,7 +13762,6 @@ const PERCENTILE_EXC = {
13856
13762
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13857
13763
  arg("percentile (number)", _t("The percentile, exclusive of 0 and 1, whose value within 'data' will be calculated and returned.")),
13858
13764
  ],
13859
- returns: ["NUMBER"],
13860
13765
  compute: function (data, percentile) {
13861
13766
  return {
13862
13767
  value: centile([data], percentile, false, this.locale),
@@ -13874,7 +13779,6 @@ const PERCENTILE_INC = {
13874
13779
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13875
13780
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13876
13781
  ],
13877
- returns: ["NUMBER"],
13878
13782
  compute: function (data, percentile) {
13879
13783
  return {
13880
13784
  value: centile([data], percentile, true, this.locale),
@@ -13894,7 +13798,6 @@ const POLYFIT_COEFFS = {
13894
13798
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13895
13799
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13896
13800
  ],
13897
- returns: ["RANGE<NUMBER>"],
13898
13801
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13899
13802
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13900
13803
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
@@ -13913,7 +13816,6 @@ const POLYFIT_FORECAST = {
13913
13816
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13914
13817
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13915
13818
  ],
13916
- returns: ["NUMBER"],
13917
13819
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13918
13820
  const _order = toNumber(order, this.locale);
13919
13821
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
@@ -13931,7 +13833,6 @@ const QUARTILE = {
13931
13833
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13932
13834
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13933
13835
  ],
13934
- returns: ["NUMBER"],
13935
13836
  compute: function (data, quartileNumber) {
13936
13837
  return QUARTILE_INC.compute.bind(this)(data, quartileNumber);
13937
13838
  },
@@ -13946,7 +13847,6 @@ const QUARTILE_EXC = {
13946
13847
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13947
13848
  arg("quartile_number (number)", _t("Which quartile value, exclusive of 0 and 4, to return.")),
13948
13849
  ],
13949
- returns: ["NUMBER"],
13950
13850
  compute: function (data, quartileNumber) {
13951
13851
  const _quartileNumber = Math.trunc(toNumber(quartileNumber, this.locale));
13952
13852
  const percent = { value: 0.25 * _quartileNumber };
@@ -13966,7 +13866,6 @@ const QUARTILE_INC = {
13966
13866
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13967
13867
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13968
13868
  ],
13969
- returns: ["NUMBER"],
13970
13869
  compute: function (data, quartileNumber) {
13971
13870
  const percent = { value: 0.25 * Math.trunc(toNumber(quartileNumber, this.locale)) };
13972
13871
  return {
@@ -13985,7 +13884,6 @@ const RANK = {
13985
13884
  arg("data (range)", _t("The range containing the dataset to consider.")),
13986
13885
  arg("is_ascending (boolean, default=FALSE)", _t("Whether to consider the values in data in descending or ascending order.")),
13987
13886
  ],
13988
- returns: ["ANY"],
13989
13887
  compute: function (value, data, isAscending = { value: false }) {
13990
13888
  const _isAscending = toBoolean(isAscending);
13991
13889
  const _value = toNumber(value, this.locale);
@@ -14021,7 +13919,6 @@ const RSQ = {
14021
13919
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14022
13920
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14023
13921
  ],
14024
- returns: ["NUMBER"],
14025
13922
  compute: function (dataY, dataX) {
14026
13923
  return Math.pow(pearson(dataX, dataY), 2.0);
14027
13924
  },
@@ -14036,7 +13933,6 @@ const SLOPE = {
14036
13933
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14037
13934
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14038
13935
  ],
14039
- returns: ["NUMBER"],
14040
13936
  compute: function (dataY, dataX) {
14041
13937
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14042
13938
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -14053,7 +13949,6 @@ const SMALL = {
14053
13949
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
14054
13950
  arg("n (number)", _t("The rank from smallest to largest of the element to return.")),
14055
13951
  ],
14056
- returns: ["NUMBER"],
14057
13952
  compute: function (data, n) {
14058
13953
  const _n = Math.trunc(toNumber(n?.value, this.locale));
14059
13954
  let largests = [];
@@ -14086,7 +13981,6 @@ const SPEARMAN = {
14086
13981
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14087
13982
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14088
13983
  ],
14089
- returns: ["NUMBER"],
14090
13984
  compute: function (dataX, dataY) {
14091
13985
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14092
13986
  const n = flatDataX.length;
@@ -14113,7 +14007,6 @@ const STDEV = {
14113
14007
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14114
14008
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14115
14009
  ],
14116
- returns: ["NUMBER"],
14117
14010
  compute: function (...args) {
14118
14011
  return Math.sqrt(VAR.compute.bind(this)(...args));
14119
14012
  },
@@ -14128,7 +14021,6 @@ const STDEV_P = {
14128
14021
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14129
14022
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14130
14023
  ],
14131
- returns: ["NUMBER"],
14132
14024
  compute: function (...args) {
14133
14025
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
14134
14026
  },
@@ -14143,7 +14035,6 @@ const STDEV_S = {
14143
14035
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14144
14036
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14145
14037
  ],
14146
- returns: ["NUMBER"],
14147
14038
  compute: function (...args) {
14148
14039
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
14149
14040
  },
@@ -14158,7 +14049,6 @@ const STDEVA = {
14158
14049
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14159
14050
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14160
14051
  ],
14161
- returns: ["NUMBER"],
14162
14052
  compute: function (...args) {
14163
14053
  return Math.sqrt(VARA.compute.bind(this)(...args));
14164
14054
  },
@@ -14173,7 +14063,6 @@ const STDEVP = {
14173
14063
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14174
14064
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14175
14065
  ],
14176
- returns: ["NUMBER"],
14177
14066
  compute: function (...args) {
14178
14067
  return Math.sqrt(VARP.compute.bind(this)(...args));
14179
14068
  },
@@ -14188,7 +14077,6 @@ const STDEVPA = {
14188
14077
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14189
14078
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14190
14079
  ],
14191
- returns: ["NUMBER"],
14192
14080
  compute: function (...args) {
14193
14081
  return Math.sqrt(VARPA.compute.bind(this)(...args));
14194
14082
  },
@@ -14203,7 +14091,6 @@ const STEYX = {
14203
14091
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14204
14092
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14205
14093
  ],
14206
- returns: ["NUMBER"],
14207
14094
  compute: function (dataY, dataX) {
14208
14095
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14209
14096
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
@@ -14222,7 +14109,6 @@ const TREND = {
14222
14109
  arg("new_data_x (number, range<number>, optional, default=known_data_x)", _t("The data points to return the y values for on the ideal curve fit.")),
14223
14110
  arg("b (boolean, optional, default=TRUE)", _t("Given a general linear form of y = m*x+b for a curve fit, calculates b if TRUE or forces b to be 0 and only calculates the m values if FALSE, i.e. forces the curve fit to pass through the origin.")),
14224
14111
  ],
14225
- returns: ["NUMBER"],
14226
14112
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
14227
14113
  return predictLinearValues(toNumberMatrix(knownDataY, "the first argument (known_data_y)"), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b));
14228
14114
  },
@@ -14236,7 +14122,6 @@ const VAR = {
14236
14122
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14237
14123
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14238
14124
  ],
14239
- returns: ["NUMBER"],
14240
14125
  compute: function (...args) {
14241
14126
  return variance(args, true, false, this.locale);
14242
14127
  },
@@ -14251,7 +14136,6 @@ const VAR_P = {
14251
14136
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14252
14137
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14253
14138
  ],
14254
- returns: ["NUMBER"],
14255
14139
  compute: function (...args) {
14256
14140
  return variance(args, false, false, this.locale);
14257
14141
  },
@@ -14266,7 +14150,6 @@ const VAR_S = {
14266
14150
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14267
14151
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14268
14152
  ],
14269
- returns: ["NUMBER"],
14270
14153
  compute: function (...args) {
14271
14154
  return variance(args, true, false, this.locale);
14272
14155
  },
@@ -14281,7 +14164,6 @@ const VARA = {
14281
14164
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14282
14165
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14283
14166
  ],
14284
- returns: ["NUMBER"],
14285
14167
  compute: function (...args) {
14286
14168
  return variance(args, true, true, this.locale);
14287
14169
  },
@@ -14296,7 +14178,6 @@ const VARP = {
14296
14178
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14297
14179
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14298
14180
  ],
14299
- returns: ["NUMBER"],
14300
14181
  compute: function (...args) {
14301
14182
  return variance(args, false, false, this.locale);
14302
14183
  },
@@ -14311,7 +14192,6 @@ const VARPA = {
14311
14192
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14312
14193
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14313
14194
  ],
14314
- returns: ["NUMBER"],
14315
14195
  compute: function (...args) {
14316
14196
  return variance(args, false, true, this.locale);
14317
14197
  },
@@ -14477,7 +14357,6 @@ const databaseArgs = [
14477
14357
  const DAVERAGE = {
14478
14358
  description: _t("Average of a set of values from a table-like range."),
14479
14359
  args: databaseArgs,
14480
- returns: ["NUMBER"],
14481
14360
  compute: function (database, field, criteria) {
14482
14361
  const cells = getMatchingCells(database, field, criteria, this.locale);
14483
14362
  return AVERAGE.compute.bind(this)([cells]);
@@ -14490,7 +14369,6 @@ const DAVERAGE = {
14490
14369
  const DCOUNT = {
14491
14370
  description: _t("Counts values from a table-like range."),
14492
14371
  args: databaseArgs,
14493
- returns: ["NUMBER"],
14494
14372
  compute: function (database, field, criteria) {
14495
14373
  const cells = getMatchingCells(database, field, criteria, this.locale);
14496
14374
  return COUNT.compute.bind(this)([cells]);
@@ -14503,7 +14381,6 @@ const DCOUNT = {
14503
14381
  const DCOUNTA = {
14504
14382
  description: _t("Counts values and text from a table-like range."),
14505
14383
  args: databaseArgs,
14506
- returns: ["NUMBER"],
14507
14384
  compute: function (database, field, criteria) {
14508
14385
  const cells = getMatchingCells(database, field, criteria, this.locale);
14509
14386
  return COUNTA.compute.bind(this)([cells]);
@@ -14516,7 +14393,6 @@ const DCOUNTA = {
14516
14393
  const DGET = {
14517
14394
  description: _t("Single value from a table-like range."),
14518
14395
  args: databaseArgs,
14519
- returns: ["NUMBER"],
14520
14396
  compute: function (database, field, criteria) {
14521
14397
  const cells = getMatchingCells(database, field, criteria, this.locale);
14522
14398
  assert(() => cells.length === 1, _t("More than one match found in DGET evaluation."));
@@ -14530,7 +14406,6 @@ const DGET = {
14530
14406
  const DMAX = {
14531
14407
  description: _t("Maximum of values from a table-like range."),
14532
14408
  args: databaseArgs,
14533
- returns: ["NUMBER"],
14534
14409
  compute: function (database, field, criteria) {
14535
14410
  const cells = getMatchingCells(database, field, criteria, this.locale);
14536
14411
  return MAX.compute.bind(this)([cells]);
@@ -14543,7 +14418,6 @@ const DMAX = {
14543
14418
  const DMIN = {
14544
14419
  description: _t("Minimum of values from a table-like range."),
14545
14420
  args: databaseArgs,
14546
- returns: ["NUMBER"],
14547
14421
  compute: function (database, field, criteria) {
14548
14422
  const cells = getMatchingCells(database, field, criteria, this.locale);
14549
14423
  return MIN.compute.bind(this)([cells]);
@@ -14556,7 +14430,6 @@ const DMIN = {
14556
14430
  const DPRODUCT = {
14557
14431
  description: _t("Product of values from a table-like range."),
14558
14432
  args: databaseArgs,
14559
- returns: ["NUMBER"],
14560
14433
  compute: function (database, field, criteria) {
14561
14434
  const cells = getMatchingCells(database, field, criteria, this.locale);
14562
14435
  return PRODUCT.compute.bind(this)([cells]);
@@ -14569,7 +14442,6 @@ const DPRODUCT = {
14569
14442
  const DSTDEV = {
14570
14443
  description: _t("Standard deviation of population sample from table."),
14571
14444
  args: databaseArgs,
14572
- returns: ["NUMBER"],
14573
14445
  compute: function (database, field, criteria) {
14574
14446
  const cells = getMatchingCells(database, field, criteria, this.locale);
14575
14447
  return STDEV.compute.bind(this)([cells]);
@@ -14582,7 +14454,6 @@ const DSTDEV = {
14582
14454
  const DSTDEVP = {
14583
14455
  description: _t("Standard deviation of entire population from table."),
14584
14456
  args: databaseArgs,
14585
- returns: ["NUMBER"],
14586
14457
  compute: function (database, field, criteria) {
14587
14458
  const cells = getMatchingCells(database, field, criteria, this.locale);
14588
14459
  return STDEVP.compute.bind(this)([cells]);
@@ -14595,7 +14466,6 @@ const DSTDEVP = {
14595
14466
  const DSUM = {
14596
14467
  description: _t("Sum of values from a table-like range."),
14597
14468
  args: databaseArgs,
14598
- returns: ["NUMBER"],
14599
14469
  compute: function (database, field, criteria) {
14600
14470
  const cells = getMatchingCells(database, field, criteria, this.locale);
14601
14471
  return SUM.compute.bind(this)([cells]);
@@ -14608,7 +14478,6 @@ const DSUM = {
14608
14478
  const DVAR = {
14609
14479
  description: _t("Variance of population sample from table-like range."),
14610
14480
  args: databaseArgs,
14611
- returns: ["NUMBER"],
14612
14481
  compute: function (database, field, criteria) {
14613
14482
  const cells = getMatchingCells(database, field, criteria, this.locale);
14614
14483
  return VAR.compute.bind(this)([cells]);
@@ -14621,7 +14490,6 @@ const DVAR = {
14621
14490
  const DVARP = {
14622
14491
  description: _t("Variance of a population from a table-like range."),
14623
14492
  args: databaseArgs,
14624
- returns: ["NUMBER"],
14625
14493
  compute: function (database, field, criteria) {
14626
14494
  const cells = getMatchingCells(database, field, criteria, this.locale);
14627
14495
  return VARP.compute.bind(this)([cells]);
@@ -14666,7 +14534,6 @@ const DATE = {
14666
14534
  arg("month (number)", _t("The month component of the date.")),
14667
14535
  arg("day (number)", _t("The day component of the date.")),
14668
14536
  ],
14669
- returns: ["DATE"],
14670
14537
  compute: function (year, month, day) {
14671
14538
  let _year = Math.trunc(toNumber(year, this.locale));
14672
14539
  const _month = Math.trunc(toNumber(month, this.locale));
@@ -14697,7 +14564,6 @@ const DATEDIF = {
14697
14564
  arg("end_date (date)", _t("The end date to consider in the calculation. Must be a reference to a cell containing a DATE, a function returning a DATE type, or a number.")),
14698
14565
  arg("unit (string)", _t('A text abbreviation for unit of time. Accepted values are "Y" (the number of whole years between start_date and end_date), "M" (the number of whole months between start_date and end_date), "D" (the number of days between start_date and end_date), "MD" (the number of days between start_date and end_date after subtracting whole months), "YM" (the number of whole months between start_date and end_date after subtracting whole years), "YD" (the number of days between start_date and end_date, assuming start_date and end_date were no more than one year apart).')),
14699
14566
  ],
14700
- returns: ["NUMBER"],
14701
14567
  compute: function (startDate, endDate, unit) {
14702
14568
  const _unit = toString(unit).toUpperCase();
14703
14569
  assert(() => Object.values(TIME_UNIT).includes(_unit), expectStringSetError(Object.values(TIME_UNIT), toString(unit)));
@@ -14750,7 +14616,6 @@ const DATEDIF = {
14750
14616
  const DATEVALUE = {
14751
14617
  description: _t("Converts a date string to a date value."),
14752
14618
  args: [arg("date_string (string)", _t("The string representing the date."))],
14753
- returns: ["NUMBER"],
14754
14619
  compute: function (dateString) {
14755
14620
  const _dateString = toString(dateString);
14756
14621
  const internalDate = parseDateTime(_dateString, this.locale);
@@ -14765,7 +14630,6 @@ const DATEVALUE = {
14765
14630
  const DAY = {
14766
14631
  description: _t("Day of the month that a specific date falls on."),
14767
14632
  args: [arg("date (string)", _t("The date from which to extract the day."))],
14768
- returns: ["NUMBER"],
14769
14633
  compute: function (date) {
14770
14634
  return toJsDate(date, this.locale).getDate();
14771
14635
  },
@@ -14780,7 +14644,6 @@ const DAYS = {
14780
14644
  arg("end_date (date)", _t("The end of the date range.")),
14781
14645
  arg("start_date (date)", _t("The start of the date range.")),
14782
14646
  ],
14783
- returns: ["NUMBER"],
14784
14647
  compute: function (endDate, startDate) {
14785
14648
  const _endDate = toJsDate(endDate, this.locale);
14786
14649
  const _startDate = toJsDate(startDate, this.locale);
@@ -14800,7 +14663,6 @@ const DAYS360 = {
14800
14663
  arg("end_date (date)", _t("The end date to consider in the calculation.")),
14801
14664
  arg(`method (number, default=${DEFAULT_DAY_COUNT_METHOD})`, _t("An indicator of what day count method to use. (0) US NASD method (1) European method")),
14802
14665
  ],
14803
- returns: ["NUMBER"],
14804
14666
  compute: function (startDate, endDate, method = { value: DEFAULT_DAY_COUNT_METHOD }) {
14805
14667
  const _startDate = Math.trunc(toNumber(startDate, this.locale));
14806
14668
  const _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -14819,7 +14681,6 @@ const EDATE = {
14819
14681
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14820
14682
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to calculate.")),
14821
14683
  ],
14822
- returns: ["DATE"],
14823
14684
  compute: function (startDate, months) {
14824
14685
  const _startDate = toJsDate(startDate, this.locale);
14825
14686
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14840,7 +14701,6 @@ const EOMONTH = {
14840
14701
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14841
14702
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to consider.")),
14842
14703
  ],
14843
- returns: ["DATE"],
14844
14704
  compute: function (startDate, months) {
14845
14705
  const _startDate = toJsDate(startDate, this.locale);
14846
14706
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14860,7 +14720,6 @@ const EOMONTH = {
14860
14720
  const HOUR = {
14861
14721
  description: _t("Hour component of a specific time."),
14862
14722
  args: [arg("time (date)", _t("The time from which to calculate the hour component."))],
14863
- returns: ["NUMBER"],
14864
14723
  compute: function (date) {
14865
14724
  return toJsDate(date, this.locale).getHours();
14866
14725
  },
@@ -14874,7 +14733,6 @@ const ISOWEEKNUM = {
14874
14733
  args: [
14875
14734
  arg("date (date)", _t("The date for which to determine the ISO week number. Must be a reference to a cell containing a date, a function returning a date type, or a number.")),
14876
14735
  ],
14877
- returns: ["NUMBER"],
14878
14736
  compute: function (date) {
14879
14737
  const _date = toJsDate(date, this.locale);
14880
14738
  const y = _date.getFullYear();
@@ -14946,7 +14804,6 @@ const ISOWEEKNUM = {
14946
14804
  const MINUTE = {
14947
14805
  description: _t("Minute component of a specific time."),
14948
14806
  args: [arg("time (date)", _t("The time from which to calculate the minute component."))],
14949
- returns: ["NUMBER"],
14950
14807
  compute: function (date) {
14951
14808
  return toJsDate(date, this.locale).getMinutes();
14952
14809
  },
@@ -14958,7 +14815,6 @@ const MINUTE = {
14958
14815
  const MONTH = {
14959
14816
  description: _t("Month of the year a specific date falls in"),
14960
14817
  args: [arg("date (date)", _t("The date from which to extract the month."))],
14961
- returns: ["NUMBER"],
14962
14818
  compute: function (date) {
14963
14819
  return toJsDate(date, this.locale).getMonth() + 1;
14964
14820
  },
@@ -14974,7 +14830,6 @@ const NETWORKDAYS = {
14974
14830
  arg("end_date (date)", _t("The end date of the period from which to calculate the number of net working days.")),
14975
14831
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the date serial numbers to consider holidays.")),
14976
14832
  ],
14977
- returns: ["NUMBER"],
14978
14833
  compute: function (startDate, endDate, holidays) {
14979
14834
  return NETWORKDAYS_INTL.compute.bind(this)(startDate, endDate, { value: 1 }, holidays);
14980
14835
  },
@@ -15055,7 +14910,6 @@ const NETWORKDAYS_INTL = {
15055
14910
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15056
14911
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider as holidays.")),
15057
14912
  ],
15058
- returns: ["NUMBER"],
15059
14913
  compute: function (startDate, endDate, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15060
14914
  const _startDate = toJsDate(startDate, this.locale);
15061
14915
  const _endDate = toJsDate(endDate, this.locale);
@@ -15090,7 +14944,6 @@ const NETWORKDAYS_INTL = {
15090
14944
  const NOW = {
15091
14945
  description: _t("Current date and time as a date value."),
15092
14946
  args: [],
15093
- returns: ["DATE"],
15094
14947
  compute: function () {
15095
14948
  const today = DateTime.now();
15096
14949
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
@@ -15108,7 +14961,6 @@ const NOW = {
15108
14961
  const SECOND = {
15109
14962
  description: _t("Minute component of a specific time."),
15110
14963
  args: [arg("time (date)", _t("The time from which to calculate the second component."))],
15111
- returns: ["NUMBER"],
15112
14964
  compute: function (date) {
15113
14965
  return toJsDate(date, this.locale).getSeconds();
15114
14966
  },
@@ -15124,7 +14976,6 @@ const TIME = {
15124
14976
  arg("minute (number)", _t("The minute component of the time.")),
15125
14977
  arg("second (number)", _t("The second component of the time.")),
15126
14978
  ],
15127
- returns: ["DATE"],
15128
14979
  compute: function (hour, minute, second) {
15129
14980
  let _hour = Math.trunc(toNumber(hour, this.locale));
15130
14981
  let _minute = Math.trunc(toNumber(minute, this.locale));
@@ -15148,7 +14999,6 @@ const TIME = {
15148
14999
  const TIMEVALUE = {
15149
15000
  description: _t("Converts a time string into its serial number representation."),
15150
15001
  args: [arg("time_string (string)", _t("The string that holds the time representation."))],
15151
- returns: ["NUMBER"],
15152
15002
  compute: function (timeString) {
15153
15003
  const _timeString = toString(timeString);
15154
15004
  const internalDate = parseDateTime(_timeString, this.locale);
@@ -15164,7 +15014,6 @@ const TIMEVALUE = {
15164
15014
  const TODAY = {
15165
15015
  description: _t("Current date as a date value."),
15166
15016
  args: [],
15167
- returns: ["DATE"],
15168
15017
  compute: function () {
15169
15018
  const today = DateTime.now();
15170
15019
  const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
@@ -15184,7 +15033,6 @@ const WEEKDAY = {
15184
15033
  arg("date (date)", _t("The date for which to determine the day of the week. Must be a reference to a cell containing a date, a function returning a date type, or a number.")),
15185
15034
  arg(`type (number, default=${DEFAULT_TYPE})`, _t("A number indicating which numbering system to use to represent weekdays. By default, counts starting with Sunday = 1.")),
15186
15035
  ],
15187
- returns: ["NUMBER"],
15188
15036
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15189
15037
  const _date = toJsDate(date, this.locale);
15190
15038
  const _type = Math.round(toNumber(type, this.locale));
@@ -15207,7 +15055,6 @@ const WEEKNUM = {
15207
15055
  arg("date (date)", _t("The date for which to determine the week number. Must be a reference to a cell containing a date, a function returning a date type, or a number.")),
15208
15056
  arg(`type (number, default=${DEFAULT_TYPE})`, _t("A number representing the day that a week starts on. Sunday = 1.")),
15209
15057
  ],
15210
- returns: ["NUMBER"],
15211
15058
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15212
15059
  const _date = toJsDate(date, this.locale);
15213
15060
  const _type = Math.round(toNumber(type, this.locale));
@@ -15248,7 +15095,6 @@ const WORKDAY = {
15248
15095
  arg("num_days (number)", _t("The number of working days to advance from start_date. If negative, counts backwards.")),
15249
15096
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15250
15097
  ],
15251
- returns: ["NUMBER"],
15252
15098
  compute: function (startDate, numDays, holidays = { value: null }) {
15253
15099
  return WORKDAY_INTL.compute.bind(this)(startDate, numDays, { value: 1 }, holidays);
15254
15100
  },
@@ -15265,7 +15111,6 @@ const WORKDAY_INTL = {
15265
15111
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15266
15112
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15267
15113
  ],
15268
- returns: ["DATE"],
15269
15114
  compute: function (startDate, numDays, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15270
15115
  let _startDate = toJsDate(startDate, this.locale);
15271
15116
  let _numDays = Math.trunc(toNumber(numDays, this.locale));
@@ -15305,7 +15150,6 @@ const WORKDAY_INTL = {
15305
15150
  const YEAR = {
15306
15151
  description: _t("Year specified by a given date."),
15307
15152
  args: [arg("date (date)", _t("The date from which to extract the year."))],
15308
- returns: ["NUMBER"],
15309
15153
  compute: function (date) {
15310
15154
  return toJsDate(date, this.locale).getFullYear();
15311
15155
  },
@@ -15322,7 +15166,6 @@ const YEARFRAC = {
15322
15166
  arg("end_date (date)", _t("The end date to consider in the calculation. Must be a reference to a cell containing a date, a function returning a date type, or a number.")),
15323
15167
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION$1})`, _t("An indicator of what day count method to use.")),
15324
15168
  ],
15325
- returns: ["NUMBER"],
15326
15169
  compute: function (startDate, endDate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION$1 }) {
15327
15170
  let _startDate = Math.trunc(toNumber(startDate, this.locale));
15328
15171
  let _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -15339,7 +15182,6 @@ const YEARFRAC = {
15339
15182
  const MONTH_START = {
15340
15183
  description: _t("First day of the month preceding a date."),
15341
15184
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15342
- returns: ["DATE"],
15343
15185
  compute: function (date) {
15344
15186
  const _startDate = toJsDate(date, this.locale);
15345
15187
  const yStart = _startDate.getFullYear();
@@ -15357,7 +15199,6 @@ const MONTH_START = {
15357
15199
  const MONTH_END = {
15358
15200
  description: _t("Last day of the month following a date."),
15359
15201
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15360
- returns: ["DATE"],
15361
15202
  compute: function (date) {
15362
15203
  return EOMONTH.compute.bind(this)(date, { value: 0 });
15363
15204
  },
@@ -15368,7 +15209,6 @@ const MONTH_END = {
15368
15209
  const QUARTER = {
15369
15210
  description: _t("Quarter of the year a specific date falls in"),
15370
15211
  args: [arg("date (date)", _t("The date from which to extract the quarter."))],
15371
- returns: ["NUMBER"],
15372
15212
  compute: function (date) {
15373
15213
  return Math.ceil((toJsDate(date, this.locale).getMonth() + 1) / 3);
15374
15214
  },
@@ -15379,7 +15219,6 @@ const QUARTER = {
15379
15219
  const QUARTER_START = {
15380
15220
  description: _t("First day of the quarter of the year a specific date falls in."),
15381
15221
  args: [arg("date (date)", _t("The date from which to calculate the start of quarter."))],
15382
- returns: ["DATE"],
15383
15222
  compute: function (date) {
15384
15223
  const quarter = QUARTER.compute.bind(this)(date);
15385
15224
  const year = YEAR.compute.bind(this)(date);
@@ -15396,7 +15235,6 @@ const QUARTER_START = {
15396
15235
  const QUARTER_END = {
15397
15236
  description: _t("Last day of the quarter of the year a specific date falls in."),
15398
15237
  args: [arg("date (date)", _t("The date from which to calculate the end of quarter."))],
15399
- returns: ["DATE"],
15400
15238
  compute: function (date) {
15401
15239
  const quarter = QUARTER.compute.bind(this)(date);
15402
15240
  const year = YEAR.compute.bind(this)(date);
@@ -15413,7 +15251,6 @@ const QUARTER_END = {
15413
15251
  const YEAR_START = {
15414
15252
  description: _t("First day of the year a specific date falls in."),
15415
15253
  args: [arg("date (date)", _t("The date from which to calculate the start of the year."))],
15416
- returns: ["DATE"],
15417
15254
  compute: function (date) {
15418
15255
  const year = YEAR.compute.bind(this)(date);
15419
15256
  const jsDate = new DateTime(year, 0, 1);
@@ -15429,7 +15266,6 @@ const YEAR_START = {
15429
15266
  const YEAR_END = {
15430
15267
  description: _t("Last day of the year a specific date falls in."),
15431
15268
  args: [arg("date (date)", _t("The date from which to calculate the end of the year."))],
15432
- returns: ["DATE"],
15433
15269
  compute: function (date) {
15434
15270
  const year = YEAR.compute.bind(this)(date);
15435
15271
  const jsDate = new DateTime(year + 1, 0, 0);
@@ -15486,7 +15322,6 @@ const DELTA = {
15486
15322
  arg("number1 (number)", _t("The first number to compare.")),
15487
15323
  arg(`number2 (number, default=${DEFAULT_DELTA_ARG})`, _t("The second number to compare.")),
15488
15324
  ],
15489
- returns: ["NUMBER"],
15490
15325
  compute: function (number1, number2 = { value: DEFAULT_DELTA_ARG }) {
15491
15326
  const _number1 = toNumber(number1, this.locale);
15492
15327
  const _number2 = toNumber(number2, this.locale);
@@ -15677,7 +15512,6 @@ const FILTER = {
15677
15512
  arg("condition1 (boolean, range<boolean>)", _t("A column or row containing true or false values corresponding to the first column or row of range.")),
15678
15513
  arg("condition2 (boolean, range<boolean>, repeating)", _t("Additional column or row containing true or false values.")),
15679
15514
  ],
15680
- returns: ["RANGE<ANY>"],
15681
15515
  compute: function (range, ...conditions) {
15682
15516
  let _array = toMatrix(range);
15683
15517
  const _conditionsMatrices = conditions.map((cond) => matrixMap(toMatrix(cond), (data) => data.value));
@@ -15711,7 +15545,6 @@ const SORT = {
15711
15545
  arg("sort_column (any, range<number>, repeating)", _t("The index of the column in range or a range outside of range containing the values by which to sort.")),
15712
15546
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15713
15547
  ],
15714
- returns: ["RANGE"],
15715
15548
  compute: function (range, ...sortingCriteria) {
15716
15549
  const _range = transposeMatrix(range);
15717
15550
  return transposeMatrix(sortMatrix(_range, this.locale, ...sortingCriteria));
@@ -15730,7 +15563,6 @@ const SORTN = {
15730
15563
  arg("sort_column (number, range<number>, repeating)", _t("The index of the column in range or a range outside of range containing the values by which to sort.")),
15731
15564
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15732
15565
  ],
15733
- returns: ["RANGE"],
15734
15566
  compute: function (range, n, displayTiesMode, ...sortingCriteria) {
15735
15567
  const _n = toNumber(n?.value ?? 1, this.locale);
15736
15568
  assert(() => _n >= 0, _t("Wrong value of 'n'. Expected a positive number. Got %s.", _n));
@@ -15798,7 +15630,6 @@ const UNIQUE = {
15798
15630
  arg("by_column (boolean, default=FALSE)", _t("Whether to filter the data by columns or by rows.")),
15799
15631
  arg("exactly_once (boolean, default=FALSE)", _t("Whether to return only entries with no duplicates.")),
15800
15632
  ],
15801
- returns: ["RANGE<NUMBER>"],
15802
15633
  compute: function (range = { value: "" }, byColumn, exactlyOnce) {
15803
15634
  if (!isMatrix(range)) {
15804
15635
  return [[range]];
@@ -16023,7 +15854,6 @@ const ACCRINTM = {
16023
15854
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16024
15855
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16025
15856
  ],
16026
- returns: ["NUMBER"],
16027
15857
  compute: function (issue, maturity, rate, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16028
15858
  const start = Math.trunc(toNumber(issue, this.locale));
16029
15859
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16054,7 +15884,6 @@ const AMORLINC = {
16054
15884
  arg("rate (number)", _t("The deprecation rate.")),
16055
15885
  arg("day_count_convention (number, optional)", _t("An indicator of what day count method to use.")),
16056
15886
  ],
16057
- returns: ["NUMBER"],
16058
15887
  compute: function (cost, purchaseDate, firstPeriodEnd, salvage, period, rate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16059
15888
  dayCountConvention = dayCountConvention || 0;
16060
15889
  const _cost = toNumber(cost, this.locale);
@@ -16103,7 +15932,6 @@ const AMORLINC = {
16103
15932
  const COUPDAYS = {
16104
15933
  description: _t("Days in coupon period containing settlement date."),
16105
15934
  args: COUPON_FUNCTION_ARGS,
16106
- returns: ["NUMBER"],
16107
15935
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16108
15936
  dayCountConvention = dayCountConvention || 0;
16109
15937
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16130,7 +15958,6 @@ const COUPDAYS = {
16130
15958
  const COUPDAYBS = {
16131
15959
  description: _t("Days from settlement until next coupon."),
16132
15960
  args: COUPON_FUNCTION_ARGS,
16133
- returns: ["NUMBER"],
16134
15961
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16135
15962
  dayCountConvention = dayCountConvention || 0;
16136
15963
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16187,7 +16014,6 @@ const COUPDAYBS = {
16187
16014
  const COUPDAYSNC = {
16188
16015
  description: _t("Days from settlement until next coupon."),
16189
16016
  args: COUPON_FUNCTION_ARGS,
16190
- returns: ["NUMBER"],
16191
16017
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16192
16018
  dayCountConvention = dayCountConvention || 0;
16193
16019
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16217,7 +16043,6 @@ const COUPDAYSNC = {
16217
16043
  const COUPNCD = {
16218
16044
  description: _t("Next coupon date after the settlement date."),
16219
16045
  args: COUPON_FUNCTION_ARGS,
16220
- returns: ["NUMBER"],
16221
16046
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16222
16047
  dayCountConvention = dayCountConvention || 0;
16223
16048
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16243,7 +16068,6 @@ const COUPNCD = {
16243
16068
  const COUPNUM = {
16244
16069
  description: _t("Number of coupons between settlement and maturity."),
16245
16070
  args: COUPON_FUNCTION_ARGS,
16246
- returns: ["NUMBER"],
16247
16071
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16248
16072
  dayCountConvention = dayCountConvention || 0;
16249
16073
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16270,7 +16094,6 @@ const COUPNUM = {
16270
16094
  const COUPPCD = {
16271
16095
  description: _t("Last coupon date prior to or on the settlement date."),
16272
16096
  args: COUPON_FUNCTION_ARGS,
16273
- returns: ["NUMBER"],
16274
16097
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16275
16098
  dayCountConvention = dayCountConvention || 0;
16276
16099
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16303,7 +16126,6 @@ const CUMIPMT = {
16303
16126
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16304
16127
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
16305
16128
  ],
16306
- returns: ["NUMBER"],
16307
16129
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16308
16130
  const first = toNumber(firstPeriod, this.locale);
16309
16131
  const last = toNumber(lastPeriod, this.locale);
@@ -16335,7 +16157,6 @@ const CUMPRINC = {
16335
16157
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16336
16158
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
16337
16159
  ],
16338
- returns: ["NUMBER"],
16339
16160
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16340
16161
  const first = toNumber(firstPeriod, this.locale);
16341
16162
  const last = toNumber(lastPeriod, this.locale);
@@ -16366,7 +16187,6 @@ const DB = {
16366
16187
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16367
16188
  arg("month (number, optional)", _t("The number of months in the first year of depreciation.")),
16368
16189
  ],
16369
- returns: ["NUMBER"],
16370
16190
  // to do: replace by dollar format
16371
16191
  compute: function (cost, salvage, life, period, ...args) {
16372
16192
  const _cost = toNumber(cost, this.locale);
@@ -16435,7 +16255,6 @@ const DDB = {
16435
16255
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16436
16256
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The factor by which depreciation decreases.")),
16437
16257
  ],
16438
- returns: ["NUMBER"],
16439
16258
  compute: function (cost, salvage, life, period, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }) {
16440
16259
  const _cost = toNumber(cost, this.locale);
16441
16260
  const _salvage = toNumber(salvage, this.locale);
@@ -16461,7 +16280,6 @@ const DISC = {
16461
16280
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16462
16281
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16463
16282
  ],
16464
- returns: ["NUMBER"],
16465
16283
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16466
16284
  dayCountConvention = dayCountConvention || 0;
16467
16285
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -16497,7 +16315,6 @@ const DOLLARDE = {
16497
16315
  arg("fractional_price (number)", _t("The price quotation given using fractional decimal conventions.")),
16498
16316
  arg("unit (number)", _t("The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16499
16317
  ],
16500
- returns: ["NUMBER"],
16501
16318
  compute: function (fractionalPrice, unit) {
16502
16319
  const price = toNumber(fractionalPrice, this.locale);
16503
16320
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16518,7 +16335,6 @@ const DOLLARFR = {
16518
16335
  arg("decimal_price (number)", _t("The price quotation given as a decimal value.")),
16519
16336
  arg("unit (number)", _t("The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16520
16337
  ],
16521
- returns: ["NUMBER"],
16522
16338
  compute: function (decimalPrice, unit) {
16523
16339
  const price = toNumber(decimalPrice, this.locale);
16524
16340
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16543,7 +16359,6 @@ const DURATION = {
16543
16359
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16544
16360
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16545
16361
  ],
16546
- returns: ["NUMBER"],
16547
16362
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16548
16363
  const start = Math.trunc(toNumber(settlement, this.locale));
16549
16364
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16584,7 +16399,6 @@ const EFFECT = {
16584
16399
  arg("nominal_rate (number)", _t("The nominal interest rate per year.")),
16585
16400
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16586
16401
  ],
16587
- returns: ["NUMBER"],
16588
16402
  compute: function (nominal_rate, periods_per_year) {
16589
16403
  const nominal = toNumber(nominal_rate, this.locale);
16590
16404
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16614,7 +16428,6 @@ const FV = {
16614
16428
  arg(`present_value (number, default=${DEFAULT_PRESENT_VALUE})`, _t("The current value of the annuity.")),
16615
16429
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
16616
16430
  ],
16617
- returns: ["NUMBER"],
16618
16431
  // to do: replace by dollar format
16619
16432
  compute: function (rate, numberOfPeriods, paymentAmount, presentValue = { value: DEFAULT_PRESENT_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16620
16433
  presentValue = presentValue || 0;
@@ -16640,7 +16453,6 @@ const FVSCHEDULE = {
16640
16453
  arg("principal (number)", _t("The amount of initial capital or value to compound against.")),
16641
16454
  arg("rate_schedule (number, range<number>)", _t("A series of interest rates to compound against the principal.")),
16642
16455
  ],
16643
- returns: ["NUMBER"],
16644
16456
  compute: function (principalAmount, rateSchedule) {
16645
16457
  const principal = toNumber(principalAmount, this.locale);
16646
16458
  return reduceAny([rateSchedule], (acc, rate) => acc * (1 + toNumber(rate, this.locale)), principal);
@@ -16659,7 +16471,6 @@ const INTRATE = {
16659
16471
  arg("redemption (number)", _t("The amount to be received at maturity.")),
16660
16472
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16661
16473
  ],
16662
- returns: ["NUMBER"],
16663
16474
  compute: function (settlement, maturity, investment, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16664
16475
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
16665
16476
  const _maturity = Math.trunc(toNumber(maturity, this.locale));
@@ -16698,7 +16509,6 @@ const IPMT = {
16698
16509
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16699
16510
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
16700
16511
  ],
16701
- returns: ["NUMBER"],
16702
16512
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16703
16513
  const r = toNumber(rate, this.locale);
16704
16514
  const period = toNumber(currentPeriod, this.locale);
@@ -16723,7 +16533,6 @@ const IRR = {
16723
16533
  arg("cashflow_amounts (number, range<number>)", _t("An array or range containing the income or payments associated with the investment.")),
16724
16534
  arg(`rate_guess (number, default=${DEFAULT_RATE_GUESS})`, _t("An estimate for what the internal rate of return will be.")),
16725
16535
  ],
16726
- returns: ["NUMBER"],
16727
16536
  compute: function (cashFlowAmounts, rateGuess = { value: DEFAULT_RATE_GUESS }) {
16728
16537
  const _rateGuess = toNumber(rateGuess, this.locale);
16729
16538
  assertRateGuessStrictlyGreaterThanMinusOne(_rateGuess);
@@ -16785,7 +16594,6 @@ const ISPMT = {
16785
16594
  arg("number_of_periods (number)", _t("The number of payments to be made.")),
16786
16595
  arg("present_value (number)", _t("The current value of the annuity.")),
16787
16596
  ],
16788
- returns: ["NUMBER"],
16789
16597
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue) {
16790
16598
  const interestRate = toNumber(rate, this.locale);
16791
16599
  const period = toNumber(currentPeriod, this.locale);
@@ -16810,7 +16618,6 @@ const MDURATION = {
16810
16618
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16811
16619
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16812
16620
  ],
16813
- returns: ["NUMBER"],
16814
16621
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16815
16622
  const duration = DURATION.compute.bind(this)(settlement, maturity, rate, securityYield, frequency, dayCountConvention);
16816
16623
  const y = toNumber(securityYield, this.locale);
@@ -16829,7 +16636,6 @@ const MIRR = {
16829
16636
  arg("financing_rate (number)", _t("The interest rate paid on funds invested.")),
16830
16637
  arg("reinvestment_return_rate (number)", _t("The return (as a percentage) earned on reinvestment of income received from the investment.")),
16831
16638
  ],
16832
- returns: ["NUMBER"],
16833
16639
  compute: function (cashflowAmount, financingRate, reinvestmentRate) {
16834
16640
  const fRate = toNumber(financingRate, this.locale);
16835
16641
  const rRate = toNumber(reinvestmentRate, this.locale);
@@ -16881,7 +16687,6 @@ const NOMINAL = {
16881
16687
  arg("effective_rate (number)", _t("The effective interest rate per year.")),
16882
16688
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16883
16689
  ],
16884
- returns: ["NUMBER"],
16885
16690
  compute: function (effective_rate, periods_per_year) {
16886
16691
  const effective = toNumber(effective_rate, this.locale);
16887
16692
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16904,7 +16709,6 @@ const NPER = {
16904
16709
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16905
16710
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
16906
16711
  ],
16907
- returns: ["NUMBER"],
16908
16712
  compute: function (rate, paymentAmount, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16909
16713
  futureValue = futureValue || 0;
16910
16714
  endOrBeginning = endOrBeginning || 0;
@@ -16952,7 +16756,6 @@ const NPV = {
16952
16756
  arg("cashflow1 (number, range<number>)", _t("The first future cash flow.")),
16953
16757
  arg("cashflow2 (number, range<number>, repeating)", _t("Additional future cash flows.")),
16954
16758
  ],
16955
- returns: ["NUMBER"],
16956
16759
  // to do: replace by dollar format
16957
16760
  compute: function (discount, ...values) {
16958
16761
  const _discount = toNumber(discount, this.locale);
@@ -16974,7 +16777,6 @@ const PDURATION = {
16974
16777
  arg("present_value (number)", _t("The investment's current value.")),
16975
16778
  arg("future_value (number)", _t("The investment's desired future value.")),
16976
16779
  ],
16977
- returns: ["NUMBER"],
16978
16780
  compute: function (rate, presentValue, futureValue) {
16979
16781
  const _rate = toNumber(rate, this.locale);
16980
16782
  const _presentValue = toNumber(presentValue, this.locale);
@@ -17014,7 +16816,6 @@ const PMT = {
17014
16816
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17015
16817
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
17016
16818
  ],
17017
- returns: ["NUMBER"],
17018
16819
  compute: function (rate, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17019
16820
  const n = toNumber(numberOfPeriods, this.locale);
17020
16821
  const r = toNumber(rate, this.locale);
@@ -17050,7 +16851,6 @@ const PPMT = {
17050
16851
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17051
16852
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
17052
16853
  ],
17053
- returns: ["NUMBER"],
17054
16854
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17055
16855
  const n = toNumber(numberOfPeriods, this.locale);
17056
16856
  const r = toNumber(rate, this.locale);
@@ -17077,7 +16877,6 @@ const PV = {
17077
16877
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17078
16878
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
17079
16879
  ],
17080
- returns: ["NUMBER"],
17081
16880
  // to do: replace by dollar format
17082
16881
  compute: function (rate, numberOfPeriods, paymentAmount, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17083
16882
  futureValue = futureValue || 0;
@@ -17111,7 +16910,6 @@ const PRICE = {
17111
16910
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17112
16911
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17113
16912
  ],
17114
- returns: ["NUMBER"],
17115
16913
  compute: function (settlement, maturity, rate, securityYield, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17116
16914
  dayCountConvention = dayCountConvention || 0;
17117
16915
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17159,7 +16957,6 @@ const PRICEDISC = {
17159
16957
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17160
16958
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17161
16959
  ],
17162
- returns: ["NUMBER"],
17163
16960
  compute: function (settlement, maturity, discount, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17164
16961
  dayCountConvention = dayCountConvention || 0;
17165
16962
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17197,7 +16994,6 @@ const PRICEMAT = {
17197
16994
  arg("yield (number)", _t("The expected annual yield of the security.")),
17198
16995
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17199
16996
  ],
17200
- returns: ["NUMBER"],
17201
16997
  compute: function (settlement, maturity, issue, rate, securityYield, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17202
16998
  dayCountConvention = dayCountConvention || 0;
17203
16999
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17261,7 +17057,6 @@ const RATE = {
17261
17057
  arg(`end_or_beginning (number, default=${DEFAULT_END_OR_BEGINNING})`, _t("Whether payments are due at the end (0) or beginning (1) of each period.")),
17262
17058
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the interest rate will be.")),
17263
17059
  ],
17264
- returns: ["NUMBER"],
17265
17060
  compute: function (numberOfPeriods, paymentPerPeriod, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17266
17061
  const n = toNumber(numberOfPeriods, this.locale);
17267
17062
  const payment = toNumber(paymentPerPeriod, this.locale);
@@ -17307,7 +17102,6 @@ const RECEIVED = {
17307
17102
  arg("discount (number)", _t("The discount rate of the security invested in.")),
17308
17103
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17309
17104
  ],
17310
- returns: ["NUMBER"],
17311
17105
  compute: function (settlement, maturity, investment, discount, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17312
17106
  dayCountConvention = dayCountConvention || 0;
17313
17107
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17345,7 +17139,6 @@ const RRI = {
17345
17139
  arg("present_value (number)", _t("The present value of the investment.")),
17346
17140
  arg("future_value (number)", _t("The future value of the investment.")),
17347
17141
  ],
17348
- returns: ["NUMBER"],
17349
17142
  compute: function (numberOfPeriods, presentValue, futureValue) {
17350
17143
  const n = toNumber(numberOfPeriods, this.locale);
17351
17144
  const pv = toNumber(presentValue, this.locale);
@@ -17370,7 +17163,6 @@ const SLN = {
17370
17163
  arg("salvage (number)", _t("The value of the asset at the end of depreciation.")),
17371
17164
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17372
17165
  ],
17373
- returns: ["NUMBER"],
17374
17166
  compute: function (cost, salvage, life) {
17375
17167
  const _cost = toNumber(cost, this.locale);
17376
17168
  const _salvage = toNumber(salvage, this.locale);
@@ -17395,7 +17187,6 @@ const SYD = {
17395
17187
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17396
17188
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
17397
17189
  ],
17398
- returns: ["NUMBER"],
17399
17190
  compute: function (cost, salvage, life, period) {
17400
17191
  const _cost = toNumber(cost, this.locale);
17401
17192
  const _salvage = toNumber(salvage, this.locale);
@@ -17444,7 +17235,6 @@ const TBILLPRICE = {
17444
17235
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17445
17236
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17446
17237
  ],
17447
- returns: ["NUMBER"],
17448
17238
  compute: function (settlement, maturity, discount) {
17449
17239
  const start = Math.trunc(toNumber(settlement, this.locale));
17450
17240
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17467,7 +17257,6 @@ const TBILLEQ = {
17467
17257
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17468
17258
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17469
17259
  ],
17470
- returns: ["NUMBER"],
17471
17260
  compute: function (settlement, maturity, discount) {
17472
17261
  const start = Math.trunc(toNumber(settlement, this.locale));
17473
17262
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17525,7 +17314,6 @@ const TBILLYIELD = {
17525
17314
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17526
17315
  arg("price (number)", _t("The price at which the security is bought per 100 face value.")),
17527
17316
  ],
17528
- returns: ["NUMBER"],
17529
17317
  compute: function (settlement, maturity, price) {
17530
17318
  const start = Math.trunc(toNumber(settlement, this.locale));
17531
17319
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17565,7 +17353,6 @@ const VDB = {
17565
17353
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The number of months in the first year of depreciation.")),
17566
17354
  arg(`no_switch (number, default=${DEFAULT_VDB_NO_SWITCH})`, _t("Whether to switch to straight-line depreciation when the depreciation is greater than the declining balance calculation.")),
17567
17355
  ],
17568
- returns: ["NUMBER"],
17569
17356
  compute: function (cost, salvage, life, startPeriod, endPeriod, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }, noSwitch = { value: DEFAULT_VDB_NO_SWITCH }) {
17570
17357
  factor = factor || 0;
17571
17358
  const _cost = toNumber(cost, this.locale);
@@ -17630,7 +17417,6 @@ const XIRR = {
17630
17417
  arg("cashflow_dates (range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17631
17418
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the internal rate of return will be.")),
17632
17419
  ],
17633
- returns: ["NUMBER"],
17634
17420
  compute: function (cashflowAmounts, cashflowDates, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17635
17421
  const guess = toNumber(rateGuess, this.locale);
17636
17422
  const _cashFlows = cashflowAmounts.flat().map((val) => toNumber(val, this.locale));
@@ -17701,7 +17487,6 @@ const XNPV = {
17701
17487
  arg("cashflow_amounts (number, range<number>)", _t("An range containing the income or payments associated with the investment.")),
17702
17488
  arg("cashflow_dates (number, range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17703
17489
  ],
17704
- returns: ["NUMBER"],
17705
17490
  compute: function (discount, cashflowAmounts, cashflowDates) {
17706
17491
  const rate = toNumber(discount, this.locale);
17707
17492
  const _cashFlows = isMatrix(cashflowAmounts)
@@ -17768,7 +17553,6 @@ const YIELD = {
17768
17553
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17769
17554
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17770
17555
  ],
17771
- returns: ["NUMBER"],
17772
17556
  compute: function (settlement, maturity, rate, price, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17773
17557
  dayCountConvention = dayCountConvention || 0;
17774
17558
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17843,7 +17627,6 @@ const YIELDDISC = {
17843
17627
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17844
17628
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17845
17629
  ],
17846
- returns: ["NUMBER"],
17847
17630
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17848
17631
  dayCountConvention = dayCountConvention || 0;
17849
17632
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17880,7 +17663,6 @@ const YIELDMAT = {
17880
17663
  arg("price (number)", _t("The price at which the security is bought.")),
17881
17664
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17882
17665
  ],
17883
- returns: ["NUMBER"],
17884
17666
  compute: function (settlement, maturity, issue, rate, price, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17885
17667
  dayCountConvention = dayCountConvention || 0;
17886
17668
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17967,7 +17749,6 @@ const CELL = {
17967
17749
  arg("info_type (string)", _t("The type of information requested. Can be one of %s", CELL_INFO_TYPES.join(", "))),
17968
17750
  arg("reference (meta)", _t("The reference to the cell.")),
17969
17751
  ],
17970
- returns: ["ANY"],
17971
17752
  compute: function (info, reference) {
17972
17753
  const _info = toString(info).toLowerCase();
17973
17754
  assert(() => CELL_INFO_TYPES.includes(_info), _t("The info_type should be one of %s.", CELL_INFO_TYPES.join(", ")));
@@ -18018,7 +17799,6 @@ const CELL = {
18018
17799
  const ISERR = {
18019
17800
  description: _t("Whether a value is an error other than #N/A."),
18020
17801
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18021
- returns: ["BOOLEAN"],
18022
17802
  compute: function (data) {
18023
17803
  const value = data?.value;
18024
17804
  return isEvaluationError(value) && value !== CellErrorType.NotAvailable;
@@ -18031,7 +17811,6 @@ const ISERR = {
18031
17811
  const ISERROR = {
18032
17812
  description: _t("Whether a value is an error."),
18033
17813
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18034
- returns: ["BOOLEAN"],
18035
17814
  compute: function (data) {
18036
17815
  const value = data?.value;
18037
17816
  return isEvaluationError(value);
@@ -18044,7 +17823,6 @@ const ISERROR = {
18044
17823
  const ISLOGICAL = {
18045
17824
  description: _t("Whether a value is `true` or `false`."),
18046
17825
  args: [arg("value (any)", _t("The value to be verified as a logical TRUE or FALSE."))],
18047
- returns: ["BOOLEAN"],
18048
17826
  compute: function (value) {
18049
17827
  return typeof value?.value === "boolean";
18050
17828
  },
@@ -18056,7 +17834,6 @@ const ISLOGICAL = {
18056
17834
  const ISNA = {
18057
17835
  description: _t("Whether a value is the error #N/A."),
18058
17836
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18059
- returns: ["BOOLEAN"],
18060
17837
  compute: function (data) {
18061
17838
  return data?.value === CellErrorType.NotAvailable;
18062
17839
  },
@@ -18068,7 +17845,6 @@ const ISNA = {
18068
17845
  const ISNONTEXT = {
18069
17846
  description: _t("Whether a value is non-textual."),
18070
17847
  args: [arg("value (any)", _t("The value to be checked."))],
18071
- returns: ["BOOLEAN"],
18072
17848
  compute: function (value) {
18073
17849
  return !ISTEXT.compute.bind(this)(value);
18074
17850
  },
@@ -18080,7 +17856,6 @@ const ISNONTEXT = {
18080
17856
  const ISNUMBER = {
18081
17857
  description: _t("Whether a value is a number."),
18082
17858
  args: [arg("value (any)", _t("The value to be verified as a number."))],
18083
- returns: ["BOOLEAN"],
18084
17859
  compute: function (value) {
18085
17860
  return typeof value?.value === "number";
18086
17861
  },
@@ -18092,7 +17867,6 @@ const ISNUMBER = {
18092
17867
  const ISTEXT = {
18093
17868
  description: _t("Whether a value is text."),
18094
17869
  args: [arg("value (any)", _t("The value to be verified as text."))],
18095
- returns: ["BOOLEAN"],
18096
17870
  compute: function (value) {
18097
17871
  return typeof value?.value === "string" && isEvaluationError(value?.value) === false;
18098
17872
  },
@@ -18104,7 +17878,6 @@ const ISTEXT = {
18104
17878
  const ISBLANK = {
18105
17879
  description: _t("Whether the referenced cell is empty"),
18106
17880
  args: [arg("value (any)", _t("Reference to the cell that will be checked for emptiness."))],
18107
- returns: ["BOOLEAN"],
18108
17881
  compute: function (value) {
18109
17882
  return value?.value === null;
18110
17883
  },
@@ -18116,7 +17889,6 @@ const ISBLANK = {
18116
17889
  const NA = {
18117
17890
  description: _t("Returns the error value #N/A."),
18118
17891
  args: [],
18119
- returns: ["BOOLEAN"],
18120
17892
  compute: function () {
18121
17893
  return { value: CellErrorType.NotAvailable };
18122
17894
  },
@@ -18173,7 +17945,6 @@ const AND = {
18173
17945
  arg("logical_expression1 (boolean, range<boolean>)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
18174
17946
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that represent logical values.")),
18175
17947
  ],
18176
- returns: ["BOOLEAN"],
18177
17948
  compute: function (...logicalExpressions) {
18178
17949
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18179
17950
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18187,7 +17958,6 @@ const AND = {
18187
17958
  const FALSE = {
18188
17959
  description: _t("Logical value `false`."),
18189
17960
  args: [],
18190
- returns: ["BOOLEAN"],
18191
17961
  compute: function () {
18192
17962
  return false;
18193
17963
  },
@@ -18203,7 +17973,6 @@ const IF = {
18203
17973
  arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18204
17974
  arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18205
17975
  ],
18206
- returns: ["ANY"],
18207
17976
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18208
17977
  const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18209
17978
  if (result === undefined) {
@@ -18225,7 +17994,6 @@ const IFERROR = {
18225
17994
  arg("value (any)", _t("The value to return if value itself is not an error.")),
18226
17995
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18227
17996
  ],
18228
- returns: ["ANY"],
18229
17997
  compute: function (value, valueIfError = { value: "" }) {
18230
17998
  const result = isEvaluationError(value?.value) ? valueIfError : value;
18231
17999
  if (result === undefined) {
@@ -18247,7 +18015,6 @@ const IFNA = {
18247
18015
  arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18248
18016
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18249
18017
  ],
18250
- returns: ["ANY"],
18251
18018
  compute: function (value, valueIfError = { value: "" }) {
18252
18019
  const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18253
18020
  if (result === undefined) {
@@ -18271,7 +18038,6 @@ const IFS = {
18271
18038
  arg("condition2 (boolean, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18272
18039
  arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18273
18040
  ],
18274
- returns: ["ANY"],
18275
18041
  compute: function (...values) {
18276
18042
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18277
18043
  for (let n = 0; n < values.length - 1; n += 2) {
@@ -18298,7 +18064,6 @@ const NOT = {
18298
18064
  args: [
18299
18065
  arg("logical_expression (boolean)", _t("An expression or reference to a cell holding an expression that represents some logical value.")),
18300
18066
  ],
18301
- returns: ["BOOLEAN"],
18302
18067
  compute: function (logicalExpression) {
18303
18068
  return !toBoolean(logicalExpression);
18304
18069
  },
@@ -18313,7 +18078,6 @@ const OR = {
18313
18078
  arg("logical_expression1 (boolean, range<boolean>)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
18314
18079
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18315
18080
  ],
18316
- returns: ["BOOLEAN"],
18317
18081
  compute: function (...logicalExpressions) {
18318
18082
  const { result, foundBoolean } = boolOr(logicalExpressions);
18319
18083
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18327,7 +18091,6 @@ const OR = {
18327
18091
  const TRUE = {
18328
18092
  description: _t("Logical value `true`."),
18329
18093
  args: [],
18330
- returns: ["BOOLEAN"],
18331
18094
  compute: function () {
18332
18095
  return true;
18333
18096
  },
@@ -18342,7 +18105,6 @@ const XOR = {
18342
18105
  arg("logical_expression1 (boolean, range<boolean>)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
18343
18106
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18344
18107
  ],
18345
- returns: ["BOOLEAN"],
18346
18108
  compute: function (...logicalExpressions) {
18347
18109
  let foundBoolean = false;
18348
18110
  let acc = false;
@@ -18371,9 +18133,229 @@ var logical = /*#__PURE__*/Object.freeze({
18371
18133
  XOR: XOR
18372
18134
  });
18373
18135
 
18374
- //TODO This registry is only used to disable the support of exploded pivot for spreadsheet
18375
- const supportedPivotExplodedFormulaRegistry = new Registry();
18376
- supportedPivotExplodedFormulaRegistry.add("SPREADSHEET", false);
18136
+ const pivotTimeAdapterRegistry = new Registry();
18137
+ function pivotTimeAdapter(granularity) {
18138
+ return pivotTimeAdapterRegistry.get(granularity);
18139
+ }
18140
+ /**
18141
+ * The Time Adapter: Managing Time Periods for Pivot Functions
18142
+ *
18143
+ * Overview:
18144
+ * A time adapter is responsible for managing time periods associated with pivot functions.
18145
+ * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
18146
+ * The adapter's primary role is to normalize period values between spreadsheet functions,
18147
+ * and the pivot.
18148
+ * By normalizing the period value, it can be stored consistently in the pivot.
18149
+ *
18150
+ * Normalization Process:
18151
+ * When working with functions in the spreadsheet, the time adapter normalizes
18152
+ * the provided period to facilitate accurate lookup of values in the pivot.
18153
+ * For instance, if the spreadsheet function represents a day period as a number generated
18154
+ * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
18155
+ *
18156
+ */
18157
+ /**
18158
+ * Normalized value: "12/25/2023"
18159
+ *
18160
+ * Note: Those two format are equivalent:
18161
+ * - "MM/dd/yyyy" (luxon format)
18162
+ * - "mm/dd/yyyy" (spreadsheet format)
18163
+ **/
18164
+ const dayAdapter = {
18165
+ normalizeFunctionValue(value) {
18166
+ const date = toNumber(value, DEFAULT_LOCALE);
18167
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
18168
+ },
18169
+ getFormat(locale) {
18170
+ return (locale ?? DEFAULT_LOCALE).dateFormat;
18171
+ },
18172
+ formatValue(normalizedValue, locale) {
18173
+ locale = locale ?? DEFAULT_LOCALE;
18174
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18175
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18176
+ },
18177
+ toCellValue(normalizedValue) {
18178
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18179
+ },
18180
+ };
18181
+ /**
18182
+ * normalizes day of month number
18183
+ */
18184
+ const dayOfMonthAdapter = {
18185
+ normalizeFunctionValue(value) {
18186
+ const day = toNumber(value, DEFAULT_LOCALE);
18187
+ if (day < 1 || day > 31) {
18188
+ throw new EvaluationError(_t("%s is not a valid day of month (it should be a number between 1 and 31)", day));
18189
+ }
18190
+ return day;
18191
+ },
18192
+ getFormat() {
18193
+ return "0";
18194
+ },
18195
+ formatValue(normalizedValue, locale) {
18196
+ locale = locale ?? DEFAULT_LOCALE;
18197
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18198
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18199
+ },
18200
+ toCellValue(normalizedValue) {
18201
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18202
+ },
18203
+ };
18204
+ /**
18205
+ * Normalized value: "2/2023" for week 2 of 2023
18206
+ */
18207
+ const weekAdapter = {
18208
+ normalizeFunctionValue(value) {
18209
+ const [week, year] = value.split("/");
18210
+ return `${Number(week)}/${Number(year)}`;
18211
+ },
18212
+ getFormat() {
18213
+ return undefined;
18214
+ },
18215
+ formatValue(normalizedValue) {
18216
+ const [week, year] = normalizedValue.split("/");
18217
+ return _t("W%(week)s %(year)s", { week, year });
18218
+ },
18219
+ toCellValue(normalizedValue) {
18220
+ return this.formatValue(normalizedValue);
18221
+ },
18222
+ };
18223
+ /**
18224
+ * normalizes iso week number
18225
+ */
18226
+ const isoWeekNumberAdapter = {
18227
+ normalizeFunctionValue(value) {
18228
+ const isoWeek = toNumber(value, DEFAULT_LOCALE);
18229
+ if (isoWeek < 0 || isoWeek > 53) {
18230
+ throw new EvaluationError(_t("%s is not a valid week (it should be a number between 0 and 53)", isoWeek));
18231
+ }
18232
+ return isoWeek;
18233
+ },
18234
+ getFormat() {
18235
+ return "0";
18236
+ },
18237
+ formatValue(normalizedValue, locale) {
18238
+ locale = locale ?? DEFAULT_LOCALE;
18239
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18240
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18241
+ },
18242
+ toCellValue(normalizedValue) {
18243
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18244
+ },
18245
+ };
18246
+ /**
18247
+ * normalized month value is a string formatted as "MM/yyyy" (luxon format)
18248
+ * e.g. "01/2020" for January 2020
18249
+ */
18250
+ const monthAdapter = {
18251
+ normalizeFunctionValue(value) {
18252
+ const date = toNumber(value, DEFAULT_LOCALE);
18253
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
18254
+ },
18255
+ getFormat() {
18256
+ return "mmmm yyyy";
18257
+ },
18258
+ formatValue(normalizedValue, locale) {
18259
+ locale = locale ?? DEFAULT_LOCALE;
18260
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18261
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18262
+ },
18263
+ toCellValue(normalizedValue) {
18264
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18265
+ },
18266
+ };
18267
+ /**
18268
+ * normalizes month number
18269
+ */
18270
+ const monthNumberAdapter = {
18271
+ normalizeFunctionValue(value) {
18272
+ const month = toNumber(value, DEFAULT_LOCALE);
18273
+ if (month < 1 || month > 12) {
18274
+ throw new EvaluationError(_t("%s is not a valid month (it should be a number between 1 and 12)", month));
18275
+ }
18276
+ return month;
18277
+ },
18278
+ getFormat() {
18279
+ return "0";
18280
+ },
18281
+ formatValue(normalizedValue, locale) {
18282
+ locale = locale ?? DEFAULT_LOCALE;
18283
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18284
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18285
+ },
18286
+ toCellValue(normalizedValue) {
18287
+ return MONTHS[toNumber(normalizedValue, DEFAULT_LOCALE) - 1].toString();
18288
+ },
18289
+ };
18290
+ /**
18291
+ * normalized quarter value is "quarter/year"
18292
+ * e.g. "1/2020" for Q1 2020
18293
+ */
18294
+ const quarterAdapter = {
18295
+ normalizeFunctionValue(value) {
18296
+ const [quarter, year] = value.split("/");
18297
+ return `${quarter}/${year}`;
18298
+ },
18299
+ getFormat() {
18300
+ return undefined;
18301
+ },
18302
+ formatValue(normalizedValue) {
18303
+ const [quarter, year] = normalizedValue.split("/");
18304
+ return _t("Q%(quarter)s %(year)s", { quarter, year });
18305
+ },
18306
+ toCellValue(normalizedValue) {
18307
+ return this.formatValue(normalizedValue);
18308
+ },
18309
+ };
18310
+ /**
18311
+ * normalizes quarter number
18312
+ */
18313
+ const quarterNumberAdapter = {
18314
+ normalizeFunctionValue(value) {
18315
+ const quarter = toNumber(value, DEFAULT_LOCALE);
18316
+ if (quarter < 1 || quarter > 4) {
18317
+ throw new EvaluationError(_t("%s is not a valid quarter (it should be a number between 1 and 4)", quarter));
18318
+ }
18319
+ return quarter;
18320
+ },
18321
+ getFormat() {
18322
+ return "0";
18323
+ },
18324
+ formatValue(normalizedValue, locale) {
18325
+ locale = locale ?? DEFAULT_LOCALE;
18326
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18327
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18328
+ },
18329
+ toCellValue(normalizedValue) {
18330
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18331
+ },
18332
+ };
18333
+ const yearAdapter = {
18334
+ normalizeFunctionValue(value) {
18335
+ return toNumber(value, DEFAULT_LOCALE);
18336
+ },
18337
+ getFormat() {
18338
+ return "0";
18339
+ },
18340
+ formatValue(normalizedValue, locale) {
18341
+ locale = locale ?? DEFAULT_LOCALE;
18342
+ return formatValue(normalizedValue, { locale, format: "0" });
18343
+ },
18344
+ toCellValue(normalizedValue) {
18345
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18346
+ },
18347
+ };
18348
+ pivotTimeAdapterRegistry
18349
+ .add("day", dayAdapter)
18350
+ .add("week", weekAdapter)
18351
+ .add("month", monthAdapter)
18352
+ .add("quarter", quarterAdapter)
18353
+ .add("year", yearAdapter)
18354
+ .add("day_of_month", dayOfMonthAdapter)
18355
+ .add("iso_week_number", isoWeekNumberAdapter)
18356
+ .add("month_number", monthNumberAdapter)
18357
+ .add("quarter_number", quarterNumberAdapter)
18358
+ .add("year_number", yearAdapter);
18377
18359
 
18378
18360
  const AGGREGATOR_NAMES = {
18379
18361
  count: _t("Count"),
@@ -18389,7 +18371,7 @@ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "
18389
18371
  const AGGREGATORS_BY_FIELD_TYPE = {
18390
18372
  integer: NUMBER_CHAR_AGGREGATORS,
18391
18373
  char: NUMBER_CHAR_AGGREGATORS,
18392
- //TODO Support for date and boolean
18374
+ boolean: ["count_distinct", "count", "bool_and", "bool_or"],
18393
18375
  };
18394
18376
  const AGGREGATORS = {};
18395
18377
  for (const type in AGGREGATORS_BY_FIELD_TYPE) {
@@ -18499,6 +18481,44 @@ function toPivotDomain(domainStr) {
18499
18481
  function flatPivotDomain(domain) {
18500
18482
  return domain.flatMap((arg) => [arg.field, arg.value]);
18501
18483
  }
18484
+ /**
18485
+ * Parses the value defining a pivot group in a PIVOT formula
18486
+ * e.g. given the following formula PIVOT.VALUE("1", "stage_id", "42", "status", "won"),
18487
+ * the two group values are "42" and "won".
18488
+ */
18489
+ function toNormalizedPivotValue(dimension, groupValue) {
18490
+ if (groupValue === null || groupValue === "null") {
18491
+ return null;
18492
+ }
18493
+ const groupValueString = typeof groupValue === "boolean"
18494
+ ? toString(groupValue).toLocaleLowerCase()
18495
+ : toString(groupValue);
18496
+ if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
18497
+ throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
18498
+ field: dimension.displayName,
18499
+ type: dimension.type,
18500
+ }));
18501
+ }
18502
+ // represents a field which is not set (=False server side)
18503
+ if (groupValueString === "false") {
18504
+ return false;
18505
+ }
18506
+ const normalizer = pivotNormalizationValueRegistry.get(dimension.type);
18507
+ return normalizer(groupValueString, dimension.granularity);
18508
+ }
18509
+ function normalizeDateTime(value, granularity) {
18510
+ if (!granularity) {
18511
+ throw "";
18512
+ }
18513
+ return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
18514
+ }
18515
+ const pivotNormalizationValueRegistry = new Registry();
18516
+ pivotNormalizationValueRegistry
18517
+ .add("date", normalizeDateTime)
18518
+ .add("datetime", normalizeDateTime)
18519
+ .add("integer", (value) => toNumber(value, DEFAULT_LOCALE))
18520
+ .add("boolean", (value) => toBoolean(value))
18521
+ .add("char", (value) => toString(value));
18502
18522
 
18503
18523
  /**
18504
18524
  * Get the pivot ID from the formula pivot ID.
@@ -18575,7 +18595,6 @@ const ADDRESS = {
18575
18595
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18576
18596
  arg("sheet (string, optional)", _t("A string indicating the name of the sheet into which the address points.")),
18577
18597
  ],
18578
- returns: ["STRING"],
18579
18598
  compute: function (row, column, absoluteRelativeMode = { value: DEFAULT_ABSOLUTE_RELATIVE_MODE }, useA1Notation = { value: true }, sheet) {
18580
18599
  const rowNumber = strictToInteger(row, this.locale);
18581
18600
  const colNumber = strictToInteger(column, this.locale);
@@ -18612,7 +18631,6 @@ const COLUMN = {
18612
18631
  args: [
18613
18632
  arg("cell_reference (meta, default='this cell')", _t("The cell whose column number will be returned. Column A corresponds to 1. By default, the function use the cell in which the formula is entered.")),
18614
18633
  ],
18615
- returns: ["NUMBER"],
18616
18634
  compute: function (cellReference) {
18617
18635
  if (isEvaluationError(cellReference?.value)) {
18618
18636
  throw cellReference;
@@ -18630,7 +18648,6 @@ const COLUMN = {
18630
18648
  const COLUMNS = {
18631
18649
  description: _t("Number of columns in a specified array or range."),
18632
18650
  args: [arg("range (meta)", _t("The range whose column count will be returned."))],
18633
- returns: ["NUMBER"],
18634
18651
  compute: function (range) {
18635
18652
  if (isEvaluationError(range?.value)) {
18636
18653
  throw range;
@@ -18651,7 +18668,6 @@ const HLOOKUP = {
18651
18668
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18652
18669
  arg(`is_sorted (boolean, default=${DEFAULT_IS_SORTED})`, _t("Indicates whether the row to be searched (the first row of the specified range) is sorted, in which case the closest match for search_key will be returned.")),
18653
18670
  ],
18654
- returns: ["ANY"],
18655
18671
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18656
18672
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18657
18673
  assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18681,7 +18697,6 @@ const INDEX = {
18681
18697
  arg("row (number, default=0)", _t("The index of the row to be returned from within the reference range of cells.")),
18682
18698
  arg("column (number, default=0)", _t("The index of the column to be returned from within the reference range of cells.")),
18683
18699
  ],
18684
- returns: ["ANY"],
18685
18700
  compute: function (reference, row = { value: 0 }, column = { value: 0 }) {
18686
18701
  const _reference = toMatrix(reference);
18687
18702
  const _row = toNumber(row.value, this.locale);
@@ -18712,7 +18727,6 @@ const INDIRECT = {
18712
18727
  arg("reference (string)", _t("The range of cells from which the values are returned.")),
18713
18728
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18714
18729
  ],
18715
- returns: ["ANY"],
18716
18730
  compute: function (reference, useA1Notation = { value: true }) {
18717
18731
  let _reference = reference?.value?.toString();
18718
18732
  if (!_reference) {
@@ -18767,7 +18781,6 @@ const LOOKUP = {
18767
18781
  arg("search_array (range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18768
18782
  arg("result_range (range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18769
18783
  ],
18770
- returns: ["ANY"],
18771
18784
  compute: function (searchKey, searchArray, resultRange) {
18772
18785
  let nbCol = searchArray.length;
18773
18786
  let nbRow = searchArray[0].length;
@@ -18808,7 +18821,6 @@ const MATCH = {
18808
18821
  arg("range (any, range)", _t("The one-dimensional array to be searched.")),
18809
18822
  arg(`search_type (number, default=${DEFAULT_SEARCH_TYPE})`, _t("The search method. 1 (default) finds the largest value less than or equal to search_key when range is sorted in ascending order. 0 finds the exact value when range is unsorted. -1 finds the smallest value greater than or equal to search_key when range is sorted in descending order.")),
18810
18823
  ],
18811
- returns: ["NUMBER"],
18812
18824
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18813
18825
  let _searchType = toNumber(searchType, this.locale);
18814
18826
  const nbCol = range.length;
@@ -18847,7 +18859,6 @@ const ROW = {
18847
18859
  args: [
18848
18860
  arg("cell_reference (meta, default='this cell')", _t("The cell whose row number will be returned. By default, this function uses the cell in which the formula is entered.")),
18849
18861
  ],
18850
- returns: ["NUMBER"],
18851
18862
  compute: function (cellReference) {
18852
18863
  if (isEvaluationError(cellReference?.value)) {
18853
18864
  throw cellReference;
@@ -18865,7 +18876,6 @@ const ROW = {
18865
18876
  const ROWS = {
18866
18877
  description: _t("Number of rows in a specified array or range."),
18867
18878
  args: [arg("range (meta)", _t("The range whose row count will be returned."))],
18868
- returns: ["NUMBER"],
18869
18879
  compute: function (range) {
18870
18880
  if (isEvaluationError(range?.value)) {
18871
18881
  throw range;
@@ -18886,7 +18896,6 @@ const VLOOKUP = {
18886
18896
  arg("index (number)", _t("The column index of the value to be returned, where the first column in range is numbered 1.")),
18887
18897
  arg(`is_sorted (boolean, default=${DEFAULT_IS_SORTED})`, _t("Indicates whether the column to be searched (the first column of the specified range) is sorted, in which case the closest match for search_key will be returned.")),
18888
18898
  ],
18889
- returns: ["ANY"],
18890
18899
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18891
18900
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18892
18901
  assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18932,7 +18941,6 @@ const XLOOKUP = {
18932
18941
  (-2) Perform a binary search that relies on lookup_array being sorted in descending order. If not sorted, invalid results will be returned.\
18933
18942
  ")),
18934
18943
  ],
18935
- returns: ["ANY"],
18936
18944
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18937
18945
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18938
18946
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
@@ -18988,12 +18996,6 @@ const PIVOT_VALUE = {
18988
18996
  assertDomainLength(_domainArgs);
18989
18997
  const pivot = this.getters.getPivot(pivotId);
18990
18998
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18991
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
18992
- return {
18993
- value: CellErrorType.GenericError,
18994
- message: _t("This pivot does not support PIVOT.VALUE formula"),
18995
- };
18996
- }
18997
18999
  addPivotDependencies(this, coreDefinition);
18998
19000
  const error = pivot.assertIsValid({ throwOnError: false });
18999
19001
  if (error) {
@@ -19009,7 +19011,6 @@ const PIVOT_VALUE = {
19009
19011
  }
19010
19012
  return { value, format };
19011
19013
  },
19012
- returns: ["NUMBER", "STRING"],
19013
19014
  };
19014
19015
  const PIVOT_HEADER = {
19015
19016
  description: _t("Get the header of a pivot."),
@@ -19025,12 +19026,6 @@ const PIVOT_HEADER = {
19025
19026
  assertDomainLength(_domainArgs);
19026
19027
  const pivot = this.getters.getPivot(_pivotId);
19027
19028
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19028
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
19029
- return {
19030
- value: CellErrorType.GenericError,
19031
- message: _t("This pivot does not support PIVOT.VALUE formula"),
19032
- };
19033
- }
19034
19029
  addPivotDependencies(this, coreDefinition);
19035
19030
  const error = pivot.assertIsValid({ throwOnError: false });
19036
19031
  if (error) {
@@ -19055,7 +19050,6 @@ const PIVOT_HEADER = {
19055
19050
  : format,
19056
19051
  };
19057
19052
  },
19058
- returns: ["NUMBER", "STRING"],
19059
19053
  };
19060
19054
  const PIVOT = {
19061
19055
  description: _t("Get a pivot table."),
@@ -19122,7 +19116,6 @@ const PIVOT = {
19122
19116
  }
19123
19117
  return result;
19124
19118
  },
19125
- returns: ["RANGE<ANY>"],
19126
19119
  };
19127
19120
 
19128
19121
  var lookup = /*#__PURE__*/Object.freeze({
@@ -19153,7 +19146,6 @@ const ADD = {
19153
19146
  arg("value1 (number)", _t("The first addend.")),
19154
19147
  arg("value2 (number)", _t("The second addend.")),
19155
19148
  ],
19156
- returns: ["NUMBER"],
19157
19149
  compute: function (value1, value2) {
19158
19150
  return {
19159
19151
  value: toNumber(value1, this.locale) + toNumber(value2, this.locale),
@@ -19170,7 +19162,6 @@ const CONCAT = {
19170
19162
  arg("value1 (string)", _t("The value to which value2 will be appended.")),
19171
19163
  arg("value2 (string)", _t("The value to append to value1.")),
19172
19164
  ],
19173
- returns: ["STRING"],
19174
19165
  compute: function (value1, value2) {
19175
19166
  return toString(value1) + toString(value2);
19176
19167
  },
@@ -19185,7 +19176,6 @@ const DIVIDE = {
19185
19176
  arg("dividend (number)", _t("The number to be divided.")),
19186
19177
  arg("divisor (number)", _t("The number to divide by.")),
19187
19178
  ],
19188
- returns: ["NUMBER"],
19189
19179
  compute: function (dividend, divisor) {
19190
19180
  const _divisor = toNumber(divisor, this.locale);
19191
19181
  assert(() => _divisor !== 0, _t("The divisor must be different from zero."), CellErrorType.DivisionByZero);
@@ -19208,7 +19198,6 @@ const EQ = {
19208
19198
  arg("value1 (any)", _t("The first value.")),
19209
19199
  arg("value2 (any)", _t("The value to test against value1 for equality.")),
19210
19200
  ],
19211
- returns: ["BOOLEAN"],
19212
19201
  compute: function (value1, value2) {
19213
19202
  let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
19214
19203
  let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
@@ -19261,7 +19250,6 @@ const GT = {
19261
19250
  arg("value1 (any)", _t("The value to test as being greater than value2.")),
19262
19251
  arg("value2 (any)", _t("The second value.")),
19263
19252
  ],
19264
- returns: ["BOOLEAN"],
19265
19253
  compute: function (value1, value2) {
19266
19254
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19267
19255
  return v1 > v2;
@@ -19277,7 +19265,6 @@ const GTE = {
19277
19265
  arg("value1 (any)", _t("The value to test as being greater than or equal to value2.")),
19278
19266
  arg("value2 (any)", _t("The second value.")),
19279
19267
  ],
19280
- returns: ["BOOLEAN"],
19281
19268
  compute: function (value1, value2) {
19282
19269
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19283
19270
  return v1 >= v2;
@@ -19293,7 +19280,6 @@ const LT = {
19293
19280
  arg("value1 (any)", _t("The value to test as being less than value2.")),
19294
19281
  arg("value2 (any)", _t("The second value.")),
19295
19282
  ],
19296
- returns: ["BOOLEAN"],
19297
19283
  compute: function (value1, value2) {
19298
19284
  return !GTE.compute.bind(this)(value1, value2);
19299
19285
  },
@@ -19307,7 +19293,6 @@ const LTE = {
19307
19293
  arg("value1 (any)", _t("The value to test as being less than or equal to value2.")),
19308
19294
  arg("value2 (any)", _t("The second value.")),
19309
19295
  ],
19310
- returns: ["BOOLEAN"],
19311
19296
  compute: function (value1, value2) {
19312
19297
  return !GT.compute.bind(this)(value1, value2);
19313
19298
  },
@@ -19321,7 +19306,6 @@ const MINUS = {
19321
19306
  arg("value1 (number)", _t("The minuend, or number to be subtracted from.")),
19322
19307
  arg("value2 (number)", _t("The subtrahend, or number to subtract from value1.")),
19323
19308
  ],
19324
- returns: ["NUMBER"],
19325
19309
  compute: function (value1, value2) {
19326
19310
  return {
19327
19311
  value: toNumber(value1, this.locale) - toNumber(value2, this.locale),
@@ -19338,7 +19322,6 @@ const MULTIPLY = {
19338
19322
  arg("factor1 (number)", _t("The first multiplicand.")),
19339
19323
  arg("factor2 (number)", _t("The second multiplicand.")),
19340
19324
  ],
19341
- returns: ["NUMBER"],
19342
19325
  compute: function (factor1, factor2) {
19343
19326
  return {
19344
19327
  value: toNumber(factor1, this.locale) * toNumber(factor2, this.locale),
@@ -19355,7 +19338,6 @@ const NE = {
19355
19338
  arg("value1 (any)", _t("The first value.")),
19356
19339
  arg("value2 (any)", _t("The value to test against value1 for inequality.")),
19357
19340
  ],
19358
- returns: ["BOOLEAN"],
19359
19341
  compute: function (value1, value2) {
19360
19342
  return !EQ.compute.bind(this)(value1, value2);
19361
19343
  },
@@ -19369,7 +19351,6 @@ const POW = {
19369
19351
  arg("base (number)", _t("The number to raise to the exponent power.")),
19370
19352
  arg("exponent (number)", _t("The exponent to raise base to.")),
19371
19353
  ],
19372
- returns: ["NUMBER"],
19373
19354
  compute: function (base, exponent) {
19374
19355
  return POWER.compute.bind(this)(base, exponent);
19375
19356
  },
@@ -19382,7 +19363,6 @@ const UMINUS = {
19382
19363
  args: [
19383
19364
  arg("value (number)", _t("The number to have its sign reversed. Equivalently, the number to multiply by -1.")),
19384
19365
  ],
19385
- returns: ["NUMBER"],
19386
19366
  compute: function (value) {
19387
19367
  return {
19388
19368
  value: -toNumber(value, this.locale),
@@ -19396,7 +19376,6 @@ const UMINUS = {
19396
19376
  const UNARY_PERCENT = {
19397
19377
  description: _t("Value interpreted as a percentage."),
19398
19378
  args: [arg("percentage (number)", _t("The value to interpret as a percentage."))],
19399
- returns: ["NUMBER"],
19400
19379
  compute: function (percentage) {
19401
19380
  return toNumber(percentage, this.locale) / 100;
19402
19381
  },
@@ -19407,7 +19386,6 @@ const UNARY_PERCENT = {
19407
19386
  const UPLUS = {
19408
19387
  description: _t("A specified number, unchanged."),
19409
19388
  args: [arg("value (any)", _t("The number to return."))],
19410
- returns: ["ANY"],
19411
19389
  compute: function (value = { value: null }) {
19412
19390
  return value;
19413
19391
  },
@@ -19443,7 +19421,6 @@ const CHAR = {
19443
19421
  args: [
19444
19422
  arg("table_number (number)", _t("The number of the character to look up from the current Unicode table in decimal format.")),
19445
19423
  ],
19446
- returns: ["STRING"],
19447
19424
  compute: function (tableNumber) {
19448
19425
  const _tableNumber = Math.trunc(toNumber(tableNumber, this.locale));
19449
19426
  assert(() => _tableNumber >= 1, _t("The table_number (%s) is out of range.", _tableNumber.toString()));
@@ -19457,7 +19434,6 @@ const CHAR = {
19457
19434
  const CLEAN = {
19458
19435
  description: _t("Remove non-printable characters from a piece of text."),
19459
19436
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
19460
- returns: ["STRING"],
19461
19437
  compute: function (text) {
19462
19438
  const _text = toString(text);
19463
19439
  let cleanedStr = "";
@@ -19479,7 +19455,6 @@ const CONCATENATE = {
19479
19455
  arg("string1 (string, range<string>)", _t("The initial string.")),
19480
19456
  arg("string2 (string, range<string>, repeating)", _t("More strings to append in sequence.")),
19481
19457
  ],
19482
- returns: ["STRING"],
19483
19458
  compute: function (...datas) {
19484
19459
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
19485
19460
  },
@@ -19494,7 +19469,6 @@ const EXACT = {
19494
19469
  arg("string1 (string)", _t("The first string to compare.")),
19495
19470
  arg("string2 (string)", _t("The second string to compare.")),
19496
19471
  ],
19497
- returns: ["BOOLEAN"],
19498
19472
  compute: function (string1, string2) {
19499
19473
  return toString(string1) === toString(string2);
19500
19474
  },
@@ -19510,7 +19484,6 @@ const FIND = {
19510
19484
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19511
19485
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19512
19486
  ],
19513
- returns: ["NUMBER"],
19514
19487
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19515
19488
  const _searchFor = toString(searchFor);
19516
19489
  const _textToSearch = toString(textToSearch);
@@ -19533,7 +19506,6 @@ const JOIN = {
19533
19506
  arg("value_or_array1 (string, range<string>)", _t("The value or values to be appended using delimiter.")),
19534
19507
  arg("value_or_array2 (string, range<string>, repeating)", _t("More values to be appended using delimiter.")),
19535
19508
  ],
19536
- returns: ["STRING"],
19537
19509
  compute: function (delimiter, ...valuesOrArrays) {
19538
19510
  const _delimiter = toString(delimiter);
19539
19511
  return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
@@ -19548,7 +19520,6 @@ const LEFT = {
19548
19520
  arg("text (string)", _t("The string from which the left portion will be returned.")),
19549
19521
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the left side of string.")),
19550
19522
  ],
19551
- returns: ["STRING"],
19552
19523
  compute: function (text, ...args) {
19553
19524
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19554
19525
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19562,7 +19533,6 @@ const LEFT = {
19562
19533
  const LEN = {
19563
19534
  description: _t("Length of a string."),
19564
19535
  args: [arg("text (string)", _t("The string whose length will be returned."))],
19565
- returns: ["NUMBER"],
19566
19536
  compute: function (text) {
19567
19537
  return toString(text).length;
19568
19538
  },
@@ -19574,7 +19544,6 @@ const LEN = {
19574
19544
  const LOWER = {
19575
19545
  description: _t("Converts a specified string to lowercase."),
19576
19546
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
19577
- returns: ["STRING"],
19578
19547
  compute: function (text) {
19579
19548
  return toString(text).toLowerCase();
19580
19549
  },
@@ -19590,7 +19559,6 @@ const MID = {
19590
19559
  arg("starting_at (number)", _t("The index from the left of string from which to begin extracting. The first character in string has the index 1.")),
19591
19560
  arg("extract_length (number)", _t("The length of the segment to extract.")),
19592
19561
  ],
19593
- returns: ["STRING"],
19594
19562
  compute: function (text, starting_at, extract_length) {
19595
19563
  const _text = toString(text);
19596
19564
  const _starting_at = toNumber(starting_at, this.locale);
@@ -19609,7 +19577,6 @@ const PROPER = {
19609
19577
  args: [
19610
19578
  arg("text_to_capitalize (string)", _t("The text which will be returned with the first letter of each word in uppercase and all other letters in lowercase.")),
19611
19579
  ],
19612
- returns: ["STRING"],
19613
19580
  compute: function (text) {
19614
19581
  const _text = toString(text);
19615
19582
  return _text.replace(wordRegex, (word) => {
@@ -19629,7 +19596,6 @@ const REPLACE = {
19629
19596
  arg("length (number)", _t("The number of characters in the text to be replaced.")),
19630
19597
  arg("new_text (string)", _t("The text which will be inserted into the original text.")),
19631
19598
  ],
19632
- returns: ["STRING"],
19633
19599
  compute: function (text, position, length, newText) {
19634
19600
  const _position = toNumber(position, this.locale);
19635
19601
  assert(() => _position >= 1, _t("The position (%s) must be greater than or equal to 1.", _position.toString()));
@@ -19649,7 +19615,6 @@ const RIGHT = {
19649
19615
  arg("text (string)", _t("The string from which the right portion will be returned.")),
19650
19616
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the right side of string.")),
19651
19617
  ],
19652
- returns: ["STRING"],
19653
19618
  compute: function (text, ...args) {
19654
19619
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19655
19620
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19669,7 +19634,6 @@ const SEARCH = {
19669
19634
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19670
19635
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19671
19636
  ],
19672
- returns: ["NUMBER"],
19673
19637
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19674
19638
  const _searchFor = toString(searchFor).toLowerCase();
19675
19639
  const _textToSearch = toString(textToSearch).toLowerCase();
@@ -19696,7 +19660,6 @@ const SPLIT = {
19696
19660
  arg(`remove_empty_text (boolean, default=${SPLIT_DEFAULT_REMOVE_EMPTY_TEXT})`, _t("Whether or not to remove empty text messages from the split results. The default behavior is to treat \
19697
19661
  consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters.")),
19698
19662
  ],
19699
- returns: ["RANGE<STRING>"],
19700
19663
  compute: function (text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
19701
19664
  const _text = toString(text);
19702
19665
  const _delimiter = escapeRegExp(toString(delimiter));
@@ -19723,7 +19686,6 @@ const SUBSTITUTE = {
19723
19686
  arg("replace_with (string)", _t("The string that will replace search_for.")),
19724
19687
  arg("occurrence_number (number, optional)", _t("The instance of search_for within text_to_search to replace with replace_with. By default, all occurrences of search_for are replaced; however, if occurrence_number is specified, only the indicated instance of search_for is replaced.")),
19725
19688
  ],
19726
- returns: ["NUMBER"],
19727
19689
  compute: function (textToSearch, searchFor, replaceWith, occurrenceNumber) {
19728
19690
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
19729
19691
  assert(() => _occurrenceNumber >= 0, _t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber.toString()));
@@ -19753,7 +19715,6 @@ const TEXTJOIN = {
19753
19715
  arg("text1 (string, range<string>)", _t("Any text item. This could be a string, or an array of strings in a range.")),
19754
19716
  arg("text2 (string, range<string>, repeating)", _t("Additional text item(s).")),
19755
19717
  ],
19756
- returns: ["STRING"],
19757
19718
  compute: function (delimiter, ignoreEmpty, ...textsOrArrays) {
19758
19719
  const _delimiter = toString(delimiter);
19759
19720
  const _ignoreEmpty = toBoolean(ignoreEmpty);
@@ -19770,7 +19731,6 @@ const TRIM = {
19770
19731
  args: [
19771
19732
  arg("text (string)", _t("The text or reference to a cell containing text to be trimmed.")),
19772
19733
  ],
19773
- returns: ["STRING"],
19774
19734
  compute: function (text) {
19775
19735
  return trimContent(toString(text));
19776
19736
  },
@@ -19782,7 +19742,6 @@ const TRIM = {
19782
19742
  const UPPER = {
19783
19743
  description: _t("Converts a specified string to uppercase."),
19784
19744
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
19785
- returns: ["STRING"],
19786
19745
  compute: function (text) {
19787
19746
  return toString(text).toUpperCase();
19788
19747
  },
@@ -19797,7 +19756,6 @@ const TEXT = {
19797
19756
  arg("number (number)", _t("The number, date or time to format.")),
19798
19757
  arg("format (string)", _t("The pattern by which to format the number, enclosed in quotation marks.")),
19799
19758
  ],
19800
- returns: ["STRING"],
19801
19759
  compute: function (number, format) {
19802
19760
  const _number = toNumber(number, this.locale);
19803
19761
  return formatValue(_number, { format: toString(format), locale: this.locale });
@@ -19838,7 +19796,6 @@ const HYPERLINK = {
19838
19796
  arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")),
19839
19797
  arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks.")),
19840
19798
  ],
19841
- returns: ["STRING"],
19842
19799
  compute: function (url, linkLabel) {
19843
19800
  const processedUrl = toString(url).trim();
19844
19801
  const processedLabel = toString(linkLabel) || processedUrl;
@@ -19897,6 +19854,9 @@ function addInputHandling(descr) {
19897
19854
  }
19898
19855
  args[i] = arg[0][0];
19899
19856
  }
19857
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19858
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19859
+ }
19900
19860
  }
19901
19861
  return descr.compute.apply(this, args);
19902
19862
  }
@@ -21491,12 +21451,6 @@ function compileTokens(tokens) {
21491
21451
  // detect when an argument need to be evaluated as a meta argument
21492
21452
  const isMeta = argTypes.includes("META");
21493
21453
  const hasRange = argTypes.some((t) => isRangeType(t));
21494
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21495
- if (isRangeOnly) {
21496
- if (!isRangeInput(currentArg)) {
21497
- throw new BadExpressionError(_t("Function %(function_name)s expects the parameter %(arg_index)s to be a reference to a cell or a range.", { function_name: functionName, arg_index: i + 1 }));
21498
- }
21499
- }
21500
21454
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21501
21455
  }
21502
21456
  return compiledArgs;
@@ -21661,16 +21615,6 @@ function assertEnoughArgs(ast) {
21661
21615
  function isRangeType(type) {
21662
21616
  return type.startsWith("RANGE");
21663
21617
  }
21664
- function isRangeInput(arg) {
21665
- if (arg.type === "REFERENCE") {
21666
- return true;
21667
- }
21668
- if (arg.type === "FUNCALL") {
21669
- const fnDef = functions$1[arg.value.toUpperCase()];
21670
- return fnDef && isRangeType(fnDef.returns[0]);
21671
- }
21672
- return false;
21673
- }
21674
21618
 
21675
21619
  const functions = functionRegistry.content;
21676
21620
  function isExportableToExcel(tokens) {
@@ -21714,11 +21658,14 @@ const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
21714
21658
  function makeFieldProposal(field, granularity) {
21715
21659
  const groupBy = granularity ? `${field.name}:${granularity}` : field.name;
21716
21660
  const quotedGroupBy = `"${groupBy}"`;
21661
+ const fuzzySearchKey = field.string !== field.name
21662
+ ? field.string + quotedGroupBy // search on translated name and on technical name
21663
+ : quotedGroupBy;
21717
21664
  return {
21718
21665
  text: quotedGroupBy,
21719
21666
  description: field.string + (field.help ? ` (${field.help})` : ""),
21720
21667
  htmlContent: [{ value: quotedGroupBy, color: tokenColors.STRING }],
21721
- fuzzySearchKey: field.string + quotedGroupBy, // search on translated name and on technical name
21668
+ fuzzySearchKey,
21722
21669
  };
21723
21670
  }
21724
21671
  /**
@@ -21778,6 +21725,14 @@ function getNumberOfPivotFunctions(tokens) {
21778
21725
  return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS).length;
21779
21726
  }
21780
21727
 
21728
+ /**
21729
+ * Registry to enable or disable the support of positional arguments
21730
+ * (with a leading #) in pivot functions
21731
+ * e.g. =PIVOT.VALUE(1,"probability","#stage",1)
21732
+ */
21733
+ const supportedPivotPositionalFormulaRegistry = new Registry();
21734
+ supportedPivotPositionalFormulaRegistry.add("SPREADSHEET", false);
21735
+
21781
21736
  autoCompleteProviders.add("pivot_ids", {
21782
21737
  sequence: 50,
21783
21738
  autoSelectFirstProposal: true,
@@ -21796,10 +21751,6 @@ autoCompleteProviders.add("pivot_ids", {
21796
21751
  return pivotIds
21797
21752
  .map((pivotId) => {
21798
21753
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21799
- if (functionContext.parent.toUpperCase() !== "PIVOT" &&
21800
- !supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21801
- return undefined;
21802
- }
21803
21754
  const formulaId = this.getters.getPivotFormulaId(pivotId);
21804
21755
  const str = `${formulaId}`;
21805
21756
  return {
@@ -21827,15 +21778,13 @@ autoCompleteProviders.add("pivot_measures", {
21827
21778
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21828
21779
  return [];
21829
21780
  }
21830
- const dataSource = this.getters.getPivot(pivotId);
21831
- const fields = dataSource.getFields();
21781
+ const pivot = this.getters.getPivot(pivotId);
21782
+ pivot.init();
21783
+ const fields = pivot.getFields();
21832
21784
  if (!fields) {
21833
21785
  return [];
21834
21786
  }
21835
21787
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21836
- if (!supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21837
- return [];
21838
- }
21839
21788
  return definition.measures
21840
21789
  .map((measure) => {
21841
21790
  if (measure.name === "__count") {
@@ -21871,16 +21820,13 @@ autoCompleteProviders.add("pivot_group_fields", {
21871
21820
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21872
21821
  return;
21873
21822
  }
21874
- const dataSource = this.getters.getPivot(pivotId);
21875
- const fields = dataSource.getFields();
21823
+ const pivot = this.getters.getPivot(pivotId);
21824
+ pivot.init();
21825
+ const fields = pivot.getFields();
21876
21826
  if (!fields) {
21877
21827
  return;
21878
21828
  }
21879
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21880
- const { columns, rows } = dataSource.definition;
21881
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21882
- return [];
21883
- }
21829
+ const { columns, rows } = pivot.definition;
21884
21830
  let args = functionContext.args;
21885
21831
  if (functionContext?.parent.toUpperCase() === "PIVOT.VALUE") {
21886
21832
  args = args.filter((ast, index) => index % 2 === 0); // keep only the field names
@@ -21917,6 +21863,9 @@ autoCompleteProviders.add("pivot_group_fields", {
21917
21863
  return field ? makeFieldProposal(field, granularity) : undefined;
21918
21864
  })
21919
21865
  .concat(groupBys.map((groupBy) => {
21866
+ if (!supportedPivotPositionalFormulaRegistry.get(pivot.type)) {
21867
+ return undefined;
21868
+ }
21920
21869
  const fieldName = groupBy.split(":")[0];
21921
21870
  const field = fields[fieldName];
21922
21871
  if (!field) {
@@ -21965,12 +21914,8 @@ autoCompleteProviders.add("pivot_group_values", {
21965
21914
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21966
21915
  return;
21967
21916
  }
21968
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21969
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21970
- return [];
21971
- }
21972
- const dataSource = this.getters.getPivot(pivotId);
21973
- if (!dataSource.isValid()) {
21917
+ const pivot = this.getters.getPivot(pivotId);
21918
+ if (!pivot.isValid()) {
21974
21919
  return;
21975
21920
  }
21976
21921
  const argPosition = functionContext.argPosition;
@@ -21978,7 +21923,46 @@ autoCompleteProviders.add("pivot_group_values", {
21978
21923
  if (!groupByField) {
21979
21924
  return;
21980
21925
  }
21981
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21926
+ let dimension;
21927
+ try {
21928
+ dimension = pivot.definition.getDimension(groupByField);
21929
+ }
21930
+ catch (error) {
21931
+ return undefined;
21932
+ }
21933
+ if (dimension.granularity === "month_number") {
21934
+ return Object.values(MONTHS).map((monthDisplayName, index) => ({
21935
+ text: `${index + 1}`,
21936
+ fuzzySearchKey: monthDisplayName.toString(),
21937
+ description: monthDisplayName.toString(),
21938
+ htmlContent: [{ value: `${index + 1}`, color: tokenColors.NUMBER }],
21939
+ }));
21940
+ }
21941
+ else if (dimension.granularity === "quarter_number") {
21942
+ return [1, 2, 3, 4].map((quarter) => ({
21943
+ text: `${quarter}`,
21944
+ fuzzySearchKey: `${quarter}`,
21945
+ description: _t("Quarter %s", quarter),
21946
+ htmlContent: [{ value: `${quarter}`, color: tokenColors.NUMBER }],
21947
+ }));
21948
+ }
21949
+ else if (dimension.granularity === "day_of_month") {
21950
+ return range(1, 32).map((dayOfMonth) => ({
21951
+ text: `${dayOfMonth}`,
21952
+ fuzzySearchKey: `${dayOfMonth}`,
21953
+ description: "",
21954
+ htmlContent: [{ value: `${dayOfMonth}`, color: tokenColors.NUMBER }],
21955
+ }));
21956
+ }
21957
+ else if (dimension.granularity === "iso_week_number") {
21958
+ return range(0, 54).map((isoWeekNumber) => ({
21959
+ text: `${isoWeekNumber}`,
21960
+ fuzzySearchKey: `${isoWeekNumber}`,
21961
+ description: "",
21962
+ htmlContent: [{ value: `${isoWeekNumber}`, color: tokenColors.NUMBER }],
21963
+ }));
21964
+ }
21965
+ return pivot.getPossibleFieldValues(dimension).map(({ value, label }) => {
21982
21966
  const isString = typeof value === "string";
21983
21967
  const text = isString ? `"${value}"` : value.toString();
21984
21968
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -22085,7 +22069,9 @@ autofillModifiersRegistry
22085
22069
  tooltip: content
22086
22070
  ? {
22087
22071
  props: {
22088
- content: evaluateLiteral(data.cell?.content, localeFormat).formattedValue,
22072
+ content: data.cell
22073
+ ? evaluateLiteral(data.cell, localeFormat).formattedValue
22074
+ : "",
22089
22075
  },
22090
22076
  }
22091
22077
  : undefined,
@@ -22148,9 +22134,7 @@ function getGroup(cell, cells, filter) {
22148
22134
  if (x === cell) {
22149
22135
  found = true;
22150
22136
  }
22151
- const cellValue = x?.isFormula
22152
- ? undefined
22153
- : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
22137
+ const cellValue = x === undefined || x.isFormula ? undefined : evaluateLiteral(x, { locale: DEFAULT_LOCALE });
22154
22138
  if (cellValue && filter(cellValue)) {
22155
22139
  group.push(cellValue);
22156
22140
  }
@@ -22198,7 +22182,7 @@ autofillRulesRegistry
22198
22182
  })
22199
22183
  .add("increment_alphanumeric_value", {
22200
22184
  condition: (cell) => !cell.isFormula &&
22201
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22185
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22202
22186
  alphaNumericValueRegExp.test(cell.content),
22203
22187
  generateRule: (cell, cells) => {
22204
22188
  const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
@@ -22221,7 +22205,7 @@ autofillRulesRegistry
22221
22205
  })
22222
22206
  .add("copy_text", {
22223
22207
  condition: (cell) => !cell.isFormula &&
22224
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22208
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22225
22209
  generateRule: () => {
22226
22210
  return { type: "COPY_MODIFIER" };
22227
22211
  },
@@ -22236,11 +22220,11 @@ autofillRulesRegistry
22236
22220
  })
22237
22221
  .add("increment_number", {
22238
22222
  condition: (cell) => !cell.isFormula &&
22239
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22223
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22240
22224
  generateRule: (cell, cells) => {
22241
22225
  const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
22242
22226
  const increment = calculateIncrementBasedOnGroup(group);
22243
- const evaluation = evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE });
22227
+ const evaluation = evaluateLiteral(cell, { locale: DEFAULT_LOCALE });
22244
22228
  return {
22245
22229
  type: "INCREMENT_MODIFIER",
22246
22230
  increment,
@@ -25342,8 +25326,7 @@ function zoneToRect(zone) {
25342
25326
  */
25343
25327
  function useSpreadsheetRect() {
25344
25328
  const position = useState({ x: 0, y: 0, width: 0, height: 0 });
25345
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
25346
- updatePosition();
25329
+ let spreadsheetElement = null;
25347
25330
  function updatePosition() {
25348
25331
  if (!spreadsheetElement) {
25349
25332
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -25465,7 +25448,7 @@ class Popover extends Component {
25465
25448
  if (!anchor)
25466
25449
  return;
25467
25450
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25468
- const elDims = {
25451
+ let elDims = {
25469
25452
  width: el.getBoundingClientRect().width,
25470
25453
  height: el.getBoundingClientRect().height,
25471
25454
  };
@@ -25473,7 +25456,14 @@ class Popover extends Component {
25473
25456
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25474
25457
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25475
25458
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25476
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25459
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
25460
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
25461
+ // Re-compute the dimensions after setting the max-width and max-height
25462
+ elDims = {
25463
+ width: el.getBoundingClientRect().width,
25464
+ height: el.getBoundingClientRect().height,
25465
+ };
25466
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25477
25467
  for (const property of Object.keys(style)) {
25478
25468
  el.style[property] = style[property];
25479
25469
  }
@@ -25536,8 +25526,6 @@ class PopoverPositionContext {
25536
25526
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25537
25527
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25538
25528
  const cssProperties = {
25539
- "max-height": maxHeight + "px",
25540
- "max-width": maxWidth + "px",
25541
25529
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25542
25530
  this.spreadsheetOffset.y -
25543
25531
  verticalOffset +
@@ -31351,10 +31339,8 @@ class ChartTitle extends Component {
31351
31339
 
31352
31340
  class AxisDesignEditor extends Component {
31353
31341
  static template = "o-spreadsheet-AxisDesignEditor";
31354
- static components = {
31355
- Section,
31356
- ChartTitle,
31357
- };
31342
+ static components = { Section, ChartTitle };
31343
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31358
31344
  state = useState({ currentAxis: "x" });
31359
31345
  get axisTitleStyle() {
31360
31346
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31505,6 +31491,12 @@ class ChartWithAxisDesignPanel extends Component {
31505
31491
  AxisDesignEditor,
31506
31492
  RoundColorPicker,
31507
31493
  };
31494
+ static props = {
31495
+ figureId: String,
31496
+ definition: Object,
31497
+ canUpdateChart: Function,
31498
+ updateChart: Function,
31499
+ };
31508
31500
  state = useState({ index: 0 });
31509
31501
  get axesList() {
31510
31502
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -33449,13 +33441,17 @@ class SelectMenu extends Component {
33449
33441
  class: { type: String, optional: true },
33450
33442
  };
33451
33443
  static components = { Menu };
33444
+ menuId = new UuidGenerator().uuidv4();
33452
33445
  selectRef = useRef("select");
33453
33446
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33454
33447
  state = useState({
33455
33448
  isMenuOpen: false,
33456
33449
  });
33457
- onClick() {
33458
- this.state.isMenuOpen = true;
33450
+ onClick(ev) {
33451
+ if (ev.closedMenuId === this.menuId) {
33452
+ return;
33453
+ }
33454
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33459
33455
  }
33460
33456
  onMenuClosed() {
33461
33457
  this.state.isMenuOpen = false;
@@ -33463,7 +33459,7 @@ class SelectMenu extends Component {
33463
33459
  get menuPosition() {
33464
33460
  return {
33465
33461
  x: this.selectRect.x,
33466
- y: this.selectRect.y,
33462
+ y: this.selectRect.y + this.selectRect.height,
33467
33463
  };
33468
33464
  }
33469
33465
  }
@@ -34403,9 +34399,9 @@ class FindAndReplacePanel extends Component {
34403
34399
  static props = {
34404
34400
  onCloseSidePanel: Function,
34405
34401
  };
34406
- dataRange = "";
34407
34402
  searchInput = useRef("searchInput");
34408
34403
  store;
34404
+ state;
34409
34405
  get hasSearchResult() {
34410
34406
  return this.store.selectedMatchIndex !== null;
34411
34407
  }
@@ -34435,6 +34431,7 @@ class FindAndReplacePanel extends Component {
34435
34431
  }
34436
34432
  setup() {
34437
34433
  this.store = useLocalStore(FindAndReplaceStore);
34434
+ this.state = useState({ dataRange: "" });
34438
34435
  onMounted(() => this.searchInput.el?.focus());
34439
34436
  }
34440
34437
  onFocusSearch() {
@@ -34471,13 +34468,13 @@ class FindAndReplacePanel extends Component {
34471
34468
  this.store.updateSearchOptions({ searchScope });
34472
34469
  }
34473
34470
  onSearchRangeChanged(ranges) {
34474
- this.dataRange = ranges[0];
34471
+ this.state.dataRange = ranges[0];
34475
34472
  }
34476
34473
  updateDataRange() {
34477
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34474
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34478
34475
  return;
34479
34476
  }
34480
- const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange);
34477
+ const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
34481
34478
  this.store.updateSearchOptions({ specificRange });
34482
34479
  }
34483
34480
  }
@@ -34522,28 +34519,30 @@ class MoreFormatsPanel extends Component {
34522
34519
  }
34523
34520
  }
34524
34521
 
34525
- /** @odoo-module */
34526
- class EditableName extends Component {
34527
- static template = "o-spreadsheet-EditableName";
34522
+ css /* scss */ `
34523
+ .pivot-defer-update {
34524
+ min-height: 35px;
34525
+ background-color: #f8f9fa;
34526
+ }
34527
+ `;
34528
+ class PivotDeferUpdate extends Component {
34529
+ static template = "o-spreadsheet-PivotDeferUpdate";
34528
34530
  static props = {
34529
- name: String,
34530
- displayName: String,
34531
- onChanged: Function,
34531
+ deferUpdate: Boolean,
34532
+ isDirty: Boolean,
34533
+ toggleDeferUpdate: Function,
34534
+ discard: Function,
34535
+ apply: Function,
34532
34536
  };
34533
- state;
34534
- setup() {
34535
- this.state = useState({
34536
- isEditing: false,
34537
- name: "",
34538
- });
34539
- }
34540
- rename() {
34541
- this.state.isEditing = true;
34542
- this.state.name = this.props.name;
34537
+ static components = {
34538
+ Section,
34539
+ Checkbox,
34540
+ };
34541
+ get deferUpdatesLabel() {
34542
+ return _t("Defer updates");
34543
34543
  }
34544
- save() {
34545
- this.props.onChanged(this.state.name.trim());
34546
- this.state.isEditing = false;
34544
+ get deferUpdatesTooltip() {
34545
+ return _t("Changing the pivot definition requires to reload the data. It may take some time.");
34547
34546
  }
34548
34547
  }
34549
34548
 
@@ -34885,6 +34884,135 @@ class PivotLayoutConfigurator extends Component {
34885
34884
  }
34886
34885
  }
34887
34886
 
34887
+ css /* scss */ `
34888
+ .os-cog-wheel-menu-icon {
34889
+ cursor: pointer;
34890
+ }
34891
+
34892
+ .os-cog-wheel-menu {
34893
+ background: white;
34894
+ .btn-link {
34895
+ text-decoration: none;
34896
+ color: #017e84;
34897
+ font-weight: 500;
34898
+ &:hover {
34899
+ color: #01585c;
34900
+ }
34901
+ }
34902
+ }
34903
+ `;
34904
+ class CogWheelMenu extends Component {
34905
+ static template = "o-spreadsheet-CogWheelMenu";
34906
+ static components = { Popover };
34907
+ static props = {
34908
+ items: Array,
34909
+ };
34910
+ buttonRef = useRef("button");
34911
+ popover = useState({ isOpen: false });
34912
+ setup() {
34913
+ useExternalListener(window, "click", (ev) => {
34914
+ if (ev.target !== this.buttonRef.el) {
34915
+ this.popover.isOpen = false;
34916
+ }
34917
+ });
34918
+ }
34919
+ get popoverProps() {
34920
+ const { x, y, width, height } = this.buttonRef.el.getBoundingClientRect();
34921
+ return {
34922
+ anchorRect: { x, y, width, height },
34923
+ positioning: "BottomLeft",
34924
+ };
34925
+ }
34926
+ togglePopover() {
34927
+ this.popover.isOpen = !this.popover.isOpen;
34928
+ }
34929
+ }
34930
+
34931
+ /** @odoo-module */
34932
+ class EditableName extends Component {
34933
+ static template = "o-spreadsheet-EditableName";
34934
+ static props = {
34935
+ name: String,
34936
+ displayName: String,
34937
+ onChanged: Function,
34938
+ };
34939
+ state;
34940
+ setup() {
34941
+ this.state = useState({
34942
+ isEditing: false,
34943
+ name: "",
34944
+ });
34945
+ }
34946
+ rename() {
34947
+ this.state.isEditing = true;
34948
+ this.state.name = this.props.name;
34949
+ }
34950
+ save() {
34951
+ this.props.onChanged(this.state.name.trim());
34952
+ this.state.isEditing = false;
34953
+ }
34954
+ }
34955
+
34956
+ class PivotTitleSection extends Component {
34957
+ static template = "o-spreadsheet-PivotTitleSection";
34958
+ static components = { CogWheelMenu, Section, EditableName };
34959
+ static props = {
34960
+ pivotId: String,
34961
+ };
34962
+ get cogWheelMenuItems() {
34963
+ return [
34964
+ {
34965
+ name: "Duplicate",
34966
+ icon: "fa-copy",
34967
+ onClick: () => this.duplicatePivot(),
34968
+ },
34969
+ {
34970
+ name: "Delete",
34971
+ icon: "fa-trash",
34972
+ onClick: () => this.delete(),
34973
+ },
34974
+ ];
34975
+ }
34976
+ get name() {
34977
+ return this.env.model.getters.getPivotName(this.props.pivotId);
34978
+ }
34979
+ get displayName() {
34980
+ return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
34981
+ }
34982
+ duplicatePivot() {
34983
+ const newPivotId = this.env.model.uuidGenerator.uuidv4();
34984
+ const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
34985
+ pivotId: this.props.pivotId,
34986
+ newPivotId,
34987
+ });
34988
+ const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
34989
+ const type = result.isSuccessful ? "success" : "danger";
34990
+ this.env.notifyUser({
34991
+ text,
34992
+ sticky: false,
34993
+ type,
34994
+ });
34995
+ if (result.isSuccessful) {
34996
+ this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
34997
+ }
34998
+ }
34999
+ delete() {
35000
+ this.env.askConfirmation(_t("Are you sure you want to delete this pivot?"), () => {
35001
+ this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
35002
+ });
35003
+ }
35004
+ onNameChanged(name) {
35005
+ const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
35006
+ this.env.model.dispatch("UPDATE_PIVOT", {
35007
+ pivotId: this.props.pivotId,
35008
+ pivot: {
35009
+ ...pivot,
35010
+ name,
35011
+ },
35012
+ });
35013
+ }
35014
+ }
35015
+
34888
35016
  /**
34889
35017
  * Represent a pivot runtime definition. A pivot runtime definition is a pivot
34890
35018
  * definition that has been enriched to include the display name of its attributes
@@ -35189,7 +35317,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
35189
35317
  }
35190
35318
  const row = rows[index];
35191
35319
  const rowName = row.nameWithGranularity;
35192
- const groups = groupBy(dataEntries, row);
35320
+ const groups = groupPivotDataEntriesBy(dataEntries, row);
35193
35321
  const orderedKeys = orderDataEntriesKeys(groups, row);
35194
35322
  const pivotTableRows = [];
35195
35323
  const _fields = fields.concat(rowName);
@@ -35219,7 +35347,7 @@ function dataEntriesToColumnsTree(dataEntries, columns, index) {
35219
35347
  }
35220
35348
  const column = columns[index];
35221
35349
  const colName = columns[index].nameWithGranularity;
35222
- const groups = groupBy(dataEntries, column);
35350
+ const groups = groupPivotDataEntriesBy(dataEntries, column);
35223
35351
  const orderedKeys = orderDataEntriesKeys(groups, columns[index]);
35224
35352
  return orderedKeys.map((value) => {
35225
35353
  return {
@@ -35317,7 +35445,7 @@ function columnsTreeToColumns(mainTree, definition) {
35317
35445
  /**
35318
35446
  * Group the dataEntries based on the given dimension
35319
35447
  */
35320
- function groupBy(dataEntries, dimension) {
35448
+ function groupPivotDataEntriesBy(dataEntries, dimension) {
35321
35449
  return Object.groupBy(dataEntries, keySelector(dimension));
35322
35450
  }
35323
35451
  /**
@@ -35367,7 +35495,7 @@ function createDate(dimension, value, locale) {
35367
35495
  number = Math.floor(date.getMonth() / 3) + 1;
35368
35496
  break;
35369
35497
  case "month_number":
35370
- number = date.getMonth();
35498
+ number = date.getMonth() + 1;
35371
35499
  break;
35372
35500
  case "iso_week_number":
35373
35501
  number = date.getIsoWeek();
@@ -35379,7 +35507,7 @@ function createDate(dimension, value, locale) {
35379
35507
  number = Math.floor(toNumber(value, locale));
35380
35508
  break;
35381
35509
  }
35382
- MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = number;
35510
+ MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = toNormalizedPivotValue(dimension, number);
35383
35511
  }
35384
35512
  return MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`];
35385
35513
  }
@@ -35525,7 +35653,7 @@ class SpreadsheetPivot {
35525
35653
  return this._definition;
35526
35654
  }
35527
35655
  isValid() {
35528
- if (this.invalidRangeError || !this._definition) {
35656
+ if (this.invalidRangeError || !this.definition) {
35529
35657
  return false;
35530
35658
  }
35531
35659
  for (const measure of this.definition.measures) {
@@ -35582,25 +35710,19 @@ class SpreadsheetPivot {
35582
35710
  const dimension = this.getDimension(lastNode.field);
35583
35711
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
35584
35712
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
35713
+ if (dimension.type === "date") {
35714
+ const adapter = pivotTimeAdapter(dimension.granularity);
35715
+ return {
35716
+ value: adapter.toCellValue(toNormalizedPivotValue(dimension, lastNode.value)),
35717
+ format: adapter.getFormat(this.getters.getLocale()),
35718
+ };
35719
+ }
35585
35720
  if (!finalCell) {
35586
35721
  return { value: "" };
35587
35722
  }
35588
35723
  if (finalCell.value === null) {
35589
35724
  return { value: _t("(Undefined)") };
35590
35725
  }
35591
- if (dimension.type === "date") {
35592
- if (dimension.granularity === "day") {
35593
- return {
35594
- value: toNumber(finalCell.value, this.getters.getLocale()),
35595
- format: this.getters.getLocale().dateFormat,
35596
- };
35597
- }
35598
- if (dimension.granularity === "month_number") {
35599
- return {
35600
- value: MONTHS[toNumber(finalCell.value, this.getters.getLocale())].toString(),
35601
- };
35602
- }
35603
- }
35604
35726
  return {
35605
35727
  value: finalCell.value,
35606
35728
  format: finalCell.format,
@@ -35625,9 +35747,12 @@ class SpreadsheetPivot {
35625
35747
  format: operator.format(values[0]),
35626
35748
  };
35627
35749
  }
35628
- getPossibleFieldValues(groupBy) {
35629
- //TODO This method should be implemented for the autocomplete feature
35630
- throw new Error("Method not implemented.");
35750
+ getPossibleFieldValues(dimension) {
35751
+ const values = [];
35752
+ for (const value in groupPivotDataEntriesBy(this.dataEntries, dimension)) {
35753
+ values.push({ value, label: "" });
35754
+ }
35755
+ return values;
35631
35756
  }
35632
35757
  getTableStructure() {
35633
35758
  if (!this.isValid()) {
@@ -35647,7 +35772,8 @@ class SpreadsheetPivot {
35647
35772
  filterDataEntriesFromDomainNode(dataEntries, domain) {
35648
35773
  const { field, value } = domain;
35649
35774
  const dimension = this.getDimension(field);
35650
- return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` === value);
35775
+ return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` ===
35776
+ `${toNormalizedPivotValue(dimension, value)}`);
35651
35777
  }
35652
35778
  getDimension(nameWithGranularity) {
35653
35779
  return this.definition.getDimension(nameWithGranularity);
@@ -35783,15 +35909,8 @@ pivotRegistry.add("SPREADSHEET", {
35783
35909
 
35784
35910
  class PivotSidePanelStore extends SpreadsheetStore {
35785
35911
  pivotId;
35786
- mutators = [
35787
- "reset",
35788
- "deferUpdates",
35789
- "applyUpdate",
35790
- "discardPendingUpdate",
35791
- "renamePivot",
35792
- "update",
35793
- ];
35794
- updatesAreDeferred = true;
35912
+ mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
35913
+ updatesAreDeferred = false;
35795
35914
  draft = null;
35796
35915
  constructor(get, pivotId) {
35797
35916
  super(get);
@@ -35908,16 +36027,6 @@ class PivotSidePanelStore extends SpreadsheetStore {
35908
36027
  discardPendingUpdate() {
35909
36028
  this.draft = null;
35910
36029
  }
35911
- renamePivot(name) {
35912
- const pivot = this.getters.getPivotCoreDefinition(this.pivotId);
35913
- this.model.dispatch("UPDATE_PIVOT", {
35914
- pivotId: this.pivotId,
35915
- pivot: {
35916
- ...pivot,
35917
- name,
35918
- },
35919
- });
35920
- }
35921
36030
  update(definitionUpdate) {
35922
36031
  const coreDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
35923
36032
  const definition = { ...coreDefinition, ...this.draft, ...definitionUpdate };
@@ -36000,8 +36109,9 @@ class PivotSpreadsheetSidePanel extends Component {
36000
36109
  PivotLayoutConfigurator,
36001
36110
  Section,
36002
36111
  SelectionInput,
36003
- EditableName,
36004
36112
  Checkbox,
36113
+ PivotDeferUpdate,
36114
+ PivotTitleSection,
36005
36115
  };
36006
36116
  store;
36007
36117
  state;
@@ -36030,21 +36140,9 @@ class PivotSpreadsheetSidePanel extends Component {
36030
36140
  get pivot() {
36031
36141
  return this.store.pivot;
36032
36142
  }
36033
- get name() {
36034
- return this.env.model.getters.getPivotName(this.props.pivotId);
36035
- }
36036
- get displayName() {
36037
- return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
36038
- }
36039
36143
  get definition() {
36040
36144
  return this.store.definition;
36041
36145
  }
36042
- get deferUpdatesLabel() {
36043
- return _t("Defer updates");
36044
- }
36045
- get deferUpdatesTooltip() {
36046
- return _t("Changing the pivot definition requires to reload the data. It may take some time.");
36047
- }
36048
36146
  onSelectionChanged(ranges) {
36049
36147
  this.state.rangeHasChanged = true;
36050
36148
  this.state.range = ranges[0];
@@ -36065,35 +36163,9 @@ class PivotSpreadsheetSidePanel extends Component {
36065
36163
  this.store.applyUpdate();
36066
36164
  }
36067
36165
  }
36068
- duplicatePivot() {
36069
- const newPivotId = this.env.model.uuidGenerator.uuidv4();
36070
- const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
36071
- pivotId: this.props.pivotId,
36072
- newPivotId,
36073
- });
36074
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
36075
- const type = result.isSuccessful ? "success" : "danger";
36076
- this.env.notifyUser({
36077
- text,
36078
- sticky: false,
36079
- type,
36080
- });
36081
- if (result.isSuccessful) {
36082
- this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
36083
- }
36084
- }
36085
- onNameChanged(name) {
36086
- this.store.renamePivot(name);
36087
- }
36088
36166
  onDimensionsUpdated(definition) {
36089
36167
  this.store.update(definition);
36090
36168
  }
36091
- back() {
36092
- this.env.openSidePanel("PivotSidePanel", {});
36093
- }
36094
- delete() {
36095
- this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
36096
- }
36097
36169
  }
36098
36170
 
36099
36171
  const pivotSidePanelRegistry = new Registry();
@@ -36101,44 +36173,17 @@ pivotSidePanelRegistry.add("SPREADSHEET", {
36101
36173
  editor: PivotSpreadsheetSidePanel,
36102
36174
  });
36103
36175
 
36104
- css /* scss */ `
36105
- .o_pivot_list_item {
36106
- cursor: pointer;
36107
- &:hover {
36108
- background-color: #f1f3f4;
36109
- }
36110
- }
36111
- `;
36112
- class PivotListItem extends Component {
36113
- static template = "o-spreadsheet-PivotListItem";
36114
- static props = { pivotId: String };
36115
- setup() {
36116
- const previewRef = useRef("pivotListItem");
36117
- useHighlightsOnHover(previewRef, this);
36118
- }
36119
- selectPivot() {
36120
- this.env.openSidePanel("PivotSidePanel", { pivotId: this.props.pivotId });
36121
- }
36122
- get highlights() {
36123
- return getPivotHighlights(this.env.model.getters, this.props.pivotId);
36124
- }
36125
- }
36126
-
36127
36176
  class PivotSidePanel extends Component {
36128
36177
  static template = "o-spreadsheet-PivotSidePanel";
36129
36178
  static props = {
36130
- pivotId: { type: String, optional: true },
36179
+ pivotId: String,
36131
36180
  onCloseSidePanel: Function,
36132
36181
  };
36133
36182
  static components = {
36134
36183
  PivotLayoutConfigurator,
36135
36184
  Section,
36136
- PivotListItem,
36137
36185
  };
36138
36186
  get sidePanelEditor() {
36139
- if (!this.props.pivotId) {
36140
- throw new Error("pivotId is required to call this function.");
36141
- }
36142
36187
  const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
36143
36188
  if (!pivot) {
36144
36189
  throw new Error("pivotId does not correspond to a pivot.");
@@ -36155,6 +36200,7 @@ css /* scss */ `
36155
36200
  class RemoveDuplicatesPanel extends Component {
36156
36201
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36157
36202
  static components = { ValidationMessages, Section, Checkbox };
36203
+ static props = { onCloseSidePanel: Function };
36158
36204
  state = useState({
36159
36205
  hasHeader: false,
36160
36206
  columns: {},
@@ -37297,21 +37343,15 @@ sidePanelRegistry.add("TableStyleEditorPanel", {
37297
37343
  });
37298
37344
  sidePanelRegistry.add("PivotSidePanel", {
37299
37345
  title: (env, props) => {
37300
- if (props.pivotId) {
37301
- return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37302
- }
37303
- return _t("List of Pivots");
37346
+ return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37304
37347
  },
37305
37348
  Body: PivotSidePanel,
37306
- computeState: (getters, initialProps) => {
37307
- if (!getters.getPivotIds().length) {
37308
- return { isOpen: false };
37309
- }
37310
- let { pivotId } = initialProps;
37311
- if (pivotId && !getters.isExistingPivot(pivotId)) {
37312
- pivotId = undefined;
37313
- }
37314
- return { isOpen: true, props: { pivotId }, key: `pivot_key_${pivotId}` };
37349
+ computeState: (getters, props) => {
37350
+ return {
37351
+ isOpen: getters.isExistingPivot(props.pivotId),
37352
+ props,
37353
+ key: `pivot_key_${props.pivotId}`,
37354
+ };
37315
37355
  },
37316
37356
  });
37317
37357
 
@@ -41569,133 +41609,6 @@ class Grid extends Component {
41569
41609
  }
41570
41610
  }
41571
41611
 
41572
- const pivotTimeAdapterRegistry = new Registry();
41573
- function pivotTimeAdapter(granularity) {
41574
- return pivotTimeAdapterRegistry.get(granularity);
41575
- }
41576
- /**
41577
- * The Time Adapter: Managing Time Periods for Pivot Functions
41578
- *
41579
- * Overview:
41580
- * A time adapter is responsible for managing time periods associated with pivot functions.
41581
- * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
41582
- * The adapter's primary role is to normalize period values between spreadsheet functions,
41583
- * and the pivot.
41584
- * By normalizing the period value, it can be stored consistently in the pivot.
41585
- *
41586
- * Normalization Process:
41587
- * When working with functions in the spreadsheet, the time adapter normalizes
41588
- * the provided period to facilitate accurate lookup of values in the pivot.
41589
- * For instance, if the spreadsheet function represents a day period as a number generated
41590
- * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
41591
- *
41592
- */
41593
- /**
41594
- * Normalized value: "12/25/2023"
41595
- *
41596
- * Note: Those two format are equivalent:
41597
- * - "MM/dd/yyyy" (luxon format)
41598
- * - "mm/dd/yyyy" (spreadsheet format)
41599
- **/
41600
- const dayAdapter = {
41601
- normalizeFunctionValue(value) {
41602
- const date = toNumber(value, DEFAULT_LOCALE);
41603
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
41604
- },
41605
- getFormat(locale) {
41606
- return (locale ?? DEFAULT_LOCALE).dateFormat;
41607
- },
41608
- formatValue(normalizedValue, locale) {
41609
- locale = locale ?? DEFAULT_LOCALE;
41610
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41611
- return formatValue(value, { locale, format: this.getFormat(locale) });
41612
- },
41613
- toCellValue(normalizedValue) {
41614
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41615
- },
41616
- };
41617
- /**
41618
- * Normalized value: "2/2023" for week 2 of 2023
41619
- */
41620
- const weekAdapter = {
41621
- normalizeFunctionValue(value) {
41622
- const [week, year] = value.split("/");
41623
- return `${Number(week)}/${Number(year)}`;
41624
- },
41625
- getFormat() {
41626
- return undefined;
41627
- },
41628
- formatValue(normalizedValue) {
41629
- const [week, year] = normalizedValue.split("/");
41630
- return _t("W%(week)s %(year)s", { week, year });
41631
- },
41632
- toCellValue(normalizedValue) {
41633
- return this.formatValue(normalizedValue);
41634
- },
41635
- };
41636
- /**
41637
- * normalized month value is a string formatted as "MM/yyyy" (luxon format)
41638
- * e.g. "01/2020" for January 2020
41639
- */
41640
- const monthAdapter = {
41641
- normalizeFunctionValue(value) {
41642
- const date = toNumber(value, DEFAULT_LOCALE);
41643
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
41644
- },
41645
- getFormat() {
41646
- return "mmmm yyyy";
41647
- },
41648
- formatValue(normalizedValue, locale) {
41649
- locale = locale ?? DEFAULT_LOCALE;
41650
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41651
- return formatValue(value, { locale, format: this.getFormat(locale) });
41652
- },
41653
- toCellValue(normalizedValue) {
41654
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41655
- },
41656
- };
41657
- /**
41658
- * normalized quarter value is "quarter/year"
41659
- * e.g. "1/2020" for Q1 2020
41660
- */
41661
- const quarterAdapter = {
41662
- normalizeFunctionValue(value) {
41663
- const [quarter, year] = value.split("/");
41664
- return `${quarter}/${year}`;
41665
- },
41666
- getFormat() {
41667
- return undefined;
41668
- },
41669
- formatValue(normalizedValue) {
41670
- const [quarter, year] = normalizedValue.split("/");
41671
- return _t("Q%(quarter)s %(year)s", { quarter, year });
41672
- },
41673
- toCellValue(normalizedValue) {
41674
- return this.formatValue(normalizedValue);
41675
- },
41676
- };
41677
- const yearAdapter = {
41678
- normalizeFunctionValue(value) {
41679
- return toNumber(value, DEFAULT_LOCALE);
41680
- },
41681
- getFormat() {
41682
- return "0";
41683
- },
41684
- formatValue(normalizedValue, locale) {
41685
- locale = locale ?? DEFAULT_LOCALE;
41686
- return formatValue(normalizedValue, { locale, format: "0" });
41687
- },
41688
- toCellValue(normalizedValue) {
41689
- return normalizedValue;
41690
- },
41691
- };
41692
- pivotTimeAdapterRegistry
41693
- .add("day", dayAdapter)
41694
- .add("week", weekAdapter)
41695
- .add("month", monthAdapter)
41696
- .add("quarter", quarterAdapter)
41697
- .add("year", yearAdapter);
41698
-
41699
41612
  /**
41700
41613
  * Represent a raw XML string
41701
41614
  */
@@ -46894,9 +46807,14 @@ class CellPlugin extends CorePlugin {
46894
46807
  }
46895
46808
  createLiteralCell(id, content, format, style) {
46896
46809
  const locale = this.getters.getLocale();
46897
- format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
46810
+ const parsedValue = parseLiteral(content, locale);
46811
+ format =
46812
+ format ||
46813
+ (typeof parsedValue === "number"
46814
+ ? detectDateFormat(content, locale) || detectNumberFormat(content)
46815
+ : undefined);
46898
46816
  if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
46899
- content = toString(parseLiteral(content, locale));
46817
+ content = toString(parsedValue);
46900
46818
  }
46901
46819
  return {
46902
46820
  id,
@@ -46904,6 +46822,7 @@ class CellPlugin extends CorePlugin {
46904
46822
  style,
46905
46823
  format,
46906
46824
  isFormula: false,
46825
+ parsedValue,
46907
46826
  };
46908
46827
  }
46909
46828
  createFormulaCell(id, content, format, style, sheetId) {
@@ -51646,6 +51565,9 @@ class PositionMap {
51646
51565
  get({ sheetId, col, row }) {
51647
51566
  return this.map[sheetId]?.[col]?.[row];
51648
51567
  }
51568
+ getSheet(sheetId) {
51569
+ return this.map[sheetId];
51570
+ }
51649
51571
  has({ sheetId, col, row }) {
51650
51572
  return this.map[sheetId]?.[col]?.[row] !== undefined;
51651
51573
  }
@@ -51664,6 +51586,19 @@ class PositionMap {
51664
51586
  }
51665
51587
  return keys;
51666
51588
  }
51589
+ keysForSheet(sheetId) {
51590
+ const map = this.map[sheetId];
51591
+ if (!map) {
51592
+ return [];
51593
+ }
51594
+ const keys = [];
51595
+ for (const col in map) {
51596
+ for (const row in map[col]) {
51597
+ keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
51598
+ }
51599
+ }
51600
+ return keys;
51601
+ }
51667
51602
  }
51668
51603
 
51669
51604
  function quickselect(arr, k, left, right, compare) {
@@ -52742,6 +52677,9 @@ class Evaluator {
52742
52677
  getEvaluatedPositions() {
52743
52678
  return this.evaluatedCells.keys();
52744
52679
  }
52680
+ getEvaluatedPositionsInSheet(sheetId) {
52681
+ return this.evaluatedCells.keysForSheet(sheetId);
52682
+ }
52745
52683
  getArrayFormulaSpreadingOn(position) {
52746
52684
  if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
52747
52685
  return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
@@ -52750,6 +52688,9 @@ class Evaluator {
52750
52688
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
52751
52689
  }
52752
52690
  updateDependencies(position) {
52691
+ // removing dependencies is slow because it requires
52692
+ // to traverse the entire r-tree.
52693
+ // The data structure is optimized for searches the other way around
52753
52694
  this.formulaDependencies().removeAllDependencies(position);
52754
52695
  const dependencies = this.getDirectDependencies(position);
52755
52696
  this.formulaDependencies().addDependencies(position, dependencies);
@@ -52915,7 +52856,7 @@ class Evaluator {
52915
52856
  this.cellsBeingComputed.add(cellId);
52916
52857
  return cell.isFormula
52917
52858
  ? this.computeFormulaCell(position.sheetId, cell)
52918
- : evaluateLiteral(cell.content, localeFormat);
52859
+ : evaluateLiteral(cell, localeFormat);
52919
52860
  }
52920
52861
  catch (e) {
52921
52862
  e.value = e?.value || CellErrorType.GenericError;
@@ -53185,6 +53126,7 @@ class EvaluationPlugin extends UIPlugin {
53185
53126
  "getEvaluatedCell",
53186
53127
  "getEvaluatedCells",
53187
53128
  "getEvaluatedCellsInZone",
53129
+ "getEvaluatedCellsPositions",
53188
53130
  "getSpreadZone",
53189
53131
  "getArrayFormulaSpreadingOn",
53190
53132
  "isEmpty",
@@ -53276,13 +53218,12 @@ class EvaluationPlugin extends UIPlugin {
53276
53218
  return this.evaluator.getEvaluatedCell(position);
53277
53219
  }
53278
53220
  getEvaluatedCells(sheetId) {
53279
- const rawCells = this.getters.getCells(sheetId) || {};
53280
- const record = {};
53281
- for (let cellId of Object.keys(rawCells)) {
53282
- const position = this.getters.getCellPosition(cellId);
53283
- record[cellId] = this.getEvaluatedCell(position);
53284
- }
53285
- return record;
53221
+ return this.evaluator
53222
+ .getEvaluatedPositionsInSheet(sheetId)
53223
+ .map((position) => this.getEvaluatedCell(position));
53224
+ }
53225
+ getEvaluatedCellsPositions(sheetId) {
53226
+ return this.evaluator.getEvaluatedPositionsInSheet(sheetId);
53286
53227
  }
53287
53228
  getEvaluatedCellsInZone(sheetId, zone) {
53288
53229
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
@@ -54619,17 +54560,18 @@ class PivotUIPlugin extends UIPlugin {
54619
54560
  if (pivotCell.type === "EMPTY") {
54620
54561
  return undefined;
54621
54562
  }
54622
- const domain = pivotCell.domain;
54563
+ let domain = pivotCell.domain;
54623
54564
  if (domain.at(-1)?.field === "measure") {
54624
- return domain.slice(0, -1);
54565
+ domain = domain.slice(0, -1);
54625
54566
  }
54626
- return domain;
54567
+ return { domainArgs: domain, isHeader: pivotCell.type === "HEADER" };
54627
54568
  }
54628
- const domain = toPivotDomain(args.slice(functionName === "PIVOT.VALUE" ? 2 : 1).map((x) => `${x}`));
54569
+ let domain = toPivotDomain(args.slice(functionName === "PIVOT.VALUE" ? 2 : 1).map((x) => `${x}`));
54629
54570
  if (domain.at(-1)?.field === "measure") {
54630
- return domain.slice(0, -1);
54571
+ domain = domain.slice(0, -1);
54631
54572
  }
54632
- return domain;
54573
+ const isHeader = functionName === "PIVOT.HEADER";
54574
+ return { domainArgs: domain, isHeader };
54633
54575
  }
54634
54576
  getPivot(pivotId) {
54635
54577
  return this.pivots[pivotId];
@@ -55949,7 +55891,10 @@ class Session extends EventBus {
55949
55891
  /**
55950
55892
  * Notify the server that the user client left the collaborative session
55951
55893
  */
55952
- leave() {
55894
+ leave(data) {
55895
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55896
+ this.snapshot(data);
55897
+ }
55953
55898
  delete this.clients[this.clientId];
55954
55899
  this.transportService.leave(this.clientId);
55955
55900
  this.transportService.sendMessage({
@@ -56363,7 +56308,7 @@ class DataCleanupPlugin extends UIPlugin {
56363
56308
  bottom: rowIndex,
56364
56309
  }));
56365
56310
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
56366
- const data = handler.copy(getClipboardDataPositions(rowsToKeep));
56311
+ const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep));
56367
56312
  if (!data) {
56368
56313
  return;
56369
56314
  }
@@ -56376,7 +56321,7 @@ class DataCleanupPlugin extends UIPlugin {
56376
56321
  right: zone.left,
56377
56322
  bottom: zone.top,
56378
56323
  };
56379
- handler.paste({ zones: [zonePasted] }, data, { isCutOperation: false });
56324
+ handler.paste({ zones: [zonePasted], sheetId }, data, { isCutOperation: false });
56380
56325
  const remainingZone = {
56381
56326
  left: zone.left,
56382
56327
  top: zone.top - (hasHeader ? 1 : 0),
@@ -58250,12 +58195,14 @@ class ClipboardPlugin extends UIPlugin {
58250
58195
  }
58251
58196
  let zone = undefined;
58252
58197
  let selectedZones = [];
58198
+ const sheetId = this.getters.getActiveSheetId();
58253
58199
  let target = {
58200
+ sheetId,
58254
58201
  zones,
58255
58202
  };
58256
58203
  const handlers = this.selectClipboardHandlers(copiedData);
58257
58204
  for (const handler of handlers) {
58258
- const currentTarget = handler.getPasteTarget(zones, copiedData, options);
58205
+ const currentTarget = handler.getPasteTarget(sheetId, zones, copiedData, options);
58259
58206
  if (currentTarget.figureId) {
58260
58207
  target.figureId = currentTarget.figureId;
58261
58208
  }
@@ -58424,11 +58371,12 @@ class ClipboardPlugin extends UIPlugin {
58424
58371
  return { cut: [cut], paste: [paste] };
58425
58372
  }
58426
58373
  getClipboardData(zones) {
58374
+ const sheetId = this.getters.getActiveSheetId();
58427
58375
  const selectedFigureId = this.getters.getSelectedFigureId();
58428
58376
  if (selectedFigureId) {
58429
- return { figureId: selectedFigureId };
58377
+ return { figureId: selectedFigureId, sheetId };
58430
58378
  }
58431
- return getClipboardDataPositions(zones);
58379
+ return getClipboardDataPositions(sheetId, zones);
58432
58380
  }
58433
58381
  // ---------------------------------------------------------------------------
58434
58382
  // Grid rendering
@@ -59094,8 +59042,9 @@ class GridSelectionPlugin extends UIPlugin {
59094
59042
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
59095
59043
  },
59096
59044
  ];
59045
+ const sheetId = this.getActiveSheetId();
59097
59046
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
59098
- const data = handler.copy(getClipboardDataPositions(target));
59047
+ const data = handler.copy(getClipboardDataPositions(sheetId, target));
59099
59048
  if (!data) {
59100
59049
  return;
59101
59050
  }
@@ -59108,7 +59057,7 @@ class GridSelectionPlugin extends UIPlugin {
59108
59057
  bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
59109
59058
  },
59110
59059
  ];
59111
- handler.paste({ zones: pasteTarget }, data, { isCutOperation: true });
59060
+ handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
59112
59061
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
59113
59062
  let currentIndex = cmd.base;
59114
59063
  for (const element of toRemove) {
@@ -66472,7 +66421,7 @@ class Model extends EventBus {
66472
66421
  this.session.join(this.config.client);
66473
66422
  }
66474
66423
  leaveSession() {
66475
- this.session.leave();
66424
+ this.session.leave(this.exportData());
66476
66425
  }
66477
66426
  setupUiPlugin(Plugin) {
66478
66427
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66879,7 +66828,8 @@ const registries = {
66879
66828
  pivotRegistry,
66880
66829
  pivotTimeAdapterRegistry,
66881
66830
  pivotSidePanelRegistry,
66882
- supportedPivotExplodedFormulaRegistry,
66831
+ pivotNormalizationValueRegistry,
66832
+ supportedPivotPositionalFormulaRegistry,
66883
66833
  };
66884
66834
  const helpers = {
66885
66835
  arg,
@@ -66888,6 +66838,7 @@ const helpers = {
66888
66838
  toJsDate,
66889
66839
  toNumber,
66890
66840
  toString,
66841
+ toNormalizedPivotValue,
66891
66842
  toXC,
66892
66843
  toZone,
66893
66844
  toUnboundedZone,
@@ -66982,6 +66933,9 @@ const components = {
66982
66933
  PivotDimension,
66983
66934
  PivotLayoutConfigurator,
66984
66935
  EditableName,
66936
+ PivotDeferUpdate,
66937
+ PivotTitleSection,
66938
+ CogWheelMenu,
66985
66939
  };
66986
66940
  const hooks = {
66987
66941
  useDragAndDropListItems,
@@ -67022,6 +66976,6 @@ const constants = {
67022
66976
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
67023
66977
 
67024
66978
 
67025
- __info__.version = "17.4.0-alpha.2";
67026
- __info__.date = "2024-06-06T13:31:21.327Z";
67027
- __info__.hash = "e07794d";
66979
+ __info__.version = "17.4.0-alpha.4";
66980
+ __info__.date = "2024-06-12T14:00:22.046Z";
66981
+ __info__.hash = "cefb0e4";