@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
  'use strict';
@@ -311,7 +311,10 @@ function deepCopy(obj) {
311
311
  * Check if the object is a plain old javascript object.
312
312
  */
313
313
  function isPlainObject(obj) {
314
- return typeof obj === "object" && obj?.constructor === Object;
314
+ return (typeof obj === "object" &&
315
+ obj !== null &&
316
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
317
+ (obj?.constructor === Object || obj?.constructor === undefined));
315
318
  }
316
319
  /**
317
320
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -1825,22 +1828,28 @@ function isDateAfter(date, dateAfter) {
1825
1828
  */
1826
1829
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
1827
1830
  decimalSeparator = escapeRegExp(decimalSeparator);
1828
- return new RegExp(`(^-?\\d+(${decimalSeparator}?\\d*(e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1831
+ return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1829
1832
  });
1830
1833
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1831
1834
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1832
1835
  const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1833
- const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1834
- const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1835
- const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
1836
- const pPercentFormat = "(\\s*%)?"; // pattern that match percent symbol between zero and one time
1837
- const pNumber = "(\\s*" + pIntegerAndDecimals + "|" + pOnlyDecimals + ")" + pScientificFormat + pPercentFormat;
1838
- const pMinus = "(\\s*-)?"; // pattern that match negative symbol between zero and one time
1839
- const pCurrencyFormat = "(\\s*[\\$€])?";
1836
+ const pIntegerAndDecimals = `(?:\\d+(?:${thousandsSeparator}\\d{3,})*(?:${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1837
+ const pOnlyDecimals = `(?:${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1838
+ const pScientificFormat = "(?:e(?:\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
1839
+ const pPercentFormat = "(?:\\s*%)?"; // pattern that match percent symbol between zero and one time
1840
+ const pNumber = "(?:\\s*" +
1841
+ pIntegerAndDecimals +
1842
+ "|" +
1843
+ pOnlyDecimals +
1844
+ ")" +
1845
+ pScientificFormat +
1846
+ pPercentFormat;
1847
+ const pMinus = "(?:\\s*-)?"; // pattern that match negative symbol between zero and one time
1848
+ const pCurrencyFormat = "(?:\\s*[\\$€])?";
1840
1849
  const p1 = pMinus + pCurrencyFormat + pNumber;
1841
1850
  const p2 = pMinus + pNumber + pCurrencyFormat;
1842
1851
  const p3 = pCurrencyFormat + pMinus + pNumber;
1843
- const pNumberExp = "^((" + [p1, p2, p3].join(")|(") + "))$";
1852
+ const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
1844
1853
  const numberRegexp = new RegExp(pNumberExp, "i");
1845
1854
  return numberRegexp;
1846
1855
  });
@@ -2778,7 +2787,7 @@ function evaluatePredicate(value, criterion) {
2778
2787
  return false;
2779
2788
  }
2780
2789
  if (typeof operand === "number" && operator === "=") {
2781
- return toString(value) === toString(operand);
2790
+ return value.toString() === operand.toString();
2782
2791
  }
2783
2792
  if (operator === "<>" || operator === "=") {
2784
2793
  let result;
@@ -2838,14 +2847,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2838
2847
  if (countArg % 2 === 1) {
2839
2848
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2840
2849
  }
2841
- const dimRow = args[0].length;
2842
- const dimCol = args[0][0].length;
2850
+ const firstArg = toMatrix(args[0]);
2851
+ const dimRow = firstArg.length;
2852
+ const dimCol = firstArg[0].length;
2843
2853
  let predicates = [];
2844
2854
  for (let i = 0; i < countArg - 1; i += 2) {
2845
- const criteriaRange = args[i];
2846
- if (!isMatrix(criteriaRange) ||
2847
- criteriaRange.length !== dimRow ||
2848
- criteriaRange[0].length !== dimCol) {
2855
+ const criteriaRange = toMatrix(args[i]);
2856
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2849
2857
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2850
2858
  }
2851
2859
  const description = toString(args[i + 1]);
@@ -2859,7 +2867,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2859
2867
  for (let j = 0; j < dimCol; j++) {
2860
2868
  let validatedPredicates = true;
2861
2869
  for (let k = 0; k < countArg - 1; k += 2) {
2862
- const criteriaValue = args[k][i][j].value;
2870
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2863
2871
  const criterion = predicates[k / 2];
2864
2872
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2865
2873
  if (!validatedPredicates) {
@@ -3524,10 +3532,8 @@ function detectDateFormat(content, locale) {
3524
3532
  const internalDate = parseDateTime(content, locale);
3525
3533
  return internalDate.format;
3526
3534
  }
3535
+ /** use this function only if the content corresponds to a number (means that isNumber(content) return true */
3527
3536
  function detectNumberFormat(content) {
3528
- if (!isNumber(content, DEFAULT_LOCALE)) {
3529
- return undefined;
3530
- }
3531
3537
  const digitBase = content.includes(".") ? "0.00" : "0";
3532
3538
  const matchedCurrencies = content.match(/[\$€]/);
3533
3539
  if (matchedCurrencies) {
@@ -4730,21 +4736,16 @@ function unionPositionsToZone(positions) {
4730
4736
  * Check if two zones are contiguous, ie. that they share a border
4731
4737
  */
4732
4738
  function areZoneContiguous(zone1, zone2) {
4733
- const u = union(zone1, zone2);
4734
4739
  if (zone1.right + 1 === zone2.left || zone1.left === zone2.right + 1) {
4735
- return getZoneHeight(u) <= getZoneHeight(zone1) + getZoneHeight(zone2);
4740
+ return ((zone1.top <= zone2.bottom && zone1.top >= zone2.top) ||
4741
+ (zone2.top <= zone1.bottom && zone2.top >= zone1.top));
4736
4742
  }
4737
4743
  if (zone1.bottom + 1 === zone2.top || zone1.top === zone2.bottom + 1) {
4738
- return getZoneWidth(u) <= getZoneWidth(zone1) + getZoneWidth(zone2);
4744
+ return ((zone1.left <= zone2.right && zone1.left >= zone2.left) ||
4745
+ (zone2.left <= zone1.right && zone2.left >= zone1.left));
4739
4746
  }
4740
4747
  return false;
4741
4748
  }
4742
- function getZoneHeight(zone) {
4743
- return zone.bottom - zone.top + 1;
4744
- }
4745
- function getZoneWidth(zone) {
4746
- return zone.right - zone.left + 1;
4747
- }
4748
4749
  /**
4749
4750
  * Merge contiguous and overlapping zones that are in the array into bigger zones
4750
4751
  */
@@ -5500,7 +5501,7 @@ class Registry {
5500
5501
  }
5501
5502
  }
5502
5503
 
5503
- function getClipboardDataPositions(zones) {
5504
+ function getClipboardDataPositions(sheetId, zones) {
5504
5505
  const lefts = new Set(zones.map((z) => z.left));
5505
5506
  const rights = new Set(zones.map((z) => z.right));
5506
5507
  const tops = new Set(zones.map((z) => z.top));
@@ -5514,7 +5515,7 @@ function getClipboardDataPositions(zones) {
5514
5515
  const cellsPosition = clippedZones.map((zone) => positions(zone)).flat();
5515
5516
  const columnsIndexes = [...new Set(cellsPosition.map((p) => p.col))].sort((a, b) => a - b);
5516
5517
  const rowsIndexes = [...new Set(cellsPosition.map((p) => p.row))].sort((a, b) => a - b);
5517
- return { zones, clippedZones, columnsIndexes, rowsIndexes };
5518
+ return { sheetId, zones, clippedZones, columnsIndexes, rowsIndexes };
5518
5519
  }
5519
5520
  /**
5520
5521
  * The clipped zone is copied as many times as it fits in the target.
@@ -5564,8 +5565,8 @@ class ClipboardHandler {
5564
5565
  isCutAllowed(data) {
5565
5566
  return "Success" /* CommandResult.Success */;
5566
5567
  }
5567
- getPasteTarget(target, content, options) {
5568
- return { zones: [] };
5568
+ getPasteTarget(sheetId, target, content, options) {
5569
+ return { zones: [], sheetId };
5569
5570
  }
5570
5571
  convertOSClipboardData(data) {
5571
5572
  return;
@@ -5603,7 +5604,7 @@ class AbstractCellClipboardHandler extends ClipboardHandler {
5603
5604
 
5604
5605
  class BorderClipboardHandler extends AbstractCellClipboardHandler {
5605
5606
  copy(data) {
5606
- const sheetId = this.getters.getActiveSheetId();
5607
+ const sheetId = data.sheetId;
5607
5608
  if (data.zones.length === 0) {
5608
5609
  return;
5609
5610
  }
@@ -5623,7 +5624,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
5623
5624
  if (!content) {
5624
5625
  return;
5625
5626
  }
5626
- const sheetId = this.getters.getActiveSheetId();
5627
+ const sheetId = target.sheetId;
5627
5628
  if (options?.pasteOption === "asValue") {
5628
5629
  return;
5629
5630
  }
@@ -6153,7 +6154,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6153
6154
  if (!("zones" in data) || !data.zones.length) {
6154
6155
  return;
6155
6156
  }
6156
- const sheetId = this.getters.getActiveSheetId();
6157
+ const sheetId = data.sheetId;
6157
6158
  const zones = data.zones;
6158
6159
  if (!zones.length) {
6159
6160
  return {
@@ -6182,6 +6183,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6182
6183
  format: evaluatedCell.format,
6183
6184
  content,
6184
6185
  isFormula: false,
6186
+ parsedValue: evaluatedCell.value,
6185
6187
  };
6186
6188
  }
6187
6189
  cellsInRow.push({
@@ -6196,7 +6198,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6196
6198
  return {
6197
6199
  cells: clippedCells,
6198
6200
  zones: clippedZones,
6199
- sheetId: this.getters.getActiveSheetId(),
6201
+ sheetId: data.sheetId,
6200
6202
  };
6201
6203
  }
6202
6204
  isPasteAllowed(sheetId, target, content, clipboardOptions) {
@@ -6224,7 +6226,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6224
6226
  return;
6225
6227
  }
6226
6228
  const zones = target.zones;
6227
- const sheetId = this.getters.getActiveSheetId();
6229
+ const sheetId = target.sheetId;
6228
6230
  if (!options?.isCutOperation) {
6229
6231
  this.pasteFromCopy(sheetId, zones, content.cells, options);
6230
6232
  }
@@ -6232,11 +6234,12 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6232
6234
  this.pasteFromCut(sheetId, zones, content, options);
6233
6235
  }
6234
6236
  }
6235
- getPasteTarget(target, content, options) {
6237
+ getPasteTarget(sheetId, target, content, options) {
6236
6238
  const width = content.cells[0].length;
6237
6239
  const height = content.cells.length;
6238
6240
  if (options?.isCutOperation) {
6239
6241
  return {
6242
+ sheetId,
6240
6243
  zones: [
6241
6244
  {
6242
6245
  left: target[0].left,
@@ -6248,11 +6251,9 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6248
6251
  };
6249
6252
  }
6250
6253
  if (width === 1 && height === 1) {
6251
- return { zones: [] };
6254
+ return { zones: [], sheetId };
6252
6255
  }
6253
- return {
6254
- zones: getPasteZones(target, content.cells),
6255
- };
6256
+ return { sheetId, zones: getPasteZones(target, content.cells) };
6256
6257
  }
6257
6258
  pasteFromCut(sheetId, target, content, options) {
6258
6259
  this.clearClippedZones(content);
@@ -6375,7 +6376,7 @@ class AbstractFigureClipboardHandler extends ClipboardHandler {
6375
6376
 
6376
6377
  class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6377
6378
  copy(data) {
6378
- const sheetId = this.getters.getActiveSheetId();
6379
+ const sheetId = data.sheetId;
6379
6380
  const figure = this.getters.getFigure(sheetId, data.figureId);
6380
6381
  if (!figure) {
6381
6382
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6395,22 +6396,19 @@ class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6395
6396
  copiedChart,
6396
6397
  };
6397
6398
  }
6398
- getPasteTarget(target, content, options) {
6399
+ getPasteTarget(sheetId, target, content, options) {
6399
6400
  if (!content?.copiedFigure || !content?.copiedChart) {
6400
- return { zones: [] };
6401
+ return { zones: [], sheetId };
6401
6402
  }
6402
6403
  const newId = new UuidGenerator().uuidv4();
6403
- return {
6404
- zones: [],
6405
- figureId: newId,
6406
- };
6404
+ return { zones: [], figureId: newId, sheetId };
6407
6405
  }
6408
6406
  paste(target, clippedContent, options) {
6409
6407
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedChart || !target.figureId) {
6410
6408
  return;
6411
6409
  }
6412
6410
  const { zones, figureId } = target;
6413
- const sheetId = this.getters.getActiveSheetId();
6411
+ const sheetId = target.sheetId;
6414
6412
  const numCols = this.getters.getNumberCols(sheetId);
6415
6413
  const numRows = this.getters.getNumberRows(sheetId);
6416
6414
  const targetX = this.getters.getColDimensions(sheetId, zones[0].left).start;
@@ -6456,7 +6454,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6456
6454
  return;
6457
6455
  }
6458
6456
  const { rowsIndexes, columnsIndexes } = data;
6459
- const sheetId = this.getters.getActiveSheetId();
6457
+ const sheetId = data.sheetId;
6460
6458
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6461
6459
  return {
6462
6460
  cellPositions,
@@ -6470,7 +6468,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6470
6468
  return;
6471
6469
  }
6472
6470
  const zones = target.zones;
6473
- const sheetId = this.getters.getActiveSheetId();
6471
+ const sheetId = target.sheetId;
6474
6472
  if (!options?.isCutOperation) {
6475
6473
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6476
6474
  }
@@ -6551,7 +6549,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6551
6549
  return;
6552
6550
  }
6553
6551
  const { rowsIndexes, columnsIndexes } = data;
6554
- const sheetId = this.getters.getActiveSheetId();
6552
+ const sheetId = data.sheetId;
6555
6553
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6556
6554
  return {
6557
6555
  cellPositions,
@@ -6568,7 +6566,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6568
6566
  return;
6569
6567
  }
6570
6568
  const zones = target.zones;
6571
- const sheetId = this.getters.getActiveSheetId();
6569
+ const sheetId = target.sheetId;
6572
6570
  if (!options?.isCutOperation) {
6573
6571
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6574
6572
  }
@@ -6647,7 +6645,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6647
6645
 
6648
6646
  class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6649
6647
  copy(data) {
6650
- const sheetId = this.getters.getActiveSheetId();
6648
+ const sheetId = data.sheetId;
6651
6649
  const figure = this.getters.getFigure(sheetId, data.figureId);
6652
6650
  if (!figure) {
6653
6651
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6665,15 +6663,12 @@ class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6665
6663
  sheetId,
6666
6664
  };
6667
6665
  }
6668
- getPasteTarget(target, content, options) {
6666
+ getPasteTarget(sheetId, target, content, options) {
6669
6667
  if (!content?.copiedFigure || !content?.copiedImage) {
6670
- return { zones: [] };
6668
+ return { zones: [], sheetId };
6671
6669
  }
6672
6670
  const newId = new UuidGenerator().uuidv4();
6673
- return {
6674
- zones: [],
6675
- figureId: newId,
6676
- };
6671
+ return { sheetId, zones: [], figureId: newId };
6677
6672
  }
6678
6673
  paste(target, clippedContent, options) {
6679
6674
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedImage || !target.figureId) {
@@ -6744,8 +6739,7 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
6744
6739
  if (options?.isCutOperation || !("zones" in target) || !target.zones.length) {
6745
6740
  return;
6746
6741
  }
6747
- const sheetId = this.getters.getActiveSheetId();
6748
- this.pasteFromCopy(sheetId, target.zones, content.cells, options);
6742
+ this.pasteFromCopy(target.sheetId, target.zones, content.cells, options);
6749
6743
  }
6750
6744
  pasteZone(sheetId, col, row, cells) {
6751
6745
  for (const [r, rowCells] of cells.entries()) {
@@ -6805,7 +6799,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
6805
6799
 
6806
6800
  class TableClipboardHandler extends AbstractCellClipboardHandler {
6807
6801
  copy(data) {
6808
- const sheetId = this.getters.getActiveSheetId();
6802
+ const sheetId = data.sheetId;
6809
6803
  const { rowsIndexes, columnsIndexes, zones } = data;
6810
6804
  if (!zones || !rowsIndexes.length || !columnsIndexes.length) {
6811
6805
  return { tableCells: [[]], sheetId };
@@ -6847,7 +6841,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6847
6841
  }
6848
6842
  return {
6849
6843
  tableCells,
6850
- sheetId: this.getters.getActiveSheetId(),
6844
+ sheetId: data.sheetId,
6851
6845
  };
6852
6846
  }
6853
6847
  /**
@@ -6869,7 +6863,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6869
6863
  return;
6870
6864
  }
6871
6865
  const zones = target.zones;
6872
- const sheetId = this.getters.getActiveSheetId();
6866
+ const sheetId = target.sheetId;
6873
6867
  if (!options?.isCutOperation) {
6874
6868
  this.pasteFromCopy(sheetId, zones, content.tableCells, options);
6875
6869
  }
@@ -7631,10 +7625,8 @@ function detectLink(value) {
7631
7625
  return undefined;
7632
7626
  }
7633
7627
 
7634
- function evaluateLiteral(content = "", localeFormat) {
7635
- const value = localeFormat.format === PLAIN_TEXT_FORMAT
7636
- ? content
7637
- : parseLiteral(content, localeFormat.locale);
7628
+ function evaluateLiteral(literalCell, localeFormat) {
7629
+ const value = localeFormat.format === PLAIN_TEXT_FORMAT ? literalCell.content : literalCell.parsedValue;
7638
7630
  const fPayload = { value, format: localeFormat.format };
7639
7631
  return createEvaluatedCell(fPayload, localeFormat.locale);
7640
7632
  }
@@ -7646,10 +7638,11 @@ function parseLiteral(content, locale) {
7646
7638
  return null;
7647
7639
  }
7648
7640
  if (isNumber(content, DEFAULT_LOCALE)) {
7649
- return toNumber(content, DEFAULT_LOCALE);
7641
+ return parseNumber(content, DEFAULT_LOCALE);
7650
7642
  }
7651
- if (isDateTime(content, locale)) {
7652
- return toNumber(content, locale);
7643
+ const internalDate = parseDateTime(content, locale);
7644
+ if (internalDate) {
7645
+ return internalDate.value;
7653
7646
  }
7654
7647
  if (isBoolean(content)) {
7655
7648
  return content.toUpperCase() === "TRUE" ? true : false;
@@ -7661,9 +7654,14 @@ function createEvaluatedCell(fPayload, locale = DEFAULT_LOCALE, cell) {
7661
7654
  if (!link) {
7662
7655
  return _createEvaluatedCell(fPayload, locale, cell);
7663
7656
  }
7657
+ const value = parseLiteral(link.label, locale);
7658
+ const format = fPayload.format ||
7659
+ (typeof value === "number"
7660
+ ? detectDateFormat(link.label, locale) || detectNumberFormat(link.label)
7661
+ : undefined);
7664
7662
  const linkPayload = {
7665
- value: parseLiteral(link.label, locale),
7666
- format: fPayload.format || detectDateFormat(link.label, locale) || detectNumberFormat(link.label),
7663
+ value,
7664
+ format,
7667
7665
  };
7668
7666
  return {
7669
7667
  ..._createEvaluatedCell(linkPayload, locale, cell),
@@ -10987,6 +10985,9 @@ function makeArg(str, description) {
10987
10985
  if (types.some((t) => t.startsWith("RANGE"))) {
10988
10986
  result.acceptMatrix = true;
10989
10987
  }
10988
+ if (types.every((t) => t.startsWith("RANGE"))) {
10989
+ result.acceptMatrixOnly = true;
10990
+ }
10990
10991
  return result;
10991
10992
  }
10992
10993
  /**
@@ -11241,7 +11242,6 @@ const ARRAY_CONSTRAIN = {
11241
11242
  arg("rows (number)", _t("The number of rows in the constrained array.")),
11242
11243
  arg("columns (number)", _t("The number of columns in the constrained array.")),
11243
11244
  ],
11244
- returns: ["RANGE<ANY>"],
11245
11245
  compute: function (array, rows, columns) {
11246
11246
  const _array = toMatrix(array);
11247
11247
  const _rowsArg = toInteger(rows?.value, this.locale);
@@ -11264,15 +11264,19 @@ const CHOOSECOLS = {
11264
11264
  arg("col_num (number, range<number>)", _t("The first column index of the columns to be returned.")),
11265
11265
  arg("col_num2 (number, range<number>, repeating)", _t("The columns indexes of the columns to be returned.")),
11266
11266
  ],
11267
- returns: ["RANGE<ANY>"],
11268
11267
  compute: function (array, ...columns) {
11269
11268
  const _array = toMatrix(array);
11270
11269
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11271
- 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()));
11270
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11271
+ 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(",")));
11272
11272
  const result = Array(_columns.length);
11273
11273
  for (let col = 0; col < _columns.length; col++) {
11274
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11275
- result[col] = _array[colIndex];
11274
+ if (_columns[col] > 0) {
11275
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11276
+ }
11277
+ else {
11278
+ result[col] = _array[_array.length + _columns[col]];
11279
+ }
11276
11280
  }
11277
11281
  return result;
11278
11282
  },
@@ -11288,13 +11292,18 @@ const CHOOSEROWS = {
11288
11292
  arg("row_num (number, range<number>)", _t("The first row index of the rows to be returned.")),
11289
11293
  arg("row_num2 (number, range<number>, repeating)", _t("The rows indexes of the rows to be returned.")),
11290
11294
  ],
11291
- returns: ["RANGE<ANY>"],
11292
11295
  compute: function (array, ...rows) {
11293
11296
  const _array = toMatrix(array);
11294
11297
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11295
11298
  const _nbColumns = _array.length;
11296
- 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()));
11297
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11299
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11300
+ 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(",")));
11301
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11302
+ if (_rows[row] > 0) {
11303
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11304
+ }
11305
+ return _array[col][_array[col].length + _rows[row]];
11306
+ });
11298
11307
  },
11299
11308
  isExported: true,
11300
11309
  };
@@ -11309,7 +11318,6 @@ const EXPAND = {
11309
11318
  arg("columns (number, optional)", _t("The number of columns in the expanded array. If missing, columns will not be expanded.")),
11310
11319
  arg("pad_with (any, default=0)", _t("The value with which to pad.")), // @compatibility: on Excel, pad with #N/A
11311
11320
  ],
11312
- returns: ["RANGE<ANY>"],
11313
11321
  compute: function (arg, rows, columns, padWith = { value: 0 } // TODO : Replace with #N/A errors once it's supported
11314
11322
  ) {
11315
11323
  const _array = toMatrix(arg);
@@ -11330,7 +11338,6 @@ const FLATTEN = {
11330
11338
  arg("range (any, range<any>)", _t("The first range to flatten.")),
11331
11339
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to flatten.")),
11332
11340
  ],
11333
- returns: ["RANGE<ANY>"],
11334
11341
  compute: function (...ranges) {
11335
11342
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
11336
11343
  },
@@ -11345,7 +11352,6 @@ const FREQUENCY = {
11345
11352
  arg("data (range<number>)", _t("The array of ranges containing the values to be counted.")),
11346
11353
  arg("classes (number, range<number>)", _t("The range containing the set of classes.")),
11347
11354
  ],
11348
- returns: ["RANGE<NUMBER>"],
11349
11355
  compute: function (data, classes) {
11350
11356
  const _data = flattenRowFirst([data], (data) => data.value).filter((val) => typeof val === "number");
11351
11357
  const _classes = flattenRowFirst([classes], (data) => data.value).filter((val) => typeof val === "number");
@@ -11393,7 +11399,6 @@ const HSTACK = {
11393
11399
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11394
11400
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11395
11401
  ],
11396
- returns: ["RANGE<ANY>"],
11397
11402
  compute: function (...ranges) {
11398
11403
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
11399
11404
  const result = [];
@@ -11420,7 +11425,6 @@ const MDETERM = {
11420
11425
  args: [
11421
11426
  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.")),
11422
11427
  ],
11423
- returns: ["NUMBER"],
11424
11428
  compute: function (matrix) {
11425
11429
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11426
11430
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11436,7 +11440,6 @@ const MINVERSE = {
11436
11440
  args: [
11437
11441
  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.")),
11438
11442
  ],
11439
- returns: ["RANGE<NUMBER>"],
11440
11443
  compute: function (matrix) {
11441
11444
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11442
11445
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11457,7 +11460,6 @@ const MMULT = {
11457
11460
  arg("matrix1 (number, range<number>)", _t("The first matrix in the matrix multiplication operation.")),
11458
11461
  arg("matrix2 (number, range<number>)", _t("The second matrix in the matrix multiplication operation.")),
11459
11462
  ],
11460
- returns: ["RANGE<NUMBER>"],
11461
11463
  compute: function (matrix1, matrix2) {
11462
11464
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11463
11465
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
@@ -11476,7 +11478,6 @@ const SUMPRODUCT = {
11476
11478
  arg("range1 (number, range<number>)", _t("The first range whose entries will be multiplied with corresponding entries in the other ranges.")),
11477
11479
  arg("range2 (number, range<number>, repeating)", _t("The other range whose entries will be multiplied with corresponding entries in the other ranges.")),
11478
11480
  ],
11479
- returns: ["NUMBER"],
11480
11481
  compute: function (...args) {
11481
11482
  assertSameDimensions(_t("All the ranges must have the same dimensions."), ...args);
11482
11483
  const _args = args.map(toMatrix);
@@ -11533,7 +11534,6 @@ const SUMX2MY2 = {
11533
11534
  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.")),
11534
11535
  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.")),
11535
11536
  ],
11536
- returns: ["NUMBER"],
11537
11537
  compute: function (arrayX, arrayY) {
11538
11538
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 - y ** 2);
11539
11539
  },
@@ -11548,7 +11548,6 @@ const SUMX2PY2 = {
11548
11548
  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.")),
11549
11549
  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.")),
11550
11550
  ],
11551
- returns: ["NUMBER"],
11552
11551
  compute: function (arrayX, arrayY) {
11553
11552
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 + y ** 2);
11554
11553
  },
@@ -11563,7 +11562,6 @@ const SUMXMY2 = {
11563
11562
  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.")),
11564
11563
  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.")),
11565
11564
  ],
11566
- returns: ["NUMBER"],
11567
11565
  compute: function (arrayX, arrayY) {
11568
11566
  return getSumXAndY(arrayX, arrayY, (x, y) => (x - y) ** 2);
11569
11567
  },
@@ -11599,7 +11597,6 @@ function shouldKeepValue(ignore) {
11599
11597
  const TOCOL = {
11600
11598
  description: _t("Transforms a range of cells into a single column."),
11601
11599
  args: TO_COL_ROW_ARGS,
11602
- returns: ["RANGE<ANY>"],
11603
11600
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11604
11601
  const _array = toMatrix(array);
11605
11602
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11620,7 +11617,6 @@ const TOCOL = {
11620
11617
  const TOROW = {
11621
11618
  description: _t("Transforms a range of cells into a single row."),
11622
11619
  args: TO_COL_ROW_ARGS,
11623
- returns: ["RANGE<ANY>"],
11624
11620
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11625
11621
  const _array = toMatrix(array);
11626
11622
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11642,7 +11638,6 @@ const TOROW = {
11642
11638
  const TRANSPOSE = {
11643
11639
  description: _t("Transposes the rows and columns of a range."),
11644
11640
  args: [arg("range (any, range<any>)", _t("The range to be transposed."))],
11645
- returns: ["RANGE"],
11646
11641
  compute: function (arg) {
11647
11642
  const _array = toMatrix(arg);
11648
11643
  const nbColumns = _array[0].length;
@@ -11660,7 +11655,6 @@ const VSTACK = {
11660
11655
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11661
11656
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11662
11657
  ],
11663
- returns: ["RANGE<ANY>"],
11664
11658
  compute: function (...ranges) {
11665
11659
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
11666
11660
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -11692,7 +11686,6 @@ const WRAPCOLS = {
11692
11686
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11693
11687
  _t("The value with which to fill the extra cells in the range.")),
11694
11688
  ],
11695
- returns: ["RANGE<ANY>"],
11696
11689
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11697
11690
  const _array = toMatrix(range);
11698
11691
  const nbRows = toInteger(wrapCount?.value, this.locale);
@@ -11717,7 +11710,6 @@ const WRAPROWS = {
11717
11710
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11718
11711
  _t("The value with which to fill the extra cells in the range.")),
11719
11712
  ],
11720
- returns: ["RANGE<ANY>"],
11721
11713
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11722
11714
  const _array = toMatrix(range);
11723
11715
  const nbColumns = toInteger(wrapCount?.value, this.locale);
@@ -11765,7 +11757,6 @@ const FORMAT_LARGE_NUMBER = {
11765
11757
  arg("value (number)", _t("The number.")),
11766
11758
  arg("unit (string, optional)", _t("The formatting unit. Use 'k', 'm', or 'b' to force the unit")),
11767
11759
  ],
11768
- returns: ["NUMBER"],
11769
11760
  compute: function (value, unite) {
11770
11761
  return {
11771
11762
  value: toNumber(value, this.locale),
@@ -11797,7 +11788,6 @@ const DECIMAL_REPRESENTATION = /^-?[a-z0-9]+$/i;
11797
11788
  const ABS = {
11798
11789
  description: _t("Absolute value of a number."),
11799
11790
  args: [arg("value (number)", _t("The number of which to return the absolute value."))],
11800
- returns: ["NUMBER"],
11801
11791
  compute: function (value) {
11802
11792
  return Math.abs(toNumber(value, this.locale));
11803
11793
  },
@@ -11811,7 +11801,6 @@ const ACOS = {
11811
11801
  args: [
11812
11802
  arg("value (number)", _t("The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.")),
11813
11803
  ],
11814
- returns: ["NUMBER"],
11815
11804
  compute: function (value) {
11816
11805
  const _value = toNumber(value, this.locale);
11817
11806
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11827,7 +11816,6 @@ const ACOSH = {
11827
11816
  args: [
11828
11817
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1.")),
11829
11818
  ],
11830
- returns: ["NUMBER"],
11831
11819
  compute: function (value) {
11832
11820
  const _value = toNumber(value, this.locale);
11833
11821
  assert(() => _value >= 1, _t("The value (%s) must be greater than or equal to 1.", _value.toString()));
@@ -11841,7 +11829,6 @@ const ACOSH = {
11841
11829
  const ACOT = {
11842
11830
  description: _t("Inverse cotangent of a value."),
11843
11831
  args: [arg("value (number)", _t("The value for which to calculate the inverse cotangent."))],
11844
- returns: ["NUMBER"],
11845
11832
  compute: function (value) {
11846
11833
  const _value = toNumber(value, this.locale);
11847
11834
  const sign = Math.sign(_value) || 1;
@@ -11860,7 +11847,6 @@ const ACOTH = {
11860
11847
  args: [
11861
11848
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cotangent. Must not be between -1 and 1, inclusive.")),
11862
11849
  ],
11863
- returns: ["NUMBER"],
11864
11850
  compute: function (value) {
11865
11851
  const _value = toNumber(value, this.locale);
11866
11852
  assert(() => Math.abs(_value) > 1, _t("The value (%s) cannot be between -1 and 1 inclusive.", _value.toString()));
@@ -11876,7 +11862,6 @@ const ASIN = {
11876
11862
  args: [
11877
11863
  arg("value (number)", _t("The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive.")),
11878
11864
  ],
11879
- returns: ["NUMBER"],
11880
11865
  compute: function (value) {
11881
11866
  const _value = toNumber(value, this.locale);
11882
11867
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11892,7 +11877,6 @@ const ASINH = {
11892
11877
  args: [
11893
11878
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic sine.")),
11894
11879
  ],
11895
- returns: ["NUMBER"],
11896
11880
  compute: function (value) {
11897
11881
  return Math.asinh(toNumber(value, this.locale));
11898
11882
  },
@@ -11904,7 +11888,6 @@ const ASINH = {
11904
11888
  const ATAN = {
11905
11889
  description: _t("Inverse tangent of a value, in radians."),
11906
11890
  args: [arg("value (number)", _t("The value for which to calculate the inverse tangent."))],
11907
- returns: ["NUMBER"],
11908
11891
  compute: function (value) {
11909
11892
  return Math.atan(toNumber(value, this.locale));
11910
11893
  },
@@ -11919,7 +11902,6 @@ const ATAN2 = {
11919
11902
  arg("x (number)", _t("The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11920
11903
  arg("y (number)", _t("The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11921
11904
  ],
11922
- returns: ["NUMBER"],
11923
11905
  compute: function (x, y) {
11924
11906
  const _x = toNumber(x, this.locale);
11925
11907
  const _y = toNumber(y, this.locale);
@@ -11936,7 +11918,6 @@ const ATANH = {
11936
11918
  args: [
11937
11919
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive.")),
11938
11920
  ],
11939
- returns: ["NUMBER"],
11940
11921
  compute: function (value) {
11941
11922
  const _value = toNumber(value, this.locale);
11942
11923
  assert(() => Math.abs(_value) < 1, _t("The value (%s) must be between -1 and 1 exclusive.", _value.toString()));
@@ -11953,7 +11934,6 @@ const CEILING = {
11953
11934
  arg("value (number)", _t("The value to round up to the nearest integer multiple of factor.")),
11954
11935
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
11955
11936
  ],
11956
- returns: ["NUMBER"],
11957
11937
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
11958
11938
  const _value = toNumber(value, this.locale);
11959
11939
  const _factor = toNumber(factor, this.locale);
@@ -11988,7 +11968,6 @@ const CEILING_MATH = {
11988
11968
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
11989
11969
  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.")),
11990
11970
  ],
11991
- returns: ["NUMBER"],
11992
11971
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
11993
11972
  const _significance = toNumber(significance, this.locale);
11994
11973
  const _number = toNumber(number, this.locale);
@@ -12009,7 +11988,6 @@ const CEILING_PRECISE = {
12009
11988
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12010
11989
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12011
11990
  ],
12012
- returns: ["NUMBER"],
12013
11991
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12014
11992
  const _significance = toNumber(significance, this.locale);
12015
11993
  const _number = toNumber(number, this.locale);
@@ -12026,7 +12004,6 @@ const CEILING_PRECISE = {
12026
12004
  const COS = {
12027
12005
  description: _t("Cosine of an angle provided in radians."),
12028
12006
  args: [arg("angle (number)", _t("The angle to find the cosine of, in radians."))],
12029
- returns: ["NUMBER"],
12030
12007
  compute: function (angle) {
12031
12008
  return Math.cos(toNumber(angle, this.locale));
12032
12009
  },
@@ -12038,7 +12015,6 @@ const COS = {
12038
12015
  const COSH = {
12039
12016
  description: _t("Hyperbolic cosine of any real number."),
12040
12017
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosine of."))],
12041
- returns: ["NUMBER"],
12042
12018
  compute: function (value) {
12043
12019
  return Math.cosh(toNumber(value, this.locale));
12044
12020
  },
@@ -12050,7 +12026,6 @@ const COSH = {
12050
12026
  const COT = {
12051
12027
  description: _t("Cotangent of an angle provided in radians."),
12052
12028
  args: [arg("angle (number)", _t("The angle to find the cotangent of, in radians."))],
12053
- returns: ["NUMBER"],
12054
12029
  compute: function (angle) {
12055
12030
  const _angle = toNumber(angle, this.locale);
12056
12031
  assertNotZero(_angle);
@@ -12064,7 +12039,6 @@ const COT = {
12064
12039
  const COTH = {
12065
12040
  description: _t("Hyperbolic cotangent of any real number."),
12066
12041
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cotangent of."))],
12067
- returns: ["NUMBER"],
12068
12042
  compute: function (value) {
12069
12043
  const _value = toNumber(value, this.locale);
12070
12044
  assertNotZero(_value);
@@ -12081,7 +12055,6 @@ const COUNTBLANK = {
12081
12055
  arg("value1 (any, range)", _t("The first value or range in which to count the number of blanks.")),
12082
12056
  arg("value2 (any, range, repeating)", _t("Additional values or ranges in which to count the number of blanks.")),
12083
12057
  ],
12084
- returns: ["NUMBER"],
12085
12058
  compute: function (...args) {
12086
12059
  return reduceAny(args, (acc, a) => {
12087
12060
  if (a === undefined) {
@@ -12107,7 +12080,6 @@ const COUNTIF = {
12107
12080
  arg("range (range)", _t("The range that is tested against criterion.")),
12108
12081
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12109
12082
  ],
12110
- returns: ["NUMBER"],
12111
12083
  compute: function (...args) {
12112
12084
  let count = 0;
12113
12085
  visitMatchingRanges(args, (i, j) => {
@@ -12128,7 +12100,6 @@ const COUNTIFS = {
12128
12100
  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.")),
12129
12101
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12130
12102
  ],
12131
- returns: ["NUMBER"],
12132
12103
  compute: function (...args) {
12133
12104
  let count = 0;
12134
12105
  visitMatchingRanges(args, (i, j) => {
@@ -12147,7 +12118,6 @@ const COUNTUNIQUE = {
12147
12118
  arg("value1 (any, range)", _t("The first value or range to consider for uniqueness.")),
12148
12119
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider for uniqueness.")),
12149
12120
  ],
12150
- returns: ["NUMBER"],
12151
12121
  compute: function (...args) {
12152
12122
  return countUnique(args);
12153
12123
  },
@@ -12164,7 +12134,6 @@ const COUNTUNIQUEIFS = {
12164
12134
  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.")),
12165
12135
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
12166
12136
  ],
12167
- returns: ["NUMBER"],
12168
12137
  compute: function (range, ...args) {
12169
12138
  let uniqueValues = new Set();
12170
12139
  visitMatchingRanges(args, (i, j) => {
@@ -12182,7 +12151,6 @@ const COUNTUNIQUEIFS = {
12182
12151
  const CSC = {
12183
12152
  description: _t("Cosecant of an angle provided in radians."),
12184
12153
  args: [arg("angle (number)", _t("The angle to find the cosecant of, in radians."))],
12185
- returns: ["NUMBER"],
12186
12154
  compute: function (angle) {
12187
12155
  const _angle = toNumber(angle, this.locale);
12188
12156
  assertNotZero(_angle);
@@ -12196,7 +12164,6 @@ const CSC = {
12196
12164
  const CSCH = {
12197
12165
  description: _t("Hyperbolic cosecant of any real number."),
12198
12166
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosecant of."))],
12199
- returns: ["NUMBER"],
12200
12167
  compute: function (value) {
12201
12168
  const _value = toNumber(value, this.locale);
12202
12169
  assertNotZero(_value);
@@ -12213,7 +12180,6 @@ const DECIMAL = {
12213
12180
  arg("value (string)", _t("The number to convert.")),
12214
12181
  arg("base (number)", _t("The base to convert the value from.")),
12215
12182
  ],
12216
- returns: ["NUMBER"],
12217
12183
  compute: function (value, base) {
12218
12184
  let _base = toNumber(base, this.locale);
12219
12185
  _base = Math.floor(_base);
@@ -12240,7 +12206,6 @@ const DECIMAL = {
12240
12206
  const DEGREES = {
12241
12207
  description: _t("Converts an angle value in radians to degrees."),
12242
12208
  args: [arg("angle (number)", _t("The angle to convert from radians to degrees."))],
12243
- returns: ["NUMBER"],
12244
12209
  compute: function (angle) {
12245
12210
  return (toNumber(angle, this.locale) * 180) / Math.PI;
12246
12211
  },
@@ -12252,7 +12217,6 @@ const DEGREES = {
12252
12217
  const EXP = {
12253
12218
  description: _t("Euler's number, e (~2.718) raised to a power."),
12254
12219
  args: [arg("value (number)", _t("The exponent to raise e."))],
12255
- returns: ["NUMBER"],
12256
12220
  compute: function (value) {
12257
12221
  return Math.exp(toNumber(value, this.locale));
12258
12222
  },
@@ -12267,7 +12231,6 @@ const FLOOR = {
12267
12231
  arg("value (number)", _t("The value to round down to the nearest integer multiple of factor.")),
12268
12232
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
12269
12233
  ],
12270
- returns: ["NUMBER"],
12271
12234
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
12272
12235
  const _value = toNumber(value, this.locale);
12273
12236
  const _factor = toNumber(factor, this.locale);
@@ -12302,7 +12265,6 @@ const FLOOR_MATH = {
12302
12265
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
12303
12266
  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.")),
12304
12267
  ],
12305
- returns: ["NUMBER"],
12306
12268
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
12307
12269
  const _significance = toNumber(significance, this.locale);
12308
12270
  const _number = toNumber(number, this.locale);
@@ -12323,7 +12285,6 @@ const FLOOR_PRECISE = {
12323
12285
  arg("number (number)", _t("The value to round down to the nearest integer multiple of significance.")),
12324
12286
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12325
12287
  ],
12326
- returns: ["NUMBER"],
12327
12288
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12328
12289
  const _significance = toNumber(significance, this.locale);
12329
12290
  const _number = toNumber(number, this.locale);
@@ -12340,7 +12301,6 @@ const FLOOR_PRECISE = {
12340
12301
  const ISEVEN = {
12341
12302
  description: _t("Whether the provided value is even."),
12342
12303
  args: [arg("value (number)", _t("The value to be verified as even."))],
12343
- returns: ["BOOLEAN"],
12344
12304
  compute: function (value) {
12345
12305
  const _value = strictToNumber(value, this.locale);
12346
12306
  return Math.floor(Math.abs(_value)) & 1 ? false : true;
@@ -12356,7 +12316,6 @@ const ISO_CEILING = {
12356
12316
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12357
12317
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12358
12318
  ],
12359
- returns: ["NUMBER"],
12360
12319
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12361
12320
  const _number = toNumber(number, this.locale);
12362
12321
  const _significance = toNumber(significance, this.locale);
@@ -12373,7 +12332,6 @@ const ISO_CEILING = {
12373
12332
  const ISODD = {
12374
12333
  description: _t("Whether the provided value is even."),
12375
12334
  args: [arg("value (number)", _t("The value to be verified as even."))],
12376
- returns: ["BOOLEAN"],
12377
12335
  compute: function (value) {
12378
12336
  const _value = strictToNumber(value, this.locale);
12379
12337
  return Math.floor(Math.abs(_value)) & 1 ? true : false;
@@ -12386,7 +12344,6 @@ const ISODD = {
12386
12344
  const LN = {
12387
12345
  description: _t("The logarithm of a number, base e (euler's number)."),
12388
12346
  args: [arg("value (number)", _t("The value for which to calculate the logarithm, base e."))],
12389
- returns: ["NUMBER"],
12390
12347
  compute: function (value) {
12391
12348
  const _value = toNumber(value, this.locale);
12392
12349
  assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
@@ -12412,7 +12369,6 @@ const MOD = {
12412
12369
  arg("dividend (number)", _t("The number to be divided to find the remainder.")),
12413
12370
  arg("divisor (number)", _t("The number to divide by.")),
12414
12371
  ],
12415
- returns: ["NUMBER"],
12416
12372
  compute: function (dividend, divisor) {
12417
12373
  const _divisor = toNumber(divisor, this.locale);
12418
12374
  const _dividend = toNumber(dividend, this.locale);
@@ -12431,7 +12387,6 @@ const MUNIT = {
12431
12387
  args: [
12432
12388
  arg("dimension (number)", _t("An integer specifying the dimension size of the unit matrix. It must be positive.")),
12433
12389
  ],
12434
- returns: ["RANGE<NUMBER>"],
12435
12390
  compute: function (n) {
12436
12391
  const _n = toInteger(n, this.locale);
12437
12392
  assertPositive(_t("The argument dimension must be positive"), _n);
@@ -12445,7 +12400,6 @@ const MUNIT = {
12445
12400
  const ODD = {
12446
12401
  description: _t("Rounds a number up to the nearest odd integer."),
12447
12402
  args: [arg("value (number)", _t("The value to round to the next greatest odd number."))],
12448
- returns: ["NUMBER"],
12449
12403
  compute: function (value) {
12450
12404
  const _value = toNumber(value, this.locale);
12451
12405
  let temp = Math.ceil(Math.abs(_value));
@@ -12463,7 +12417,6 @@ const ODD = {
12463
12417
  const PI = {
12464
12418
  description: _t("The number pi."),
12465
12419
  args: [],
12466
- returns: ["NUMBER"],
12467
12420
  compute: function () {
12468
12421
  return Math.PI;
12469
12422
  },
@@ -12478,7 +12431,6 @@ const POWER = {
12478
12431
  arg("base (number)", _t("The number to raise to the exponent power.")),
12479
12432
  arg("exponent (number)", _t("The exponent to raise base to.")),
12480
12433
  ],
12481
- returns: ["NUMBER"],
12482
12434
  compute: function (base, exponent) {
12483
12435
  const _base = toNumber(base, this.locale);
12484
12436
  const _exponent = toNumber(exponent, this.locale);
@@ -12496,7 +12448,6 @@ const PRODUCT = {
12496
12448
  arg("factor1 (number, range<number>)", _t("The first number or range to calculate for the product.")),
12497
12449
  arg("factor2 (number, range<number>, repeating)", _t("More numbers or ranges to calculate for the product.")),
12498
12450
  ],
12499
- returns: ["NUMBER"],
12500
12451
  compute: function (...factors) {
12501
12452
  let count = 0;
12502
12453
  let acc = 1;
@@ -12533,7 +12484,6 @@ const PRODUCT = {
12533
12484
  const RAND = {
12534
12485
  description: _t("A random number between 0 inclusive and 1 exclusive."),
12535
12486
  args: [],
12536
- returns: ["NUMBER"],
12537
12487
  compute: function () {
12538
12488
  return Math.random();
12539
12489
  },
@@ -12551,7 +12501,6 @@ const RANDARRAY = {
12551
12501
  arg("max (number, default=1)", _t("The maximum number you would like returned.")),
12552
12502
  arg("whole_number (number, default=FALSE)", _t("Return a whole number or a decimal value.")),
12553
12503
  ],
12554
- returns: ["RANGE<NUMBER>"],
12555
12504
  compute: function (rows = { value: 1 }, columns = { value: 1 }, min = { value: 0 }, max = { value: 1 }, wholeNumber = { value: false }) {
12556
12505
  const _cols = toInteger(columns, this.locale);
12557
12506
  const _rows = toInteger(rows, this.locale);
@@ -12589,7 +12538,6 @@ const RANDBETWEEN = {
12589
12538
  arg("low (number)", _t("The low end of the random range.")),
12590
12539
  arg("high (number)", _t("The high end of the random range.")),
12591
12540
  ],
12592
- returns: ["NUMBER"],
12593
12541
  compute: function (low, high) {
12594
12542
  let _low = toNumber(low, this.locale);
12595
12543
  if (!Number.isInteger(_low)) {
@@ -12616,7 +12564,6 @@ const ROUND = {
12616
12564
  arg("value (number)", _t("The value to round to places number of places.")),
12617
12565
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12618
12566
  ],
12619
- returns: ["NUMBER"],
12620
12567
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12621
12568
  const _value = toNumber(value, this.locale);
12622
12569
  let _places = toNumber(places, this.locale);
@@ -12647,7 +12594,6 @@ const ROUNDDOWN = {
12647
12594
  arg("value (number)", _t("The value to round to places number of places, always rounding down.")),
12648
12595
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12649
12596
  ],
12650
- returns: ["NUMBER"],
12651
12597
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12652
12598
  const _value = toNumber(value, this.locale);
12653
12599
  let _places = toNumber(places, this.locale);
@@ -12678,7 +12624,6 @@ const ROUNDUP = {
12678
12624
  arg("value (number)", _t("The value to round to places number of places, always rounding up.")),
12679
12625
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12680
12626
  ],
12681
- returns: ["NUMBER"],
12682
12627
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12683
12628
  const _value = toNumber(value, this.locale);
12684
12629
  let _places = toNumber(places, this.locale);
@@ -12706,7 +12651,6 @@ const ROUNDUP = {
12706
12651
  const SEC = {
12707
12652
  description: _t("Secant of an angle provided in radians."),
12708
12653
  args: [arg("angle (number)", _t("The angle to find the secant of, in radians."))],
12709
- returns: ["NUMBER"],
12710
12654
  compute: function (angle) {
12711
12655
  return 1 / Math.cos(toNumber(angle, this.locale));
12712
12656
  },
@@ -12718,7 +12662,6 @@ const SEC = {
12718
12662
  const SECH = {
12719
12663
  description: _t("Hyperbolic secant of any real number."),
12720
12664
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic secant of."))],
12721
- returns: ["NUMBER"],
12722
12665
  compute: function (value) {
12723
12666
  return 1 / Math.cosh(toNumber(value, this.locale));
12724
12667
  },
@@ -12730,7 +12673,6 @@ const SECH = {
12730
12673
  const SIN = {
12731
12674
  description: _t("Sine of an angle provided in radians."),
12732
12675
  args: [arg("angle (number)", _t("The angle to find the sine of, in radians."))],
12733
- returns: ["NUMBER"],
12734
12676
  compute: function (angle) {
12735
12677
  return Math.sin(toNumber(angle, this.locale));
12736
12678
  },
@@ -12742,7 +12684,6 @@ const SIN = {
12742
12684
  const SINH = {
12743
12685
  description: _t("Hyperbolic sine of any real number."),
12744
12686
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic sine of."))],
12745
- returns: ["NUMBER"],
12746
12687
  compute: function (value) {
12747
12688
  return Math.sinh(toNumber(value, this.locale));
12748
12689
  },
@@ -12754,7 +12695,6 @@ const SINH = {
12754
12695
  const SQRT = {
12755
12696
  description: _t("Positive square root of a positive number."),
12756
12697
  args: [arg("value (number)", _t("The number for which to calculate the positive square root."))],
12757
- returns: ["NUMBER"],
12758
12698
  compute: function (value) {
12759
12699
  const _value = toNumber(value, this.locale);
12760
12700
  assert(() => _value >= 0, _t("The value (%s) must be positive or null.", _value.toString()));
@@ -12771,7 +12711,6 @@ const SUM = {
12771
12711
  arg("value1 (number, range<number>)", _t("The first number or range to add together.")),
12772
12712
  arg("value2 (number, range<number>, repeating)", _t("Additional numbers or ranges to add to value1.")),
12773
12713
  ],
12774
- returns: ["NUMBER"],
12775
12714
  compute: function (...values) {
12776
12715
  const v1 = values[0];
12777
12716
  return {
@@ -12791,7 +12730,6 @@ const SUMIF = {
12791
12730
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12792
12731
  arg("sum_range (range, default=criteria_range)", _t("The range to be summed, if different from range.")),
12793
12732
  ],
12794
- returns: ["NUMBER"],
12795
12733
  compute: function (criteriaRange, criterion, sumRange) {
12796
12734
  if (sumRange === undefined) {
12797
12735
  sumRange = criteriaRange;
@@ -12819,7 +12757,6 @@ const SUMIFS = {
12819
12757
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges to check.")),
12820
12758
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12821
12759
  ],
12822
- returns: ["NUMBER"],
12823
12760
  compute: function (sumRange, ...criters) {
12824
12761
  let sum = 0;
12825
12762
  visitMatchingRanges(criters, (i, j) => {
@@ -12838,7 +12775,6 @@ const SUMIFS = {
12838
12775
  const TAN = {
12839
12776
  description: _t("Tangent of an angle provided in radians."),
12840
12777
  args: [arg("angle (number)", _t("The angle to find the tangent of, in radians."))],
12841
- returns: ["NUMBER"],
12842
12778
  compute: function (angle) {
12843
12779
  return Math.tan(toNumber(angle, this.locale));
12844
12780
  },
@@ -12850,7 +12786,6 @@ const TAN = {
12850
12786
  const TANH = {
12851
12787
  description: _t("Hyperbolic tangent of any real number."),
12852
12788
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic tangent of."))],
12853
- returns: ["NUMBER"],
12854
12789
  compute: function (value) {
12855
12790
  return Math.tanh(toNumber(value, this.locale));
12856
12791
  },
@@ -12874,7 +12809,6 @@ const TRUNC = {
12874
12809
  arg("value (number)", _t("The value to be truncated.")),
12875
12810
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of significant digits to the right of the decimal point to retain.")),
12876
12811
  ],
12877
- returns: ["NUMBER"],
12878
12812
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12879
12813
  const _value = toNumber(value, this.locale);
12880
12814
  const _places = toNumber(places, this.locale);
@@ -12888,7 +12822,6 @@ const TRUNC = {
12888
12822
  const INT = {
12889
12823
  description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
12890
12824
  args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
12891
- returns: ["NUMBER"],
12892
12825
  compute: function (value) {
12893
12826
  return Math.floor(toNumber(value, this.locale));
12894
12827
  },
@@ -13247,7 +13180,6 @@ const AVEDEV = {
13247
13180
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
13248
13181
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
13249
13182
  ],
13250
- returns: ["NUMBER"],
13251
13183
  compute: function (...values) {
13252
13184
  let count = 0;
13253
13185
  const sum = reduceNumbers(values, (acc, a) => {
@@ -13269,7 +13201,6 @@ const AVERAGE = {
13269
13201
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13270
13202
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13271
13203
  ],
13272
- returns: ["NUMBER"],
13273
13204
  compute: function (...values) {
13274
13205
  return {
13275
13206
  value: average(values, this.locale),
@@ -13291,7 +13222,6 @@ const AVERAGE_WEIGHTED = {
13291
13222
  arg("additional_values (number, range<number>, repeating)", _t("Additional values to average.")),
13292
13223
  arg("additional_weights (number, range<number>, repeating)", _t("Additional weights.")),
13293
13224
  ],
13294
- returns: ["NUMBER"],
13295
13225
  compute: function (...args) {
13296
13226
  let sum = 0;
13297
13227
  let count = 0;
@@ -13339,7 +13269,6 @@ const AVERAGEA = {
13339
13269
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13340
13270
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13341
13271
  ],
13342
- returns: ["NUMBER"],
13343
13272
  compute: function (...args) {
13344
13273
  let count = 0;
13345
13274
  const sum = reduceNumbersTextAs0(args, (acc, a) => {
@@ -13364,7 +13293,6 @@ const AVERAGEIF = {
13364
13293
  arg("criterion (string)", _t("The pattern or test to apply to criteria_range.")),
13365
13294
  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.")),
13366
13295
  ],
13367
- returns: ["NUMBER"],
13368
13296
  compute: function (criteriaRange, criterion, averageRange) {
13369
13297
  const _averageRange = averageRange === undefined ? toMatrix(criteriaRange) : toMatrix(averageRange);
13370
13298
  let count = 0;
@@ -13393,7 +13321,6 @@ const AVERAGEIFS = {
13393
13321
  arg("criteria_range2 (any, range, repeating)", _t("Additional criteria_range and criterion to check.")),
13394
13322
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13395
13323
  ],
13396
- returns: ["NUMBER"],
13397
13324
  compute: function (averageRange, ...args) {
13398
13325
  const _averageRange = toMatrix(averageRange);
13399
13326
  let count = 0;
@@ -13419,7 +13346,6 @@ const COUNT = {
13419
13346
  arg("value1 (number, range<number>)", _t("The first value or range to consider when counting.")),
13420
13347
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when counting.")),
13421
13348
  ],
13422
- returns: ["NUMBER"],
13423
13349
  compute: function (...values) {
13424
13350
  return countNumbers(values, this.locale);
13425
13351
  },
@@ -13434,7 +13360,6 @@ const COUNTA = {
13434
13360
  arg("value1 (any, range)", _t("The first value or range to consider when counting.")),
13435
13361
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when counting.")),
13436
13362
  ],
13437
- returns: ["NUMBER"],
13438
13363
  compute: function (...values) {
13439
13364
  return countAny(values);
13440
13365
  },
@@ -13451,7 +13376,6 @@ const COVAR = {
13451
13376
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13452
13377
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13453
13378
  ],
13454
- returns: ["NUMBER"],
13455
13379
  compute: function (dataY, dataX) {
13456
13380
  return covariance(dataY, dataX, false);
13457
13381
  },
@@ -13466,7 +13390,6 @@ const COVARIANCE_P = {
13466
13390
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13467
13391
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13468
13392
  ],
13469
- returns: ["NUMBER"],
13470
13393
  compute: function (dataY, dataX) {
13471
13394
  return covariance(dataY, dataX, false);
13472
13395
  },
@@ -13481,7 +13404,6 @@ const COVARIANCE_S = {
13481
13404
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13482
13405
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13483
13406
  ],
13484
- returns: ["NUMBER"],
13485
13407
  compute: function (dataY, dataX) {
13486
13408
  return covariance(dataY, dataX, true);
13487
13409
  },
@@ -13497,7 +13419,6 @@ const FORECAST = {
13497
13419
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13498
13420
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13499
13421
  ],
13500
- returns: ["NUMBER"],
13501
13422
  compute: function (x, dataY, dataX) {
13502
13423
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13503
13424
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
@@ -13515,7 +13436,6 @@ const GROWTH = {
13515
13436
  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.")),
13516
13437
  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.")),
13517
13438
  ],
13518
- returns: ["NUMBER"],
13519
13439
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13520
13440
  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)));
13521
13441
  },
@@ -13529,7 +13449,6 @@ const INTERCEPT = {
13529
13449
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13530
13450
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13531
13451
  ],
13532
- returns: ["NUMBER"],
13533
13452
  compute: function (dataY, dataX) {
13534
13453
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13535
13454
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -13546,7 +13465,6 @@ const LARGE = {
13546
13465
  arg("data (any, range)", _t("Array or range containing the dataset to consider.")),
13547
13466
  arg("n (number)", _t("The rank from largest to smallest of the element to return.")),
13548
13467
  ],
13549
- returns: ["NUMBER"],
13550
13468
  compute: function (data, n) {
13551
13469
  const _n = Math.trunc(toNumber(n?.value, this.locale));
13552
13470
  let largests = [];
@@ -13581,7 +13499,6 @@ const LINEST = {
13581
13499
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13582
13500
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13583
13501
  ],
13584
- returns: ["NUMBER"],
13585
13502
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13586
13503
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13587
13504
  },
@@ -13598,7 +13515,6 @@ const LOGEST = {
13598
13515
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13599
13516
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13600
13517
  ],
13601
- returns: ["NUMBER"],
13602
13518
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13603
13519
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13604
13520
  for (let i = 0; i < coeffs.length; i++) {
@@ -13617,7 +13533,6 @@ const MATTHEWS = {
13617
13533
  arg("data_x (range)", _t("The range representing the array or matrix of observed data.")),
13618
13534
  arg("data_y (range)", _t("The range representing the array or matrix of predicted data.")),
13619
13535
  ],
13620
- returns: ["NUMBER"],
13621
13536
  compute: function (dataX, dataY) {
13622
13537
  const flatX = dataX.flat();
13623
13538
  const flatY = dataY.flat();
@@ -13661,7 +13576,6 @@ const MAX = {
13661
13576
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the maximum value.")),
13662
13577
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13663
13578
  ],
13664
- returns: ["NUMBER"],
13665
13579
  compute: function (...values) {
13666
13580
  return {
13667
13581
  value: max(values, this.locale),
@@ -13679,7 +13593,6 @@ const MAXA = {
13679
13593
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the maximum value.")),
13680
13594
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13681
13595
  ],
13682
- returns: ["NUMBER"],
13683
13596
  compute: function (...args) {
13684
13597
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
13685
13598
  return Math.max(a, acc);
@@ -13700,7 +13613,6 @@ const MAXIFS = {
13700
13613
  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.")),
13701
13614
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13702
13615
  ],
13703
- returns: ["NUMBER"],
13704
13616
  compute: function (range, ...args) {
13705
13617
  let result = -Infinity;
13706
13618
  visitMatchingRanges(args, (i, j) => {
@@ -13722,7 +13634,6 @@ const MEDIAN = {
13722
13634
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the median value.")),
13723
13635
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the median value.")),
13724
13636
  ],
13725
- returns: ["NUMBER"],
13726
13637
  compute: function (...values) {
13727
13638
  let data = [];
13728
13639
  visitNumbers(values, (value) => {
@@ -13744,7 +13655,6 @@ const MIN = {
13744
13655
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13745
13656
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13746
13657
  ],
13747
- returns: ["NUMBER"],
13748
13658
  compute: function (...values) {
13749
13659
  return {
13750
13660
  value: min(values, this.locale),
@@ -13762,7 +13672,6 @@ const MINA = {
13762
13672
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13763
13673
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13764
13674
  ],
13765
- returns: ["NUMBER"],
13766
13675
  compute: function (...args) {
13767
13676
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
13768
13677
  return Math.min(a, acc);
@@ -13783,7 +13692,6 @@ const MINIFS = {
13783
13692
  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.")),
13784
13693
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13785
13694
  ],
13786
- returns: ["NUMBER"],
13787
13695
  compute: function (range, ...args) {
13788
13696
  let result = Infinity;
13789
13697
  visitMatchingRanges(args, (i, j) => {
@@ -13826,7 +13734,6 @@ const PEARSON = {
13826
13734
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13827
13735
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13828
13736
  ],
13829
- returns: ["NUMBER"],
13830
13737
  compute: function (dataY, dataX) {
13831
13738
  return pearson(dataY, dataX);
13832
13739
  },
@@ -13843,7 +13750,6 @@ const PERCENTILE = {
13843
13750
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13844
13751
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13845
13752
  ],
13846
- returns: ["NUMBER"],
13847
13753
  compute: function (data, percentile) {
13848
13754
  return PERCENTILE_INC.compute.bind(this)(data, percentile);
13849
13755
  },
@@ -13858,7 +13764,6 @@ const PERCENTILE_EXC = {
13858
13764
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13859
13765
  arg("percentile (number)", _t("The percentile, exclusive of 0 and 1, whose value within 'data' will be calculated and returned.")),
13860
13766
  ],
13861
- returns: ["NUMBER"],
13862
13767
  compute: function (data, percentile) {
13863
13768
  return {
13864
13769
  value: centile([data], percentile, false, this.locale),
@@ -13876,7 +13781,6 @@ const PERCENTILE_INC = {
13876
13781
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13877
13782
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13878
13783
  ],
13879
- returns: ["NUMBER"],
13880
13784
  compute: function (data, percentile) {
13881
13785
  return {
13882
13786
  value: centile([data], percentile, true, this.locale),
@@ -13896,7 +13800,6 @@ const POLYFIT_COEFFS = {
13896
13800
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13897
13801
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13898
13802
  ],
13899
- returns: ["RANGE<NUMBER>"],
13900
13803
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13901
13804
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13902
13805
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
@@ -13915,7 +13818,6 @@ const POLYFIT_FORECAST = {
13915
13818
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13916
13819
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13917
13820
  ],
13918
- returns: ["NUMBER"],
13919
13821
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13920
13822
  const _order = toNumber(order, this.locale);
13921
13823
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
@@ -13933,7 +13835,6 @@ const QUARTILE = {
13933
13835
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13934
13836
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13935
13837
  ],
13936
- returns: ["NUMBER"],
13937
13838
  compute: function (data, quartileNumber) {
13938
13839
  return QUARTILE_INC.compute.bind(this)(data, quartileNumber);
13939
13840
  },
@@ -13948,7 +13849,6 @@ const QUARTILE_EXC = {
13948
13849
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13949
13850
  arg("quartile_number (number)", _t("Which quartile value, exclusive of 0 and 4, to return.")),
13950
13851
  ],
13951
- returns: ["NUMBER"],
13952
13852
  compute: function (data, quartileNumber) {
13953
13853
  const _quartileNumber = Math.trunc(toNumber(quartileNumber, this.locale));
13954
13854
  const percent = { value: 0.25 * _quartileNumber };
@@ -13968,7 +13868,6 @@ const QUARTILE_INC = {
13968
13868
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13969
13869
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13970
13870
  ],
13971
- returns: ["NUMBER"],
13972
13871
  compute: function (data, quartileNumber) {
13973
13872
  const percent = { value: 0.25 * Math.trunc(toNumber(quartileNumber, this.locale)) };
13974
13873
  return {
@@ -13987,7 +13886,6 @@ const RANK = {
13987
13886
  arg("data (range)", _t("The range containing the dataset to consider.")),
13988
13887
  arg("is_ascending (boolean, default=FALSE)", _t("Whether to consider the values in data in descending or ascending order.")),
13989
13888
  ],
13990
- returns: ["ANY"],
13991
13889
  compute: function (value, data, isAscending = { value: false }) {
13992
13890
  const _isAscending = toBoolean(isAscending);
13993
13891
  const _value = toNumber(value, this.locale);
@@ -14023,7 +13921,6 @@ const RSQ = {
14023
13921
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14024
13922
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14025
13923
  ],
14026
- returns: ["NUMBER"],
14027
13924
  compute: function (dataY, dataX) {
14028
13925
  return Math.pow(pearson(dataX, dataY), 2.0);
14029
13926
  },
@@ -14038,7 +13935,6 @@ const SLOPE = {
14038
13935
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14039
13936
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14040
13937
  ],
14041
- returns: ["NUMBER"],
14042
13938
  compute: function (dataY, dataX) {
14043
13939
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14044
13940
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -14055,7 +13951,6 @@ const SMALL = {
14055
13951
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
14056
13952
  arg("n (number)", _t("The rank from smallest to largest of the element to return.")),
14057
13953
  ],
14058
- returns: ["NUMBER"],
14059
13954
  compute: function (data, n) {
14060
13955
  const _n = Math.trunc(toNumber(n?.value, this.locale));
14061
13956
  let largests = [];
@@ -14088,7 +13983,6 @@ const SPEARMAN = {
14088
13983
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14089
13984
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14090
13985
  ],
14091
- returns: ["NUMBER"],
14092
13986
  compute: function (dataX, dataY) {
14093
13987
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14094
13988
  const n = flatDataX.length;
@@ -14115,7 +14009,6 @@ const STDEV = {
14115
14009
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14116
14010
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14117
14011
  ],
14118
- returns: ["NUMBER"],
14119
14012
  compute: function (...args) {
14120
14013
  return Math.sqrt(VAR.compute.bind(this)(...args));
14121
14014
  },
@@ -14130,7 +14023,6 @@ const STDEV_P = {
14130
14023
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14131
14024
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14132
14025
  ],
14133
- returns: ["NUMBER"],
14134
14026
  compute: function (...args) {
14135
14027
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
14136
14028
  },
@@ -14145,7 +14037,6 @@ const STDEV_S = {
14145
14037
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14146
14038
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14147
14039
  ],
14148
- returns: ["NUMBER"],
14149
14040
  compute: function (...args) {
14150
14041
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
14151
14042
  },
@@ -14160,7 +14051,6 @@ const STDEVA = {
14160
14051
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14161
14052
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14162
14053
  ],
14163
- returns: ["NUMBER"],
14164
14054
  compute: function (...args) {
14165
14055
  return Math.sqrt(VARA.compute.bind(this)(...args));
14166
14056
  },
@@ -14175,7 +14065,6 @@ const STDEVP = {
14175
14065
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14176
14066
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14177
14067
  ],
14178
- returns: ["NUMBER"],
14179
14068
  compute: function (...args) {
14180
14069
  return Math.sqrt(VARP.compute.bind(this)(...args));
14181
14070
  },
@@ -14190,7 +14079,6 @@ const STDEVPA = {
14190
14079
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14191
14080
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14192
14081
  ],
14193
- returns: ["NUMBER"],
14194
14082
  compute: function (...args) {
14195
14083
  return Math.sqrt(VARPA.compute.bind(this)(...args));
14196
14084
  },
@@ -14205,7 +14093,6 @@ const STEYX = {
14205
14093
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14206
14094
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14207
14095
  ],
14208
- returns: ["NUMBER"],
14209
14096
  compute: function (dataY, dataX) {
14210
14097
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14211
14098
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
@@ -14224,7 +14111,6 @@ const TREND = {
14224
14111
  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.")),
14225
14112
  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.")),
14226
14113
  ],
14227
- returns: ["NUMBER"],
14228
14114
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
14229
14115
  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));
14230
14116
  },
@@ -14238,7 +14124,6 @@ const VAR = {
14238
14124
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14239
14125
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14240
14126
  ],
14241
- returns: ["NUMBER"],
14242
14127
  compute: function (...args) {
14243
14128
  return variance(args, true, false, this.locale);
14244
14129
  },
@@ -14253,7 +14138,6 @@ const VAR_P = {
14253
14138
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14254
14139
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14255
14140
  ],
14256
- returns: ["NUMBER"],
14257
14141
  compute: function (...args) {
14258
14142
  return variance(args, false, false, this.locale);
14259
14143
  },
@@ -14268,7 +14152,6 @@ const VAR_S = {
14268
14152
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14269
14153
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14270
14154
  ],
14271
- returns: ["NUMBER"],
14272
14155
  compute: function (...args) {
14273
14156
  return variance(args, true, false, this.locale);
14274
14157
  },
@@ -14283,7 +14166,6 @@ const VARA = {
14283
14166
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14284
14167
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14285
14168
  ],
14286
- returns: ["NUMBER"],
14287
14169
  compute: function (...args) {
14288
14170
  return variance(args, true, true, this.locale);
14289
14171
  },
@@ -14298,7 +14180,6 @@ const VARP = {
14298
14180
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14299
14181
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14300
14182
  ],
14301
- returns: ["NUMBER"],
14302
14183
  compute: function (...args) {
14303
14184
  return variance(args, false, false, this.locale);
14304
14185
  },
@@ -14313,7 +14194,6 @@ const VARPA = {
14313
14194
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14314
14195
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14315
14196
  ],
14316
- returns: ["NUMBER"],
14317
14197
  compute: function (...args) {
14318
14198
  return variance(args, false, true, this.locale);
14319
14199
  },
@@ -14479,7 +14359,6 @@ const databaseArgs = [
14479
14359
  const DAVERAGE = {
14480
14360
  description: _t("Average of a set of values from a table-like range."),
14481
14361
  args: databaseArgs,
14482
- returns: ["NUMBER"],
14483
14362
  compute: function (database, field, criteria) {
14484
14363
  const cells = getMatchingCells(database, field, criteria, this.locale);
14485
14364
  return AVERAGE.compute.bind(this)([cells]);
@@ -14492,7 +14371,6 @@ const DAVERAGE = {
14492
14371
  const DCOUNT = {
14493
14372
  description: _t("Counts values from a table-like range."),
14494
14373
  args: databaseArgs,
14495
- returns: ["NUMBER"],
14496
14374
  compute: function (database, field, criteria) {
14497
14375
  const cells = getMatchingCells(database, field, criteria, this.locale);
14498
14376
  return COUNT.compute.bind(this)([cells]);
@@ -14505,7 +14383,6 @@ const DCOUNT = {
14505
14383
  const DCOUNTA = {
14506
14384
  description: _t("Counts values and text from a table-like range."),
14507
14385
  args: databaseArgs,
14508
- returns: ["NUMBER"],
14509
14386
  compute: function (database, field, criteria) {
14510
14387
  const cells = getMatchingCells(database, field, criteria, this.locale);
14511
14388
  return COUNTA.compute.bind(this)([cells]);
@@ -14518,7 +14395,6 @@ const DCOUNTA = {
14518
14395
  const DGET = {
14519
14396
  description: _t("Single value from a table-like range."),
14520
14397
  args: databaseArgs,
14521
- returns: ["NUMBER"],
14522
14398
  compute: function (database, field, criteria) {
14523
14399
  const cells = getMatchingCells(database, field, criteria, this.locale);
14524
14400
  assert(() => cells.length === 1, _t("More than one match found in DGET evaluation."));
@@ -14532,7 +14408,6 @@ const DGET = {
14532
14408
  const DMAX = {
14533
14409
  description: _t("Maximum of values from a table-like range."),
14534
14410
  args: databaseArgs,
14535
- returns: ["NUMBER"],
14536
14411
  compute: function (database, field, criteria) {
14537
14412
  const cells = getMatchingCells(database, field, criteria, this.locale);
14538
14413
  return MAX.compute.bind(this)([cells]);
@@ -14545,7 +14420,6 @@ const DMAX = {
14545
14420
  const DMIN = {
14546
14421
  description: _t("Minimum of values from a table-like range."),
14547
14422
  args: databaseArgs,
14548
- returns: ["NUMBER"],
14549
14423
  compute: function (database, field, criteria) {
14550
14424
  const cells = getMatchingCells(database, field, criteria, this.locale);
14551
14425
  return MIN.compute.bind(this)([cells]);
@@ -14558,7 +14432,6 @@ const DMIN = {
14558
14432
  const DPRODUCT = {
14559
14433
  description: _t("Product of values from a table-like range."),
14560
14434
  args: databaseArgs,
14561
- returns: ["NUMBER"],
14562
14435
  compute: function (database, field, criteria) {
14563
14436
  const cells = getMatchingCells(database, field, criteria, this.locale);
14564
14437
  return PRODUCT.compute.bind(this)([cells]);
@@ -14571,7 +14444,6 @@ const DPRODUCT = {
14571
14444
  const DSTDEV = {
14572
14445
  description: _t("Standard deviation of population sample from table."),
14573
14446
  args: databaseArgs,
14574
- returns: ["NUMBER"],
14575
14447
  compute: function (database, field, criteria) {
14576
14448
  const cells = getMatchingCells(database, field, criteria, this.locale);
14577
14449
  return STDEV.compute.bind(this)([cells]);
@@ -14584,7 +14456,6 @@ const DSTDEV = {
14584
14456
  const DSTDEVP = {
14585
14457
  description: _t("Standard deviation of entire population from table."),
14586
14458
  args: databaseArgs,
14587
- returns: ["NUMBER"],
14588
14459
  compute: function (database, field, criteria) {
14589
14460
  const cells = getMatchingCells(database, field, criteria, this.locale);
14590
14461
  return STDEVP.compute.bind(this)([cells]);
@@ -14597,7 +14468,6 @@ const DSTDEVP = {
14597
14468
  const DSUM = {
14598
14469
  description: _t("Sum of values from a table-like range."),
14599
14470
  args: databaseArgs,
14600
- returns: ["NUMBER"],
14601
14471
  compute: function (database, field, criteria) {
14602
14472
  const cells = getMatchingCells(database, field, criteria, this.locale);
14603
14473
  return SUM.compute.bind(this)([cells]);
@@ -14610,7 +14480,6 @@ const DSUM = {
14610
14480
  const DVAR = {
14611
14481
  description: _t("Variance of population sample from table-like range."),
14612
14482
  args: databaseArgs,
14613
- returns: ["NUMBER"],
14614
14483
  compute: function (database, field, criteria) {
14615
14484
  const cells = getMatchingCells(database, field, criteria, this.locale);
14616
14485
  return VAR.compute.bind(this)([cells]);
@@ -14623,7 +14492,6 @@ const DVAR = {
14623
14492
  const DVARP = {
14624
14493
  description: _t("Variance of a population from a table-like range."),
14625
14494
  args: databaseArgs,
14626
- returns: ["NUMBER"],
14627
14495
  compute: function (database, field, criteria) {
14628
14496
  const cells = getMatchingCells(database, field, criteria, this.locale);
14629
14497
  return VARP.compute.bind(this)([cells]);
@@ -14668,7 +14536,6 @@ const DATE = {
14668
14536
  arg("month (number)", _t("The month component of the date.")),
14669
14537
  arg("day (number)", _t("The day component of the date.")),
14670
14538
  ],
14671
- returns: ["DATE"],
14672
14539
  compute: function (year, month, day) {
14673
14540
  let _year = Math.trunc(toNumber(year, this.locale));
14674
14541
  const _month = Math.trunc(toNumber(month, this.locale));
@@ -14699,7 +14566,6 @@ const DATEDIF = {
14699
14566
  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.")),
14700
14567
  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).')),
14701
14568
  ],
14702
- returns: ["NUMBER"],
14703
14569
  compute: function (startDate, endDate, unit) {
14704
14570
  const _unit = toString(unit).toUpperCase();
14705
14571
  assert(() => Object.values(TIME_UNIT).includes(_unit), expectStringSetError(Object.values(TIME_UNIT), toString(unit)));
@@ -14752,7 +14618,6 @@ const DATEDIF = {
14752
14618
  const DATEVALUE = {
14753
14619
  description: _t("Converts a date string to a date value."),
14754
14620
  args: [arg("date_string (string)", _t("The string representing the date."))],
14755
- returns: ["NUMBER"],
14756
14621
  compute: function (dateString) {
14757
14622
  const _dateString = toString(dateString);
14758
14623
  const internalDate = parseDateTime(_dateString, this.locale);
@@ -14767,7 +14632,6 @@ const DATEVALUE = {
14767
14632
  const DAY = {
14768
14633
  description: _t("Day of the month that a specific date falls on."),
14769
14634
  args: [arg("date (string)", _t("The date from which to extract the day."))],
14770
- returns: ["NUMBER"],
14771
14635
  compute: function (date) {
14772
14636
  return toJsDate(date, this.locale).getDate();
14773
14637
  },
@@ -14782,7 +14646,6 @@ const DAYS = {
14782
14646
  arg("end_date (date)", _t("The end of the date range.")),
14783
14647
  arg("start_date (date)", _t("The start of the date range.")),
14784
14648
  ],
14785
- returns: ["NUMBER"],
14786
14649
  compute: function (endDate, startDate) {
14787
14650
  const _endDate = toJsDate(endDate, this.locale);
14788
14651
  const _startDate = toJsDate(startDate, this.locale);
@@ -14802,7 +14665,6 @@ const DAYS360 = {
14802
14665
  arg("end_date (date)", _t("The end date to consider in the calculation.")),
14803
14666
  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")),
14804
14667
  ],
14805
- returns: ["NUMBER"],
14806
14668
  compute: function (startDate, endDate, method = { value: DEFAULT_DAY_COUNT_METHOD }) {
14807
14669
  const _startDate = Math.trunc(toNumber(startDate, this.locale));
14808
14670
  const _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -14821,7 +14683,6 @@ const EDATE = {
14821
14683
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14822
14684
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to calculate.")),
14823
14685
  ],
14824
- returns: ["DATE"],
14825
14686
  compute: function (startDate, months) {
14826
14687
  const _startDate = toJsDate(startDate, this.locale);
14827
14688
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14842,7 +14703,6 @@ const EOMONTH = {
14842
14703
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14843
14704
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to consider.")),
14844
14705
  ],
14845
- returns: ["DATE"],
14846
14706
  compute: function (startDate, months) {
14847
14707
  const _startDate = toJsDate(startDate, this.locale);
14848
14708
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14862,7 +14722,6 @@ const EOMONTH = {
14862
14722
  const HOUR = {
14863
14723
  description: _t("Hour component of a specific time."),
14864
14724
  args: [arg("time (date)", _t("The time from which to calculate the hour component."))],
14865
- returns: ["NUMBER"],
14866
14725
  compute: function (date) {
14867
14726
  return toJsDate(date, this.locale).getHours();
14868
14727
  },
@@ -14876,7 +14735,6 @@ const ISOWEEKNUM = {
14876
14735
  args: [
14877
14736
  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.")),
14878
14737
  ],
14879
- returns: ["NUMBER"],
14880
14738
  compute: function (date) {
14881
14739
  const _date = toJsDate(date, this.locale);
14882
14740
  const y = _date.getFullYear();
@@ -14948,7 +14806,6 @@ const ISOWEEKNUM = {
14948
14806
  const MINUTE = {
14949
14807
  description: _t("Minute component of a specific time."),
14950
14808
  args: [arg("time (date)", _t("The time from which to calculate the minute component."))],
14951
- returns: ["NUMBER"],
14952
14809
  compute: function (date) {
14953
14810
  return toJsDate(date, this.locale).getMinutes();
14954
14811
  },
@@ -14960,7 +14817,6 @@ const MINUTE = {
14960
14817
  const MONTH = {
14961
14818
  description: _t("Month of the year a specific date falls in"),
14962
14819
  args: [arg("date (date)", _t("The date from which to extract the month."))],
14963
- returns: ["NUMBER"],
14964
14820
  compute: function (date) {
14965
14821
  return toJsDate(date, this.locale).getMonth() + 1;
14966
14822
  },
@@ -14976,7 +14832,6 @@ const NETWORKDAYS = {
14976
14832
  arg("end_date (date)", _t("The end date of the period from which to calculate the number of net working days.")),
14977
14833
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the date serial numbers to consider holidays.")),
14978
14834
  ],
14979
- returns: ["NUMBER"],
14980
14835
  compute: function (startDate, endDate, holidays) {
14981
14836
  return NETWORKDAYS_INTL.compute.bind(this)(startDate, endDate, { value: 1 }, holidays);
14982
14837
  },
@@ -15057,7 +14912,6 @@ const NETWORKDAYS_INTL = {
15057
14912
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15058
14913
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider as holidays.")),
15059
14914
  ],
15060
- returns: ["NUMBER"],
15061
14915
  compute: function (startDate, endDate, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15062
14916
  const _startDate = toJsDate(startDate, this.locale);
15063
14917
  const _endDate = toJsDate(endDate, this.locale);
@@ -15092,7 +14946,6 @@ const NETWORKDAYS_INTL = {
15092
14946
  const NOW = {
15093
14947
  description: _t("Current date and time as a date value."),
15094
14948
  args: [],
15095
- returns: ["DATE"],
15096
14949
  compute: function () {
15097
14950
  const today = DateTime.now();
15098
14951
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
@@ -15110,7 +14963,6 @@ const NOW = {
15110
14963
  const SECOND = {
15111
14964
  description: _t("Minute component of a specific time."),
15112
14965
  args: [arg("time (date)", _t("The time from which to calculate the second component."))],
15113
- returns: ["NUMBER"],
15114
14966
  compute: function (date) {
15115
14967
  return toJsDate(date, this.locale).getSeconds();
15116
14968
  },
@@ -15126,7 +14978,6 @@ const TIME = {
15126
14978
  arg("minute (number)", _t("The minute component of the time.")),
15127
14979
  arg("second (number)", _t("The second component of the time.")),
15128
14980
  ],
15129
- returns: ["DATE"],
15130
14981
  compute: function (hour, minute, second) {
15131
14982
  let _hour = Math.trunc(toNumber(hour, this.locale));
15132
14983
  let _minute = Math.trunc(toNumber(minute, this.locale));
@@ -15150,7 +15001,6 @@ const TIME = {
15150
15001
  const TIMEVALUE = {
15151
15002
  description: _t("Converts a time string into its serial number representation."),
15152
15003
  args: [arg("time_string (string)", _t("The string that holds the time representation."))],
15153
- returns: ["NUMBER"],
15154
15004
  compute: function (timeString) {
15155
15005
  const _timeString = toString(timeString);
15156
15006
  const internalDate = parseDateTime(_timeString, this.locale);
@@ -15166,7 +15016,6 @@ const TIMEVALUE = {
15166
15016
  const TODAY = {
15167
15017
  description: _t("Current date as a date value."),
15168
15018
  args: [],
15169
- returns: ["DATE"],
15170
15019
  compute: function () {
15171
15020
  const today = DateTime.now();
15172
15021
  const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
@@ -15186,7 +15035,6 @@ const WEEKDAY = {
15186
15035
  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.")),
15187
15036
  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.")),
15188
15037
  ],
15189
- returns: ["NUMBER"],
15190
15038
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15191
15039
  const _date = toJsDate(date, this.locale);
15192
15040
  const _type = Math.round(toNumber(type, this.locale));
@@ -15209,7 +15057,6 @@ const WEEKNUM = {
15209
15057
  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.")),
15210
15058
  arg(`type (number, default=${DEFAULT_TYPE})`, _t("A number representing the day that a week starts on. Sunday = 1.")),
15211
15059
  ],
15212
- returns: ["NUMBER"],
15213
15060
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15214
15061
  const _date = toJsDate(date, this.locale);
15215
15062
  const _type = Math.round(toNumber(type, this.locale));
@@ -15250,7 +15097,6 @@ const WORKDAY = {
15250
15097
  arg("num_days (number)", _t("The number of working days to advance from start_date. If negative, counts backwards.")),
15251
15098
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15252
15099
  ],
15253
- returns: ["NUMBER"],
15254
15100
  compute: function (startDate, numDays, holidays = { value: null }) {
15255
15101
  return WORKDAY_INTL.compute.bind(this)(startDate, numDays, { value: 1 }, holidays);
15256
15102
  },
@@ -15267,7 +15113,6 @@ const WORKDAY_INTL = {
15267
15113
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15268
15114
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15269
15115
  ],
15270
- returns: ["DATE"],
15271
15116
  compute: function (startDate, numDays, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15272
15117
  let _startDate = toJsDate(startDate, this.locale);
15273
15118
  let _numDays = Math.trunc(toNumber(numDays, this.locale));
@@ -15307,7 +15152,6 @@ const WORKDAY_INTL = {
15307
15152
  const YEAR = {
15308
15153
  description: _t("Year specified by a given date."),
15309
15154
  args: [arg("date (date)", _t("The date from which to extract the year."))],
15310
- returns: ["NUMBER"],
15311
15155
  compute: function (date) {
15312
15156
  return toJsDate(date, this.locale).getFullYear();
15313
15157
  },
@@ -15324,7 +15168,6 @@ const YEARFRAC = {
15324
15168
  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.")),
15325
15169
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION$1})`, _t("An indicator of what day count method to use.")),
15326
15170
  ],
15327
- returns: ["NUMBER"],
15328
15171
  compute: function (startDate, endDate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION$1 }) {
15329
15172
  let _startDate = Math.trunc(toNumber(startDate, this.locale));
15330
15173
  let _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -15341,7 +15184,6 @@ const YEARFRAC = {
15341
15184
  const MONTH_START = {
15342
15185
  description: _t("First day of the month preceding a date."),
15343
15186
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15344
- returns: ["DATE"],
15345
15187
  compute: function (date) {
15346
15188
  const _startDate = toJsDate(date, this.locale);
15347
15189
  const yStart = _startDate.getFullYear();
@@ -15359,7 +15201,6 @@ const MONTH_START = {
15359
15201
  const MONTH_END = {
15360
15202
  description: _t("Last day of the month following a date."),
15361
15203
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15362
- returns: ["DATE"],
15363
15204
  compute: function (date) {
15364
15205
  return EOMONTH.compute.bind(this)(date, { value: 0 });
15365
15206
  },
@@ -15370,7 +15211,6 @@ const MONTH_END = {
15370
15211
  const QUARTER = {
15371
15212
  description: _t("Quarter of the year a specific date falls in"),
15372
15213
  args: [arg("date (date)", _t("The date from which to extract the quarter."))],
15373
- returns: ["NUMBER"],
15374
15214
  compute: function (date) {
15375
15215
  return Math.ceil((toJsDate(date, this.locale).getMonth() + 1) / 3);
15376
15216
  },
@@ -15381,7 +15221,6 @@ const QUARTER = {
15381
15221
  const QUARTER_START = {
15382
15222
  description: _t("First day of the quarter of the year a specific date falls in."),
15383
15223
  args: [arg("date (date)", _t("The date from which to calculate the start of quarter."))],
15384
- returns: ["DATE"],
15385
15224
  compute: function (date) {
15386
15225
  const quarter = QUARTER.compute.bind(this)(date);
15387
15226
  const year = YEAR.compute.bind(this)(date);
@@ -15398,7 +15237,6 @@ const QUARTER_START = {
15398
15237
  const QUARTER_END = {
15399
15238
  description: _t("Last day of the quarter of the year a specific date falls in."),
15400
15239
  args: [arg("date (date)", _t("The date from which to calculate the end of quarter."))],
15401
- returns: ["DATE"],
15402
15240
  compute: function (date) {
15403
15241
  const quarter = QUARTER.compute.bind(this)(date);
15404
15242
  const year = YEAR.compute.bind(this)(date);
@@ -15415,7 +15253,6 @@ const QUARTER_END = {
15415
15253
  const YEAR_START = {
15416
15254
  description: _t("First day of the year a specific date falls in."),
15417
15255
  args: [arg("date (date)", _t("The date from which to calculate the start of the year."))],
15418
- returns: ["DATE"],
15419
15256
  compute: function (date) {
15420
15257
  const year = YEAR.compute.bind(this)(date);
15421
15258
  const jsDate = new DateTime(year, 0, 1);
@@ -15431,7 +15268,6 @@ const YEAR_START = {
15431
15268
  const YEAR_END = {
15432
15269
  description: _t("Last day of the year a specific date falls in."),
15433
15270
  args: [arg("date (date)", _t("The date from which to calculate the end of the year."))],
15434
- returns: ["DATE"],
15435
15271
  compute: function (date) {
15436
15272
  const year = YEAR.compute.bind(this)(date);
15437
15273
  const jsDate = new DateTime(year + 1, 0, 0);
@@ -15488,7 +15324,6 @@ const DELTA = {
15488
15324
  arg("number1 (number)", _t("The first number to compare.")),
15489
15325
  arg(`number2 (number, default=${DEFAULT_DELTA_ARG})`, _t("The second number to compare.")),
15490
15326
  ],
15491
- returns: ["NUMBER"],
15492
15327
  compute: function (number1, number2 = { value: DEFAULT_DELTA_ARG }) {
15493
15328
  const _number1 = toNumber(number1, this.locale);
15494
15329
  const _number2 = toNumber(number2, this.locale);
@@ -15679,7 +15514,6 @@ const FILTER = {
15679
15514
  arg("condition1 (boolean, range<boolean>)", _t("A column or row containing true or false values corresponding to the first column or row of range.")),
15680
15515
  arg("condition2 (boolean, range<boolean>, repeating)", _t("Additional column or row containing true or false values.")),
15681
15516
  ],
15682
- returns: ["RANGE<ANY>"],
15683
15517
  compute: function (range, ...conditions) {
15684
15518
  let _array = toMatrix(range);
15685
15519
  const _conditionsMatrices = conditions.map((cond) => matrixMap(toMatrix(cond), (data) => data.value));
@@ -15713,7 +15547,6 @@ const SORT = {
15713
15547
  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.")),
15714
15548
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15715
15549
  ],
15716
- returns: ["RANGE"],
15717
15550
  compute: function (range, ...sortingCriteria) {
15718
15551
  const _range = transposeMatrix(range);
15719
15552
  return transposeMatrix(sortMatrix(_range, this.locale, ...sortingCriteria));
@@ -15732,7 +15565,6 @@ const SORTN = {
15732
15565
  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.")),
15733
15566
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15734
15567
  ],
15735
- returns: ["RANGE"],
15736
15568
  compute: function (range, n, displayTiesMode, ...sortingCriteria) {
15737
15569
  const _n = toNumber(n?.value ?? 1, this.locale);
15738
15570
  assert(() => _n >= 0, _t("Wrong value of 'n'. Expected a positive number. Got %s.", _n));
@@ -15800,7 +15632,6 @@ const UNIQUE = {
15800
15632
  arg("by_column (boolean, default=FALSE)", _t("Whether to filter the data by columns or by rows.")),
15801
15633
  arg("exactly_once (boolean, default=FALSE)", _t("Whether to return only entries with no duplicates.")),
15802
15634
  ],
15803
- returns: ["RANGE<NUMBER>"],
15804
15635
  compute: function (range = { value: "" }, byColumn, exactlyOnce) {
15805
15636
  if (!isMatrix(range)) {
15806
15637
  return [[range]];
@@ -16025,7 +15856,6 @@ const ACCRINTM = {
16025
15856
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16026
15857
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16027
15858
  ],
16028
- returns: ["NUMBER"],
16029
15859
  compute: function (issue, maturity, rate, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16030
15860
  const start = Math.trunc(toNumber(issue, this.locale));
16031
15861
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16056,7 +15886,6 @@ const AMORLINC = {
16056
15886
  arg("rate (number)", _t("The deprecation rate.")),
16057
15887
  arg("day_count_convention (number, optional)", _t("An indicator of what day count method to use.")),
16058
15888
  ],
16059
- returns: ["NUMBER"],
16060
15889
  compute: function (cost, purchaseDate, firstPeriodEnd, salvage, period, rate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16061
15890
  dayCountConvention = dayCountConvention || 0;
16062
15891
  const _cost = toNumber(cost, this.locale);
@@ -16105,7 +15934,6 @@ const AMORLINC = {
16105
15934
  const COUPDAYS = {
16106
15935
  description: _t("Days in coupon period containing settlement date."),
16107
15936
  args: COUPON_FUNCTION_ARGS,
16108
- returns: ["NUMBER"],
16109
15937
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16110
15938
  dayCountConvention = dayCountConvention || 0;
16111
15939
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16132,7 +15960,6 @@ const COUPDAYS = {
16132
15960
  const COUPDAYBS = {
16133
15961
  description: _t("Days from settlement until next coupon."),
16134
15962
  args: COUPON_FUNCTION_ARGS,
16135
- returns: ["NUMBER"],
16136
15963
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16137
15964
  dayCountConvention = dayCountConvention || 0;
16138
15965
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16189,7 +16016,6 @@ const COUPDAYBS = {
16189
16016
  const COUPDAYSNC = {
16190
16017
  description: _t("Days from settlement until next coupon."),
16191
16018
  args: COUPON_FUNCTION_ARGS,
16192
- returns: ["NUMBER"],
16193
16019
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16194
16020
  dayCountConvention = dayCountConvention || 0;
16195
16021
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16219,7 +16045,6 @@ const COUPDAYSNC = {
16219
16045
  const COUPNCD = {
16220
16046
  description: _t("Next coupon date after the settlement date."),
16221
16047
  args: COUPON_FUNCTION_ARGS,
16222
- returns: ["NUMBER"],
16223
16048
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16224
16049
  dayCountConvention = dayCountConvention || 0;
16225
16050
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16245,7 +16070,6 @@ const COUPNCD = {
16245
16070
  const COUPNUM = {
16246
16071
  description: _t("Number of coupons between settlement and maturity."),
16247
16072
  args: COUPON_FUNCTION_ARGS,
16248
- returns: ["NUMBER"],
16249
16073
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16250
16074
  dayCountConvention = dayCountConvention || 0;
16251
16075
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16272,7 +16096,6 @@ const COUPNUM = {
16272
16096
  const COUPPCD = {
16273
16097
  description: _t("Last coupon date prior to or on the settlement date."),
16274
16098
  args: COUPON_FUNCTION_ARGS,
16275
- returns: ["NUMBER"],
16276
16099
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16277
16100
  dayCountConvention = dayCountConvention || 0;
16278
16101
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16305,7 +16128,6 @@ const CUMIPMT = {
16305
16128
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16306
16129
  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.")),
16307
16130
  ],
16308
- returns: ["NUMBER"],
16309
16131
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16310
16132
  const first = toNumber(firstPeriod, this.locale);
16311
16133
  const last = toNumber(lastPeriod, this.locale);
@@ -16337,7 +16159,6 @@ const CUMPRINC = {
16337
16159
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16338
16160
  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.")),
16339
16161
  ],
16340
- returns: ["NUMBER"],
16341
16162
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16342
16163
  const first = toNumber(firstPeriod, this.locale);
16343
16164
  const last = toNumber(lastPeriod, this.locale);
@@ -16368,7 +16189,6 @@ const DB = {
16368
16189
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16369
16190
  arg("month (number, optional)", _t("The number of months in the first year of depreciation.")),
16370
16191
  ],
16371
- returns: ["NUMBER"],
16372
16192
  // to do: replace by dollar format
16373
16193
  compute: function (cost, salvage, life, period, ...args) {
16374
16194
  const _cost = toNumber(cost, this.locale);
@@ -16437,7 +16257,6 @@ const DDB = {
16437
16257
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16438
16258
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The factor by which depreciation decreases.")),
16439
16259
  ],
16440
- returns: ["NUMBER"],
16441
16260
  compute: function (cost, salvage, life, period, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }) {
16442
16261
  const _cost = toNumber(cost, this.locale);
16443
16262
  const _salvage = toNumber(salvage, this.locale);
@@ -16463,7 +16282,6 @@ const DISC = {
16463
16282
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16464
16283
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16465
16284
  ],
16466
- returns: ["NUMBER"],
16467
16285
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16468
16286
  dayCountConvention = dayCountConvention || 0;
16469
16287
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -16499,7 +16317,6 @@ const DOLLARDE = {
16499
16317
  arg("fractional_price (number)", _t("The price quotation given using fractional decimal conventions.")),
16500
16318
  arg("unit (number)", _t("The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16501
16319
  ],
16502
- returns: ["NUMBER"],
16503
16320
  compute: function (fractionalPrice, unit) {
16504
16321
  const price = toNumber(fractionalPrice, this.locale);
16505
16322
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16520,7 +16337,6 @@ const DOLLARFR = {
16520
16337
  arg("decimal_price (number)", _t("The price quotation given as a decimal value.")),
16521
16338
  arg("unit (number)", _t("The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16522
16339
  ],
16523
- returns: ["NUMBER"],
16524
16340
  compute: function (decimalPrice, unit) {
16525
16341
  const price = toNumber(decimalPrice, this.locale);
16526
16342
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16545,7 +16361,6 @@ const DURATION = {
16545
16361
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16546
16362
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16547
16363
  ],
16548
- returns: ["NUMBER"],
16549
16364
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16550
16365
  const start = Math.trunc(toNumber(settlement, this.locale));
16551
16366
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16586,7 +16401,6 @@ const EFFECT = {
16586
16401
  arg("nominal_rate (number)", _t("The nominal interest rate per year.")),
16587
16402
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16588
16403
  ],
16589
- returns: ["NUMBER"],
16590
16404
  compute: function (nominal_rate, periods_per_year) {
16591
16405
  const nominal = toNumber(nominal_rate, this.locale);
16592
16406
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16616,7 +16430,6 @@ const FV = {
16616
16430
  arg(`present_value (number, default=${DEFAULT_PRESENT_VALUE})`, _t("The current value of the annuity.")),
16617
16431
  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.")),
16618
16432
  ],
16619
- returns: ["NUMBER"],
16620
16433
  // to do: replace by dollar format
16621
16434
  compute: function (rate, numberOfPeriods, paymentAmount, presentValue = { value: DEFAULT_PRESENT_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16622
16435
  presentValue = presentValue || 0;
@@ -16642,7 +16455,6 @@ const FVSCHEDULE = {
16642
16455
  arg("principal (number)", _t("The amount of initial capital or value to compound against.")),
16643
16456
  arg("rate_schedule (number, range<number>)", _t("A series of interest rates to compound against the principal.")),
16644
16457
  ],
16645
- returns: ["NUMBER"],
16646
16458
  compute: function (principalAmount, rateSchedule) {
16647
16459
  const principal = toNumber(principalAmount, this.locale);
16648
16460
  return reduceAny([rateSchedule], (acc, rate) => acc * (1 + toNumber(rate, this.locale)), principal);
@@ -16661,7 +16473,6 @@ const INTRATE = {
16661
16473
  arg("redemption (number)", _t("The amount to be received at maturity.")),
16662
16474
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16663
16475
  ],
16664
- returns: ["NUMBER"],
16665
16476
  compute: function (settlement, maturity, investment, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16666
16477
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
16667
16478
  const _maturity = Math.trunc(toNumber(maturity, this.locale));
@@ -16700,7 +16511,6 @@ const IPMT = {
16700
16511
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16701
16512
  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.")),
16702
16513
  ],
16703
- returns: ["NUMBER"],
16704
16514
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16705
16515
  const r = toNumber(rate, this.locale);
16706
16516
  const period = toNumber(currentPeriod, this.locale);
@@ -16725,7 +16535,6 @@ const IRR = {
16725
16535
  arg("cashflow_amounts (number, range<number>)", _t("An array or range containing the income or payments associated with the investment.")),
16726
16536
  arg(`rate_guess (number, default=${DEFAULT_RATE_GUESS})`, _t("An estimate for what the internal rate of return will be.")),
16727
16537
  ],
16728
- returns: ["NUMBER"],
16729
16538
  compute: function (cashFlowAmounts, rateGuess = { value: DEFAULT_RATE_GUESS }) {
16730
16539
  const _rateGuess = toNumber(rateGuess, this.locale);
16731
16540
  assertRateGuessStrictlyGreaterThanMinusOne(_rateGuess);
@@ -16787,7 +16596,6 @@ const ISPMT = {
16787
16596
  arg("number_of_periods (number)", _t("The number of payments to be made.")),
16788
16597
  arg("present_value (number)", _t("The current value of the annuity.")),
16789
16598
  ],
16790
- returns: ["NUMBER"],
16791
16599
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue) {
16792
16600
  const interestRate = toNumber(rate, this.locale);
16793
16601
  const period = toNumber(currentPeriod, this.locale);
@@ -16812,7 +16620,6 @@ const MDURATION = {
16812
16620
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16813
16621
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16814
16622
  ],
16815
- returns: ["NUMBER"],
16816
16623
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16817
16624
  const duration = DURATION.compute.bind(this)(settlement, maturity, rate, securityYield, frequency, dayCountConvention);
16818
16625
  const y = toNumber(securityYield, this.locale);
@@ -16831,7 +16638,6 @@ const MIRR = {
16831
16638
  arg("financing_rate (number)", _t("The interest rate paid on funds invested.")),
16832
16639
  arg("reinvestment_return_rate (number)", _t("The return (as a percentage) earned on reinvestment of income received from the investment.")),
16833
16640
  ],
16834
- returns: ["NUMBER"],
16835
16641
  compute: function (cashflowAmount, financingRate, reinvestmentRate) {
16836
16642
  const fRate = toNumber(financingRate, this.locale);
16837
16643
  const rRate = toNumber(reinvestmentRate, this.locale);
@@ -16883,7 +16689,6 @@ const NOMINAL = {
16883
16689
  arg("effective_rate (number)", _t("The effective interest rate per year.")),
16884
16690
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16885
16691
  ],
16886
- returns: ["NUMBER"],
16887
16692
  compute: function (effective_rate, periods_per_year) {
16888
16693
  const effective = toNumber(effective_rate, this.locale);
16889
16694
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16906,7 +16711,6 @@ const NPER = {
16906
16711
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16907
16712
  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.")),
16908
16713
  ],
16909
- returns: ["NUMBER"],
16910
16714
  compute: function (rate, paymentAmount, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16911
16715
  futureValue = futureValue || 0;
16912
16716
  endOrBeginning = endOrBeginning || 0;
@@ -16954,7 +16758,6 @@ const NPV = {
16954
16758
  arg("cashflow1 (number, range<number>)", _t("The first future cash flow.")),
16955
16759
  arg("cashflow2 (number, range<number>, repeating)", _t("Additional future cash flows.")),
16956
16760
  ],
16957
- returns: ["NUMBER"],
16958
16761
  // to do: replace by dollar format
16959
16762
  compute: function (discount, ...values) {
16960
16763
  const _discount = toNumber(discount, this.locale);
@@ -16976,7 +16779,6 @@ const PDURATION = {
16976
16779
  arg("present_value (number)", _t("The investment's current value.")),
16977
16780
  arg("future_value (number)", _t("The investment's desired future value.")),
16978
16781
  ],
16979
- returns: ["NUMBER"],
16980
16782
  compute: function (rate, presentValue, futureValue) {
16981
16783
  const _rate = toNumber(rate, this.locale);
16982
16784
  const _presentValue = toNumber(presentValue, this.locale);
@@ -17016,7 +16818,6 @@ const PMT = {
17016
16818
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17017
16819
  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.")),
17018
16820
  ],
17019
- returns: ["NUMBER"],
17020
16821
  compute: function (rate, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17021
16822
  const n = toNumber(numberOfPeriods, this.locale);
17022
16823
  const r = toNumber(rate, this.locale);
@@ -17052,7 +16853,6 @@ const PPMT = {
17052
16853
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17053
16854
  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.")),
17054
16855
  ],
17055
- returns: ["NUMBER"],
17056
16856
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17057
16857
  const n = toNumber(numberOfPeriods, this.locale);
17058
16858
  const r = toNumber(rate, this.locale);
@@ -17079,7 +16879,6 @@ const PV = {
17079
16879
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17080
16880
  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.")),
17081
16881
  ],
17082
- returns: ["NUMBER"],
17083
16882
  // to do: replace by dollar format
17084
16883
  compute: function (rate, numberOfPeriods, paymentAmount, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17085
16884
  futureValue = futureValue || 0;
@@ -17113,7 +16912,6 @@ const PRICE = {
17113
16912
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17114
16913
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17115
16914
  ],
17116
- returns: ["NUMBER"],
17117
16915
  compute: function (settlement, maturity, rate, securityYield, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17118
16916
  dayCountConvention = dayCountConvention || 0;
17119
16917
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17161,7 +16959,6 @@ const PRICEDISC = {
17161
16959
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17162
16960
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17163
16961
  ],
17164
- returns: ["NUMBER"],
17165
16962
  compute: function (settlement, maturity, discount, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17166
16963
  dayCountConvention = dayCountConvention || 0;
17167
16964
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17199,7 +16996,6 @@ const PRICEMAT = {
17199
16996
  arg("yield (number)", _t("The expected annual yield of the security.")),
17200
16997
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17201
16998
  ],
17202
- returns: ["NUMBER"],
17203
16999
  compute: function (settlement, maturity, issue, rate, securityYield, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17204
17000
  dayCountConvention = dayCountConvention || 0;
17205
17001
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17263,7 +17059,6 @@ const RATE = {
17263
17059
  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.")),
17264
17060
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the interest rate will be.")),
17265
17061
  ],
17266
- returns: ["NUMBER"],
17267
17062
  compute: function (numberOfPeriods, paymentPerPeriod, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17268
17063
  const n = toNumber(numberOfPeriods, this.locale);
17269
17064
  const payment = toNumber(paymentPerPeriod, this.locale);
@@ -17309,7 +17104,6 @@ const RECEIVED = {
17309
17104
  arg("discount (number)", _t("The discount rate of the security invested in.")),
17310
17105
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17311
17106
  ],
17312
- returns: ["NUMBER"],
17313
17107
  compute: function (settlement, maturity, investment, discount, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17314
17108
  dayCountConvention = dayCountConvention || 0;
17315
17109
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17347,7 +17141,6 @@ const RRI = {
17347
17141
  arg("present_value (number)", _t("The present value of the investment.")),
17348
17142
  arg("future_value (number)", _t("The future value of the investment.")),
17349
17143
  ],
17350
- returns: ["NUMBER"],
17351
17144
  compute: function (numberOfPeriods, presentValue, futureValue) {
17352
17145
  const n = toNumber(numberOfPeriods, this.locale);
17353
17146
  const pv = toNumber(presentValue, this.locale);
@@ -17372,7 +17165,6 @@ const SLN = {
17372
17165
  arg("salvage (number)", _t("The value of the asset at the end of depreciation.")),
17373
17166
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17374
17167
  ],
17375
- returns: ["NUMBER"],
17376
17168
  compute: function (cost, salvage, life) {
17377
17169
  const _cost = toNumber(cost, this.locale);
17378
17170
  const _salvage = toNumber(salvage, this.locale);
@@ -17397,7 +17189,6 @@ const SYD = {
17397
17189
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17398
17190
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
17399
17191
  ],
17400
- returns: ["NUMBER"],
17401
17192
  compute: function (cost, salvage, life, period) {
17402
17193
  const _cost = toNumber(cost, this.locale);
17403
17194
  const _salvage = toNumber(salvage, this.locale);
@@ -17446,7 +17237,6 @@ const TBILLPRICE = {
17446
17237
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17447
17238
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17448
17239
  ],
17449
- returns: ["NUMBER"],
17450
17240
  compute: function (settlement, maturity, discount) {
17451
17241
  const start = Math.trunc(toNumber(settlement, this.locale));
17452
17242
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17469,7 +17259,6 @@ const TBILLEQ = {
17469
17259
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17470
17260
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17471
17261
  ],
17472
- returns: ["NUMBER"],
17473
17262
  compute: function (settlement, maturity, discount) {
17474
17263
  const start = Math.trunc(toNumber(settlement, this.locale));
17475
17264
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17527,7 +17316,6 @@ const TBILLYIELD = {
17527
17316
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17528
17317
  arg("price (number)", _t("The price at which the security is bought per 100 face value.")),
17529
17318
  ],
17530
- returns: ["NUMBER"],
17531
17319
  compute: function (settlement, maturity, price) {
17532
17320
  const start = Math.trunc(toNumber(settlement, this.locale));
17533
17321
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17567,7 +17355,6 @@ const VDB = {
17567
17355
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The number of months in the first year of depreciation.")),
17568
17356
  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.")),
17569
17357
  ],
17570
- returns: ["NUMBER"],
17571
17358
  compute: function (cost, salvage, life, startPeriod, endPeriod, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }, noSwitch = { value: DEFAULT_VDB_NO_SWITCH }) {
17572
17359
  factor = factor || 0;
17573
17360
  const _cost = toNumber(cost, this.locale);
@@ -17632,7 +17419,6 @@ const XIRR = {
17632
17419
  arg("cashflow_dates (range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17633
17420
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the internal rate of return will be.")),
17634
17421
  ],
17635
- returns: ["NUMBER"],
17636
17422
  compute: function (cashflowAmounts, cashflowDates, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17637
17423
  const guess = toNumber(rateGuess, this.locale);
17638
17424
  const _cashFlows = cashflowAmounts.flat().map((val) => toNumber(val, this.locale));
@@ -17703,7 +17489,6 @@ const XNPV = {
17703
17489
  arg("cashflow_amounts (number, range<number>)", _t("An range containing the income or payments associated with the investment.")),
17704
17490
  arg("cashflow_dates (number, range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17705
17491
  ],
17706
- returns: ["NUMBER"],
17707
17492
  compute: function (discount, cashflowAmounts, cashflowDates) {
17708
17493
  const rate = toNumber(discount, this.locale);
17709
17494
  const _cashFlows = isMatrix(cashflowAmounts)
@@ -17770,7 +17555,6 @@ const YIELD = {
17770
17555
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17771
17556
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17772
17557
  ],
17773
- returns: ["NUMBER"],
17774
17558
  compute: function (settlement, maturity, rate, price, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17775
17559
  dayCountConvention = dayCountConvention || 0;
17776
17560
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17845,7 +17629,6 @@ const YIELDDISC = {
17845
17629
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17846
17630
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17847
17631
  ],
17848
- returns: ["NUMBER"],
17849
17632
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17850
17633
  dayCountConvention = dayCountConvention || 0;
17851
17634
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17882,7 +17665,6 @@ const YIELDMAT = {
17882
17665
  arg("price (number)", _t("The price at which the security is bought.")),
17883
17666
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17884
17667
  ],
17885
- returns: ["NUMBER"],
17886
17668
  compute: function (settlement, maturity, issue, rate, price, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17887
17669
  dayCountConvention = dayCountConvention || 0;
17888
17670
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17969,7 +17751,6 @@ const CELL = {
17969
17751
  arg("info_type (string)", _t("The type of information requested. Can be one of %s", CELL_INFO_TYPES.join(", "))),
17970
17752
  arg("reference (meta)", _t("The reference to the cell.")),
17971
17753
  ],
17972
- returns: ["ANY"],
17973
17754
  compute: function (info, reference) {
17974
17755
  const _info = toString(info).toLowerCase();
17975
17756
  assert(() => CELL_INFO_TYPES.includes(_info), _t("The info_type should be one of %s.", CELL_INFO_TYPES.join(", ")));
@@ -18020,7 +17801,6 @@ const CELL = {
18020
17801
  const ISERR = {
18021
17802
  description: _t("Whether a value is an error other than #N/A."),
18022
17803
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18023
- returns: ["BOOLEAN"],
18024
17804
  compute: function (data) {
18025
17805
  const value = data?.value;
18026
17806
  return isEvaluationError(value) && value !== CellErrorType.NotAvailable;
@@ -18033,7 +17813,6 @@ const ISERR = {
18033
17813
  const ISERROR = {
18034
17814
  description: _t("Whether a value is an error."),
18035
17815
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18036
- returns: ["BOOLEAN"],
18037
17816
  compute: function (data) {
18038
17817
  const value = data?.value;
18039
17818
  return isEvaluationError(value);
@@ -18046,7 +17825,6 @@ const ISERROR = {
18046
17825
  const ISLOGICAL = {
18047
17826
  description: _t("Whether a value is `true` or `false`."),
18048
17827
  args: [arg("value (any)", _t("The value to be verified as a logical TRUE or FALSE."))],
18049
- returns: ["BOOLEAN"],
18050
17828
  compute: function (value) {
18051
17829
  return typeof value?.value === "boolean";
18052
17830
  },
@@ -18058,7 +17836,6 @@ const ISLOGICAL = {
18058
17836
  const ISNA = {
18059
17837
  description: _t("Whether a value is the error #N/A."),
18060
17838
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18061
- returns: ["BOOLEAN"],
18062
17839
  compute: function (data) {
18063
17840
  return data?.value === CellErrorType.NotAvailable;
18064
17841
  },
@@ -18070,7 +17847,6 @@ const ISNA = {
18070
17847
  const ISNONTEXT = {
18071
17848
  description: _t("Whether a value is non-textual."),
18072
17849
  args: [arg("value (any)", _t("The value to be checked."))],
18073
- returns: ["BOOLEAN"],
18074
17850
  compute: function (value) {
18075
17851
  return !ISTEXT.compute.bind(this)(value);
18076
17852
  },
@@ -18082,7 +17858,6 @@ const ISNONTEXT = {
18082
17858
  const ISNUMBER = {
18083
17859
  description: _t("Whether a value is a number."),
18084
17860
  args: [arg("value (any)", _t("The value to be verified as a number."))],
18085
- returns: ["BOOLEAN"],
18086
17861
  compute: function (value) {
18087
17862
  return typeof value?.value === "number";
18088
17863
  },
@@ -18094,7 +17869,6 @@ const ISNUMBER = {
18094
17869
  const ISTEXT = {
18095
17870
  description: _t("Whether a value is text."),
18096
17871
  args: [arg("value (any)", _t("The value to be verified as text."))],
18097
- returns: ["BOOLEAN"],
18098
17872
  compute: function (value) {
18099
17873
  return typeof value?.value === "string" && isEvaluationError(value?.value) === false;
18100
17874
  },
@@ -18106,7 +17880,6 @@ const ISTEXT = {
18106
17880
  const ISBLANK = {
18107
17881
  description: _t("Whether the referenced cell is empty"),
18108
17882
  args: [arg("value (any)", _t("Reference to the cell that will be checked for emptiness."))],
18109
- returns: ["BOOLEAN"],
18110
17883
  compute: function (value) {
18111
17884
  return value?.value === null;
18112
17885
  },
@@ -18118,7 +17891,6 @@ const ISBLANK = {
18118
17891
  const NA = {
18119
17892
  description: _t("Returns the error value #N/A."),
18120
17893
  args: [],
18121
- returns: ["BOOLEAN"],
18122
17894
  compute: function () {
18123
17895
  return { value: CellErrorType.NotAvailable };
18124
17896
  },
@@ -18175,7 +17947,6 @@ const AND = {
18175
17947
  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.")),
18176
17948
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that represent logical values.")),
18177
17949
  ],
18178
- returns: ["BOOLEAN"],
18179
17950
  compute: function (...logicalExpressions) {
18180
17951
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18181
17952
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18189,7 +17960,6 @@ const AND = {
18189
17960
  const FALSE = {
18190
17961
  description: _t("Logical value `false`."),
18191
17962
  args: [],
18192
- returns: ["BOOLEAN"],
18193
17963
  compute: function () {
18194
17964
  return false;
18195
17965
  },
@@ -18205,7 +17975,6 @@ const IF = {
18205
17975
  arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18206
17976
  arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18207
17977
  ],
18208
- returns: ["ANY"],
18209
17978
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18210
17979
  const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18211
17980
  if (result === undefined) {
@@ -18227,7 +17996,6 @@ const IFERROR = {
18227
17996
  arg("value (any)", _t("The value to return if value itself is not an error.")),
18228
17997
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18229
17998
  ],
18230
- returns: ["ANY"],
18231
17999
  compute: function (value, valueIfError = { value: "" }) {
18232
18000
  const result = isEvaluationError(value?.value) ? valueIfError : value;
18233
18001
  if (result === undefined) {
@@ -18249,7 +18017,6 @@ const IFNA = {
18249
18017
  arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18250
18018
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18251
18019
  ],
18252
- returns: ["ANY"],
18253
18020
  compute: function (value, valueIfError = { value: "" }) {
18254
18021
  const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18255
18022
  if (result === undefined) {
@@ -18273,7 +18040,6 @@ const IFS = {
18273
18040
  arg("condition2 (boolean, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18274
18041
  arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18275
18042
  ],
18276
- returns: ["ANY"],
18277
18043
  compute: function (...values) {
18278
18044
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18279
18045
  for (let n = 0; n < values.length - 1; n += 2) {
@@ -18300,7 +18066,6 @@ const NOT = {
18300
18066
  args: [
18301
18067
  arg("logical_expression (boolean)", _t("An expression or reference to a cell holding an expression that represents some logical value.")),
18302
18068
  ],
18303
- returns: ["BOOLEAN"],
18304
18069
  compute: function (logicalExpression) {
18305
18070
  return !toBoolean(logicalExpression);
18306
18071
  },
@@ -18315,7 +18080,6 @@ const OR = {
18315
18080
  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.")),
18316
18081
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18317
18082
  ],
18318
- returns: ["BOOLEAN"],
18319
18083
  compute: function (...logicalExpressions) {
18320
18084
  const { result, foundBoolean } = boolOr(logicalExpressions);
18321
18085
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18329,7 +18093,6 @@ const OR = {
18329
18093
  const TRUE = {
18330
18094
  description: _t("Logical value `true`."),
18331
18095
  args: [],
18332
- returns: ["BOOLEAN"],
18333
18096
  compute: function () {
18334
18097
  return true;
18335
18098
  },
@@ -18344,7 +18107,6 @@ const XOR = {
18344
18107
  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.")),
18345
18108
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18346
18109
  ],
18347
- returns: ["BOOLEAN"],
18348
18110
  compute: function (...logicalExpressions) {
18349
18111
  let foundBoolean = false;
18350
18112
  let acc = false;
@@ -18373,9 +18135,229 @@ var logical = /*#__PURE__*/Object.freeze({
18373
18135
  XOR: XOR
18374
18136
  });
18375
18137
 
18376
- //TODO This registry is only used to disable the support of exploded pivot for spreadsheet
18377
- const supportedPivotExplodedFormulaRegistry = new Registry();
18378
- supportedPivotExplodedFormulaRegistry.add("SPREADSHEET", false);
18138
+ const pivotTimeAdapterRegistry = new Registry();
18139
+ function pivotTimeAdapter(granularity) {
18140
+ return pivotTimeAdapterRegistry.get(granularity);
18141
+ }
18142
+ /**
18143
+ * The Time Adapter: Managing Time Periods for Pivot Functions
18144
+ *
18145
+ * Overview:
18146
+ * A time adapter is responsible for managing time periods associated with pivot functions.
18147
+ * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
18148
+ * The adapter's primary role is to normalize period values between spreadsheet functions,
18149
+ * and the pivot.
18150
+ * By normalizing the period value, it can be stored consistently in the pivot.
18151
+ *
18152
+ * Normalization Process:
18153
+ * When working with functions in the spreadsheet, the time adapter normalizes
18154
+ * the provided period to facilitate accurate lookup of values in the pivot.
18155
+ * For instance, if the spreadsheet function represents a day period as a number generated
18156
+ * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
18157
+ *
18158
+ */
18159
+ /**
18160
+ * Normalized value: "12/25/2023"
18161
+ *
18162
+ * Note: Those two format are equivalent:
18163
+ * - "MM/dd/yyyy" (luxon format)
18164
+ * - "mm/dd/yyyy" (spreadsheet format)
18165
+ **/
18166
+ const dayAdapter = {
18167
+ normalizeFunctionValue(value) {
18168
+ const date = toNumber(value, DEFAULT_LOCALE);
18169
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
18170
+ },
18171
+ getFormat(locale) {
18172
+ return (locale ?? DEFAULT_LOCALE).dateFormat;
18173
+ },
18174
+ formatValue(normalizedValue, locale) {
18175
+ locale = locale ?? DEFAULT_LOCALE;
18176
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18177
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18178
+ },
18179
+ toCellValue(normalizedValue) {
18180
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18181
+ },
18182
+ };
18183
+ /**
18184
+ * normalizes day of month number
18185
+ */
18186
+ const dayOfMonthAdapter = {
18187
+ normalizeFunctionValue(value) {
18188
+ const day = toNumber(value, DEFAULT_LOCALE);
18189
+ if (day < 1 || day > 31) {
18190
+ throw new EvaluationError(_t("%s is not a valid day of month (it should be a number between 1 and 31)", day));
18191
+ }
18192
+ return day;
18193
+ },
18194
+ getFormat() {
18195
+ return "0";
18196
+ },
18197
+ formatValue(normalizedValue, locale) {
18198
+ locale = locale ?? DEFAULT_LOCALE;
18199
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18200
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18201
+ },
18202
+ toCellValue(normalizedValue) {
18203
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18204
+ },
18205
+ };
18206
+ /**
18207
+ * Normalized value: "2/2023" for week 2 of 2023
18208
+ */
18209
+ const weekAdapter = {
18210
+ normalizeFunctionValue(value) {
18211
+ const [week, year] = value.split("/");
18212
+ return `${Number(week)}/${Number(year)}`;
18213
+ },
18214
+ getFormat() {
18215
+ return undefined;
18216
+ },
18217
+ formatValue(normalizedValue) {
18218
+ const [week, year] = normalizedValue.split("/");
18219
+ return _t("W%(week)s %(year)s", { week, year });
18220
+ },
18221
+ toCellValue(normalizedValue) {
18222
+ return this.formatValue(normalizedValue);
18223
+ },
18224
+ };
18225
+ /**
18226
+ * normalizes iso week number
18227
+ */
18228
+ const isoWeekNumberAdapter = {
18229
+ normalizeFunctionValue(value) {
18230
+ const isoWeek = toNumber(value, DEFAULT_LOCALE);
18231
+ if (isoWeek < 0 || isoWeek > 53) {
18232
+ throw new EvaluationError(_t("%s is not a valid week (it should be a number between 0 and 53)", isoWeek));
18233
+ }
18234
+ return isoWeek;
18235
+ },
18236
+ getFormat() {
18237
+ return "0";
18238
+ },
18239
+ formatValue(normalizedValue, locale) {
18240
+ locale = locale ?? DEFAULT_LOCALE;
18241
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18242
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18243
+ },
18244
+ toCellValue(normalizedValue) {
18245
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18246
+ },
18247
+ };
18248
+ /**
18249
+ * normalized month value is a string formatted as "MM/yyyy" (luxon format)
18250
+ * e.g. "01/2020" for January 2020
18251
+ */
18252
+ const monthAdapter = {
18253
+ normalizeFunctionValue(value) {
18254
+ const date = toNumber(value, DEFAULT_LOCALE);
18255
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
18256
+ },
18257
+ getFormat() {
18258
+ return "mmmm yyyy";
18259
+ },
18260
+ formatValue(normalizedValue, locale) {
18261
+ locale = locale ?? DEFAULT_LOCALE;
18262
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18263
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18264
+ },
18265
+ toCellValue(normalizedValue) {
18266
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18267
+ },
18268
+ };
18269
+ /**
18270
+ * normalizes month number
18271
+ */
18272
+ const monthNumberAdapter = {
18273
+ normalizeFunctionValue(value) {
18274
+ const month = toNumber(value, DEFAULT_LOCALE);
18275
+ if (month < 1 || month > 12) {
18276
+ throw new EvaluationError(_t("%s is not a valid month (it should be a number between 1 and 12)", month));
18277
+ }
18278
+ return month;
18279
+ },
18280
+ getFormat() {
18281
+ return "0";
18282
+ },
18283
+ formatValue(normalizedValue, locale) {
18284
+ locale = locale ?? DEFAULT_LOCALE;
18285
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18286
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18287
+ },
18288
+ toCellValue(normalizedValue) {
18289
+ return MONTHS[toNumber(normalizedValue, DEFAULT_LOCALE) - 1].toString();
18290
+ },
18291
+ };
18292
+ /**
18293
+ * normalized quarter value is "quarter/year"
18294
+ * e.g. "1/2020" for Q1 2020
18295
+ */
18296
+ const quarterAdapter = {
18297
+ normalizeFunctionValue(value) {
18298
+ const [quarter, year] = value.split("/");
18299
+ return `${quarter}/${year}`;
18300
+ },
18301
+ getFormat() {
18302
+ return undefined;
18303
+ },
18304
+ formatValue(normalizedValue) {
18305
+ const [quarter, year] = normalizedValue.split("/");
18306
+ return _t("Q%(quarter)s %(year)s", { quarter, year });
18307
+ },
18308
+ toCellValue(normalizedValue) {
18309
+ return this.formatValue(normalizedValue);
18310
+ },
18311
+ };
18312
+ /**
18313
+ * normalizes quarter number
18314
+ */
18315
+ const quarterNumberAdapter = {
18316
+ normalizeFunctionValue(value) {
18317
+ const quarter = toNumber(value, DEFAULT_LOCALE);
18318
+ if (quarter < 1 || quarter > 4) {
18319
+ throw new EvaluationError(_t("%s is not a valid quarter (it should be a number between 1 and 4)", quarter));
18320
+ }
18321
+ return quarter;
18322
+ },
18323
+ getFormat() {
18324
+ return "0";
18325
+ },
18326
+ formatValue(normalizedValue, locale) {
18327
+ locale = locale ?? DEFAULT_LOCALE;
18328
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18329
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18330
+ },
18331
+ toCellValue(normalizedValue) {
18332
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18333
+ },
18334
+ };
18335
+ const yearAdapter = {
18336
+ normalizeFunctionValue(value) {
18337
+ return toNumber(value, DEFAULT_LOCALE);
18338
+ },
18339
+ getFormat() {
18340
+ return "0";
18341
+ },
18342
+ formatValue(normalizedValue, locale) {
18343
+ locale = locale ?? DEFAULT_LOCALE;
18344
+ return formatValue(normalizedValue, { locale, format: "0" });
18345
+ },
18346
+ toCellValue(normalizedValue) {
18347
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18348
+ },
18349
+ };
18350
+ pivotTimeAdapterRegistry
18351
+ .add("day", dayAdapter)
18352
+ .add("week", weekAdapter)
18353
+ .add("month", monthAdapter)
18354
+ .add("quarter", quarterAdapter)
18355
+ .add("year", yearAdapter)
18356
+ .add("day_of_month", dayOfMonthAdapter)
18357
+ .add("iso_week_number", isoWeekNumberAdapter)
18358
+ .add("month_number", monthNumberAdapter)
18359
+ .add("quarter_number", quarterNumberAdapter)
18360
+ .add("year_number", yearAdapter);
18379
18361
 
18380
18362
  const AGGREGATOR_NAMES = {
18381
18363
  count: _t("Count"),
@@ -18391,7 +18373,7 @@ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "
18391
18373
  const AGGREGATORS_BY_FIELD_TYPE = {
18392
18374
  integer: NUMBER_CHAR_AGGREGATORS,
18393
18375
  char: NUMBER_CHAR_AGGREGATORS,
18394
- //TODO Support for date and boolean
18376
+ boolean: ["count_distinct", "count", "bool_and", "bool_or"],
18395
18377
  };
18396
18378
  const AGGREGATORS = {};
18397
18379
  for (const type in AGGREGATORS_BY_FIELD_TYPE) {
@@ -18501,6 +18483,44 @@ function toPivotDomain(domainStr) {
18501
18483
  function flatPivotDomain(domain) {
18502
18484
  return domain.flatMap((arg) => [arg.field, arg.value]);
18503
18485
  }
18486
+ /**
18487
+ * Parses the value defining a pivot group in a PIVOT formula
18488
+ * e.g. given the following formula PIVOT.VALUE("1", "stage_id", "42", "status", "won"),
18489
+ * the two group values are "42" and "won".
18490
+ */
18491
+ function toNormalizedPivotValue(dimension, groupValue) {
18492
+ if (groupValue === null || groupValue === "null") {
18493
+ return null;
18494
+ }
18495
+ const groupValueString = typeof groupValue === "boolean"
18496
+ ? toString(groupValue).toLocaleLowerCase()
18497
+ : toString(groupValue);
18498
+ if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
18499
+ throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
18500
+ field: dimension.displayName,
18501
+ type: dimension.type,
18502
+ }));
18503
+ }
18504
+ // represents a field which is not set (=False server side)
18505
+ if (groupValueString === "false") {
18506
+ return false;
18507
+ }
18508
+ const normalizer = pivotNormalizationValueRegistry.get(dimension.type);
18509
+ return normalizer(groupValueString, dimension.granularity);
18510
+ }
18511
+ function normalizeDateTime(value, granularity) {
18512
+ if (!granularity) {
18513
+ throw "";
18514
+ }
18515
+ return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
18516
+ }
18517
+ const pivotNormalizationValueRegistry = new Registry();
18518
+ pivotNormalizationValueRegistry
18519
+ .add("date", normalizeDateTime)
18520
+ .add("datetime", normalizeDateTime)
18521
+ .add("integer", (value) => toNumber(value, DEFAULT_LOCALE))
18522
+ .add("boolean", (value) => toBoolean(value))
18523
+ .add("char", (value) => toString(value));
18504
18524
 
18505
18525
  /**
18506
18526
  * Get the pivot ID from the formula pivot ID.
@@ -18577,7 +18597,6 @@ const ADDRESS = {
18577
18597
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18578
18598
  arg("sheet (string, optional)", _t("A string indicating the name of the sheet into which the address points.")),
18579
18599
  ],
18580
- returns: ["STRING"],
18581
18600
  compute: function (row, column, absoluteRelativeMode = { value: DEFAULT_ABSOLUTE_RELATIVE_MODE }, useA1Notation = { value: true }, sheet) {
18582
18601
  const rowNumber = strictToInteger(row, this.locale);
18583
18602
  const colNumber = strictToInteger(column, this.locale);
@@ -18614,7 +18633,6 @@ const COLUMN = {
18614
18633
  args: [
18615
18634
  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.")),
18616
18635
  ],
18617
- returns: ["NUMBER"],
18618
18636
  compute: function (cellReference) {
18619
18637
  if (isEvaluationError(cellReference?.value)) {
18620
18638
  throw cellReference;
@@ -18632,7 +18650,6 @@ const COLUMN = {
18632
18650
  const COLUMNS = {
18633
18651
  description: _t("Number of columns in a specified array or range."),
18634
18652
  args: [arg("range (meta)", _t("The range whose column count will be returned."))],
18635
- returns: ["NUMBER"],
18636
18653
  compute: function (range) {
18637
18654
  if (isEvaluationError(range?.value)) {
18638
18655
  throw range;
@@ -18653,7 +18670,6 @@ const HLOOKUP = {
18653
18670
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18654
18671
  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.")),
18655
18672
  ],
18656
- returns: ["ANY"],
18657
18673
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18658
18674
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18659
18675
  assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18683,7 +18699,6 @@ const INDEX = {
18683
18699
  arg("row (number, default=0)", _t("The index of the row to be returned from within the reference range of cells.")),
18684
18700
  arg("column (number, default=0)", _t("The index of the column to be returned from within the reference range of cells.")),
18685
18701
  ],
18686
- returns: ["ANY"],
18687
18702
  compute: function (reference, row = { value: 0 }, column = { value: 0 }) {
18688
18703
  const _reference = toMatrix(reference);
18689
18704
  const _row = toNumber(row.value, this.locale);
@@ -18714,7 +18729,6 @@ const INDIRECT = {
18714
18729
  arg("reference (string)", _t("The range of cells from which the values are returned.")),
18715
18730
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18716
18731
  ],
18717
- returns: ["ANY"],
18718
18732
  compute: function (reference, useA1Notation = { value: true }) {
18719
18733
  let _reference = reference?.value?.toString();
18720
18734
  if (!_reference) {
@@ -18769,7 +18783,6 @@ const LOOKUP = {
18769
18783
  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.")),
18770
18784
  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.")),
18771
18785
  ],
18772
- returns: ["ANY"],
18773
18786
  compute: function (searchKey, searchArray, resultRange) {
18774
18787
  let nbCol = searchArray.length;
18775
18788
  let nbRow = searchArray[0].length;
@@ -18810,7 +18823,6 @@ const MATCH = {
18810
18823
  arg("range (any, range)", _t("The one-dimensional array to be searched.")),
18811
18824
  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.")),
18812
18825
  ],
18813
- returns: ["NUMBER"],
18814
18826
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18815
18827
  let _searchType = toNumber(searchType, this.locale);
18816
18828
  const nbCol = range.length;
@@ -18849,7 +18861,6 @@ const ROW = {
18849
18861
  args: [
18850
18862
  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.")),
18851
18863
  ],
18852
- returns: ["NUMBER"],
18853
18864
  compute: function (cellReference) {
18854
18865
  if (isEvaluationError(cellReference?.value)) {
18855
18866
  throw cellReference;
@@ -18867,7 +18878,6 @@ const ROW = {
18867
18878
  const ROWS = {
18868
18879
  description: _t("Number of rows in a specified array or range."),
18869
18880
  args: [arg("range (meta)", _t("The range whose row count will be returned."))],
18870
- returns: ["NUMBER"],
18871
18881
  compute: function (range) {
18872
18882
  if (isEvaluationError(range?.value)) {
18873
18883
  throw range;
@@ -18888,7 +18898,6 @@ const VLOOKUP = {
18888
18898
  arg("index (number)", _t("The column index of the value to be returned, where the first column in range is numbered 1.")),
18889
18899
  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.")),
18890
18900
  ],
18891
- returns: ["ANY"],
18892
18901
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18893
18902
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18894
18903
  assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18934,7 +18943,6 @@ const XLOOKUP = {
18934
18943
  (-2) Perform a binary search that relies on lookup_array being sorted in descending order. If not sorted, invalid results will be returned.\
18935
18944
  ")),
18936
18945
  ],
18937
- returns: ["ANY"],
18938
18946
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18939
18947
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18940
18948
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
@@ -18990,12 +18998,6 @@ const PIVOT_VALUE = {
18990
18998
  assertDomainLength(_domainArgs);
18991
18999
  const pivot = this.getters.getPivot(pivotId);
18992
19000
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18993
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
18994
- return {
18995
- value: CellErrorType.GenericError,
18996
- message: _t("This pivot does not support PIVOT.VALUE formula"),
18997
- };
18998
- }
18999
19001
  addPivotDependencies(this, coreDefinition);
19000
19002
  const error = pivot.assertIsValid({ throwOnError: false });
19001
19003
  if (error) {
@@ -19011,7 +19013,6 @@ const PIVOT_VALUE = {
19011
19013
  }
19012
19014
  return { value, format };
19013
19015
  },
19014
- returns: ["NUMBER", "STRING"],
19015
19016
  };
19016
19017
  const PIVOT_HEADER = {
19017
19018
  description: _t("Get the header of a pivot."),
@@ -19027,12 +19028,6 @@ const PIVOT_HEADER = {
19027
19028
  assertDomainLength(_domainArgs);
19028
19029
  const pivot = this.getters.getPivot(_pivotId);
19029
19030
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19030
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
19031
- return {
19032
- value: CellErrorType.GenericError,
19033
- message: _t("This pivot does not support PIVOT.VALUE formula"),
19034
- };
19035
- }
19036
19031
  addPivotDependencies(this, coreDefinition);
19037
19032
  const error = pivot.assertIsValid({ throwOnError: false });
19038
19033
  if (error) {
@@ -19057,7 +19052,6 @@ const PIVOT_HEADER = {
19057
19052
  : format,
19058
19053
  };
19059
19054
  },
19060
- returns: ["NUMBER", "STRING"],
19061
19055
  };
19062
19056
  const PIVOT = {
19063
19057
  description: _t("Get a pivot table."),
@@ -19124,7 +19118,6 @@ const PIVOT = {
19124
19118
  }
19125
19119
  return result;
19126
19120
  },
19127
- returns: ["RANGE<ANY>"],
19128
19121
  };
19129
19122
 
19130
19123
  var lookup = /*#__PURE__*/Object.freeze({
@@ -19155,7 +19148,6 @@ const ADD = {
19155
19148
  arg("value1 (number)", _t("The first addend.")),
19156
19149
  arg("value2 (number)", _t("The second addend.")),
19157
19150
  ],
19158
- returns: ["NUMBER"],
19159
19151
  compute: function (value1, value2) {
19160
19152
  return {
19161
19153
  value: toNumber(value1, this.locale) + toNumber(value2, this.locale),
@@ -19172,7 +19164,6 @@ const CONCAT = {
19172
19164
  arg("value1 (string)", _t("The value to which value2 will be appended.")),
19173
19165
  arg("value2 (string)", _t("The value to append to value1.")),
19174
19166
  ],
19175
- returns: ["STRING"],
19176
19167
  compute: function (value1, value2) {
19177
19168
  return toString(value1) + toString(value2);
19178
19169
  },
@@ -19187,7 +19178,6 @@ const DIVIDE = {
19187
19178
  arg("dividend (number)", _t("The number to be divided.")),
19188
19179
  arg("divisor (number)", _t("The number to divide by.")),
19189
19180
  ],
19190
- returns: ["NUMBER"],
19191
19181
  compute: function (dividend, divisor) {
19192
19182
  const _divisor = toNumber(divisor, this.locale);
19193
19183
  assert(() => _divisor !== 0, _t("The divisor must be different from zero."), CellErrorType.DivisionByZero);
@@ -19210,7 +19200,6 @@ const EQ = {
19210
19200
  arg("value1 (any)", _t("The first value.")),
19211
19201
  arg("value2 (any)", _t("The value to test against value1 for equality.")),
19212
19202
  ],
19213
- returns: ["BOOLEAN"],
19214
19203
  compute: function (value1, value2) {
19215
19204
  let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
19216
19205
  let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
@@ -19263,7 +19252,6 @@ const GT = {
19263
19252
  arg("value1 (any)", _t("The value to test as being greater than value2.")),
19264
19253
  arg("value2 (any)", _t("The second value.")),
19265
19254
  ],
19266
- returns: ["BOOLEAN"],
19267
19255
  compute: function (value1, value2) {
19268
19256
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19269
19257
  return v1 > v2;
@@ -19279,7 +19267,6 @@ const GTE = {
19279
19267
  arg("value1 (any)", _t("The value to test as being greater than or equal to value2.")),
19280
19268
  arg("value2 (any)", _t("The second value.")),
19281
19269
  ],
19282
- returns: ["BOOLEAN"],
19283
19270
  compute: function (value1, value2) {
19284
19271
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19285
19272
  return v1 >= v2;
@@ -19295,7 +19282,6 @@ const LT = {
19295
19282
  arg("value1 (any)", _t("The value to test as being less than value2.")),
19296
19283
  arg("value2 (any)", _t("The second value.")),
19297
19284
  ],
19298
- returns: ["BOOLEAN"],
19299
19285
  compute: function (value1, value2) {
19300
19286
  return !GTE.compute.bind(this)(value1, value2);
19301
19287
  },
@@ -19309,7 +19295,6 @@ const LTE = {
19309
19295
  arg("value1 (any)", _t("The value to test as being less than or equal to value2.")),
19310
19296
  arg("value2 (any)", _t("The second value.")),
19311
19297
  ],
19312
- returns: ["BOOLEAN"],
19313
19298
  compute: function (value1, value2) {
19314
19299
  return !GT.compute.bind(this)(value1, value2);
19315
19300
  },
@@ -19323,7 +19308,6 @@ const MINUS = {
19323
19308
  arg("value1 (number)", _t("The minuend, or number to be subtracted from.")),
19324
19309
  arg("value2 (number)", _t("The subtrahend, or number to subtract from value1.")),
19325
19310
  ],
19326
- returns: ["NUMBER"],
19327
19311
  compute: function (value1, value2) {
19328
19312
  return {
19329
19313
  value: toNumber(value1, this.locale) - toNumber(value2, this.locale),
@@ -19340,7 +19324,6 @@ const MULTIPLY = {
19340
19324
  arg("factor1 (number)", _t("The first multiplicand.")),
19341
19325
  arg("factor2 (number)", _t("The second multiplicand.")),
19342
19326
  ],
19343
- returns: ["NUMBER"],
19344
19327
  compute: function (factor1, factor2) {
19345
19328
  return {
19346
19329
  value: toNumber(factor1, this.locale) * toNumber(factor2, this.locale),
@@ -19357,7 +19340,6 @@ const NE = {
19357
19340
  arg("value1 (any)", _t("The first value.")),
19358
19341
  arg("value2 (any)", _t("The value to test against value1 for inequality.")),
19359
19342
  ],
19360
- returns: ["BOOLEAN"],
19361
19343
  compute: function (value1, value2) {
19362
19344
  return !EQ.compute.bind(this)(value1, value2);
19363
19345
  },
@@ -19371,7 +19353,6 @@ const POW = {
19371
19353
  arg("base (number)", _t("The number to raise to the exponent power.")),
19372
19354
  arg("exponent (number)", _t("The exponent to raise base to.")),
19373
19355
  ],
19374
- returns: ["NUMBER"],
19375
19356
  compute: function (base, exponent) {
19376
19357
  return POWER.compute.bind(this)(base, exponent);
19377
19358
  },
@@ -19384,7 +19365,6 @@ const UMINUS = {
19384
19365
  args: [
19385
19366
  arg("value (number)", _t("The number to have its sign reversed. Equivalently, the number to multiply by -1.")),
19386
19367
  ],
19387
- returns: ["NUMBER"],
19388
19368
  compute: function (value) {
19389
19369
  return {
19390
19370
  value: -toNumber(value, this.locale),
@@ -19398,7 +19378,6 @@ const UMINUS = {
19398
19378
  const UNARY_PERCENT = {
19399
19379
  description: _t("Value interpreted as a percentage."),
19400
19380
  args: [arg("percentage (number)", _t("The value to interpret as a percentage."))],
19401
- returns: ["NUMBER"],
19402
19381
  compute: function (percentage) {
19403
19382
  return toNumber(percentage, this.locale) / 100;
19404
19383
  },
@@ -19409,7 +19388,6 @@ const UNARY_PERCENT = {
19409
19388
  const UPLUS = {
19410
19389
  description: _t("A specified number, unchanged."),
19411
19390
  args: [arg("value (any)", _t("The number to return."))],
19412
- returns: ["ANY"],
19413
19391
  compute: function (value = { value: null }) {
19414
19392
  return value;
19415
19393
  },
@@ -19445,7 +19423,6 @@ const CHAR = {
19445
19423
  args: [
19446
19424
  arg("table_number (number)", _t("The number of the character to look up from the current Unicode table in decimal format.")),
19447
19425
  ],
19448
- returns: ["STRING"],
19449
19426
  compute: function (tableNumber) {
19450
19427
  const _tableNumber = Math.trunc(toNumber(tableNumber, this.locale));
19451
19428
  assert(() => _tableNumber >= 1, _t("The table_number (%s) is out of range.", _tableNumber.toString()));
@@ -19459,7 +19436,6 @@ const CHAR = {
19459
19436
  const CLEAN = {
19460
19437
  description: _t("Remove non-printable characters from a piece of text."),
19461
19438
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
19462
- returns: ["STRING"],
19463
19439
  compute: function (text) {
19464
19440
  const _text = toString(text);
19465
19441
  let cleanedStr = "";
@@ -19481,7 +19457,6 @@ const CONCATENATE = {
19481
19457
  arg("string1 (string, range<string>)", _t("The initial string.")),
19482
19458
  arg("string2 (string, range<string>, repeating)", _t("More strings to append in sequence.")),
19483
19459
  ],
19484
- returns: ["STRING"],
19485
19460
  compute: function (...datas) {
19486
19461
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
19487
19462
  },
@@ -19496,7 +19471,6 @@ const EXACT = {
19496
19471
  arg("string1 (string)", _t("The first string to compare.")),
19497
19472
  arg("string2 (string)", _t("The second string to compare.")),
19498
19473
  ],
19499
- returns: ["BOOLEAN"],
19500
19474
  compute: function (string1, string2) {
19501
19475
  return toString(string1) === toString(string2);
19502
19476
  },
@@ -19512,7 +19486,6 @@ const FIND = {
19512
19486
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19513
19487
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19514
19488
  ],
19515
- returns: ["NUMBER"],
19516
19489
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19517
19490
  const _searchFor = toString(searchFor);
19518
19491
  const _textToSearch = toString(textToSearch);
@@ -19535,7 +19508,6 @@ const JOIN = {
19535
19508
  arg("value_or_array1 (string, range<string>)", _t("The value or values to be appended using delimiter.")),
19536
19509
  arg("value_or_array2 (string, range<string>, repeating)", _t("More values to be appended using delimiter.")),
19537
19510
  ],
19538
- returns: ["STRING"],
19539
19511
  compute: function (delimiter, ...valuesOrArrays) {
19540
19512
  const _delimiter = toString(delimiter);
19541
19513
  return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
@@ -19550,7 +19522,6 @@ const LEFT = {
19550
19522
  arg("text (string)", _t("The string from which the left portion will be returned.")),
19551
19523
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the left side of string.")),
19552
19524
  ],
19553
- returns: ["STRING"],
19554
19525
  compute: function (text, ...args) {
19555
19526
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19556
19527
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19564,7 +19535,6 @@ const LEFT = {
19564
19535
  const LEN = {
19565
19536
  description: _t("Length of a string."),
19566
19537
  args: [arg("text (string)", _t("The string whose length will be returned."))],
19567
- returns: ["NUMBER"],
19568
19538
  compute: function (text) {
19569
19539
  return toString(text).length;
19570
19540
  },
@@ -19576,7 +19546,6 @@ const LEN = {
19576
19546
  const LOWER = {
19577
19547
  description: _t("Converts a specified string to lowercase."),
19578
19548
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
19579
- returns: ["STRING"],
19580
19549
  compute: function (text) {
19581
19550
  return toString(text).toLowerCase();
19582
19551
  },
@@ -19592,7 +19561,6 @@ const MID = {
19592
19561
  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.")),
19593
19562
  arg("extract_length (number)", _t("The length of the segment to extract.")),
19594
19563
  ],
19595
- returns: ["STRING"],
19596
19564
  compute: function (text, starting_at, extract_length) {
19597
19565
  const _text = toString(text);
19598
19566
  const _starting_at = toNumber(starting_at, this.locale);
@@ -19611,7 +19579,6 @@ const PROPER = {
19611
19579
  args: [
19612
19580
  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.")),
19613
19581
  ],
19614
- returns: ["STRING"],
19615
19582
  compute: function (text) {
19616
19583
  const _text = toString(text);
19617
19584
  return _text.replace(wordRegex, (word) => {
@@ -19631,7 +19598,6 @@ const REPLACE = {
19631
19598
  arg("length (number)", _t("The number of characters in the text to be replaced.")),
19632
19599
  arg("new_text (string)", _t("The text which will be inserted into the original text.")),
19633
19600
  ],
19634
- returns: ["STRING"],
19635
19601
  compute: function (text, position, length, newText) {
19636
19602
  const _position = toNumber(position, this.locale);
19637
19603
  assert(() => _position >= 1, _t("The position (%s) must be greater than or equal to 1.", _position.toString()));
@@ -19651,7 +19617,6 @@ const RIGHT = {
19651
19617
  arg("text (string)", _t("The string from which the right portion will be returned.")),
19652
19618
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the right side of string.")),
19653
19619
  ],
19654
- returns: ["STRING"],
19655
19620
  compute: function (text, ...args) {
19656
19621
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19657
19622
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19671,7 +19636,6 @@ const SEARCH = {
19671
19636
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19672
19637
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19673
19638
  ],
19674
- returns: ["NUMBER"],
19675
19639
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19676
19640
  const _searchFor = toString(searchFor).toLowerCase();
19677
19641
  const _textToSearch = toString(textToSearch).toLowerCase();
@@ -19698,7 +19662,6 @@ const SPLIT = {
19698
19662
  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 \
19699
19663
  consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters.")),
19700
19664
  ],
19701
- returns: ["RANGE<STRING>"],
19702
19665
  compute: function (text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
19703
19666
  const _text = toString(text);
19704
19667
  const _delimiter = escapeRegExp(toString(delimiter));
@@ -19725,7 +19688,6 @@ const SUBSTITUTE = {
19725
19688
  arg("replace_with (string)", _t("The string that will replace search_for.")),
19726
19689
  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.")),
19727
19690
  ],
19728
- returns: ["NUMBER"],
19729
19691
  compute: function (textToSearch, searchFor, replaceWith, occurrenceNumber) {
19730
19692
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
19731
19693
  assert(() => _occurrenceNumber >= 0, _t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber.toString()));
@@ -19755,7 +19717,6 @@ const TEXTJOIN = {
19755
19717
  arg("text1 (string, range<string>)", _t("Any text item. This could be a string, or an array of strings in a range.")),
19756
19718
  arg("text2 (string, range<string>, repeating)", _t("Additional text item(s).")),
19757
19719
  ],
19758
- returns: ["STRING"],
19759
19720
  compute: function (delimiter, ignoreEmpty, ...textsOrArrays) {
19760
19721
  const _delimiter = toString(delimiter);
19761
19722
  const _ignoreEmpty = toBoolean(ignoreEmpty);
@@ -19772,7 +19733,6 @@ const TRIM = {
19772
19733
  args: [
19773
19734
  arg("text (string)", _t("The text or reference to a cell containing text to be trimmed.")),
19774
19735
  ],
19775
- returns: ["STRING"],
19776
19736
  compute: function (text) {
19777
19737
  return trimContent(toString(text));
19778
19738
  },
@@ -19784,7 +19744,6 @@ const TRIM = {
19784
19744
  const UPPER = {
19785
19745
  description: _t("Converts a specified string to uppercase."),
19786
19746
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
19787
- returns: ["STRING"],
19788
19747
  compute: function (text) {
19789
19748
  return toString(text).toUpperCase();
19790
19749
  },
@@ -19799,7 +19758,6 @@ const TEXT = {
19799
19758
  arg("number (number)", _t("The number, date or time to format.")),
19800
19759
  arg("format (string)", _t("The pattern by which to format the number, enclosed in quotation marks.")),
19801
19760
  ],
19802
- returns: ["STRING"],
19803
19761
  compute: function (number, format) {
19804
19762
  const _number = toNumber(number, this.locale);
19805
19763
  return formatValue(_number, { format: toString(format), locale: this.locale });
@@ -19840,7 +19798,6 @@ const HYPERLINK = {
19840
19798
  arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")),
19841
19799
  arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks.")),
19842
19800
  ],
19843
- returns: ["STRING"],
19844
19801
  compute: function (url, linkLabel) {
19845
19802
  const processedUrl = toString(url).trim();
19846
19803
  const processedLabel = toString(linkLabel) || processedUrl;
@@ -19899,6 +19856,9 @@ function addInputHandling(descr) {
19899
19856
  }
19900
19857
  args[i] = arg[0][0];
19901
19858
  }
19859
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19860
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19861
+ }
19902
19862
  }
19903
19863
  return descr.compute.apply(this, args);
19904
19864
  }
@@ -21493,12 +21453,6 @@ function compileTokens(tokens) {
21493
21453
  // detect when an argument need to be evaluated as a meta argument
21494
21454
  const isMeta = argTypes.includes("META");
21495
21455
  const hasRange = argTypes.some((t) => isRangeType(t));
21496
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21497
- if (isRangeOnly) {
21498
- if (!isRangeInput(currentArg)) {
21499
- 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 }));
21500
- }
21501
- }
21502
21456
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21503
21457
  }
21504
21458
  return compiledArgs;
@@ -21663,16 +21617,6 @@ function assertEnoughArgs(ast) {
21663
21617
  function isRangeType(type) {
21664
21618
  return type.startsWith("RANGE");
21665
21619
  }
21666
- function isRangeInput(arg) {
21667
- if (arg.type === "REFERENCE") {
21668
- return true;
21669
- }
21670
- if (arg.type === "FUNCALL") {
21671
- const fnDef = functions$1[arg.value.toUpperCase()];
21672
- return fnDef && isRangeType(fnDef.returns[0]);
21673
- }
21674
- return false;
21675
- }
21676
21620
 
21677
21621
  const functions = functionRegistry.content;
21678
21622
  function isExportableToExcel(tokens) {
@@ -21716,11 +21660,14 @@ const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
21716
21660
  function makeFieldProposal(field, granularity) {
21717
21661
  const groupBy = granularity ? `${field.name}:${granularity}` : field.name;
21718
21662
  const quotedGroupBy = `"${groupBy}"`;
21663
+ const fuzzySearchKey = field.string !== field.name
21664
+ ? field.string + quotedGroupBy // search on translated name and on technical name
21665
+ : quotedGroupBy;
21719
21666
  return {
21720
21667
  text: quotedGroupBy,
21721
21668
  description: field.string + (field.help ? ` (${field.help})` : ""),
21722
21669
  htmlContent: [{ value: quotedGroupBy, color: tokenColors.STRING }],
21723
- fuzzySearchKey: field.string + quotedGroupBy, // search on translated name and on technical name
21670
+ fuzzySearchKey,
21724
21671
  };
21725
21672
  }
21726
21673
  /**
@@ -21780,6 +21727,14 @@ function getNumberOfPivotFunctions(tokens) {
21780
21727
  return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS).length;
21781
21728
  }
21782
21729
 
21730
+ /**
21731
+ * Registry to enable or disable the support of positional arguments
21732
+ * (with a leading #) in pivot functions
21733
+ * e.g. =PIVOT.VALUE(1,"probability","#stage",1)
21734
+ */
21735
+ const supportedPivotPositionalFormulaRegistry = new Registry();
21736
+ supportedPivotPositionalFormulaRegistry.add("SPREADSHEET", false);
21737
+
21783
21738
  autoCompleteProviders.add("pivot_ids", {
21784
21739
  sequence: 50,
21785
21740
  autoSelectFirstProposal: true,
@@ -21798,10 +21753,6 @@ autoCompleteProviders.add("pivot_ids", {
21798
21753
  return pivotIds
21799
21754
  .map((pivotId) => {
21800
21755
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21801
- if (functionContext.parent.toUpperCase() !== "PIVOT" &&
21802
- !supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21803
- return undefined;
21804
- }
21805
21756
  const formulaId = this.getters.getPivotFormulaId(pivotId);
21806
21757
  const str = `${formulaId}`;
21807
21758
  return {
@@ -21829,15 +21780,13 @@ autoCompleteProviders.add("pivot_measures", {
21829
21780
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21830
21781
  return [];
21831
21782
  }
21832
- const dataSource = this.getters.getPivot(pivotId);
21833
- const fields = dataSource.getFields();
21783
+ const pivot = this.getters.getPivot(pivotId);
21784
+ pivot.init();
21785
+ const fields = pivot.getFields();
21834
21786
  if (!fields) {
21835
21787
  return [];
21836
21788
  }
21837
21789
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21838
- if (!supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21839
- return [];
21840
- }
21841
21790
  return definition.measures
21842
21791
  .map((measure) => {
21843
21792
  if (measure.name === "__count") {
@@ -21873,16 +21822,13 @@ autoCompleteProviders.add("pivot_group_fields", {
21873
21822
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21874
21823
  return;
21875
21824
  }
21876
- const dataSource = this.getters.getPivot(pivotId);
21877
- const fields = dataSource.getFields();
21825
+ const pivot = this.getters.getPivot(pivotId);
21826
+ pivot.init();
21827
+ const fields = pivot.getFields();
21878
21828
  if (!fields) {
21879
21829
  return;
21880
21830
  }
21881
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21882
- const { columns, rows } = dataSource.definition;
21883
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21884
- return [];
21885
- }
21831
+ const { columns, rows } = pivot.definition;
21886
21832
  let args = functionContext.args;
21887
21833
  if (functionContext?.parent.toUpperCase() === "PIVOT.VALUE") {
21888
21834
  args = args.filter((ast, index) => index % 2 === 0); // keep only the field names
@@ -21919,6 +21865,9 @@ autoCompleteProviders.add("pivot_group_fields", {
21919
21865
  return field ? makeFieldProposal(field, granularity) : undefined;
21920
21866
  })
21921
21867
  .concat(groupBys.map((groupBy) => {
21868
+ if (!supportedPivotPositionalFormulaRegistry.get(pivot.type)) {
21869
+ return undefined;
21870
+ }
21922
21871
  const fieldName = groupBy.split(":")[0];
21923
21872
  const field = fields[fieldName];
21924
21873
  if (!field) {
@@ -21967,12 +21916,8 @@ autoCompleteProviders.add("pivot_group_values", {
21967
21916
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21968
21917
  return;
21969
21918
  }
21970
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21971
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21972
- return [];
21973
- }
21974
- const dataSource = this.getters.getPivot(pivotId);
21975
- if (!dataSource.isValid()) {
21919
+ const pivot = this.getters.getPivot(pivotId);
21920
+ if (!pivot.isValid()) {
21976
21921
  return;
21977
21922
  }
21978
21923
  const argPosition = functionContext.argPosition;
@@ -21980,7 +21925,46 @@ autoCompleteProviders.add("pivot_group_values", {
21980
21925
  if (!groupByField) {
21981
21926
  return;
21982
21927
  }
21983
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21928
+ let dimension;
21929
+ try {
21930
+ dimension = pivot.definition.getDimension(groupByField);
21931
+ }
21932
+ catch (error) {
21933
+ return undefined;
21934
+ }
21935
+ if (dimension.granularity === "month_number") {
21936
+ return Object.values(MONTHS).map((monthDisplayName, index) => ({
21937
+ text: `${index + 1}`,
21938
+ fuzzySearchKey: monthDisplayName.toString(),
21939
+ description: monthDisplayName.toString(),
21940
+ htmlContent: [{ value: `${index + 1}`, color: tokenColors.NUMBER }],
21941
+ }));
21942
+ }
21943
+ else if (dimension.granularity === "quarter_number") {
21944
+ return [1, 2, 3, 4].map((quarter) => ({
21945
+ text: `${quarter}`,
21946
+ fuzzySearchKey: `${quarter}`,
21947
+ description: _t("Quarter %s", quarter),
21948
+ htmlContent: [{ value: `${quarter}`, color: tokenColors.NUMBER }],
21949
+ }));
21950
+ }
21951
+ else if (dimension.granularity === "day_of_month") {
21952
+ return range(1, 32).map((dayOfMonth) => ({
21953
+ text: `${dayOfMonth}`,
21954
+ fuzzySearchKey: `${dayOfMonth}`,
21955
+ description: "",
21956
+ htmlContent: [{ value: `${dayOfMonth}`, color: tokenColors.NUMBER }],
21957
+ }));
21958
+ }
21959
+ else if (dimension.granularity === "iso_week_number") {
21960
+ return range(0, 54).map((isoWeekNumber) => ({
21961
+ text: `${isoWeekNumber}`,
21962
+ fuzzySearchKey: `${isoWeekNumber}`,
21963
+ description: "",
21964
+ htmlContent: [{ value: `${isoWeekNumber}`, color: tokenColors.NUMBER }],
21965
+ }));
21966
+ }
21967
+ return pivot.getPossibleFieldValues(dimension).map(({ value, label }) => {
21984
21968
  const isString = typeof value === "string";
21985
21969
  const text = isString ? `"${value}"` : value.toString();
21986
21970
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -22087,7 +22071,9 @@ autofillModifiersRegistry
22087
22071
  tooltip: content
22088
22072
  ? {
22089
22073
  props: {
22090
- content: evaluateLiteral(data.cell?.content, localeFormat).formattedValue,
22074
+ content: data.cell
22075
+ ? evaluateLiteral(data.cell, localeFormat).formattedValue
22076
+ : "",
22091
22077
  },
22092
22078
  }
22093
22079
  : undefined,
@@ -22150,9 +22136,7 @@ function getGroup(cell, cells, filter) {
22150
22136
  if (x === cell) {
22151
22137
  found = true;
22152
22138
  }
22153
- const cellValue = x?.isFormula
22154
- ? undefined
22155
- : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
22139
+ const cellValue = x === undefined || x.isFormula ? undefined : evaluateLiteral(x, { locale: DEFAULT_LOCALE });
22156
22140
  if (cellValue && filter(cellValue)) {
22157
22141
  group.push(cellValue);
22158
22142
  }
@@ -22200,7 +22184,7 @@ autofillRulesRegistry
22200
22184
  })
22201
22185
  .add("increment_alphanumeric_value", {
22202
22186
  condition: (cell) => !cell.isFormula &&
22203
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22187
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22204
22188
  alphaNumericValueRegExp.test(cell.content),
22205
22189
  generateRule: (cell, cells) => {
22206
22190
  const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
@@ -22223,7 +22207,7 @@ autofillRulesRegistry
22223
22207
  })
22224
22208
  .add("copy_text", {
22225
22209
  condition: (cell) => !cell.isFormula &&
22226
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22210
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22227
22211
  generateRule: () => {
22228
22212
  return { type: "COPY_MODIFIER" };
22229
22213
  },
@@ -22238,11 +22222,11 @@ autofillRulesRegistry
22238
22222
  })
22239
22223
  .add("increment_number", {
22240
22224
  condition: (cell) => !cell.isFormula &&
22241
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22225
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22242
22226
  generateRule: (cell, cells) => {
22243
22227
  const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
22244
22228
  const increment = calculateIncrementBasedOnGroup(group);
22245
- const evaluation = evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE });
22229
+ const evaluation = evaluateLiteral(cell, { locale: DEFAULT_LOCALE });
22246
22230
  return {
22247
22231
  type: "INCREMENT_MODIFIER",
22248
22232
  increment,
@@ -25344,8 +25328,7 @@ function zoneToRect(zone) {
25344
25328
  */
25345
25329
  function useSpreadsheetRect() {
25346
25330
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
25347
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
25348
- updatePosition();
25331
+ let spreadsheetElement = null;
25349
25332
  function updatePosition() {
25350
25333
  if (!spreadsheetElement) {
25351
25334
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -25467,7 +25450,7 @@ class Popover extends owl.Component {
25467
25450
  if (!anchor)
25468
25451
  return;
25469
25452
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25470
- const elDims = {
25453
+ let elDims = {
25471
25454
  width: el.getBoundingClientRect().width,
25472
25455
  height: el.getBoundingClientRect().height,
25473
25456
  };
@@ -25475,7 +25458,14 @@ class Popover extends owl.Component {
25475
25458
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25476
25459
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25477
25460
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25478
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25461
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
25462
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
25463
+ // Re-compute the dimensions after setting the max-width and max-height
25464
+ elDims = {
25465
+ width: el.getBoundingClientRect().width,
25466
+ height: el.getBoundingClientRect().height,
25467
+ };
25468
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25479
25469
  for (const property of Object.keys(style)) {
25480
25470
  el.style[property] = style[property];
25481
25471
  }
@@ -25538,8 +25528,6 @@ class PopoverPositionContext {
25538
25528
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25539
25529
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25540
25530
  const cssProperties = {
25541
- "max-height": maxHeight + "px",
25542
- "max-width": maxWidth + "px",
25543
25531
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25544
25532
  this.spreadsheetOffset.y -
25545
25533
  verticalOffset +
@@ -31353,10 +31341,8 @@ class ChartTitle extends owl.Component {
31353
31341
 
31354
31342
  class AxisDesignEditor extends owl.Component {
31355
31343
  static template = "o-spreadsheet-AxisDesignEditor";
31356
- static components = {
31357
- Section,
31358
- ChartTitle,
31359
- };
31344
+ static components = { Section, ChartTitle };
31345
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31360
31346
  state = owl.useState({ currentAxis: "x" });
31361
31347
  get axisTitleStyle() {
31362
31348
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31507,6 +31493,12 @@ class ChartWithAxisDesignPanel extends owl.Component {
31507
31493
  AxisDesignEditor,
31508
31494
  RoundColorPicker,
31509
31495
  };
31496
+ static props = {
31497
+ figureId: String,
31498
+ definition: Object,
31499
+ canUpdateChart: Function,
31500
+ updateChart: Function,
31501
+ };
31510
31502
  state = owl.useState({ index: 0 });
31511
31503
  get axesList() {
31512
31504
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -33451,13 +33443,17 @@ class SelectMenu extends owl.Component {
33451
33443
  class: { type: String, optional: true },
33452
33444
  };
33453
33445
  static components = { Menu };
33446
+ menuId = new UuidGenerator().uuidv4();
33454
33447
  selectRef = owl.useRef("select");
33455
33448
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33456
33449
  state = owl.useState({
33457
33450
  isMenuOpen: false,
33458
33451
  });
33459
- onClick() {
33460
- this.state.isMenuOpen = true;
33452
+ onClick(ev) {
33453
+ if (ev.closedMenuId === this.menuId) {
33454
+ return;
33455
+ }
33456
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33461
33457
  }
33462
33458
  onMenuClosed() {
33463
33459
  this.state.isMenuOpen = false;
@@ -33465,7 +33461,7 @@ class SelectMenu extends owl.Component {
33465
33461
  get menuPosition() {
33466
33462
  return {
33467
33463
  x: this.selectRect.x,
33468
- y: this.selectRect.y,
33464
+ y: this.selectRect.y + this.selectRect.height,
33469
33465
  };
33470
33466
  }
33471
33467
  }
@@ -34405,9 +34401,9 @@ class FindAndReplacePanel extends owl.Component {
34405
34401
  static props = {
34406
34402
  onCloseSidePanel: Function,
34407
34403
  };
34408
- dataRange = "";
34409
34404
  searchInput = owl.useRef("searchInput");
34410
34405
  store;
34406
+ state;
34411
34407
  get hasSearchResult() {
34412
34408
  return this.store.selectedMatchIndex !== null;
34413
34409
  }
@@ -34437,6 +34433,7 @@ class FindAndReplacePanel extends owl.Component {
34437
34433
  }
34438
34434
  setup() {
34439
34435
  this.store = useLocalStore(FindAndReplaceStore);
34436
+ this.state = owl.useState({ dataRange: "" });
34440
34437
  owl.onMounted(() => this.searchInput.el?.focus());
34441
34438
  }
34442
34439
  onFocusSearch() {
@@ -34473,13 +34470,13 @@ class FindAndReplacePanel extends owl.Component {
34473
34470
  this.store.updateSearchOptions({ searchScope });
34474
34471
  }
34475
34472
  onSearchRangeChanged(ranges) {
34476
- this.dataRange = ranges[0];
34473
+ this.state.dataRange = ranges[0];
34477
34474
  }
34478
34475
  updateDataRange() {
34479
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34476
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34480
34477
  return;
34481
34478
  }
34482
- const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange);
34479
+ const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
34483
34480
  this.store.updateSearchOptions({ specificRange });
34484
34481
  }
34485
34482
  }
@@ -34524,28 +34521,30 @@ class MoreFormatsPanel extends owl.Component {
34524
34521
  }
34525
34522
  }
34526
34523
 
34527
- /** @odoo-module */
34528
- class EditableName extends owl.Component {
34529
- static template = "o-spreadsheet-EditableName";
34524
+ css /* scss */ `
34525
+ .pivot-defer-update {
34526
+ min-height: 35px;
34527
+ background-color: #f8f9fa;
34528
+ }
34529
+ `;
34530
+ class PivotDeferUpdate extends owl.Component {
34531
+ static template = "o-spreadsheet-PivotDeferUpdate";
34530
34532
  static props = {
34531
- name: String,
34532
- displayName: String,
34533
- onChanged: Function,
34533
+ deferUpdate: Boolean,
34534
+ isDirty: Boolean,
34535
+ toggleDeferUpdate: Function,
34536
+ discard: Function,
34537
+ apply: Function,
34534
34538
  };
34535
- state;
34536
- setup() {
34537
- this.state = owl.useState({
34538
- isEditing: false,
34539
- name: "",
34540
- });
34541
- }
34542
- rename() {
34543
- this.state.isEditing = true;
34544
- this.state.name = this.props.name;
34539
+ static components = {
34540
+ Section,
34541
+ Checkbox,
34542
+ };
34543
+ get deferUpdatesLabel() {
34544
+ return _t("Defer updates");
34545
34545
  }
34546
- save() {
34547
- this.props.onChanged(this.state.name.trim());
34548
- this.state.isEditing = false;
34546
+ get deferUpdatesTooltip() {
34547
+ return _t("Changing the pivot definition requires to reload the data. It may take some time.");
34549
34548
  }
34550
34549
  }
34551
34550
 
@@ -34887,6 +34886,135 @@ class PivotLayoutConfigurator extends owl.Component {
34887
34886
  }
34888
34887
  }
34889
34888
 
34889
+ css /* scss */ `
34890
+ .os-cog-wheel-menu-icon {
34891
+ cursor: pointer;
34892
+ }
34893
+
34894
+ .os-cog-wheel-menu {
34895
+ background: white;
34896
+ .btn-link {
34897
+ text-decoration: none;
34898
+ color: #017e84;
34899
+ font-weight: 500;
34900
+ &:hover {
34901
+ color: #01585c;
34902
+ }
34903
+ }
34904
+ }
34905
+ `;
34906
+ class CogWheelMenu extends owl.Component {
34907
+ static template = "o-spreadsheet-CogWheelMenu";
34908
+ static components = { Popover };
34909
+ static props = {
34910
+ items: Array,
34911
+ };
34912
+ buttonRef = owl.useRef("button");
34913
+ popover = owl.useState({ isOpen: false });
34914
+ setup() {
34915
+ owl.useExternalListener(window, "click", (ev) => {
34916
+ if (ev.target !== this.buttonRef.el) {
34917
+ this.popover.isOpen = false;
34918
+ }
34919
+ });
34920
+ }
34921
+ get popoverProps() {
34922
+ const { x, y, width, height } = this.buttonRef.el.getBoundingClientRect();
34923
+ return {
34924
+ anchorRect: { x, y, width, height },
34925
+ positioning: "BottomLeft",
34926
+ };
34927
+ }
34928
+ togglePopover() {
34929
+ this.popover.isOpen = !this.popover.isOpen;
34930
+ }
34931
+ }
34932
+
34933
+ /** @odoo-module */
34934
+ class EditableName extends owl.Component {
34935
+ static template = "o-spreadsheet-EditableName";
34936
+ static props = {
34937
+ name: String,
34938
+ displayName: String,
34939
+ onChanged: Function,
34940
+ };
34941
+ state;
34942
+ setup() {
34943
+ this.state = owl.useState({
34944
+ isEditing: false,
34945
+ name: "",
34946
+ });
34947
+ }
34948
+ rename() {
34949
+ this.state.isEditing = true;
34950
+ this.state.name = this.props.name;
34951
+ }
34952
+ save() {
34953
+ this.props.onChanged(this.state.name.trim());
34954
+ this.state.isEditing = false;
34955
+ }
34956
+ }
34957
+
34958
+ class PivotTitleSection extends owl.Component {
34959
+ static template = "o-spreadsheet-PivotTitleSection";
34960
+ static components = { CogWheelMenu, Section, EditableName };
34961
+ static props = {
34962
+ pivotId: String,
34963
+ };
34964
+ get cogWheelMenuItems() {
34965
+ return [
34966
+ {
34967
+ name: "Duplicate",
34968
+ icon: "fa-copy",
34969
+ onClick: () => this.duplicatePivot(),
34970
+ },
34971
+ {
34972
+ name: "Delete",
34973
+ icon: "fa-trash",
34974
+ onClick: () => this.delete(),
34975
+ },
34976
+ ];
34977
+ }
34978
+ get name() {
34979
+ return this.env.model.getters.getPivotName(this.props.pivotId);
34980
+ }
34981
+ get displayName() {
34982
+ return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
34983
+ }
34984
+ duplicatePivot() {
34985
+ const newPivotId = this.env.model.uuidGenerator.uuidv4();
34986
+ const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
34987
+ pivotId: this.props.pivotId,
34988
+ newPivotId,
34989
+ });
34990
+ const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
34991
+ const type = result.isSuccessful ? "success" : "danger";
34992
+ this.env.notifyUser({
34993
+ text,
34994
+ sticky: false,
34995
+ type,
34996
+ });
34997
+ if (result.isSuccessful) {
34998
+ this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
34999
+ }
35000
+ }
35001
+ delete() {
35002
+ this.env.askConfirmation(_t("Are you sure you want to delete this pivot?"), () => {
35003
+ this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
35004
+ });
35005
+ }
35006
+ onNameChanged(name) {
35007
+ const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
35008
+ this.env.model.dispatch("UPDATE_PIVOT", {
35009
+ pivotId: this.props.pivotId,
35010
+ pivot: {
35011
+ ...pivot,
35012
+ name,
35013
+ },
35014
+ });
35015
+ }
35016
+ }
35017
+
34890
35018
  /**
34891
35019
  * Represent a pivot runtime definition. A pivot runtime definition is a pivot
34892
35020
  * definition that has been enriched to include the display name of its attributes
@@ -35191,7 +35319,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
35191
35319
  }
35192
35320
  const row = rows[index];
35193
35321
  const rowName = row.nameWithGranularity;
35194
- const groups = groupBy(dataEntries, row);
35322
+ const groups = groupPivotDataEntriesBy(dataEntries, row);
35195
35323
  const orderedKeys = orderDataEntriesKeys(groups, row);
35196
35324
  const pivotTableRows = [];
35197
35325
  const _fields = fields.concat(rowName);
@@ -35221,7 +35349,7 @@ function dataEntriesToColumnsTree(dataEntries, columns, index) {
35221
35349
  }
35222
35350
  const column = columns[index];
35223
35351
  const colName = columns[index].nameWithGranularity;
35224
- const groups = groupBy(dataEntries, column);
35352
+ const groups = groupPivotDataEntriesBy(dataEntries, column);
35225
35353
  const orderedKeys = orderDataEntriesKeys(groups, columns[index]);
35226
35354
  return orderedKeys.map((value) => {
35227
35355
  return {
@@ -35319,7 +35447,7 @@ function columnsTreeToColumns(mainTree, definition) {
35319
35447
  /**
35320
35448
  * Group the dataEntries based on the given dimension
35321
35449
  */
35322
- function groupBy(dataEntries, dimension) {
35450
+ function groupPivotDataEntriesBy(dataEntries, dimension) {
35323
35451
  return Object.groupBy(dataEntries, keySelector(dimension));
35324
35452
  }
35325
35453
  /**
@@ -35369,7 +35497,7 @@ function createDate(dimension, value, locale) {
35369
35497
  number = Math.floor(date.getMonth() / 3) + 1;
35370
35498
  break;
35371
35499
  case "month_number":
35372
- number = date.getMonth();
35500
+ number = date.getMonth() + 1;
35373
35501
  break;
35374
35502
  case "iso_week_number":
35375
35503
  number = date.getIsoWeek();
@@ -35381,7 +35509,7 @@ function createDate(dimension, value, locale) {
35381
35509
  number = Math.floor(toNumber(value, locale));
35382
35510
  break;
35383
35511
  }
35384
- MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = number;
35512
+ MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = toNormalizedPivotValue(dimension, number);
35385
35513
  }
35386
35514
  return MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`];
35387
35515
  }
@@ -35527,7 +35655,7 @@ class SpreadsheetPivot {
35527
35655
  return this._definition;
35528
35656
  }
35529
35657
  isValid() {
35530
- if (this.invalidRangeError || !this._definition) {
35658
+ if (this.invalidRangeError || !this.definition) {
35531
35659
  return false;
35532
35660
  }
35533
35661
  for (const measure of this.definition.measures) {
@@ -35584,25 +35712,19 @@ class SpreadsheetPivot {
35584
35712
  const dimension = this.getDimension(lastNode.field);
35585
35713
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
35586
35714
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
35715
+ if (dimension.type === "date") {
35716
+ const adapter = pivotTimeAdapter(dimension.granularity);
35717
+ return {
35718
+ value: adapter.toCellValue(toNormalizedPivotValue(dimension, lastNode.value)),
35719
+ format: adapter.getFormat(this.getters.getLocale()),
35720
+ };
35721
+ }
35587
35722
  if (!finalCell) {
35588
35723
  return { value: "" };
35589
35724
  }
35590
35725
  if (finalCell.value === null) {
35591
35726
  return { value: _t("(Undefined)") };
35592
35727
  }
35593
- if (dimension.type === "date") {
35594
- if (dimension.granularity === "day") {
35595
- return {
35596
- value: toNumber(finalCell.value, this.getters.getLocale()),
35597
- format: this.getters.getLocale().dateFormat,
35598
- };
35599
- }
35600
- if (dimension.granularity === "month_number") {
35601
- return {
35602
- value: MONTHS[toNumber(finalCell.value, this.getters.getLocale())].toString(),
35603
- };
35604
- }
35605
- }
35606
35728
  return {
35607
35729
  value: finalCell.value,
35608
35730
  format: finalCell.format,
@@ -35627,9 +35749,12 @@ class SpreadsheetPivot {
35627
35749
  format: operator.format(values[0]),
35628
35750
  };
35629
35751
  }
35630
- getPossibleFieldValues(groupBy) {
35631
- //TODO This method should be implemented for the autocomplete feature
35632
- throw new Error("Method not implemented.");
35752
+ getPossibleFieldValues(dimension) {
35753
+ const values = [];
35754
+ for (const value in groupPivotDataEntriesBy(this.dataEntries, dimension)) {
35755
+ values.push({ value, label: "" });
35756
+ }
35757
+ return values;
35633
35758
  }
35634
35759
  getTableStructure() {
35635
35760
  if (!this.isValid()) {
@@ -35649,7 +35774,8 @@ class SpreadsheetPivot {
35649
35774
  filterDataEntriesFromDomainNode(dataEntries, domain) {
35650
35775
  const { field, value } = domain;
35651
35776
  const dimension = this.getDimension(field);
35652
- return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` === value);
35777
+ return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` ===
35778
+ `${toNormalizedPivotValue(dimension, value)}`);
35653
35779
  }
35654
35780
  getDimension(nameWithGranularity) {
35655
35781
  return this.definition.getDimension(nameWithGranularity);
@@ -35785,15 +35911,8 @@ pivotRegistry.add("SPREADSHEET", {
35785
35911
 
35786
35912
  class PivotSidePanelStore extends SpreadsheetStore {
35787
35913
  pivotId;
35788
- mutators = [
35789
- "reset",
35790
- "deferUpdates",
35791
- "applyUpdate",
35792
- "discardPendingUpdate",
35793
- "renamePivot",
35794
- "update",
35795
- ];
35796
- updatesAreDeferred = true;
35914
+ mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
35915
+ updatesAreDeferred = false;
35797
35916
  draft = null;
35798
35917
  constructor(get, pivotId) {
35799
35918
  super(get);
@@ -35910,16 +36029,6 @@ class PivotSidePanelStore extends SpreadsheetStore {
35910
36029
  discardPendingUpdate() {
35911
36030
  this.draft = null;
35912
36031
  }
35913
- renamePivot(name) {
35914
- const pivot = this.getters.getPivotCoreDefinition(this.pivotId);
35915
- this.model.dispatch("UPDATE_PIVOT", {
35916
- pivotId: this.pivotId,
35917
- pivot: {
35918
- ...pivot,
35919
- name,
35920
- },
35921
- });
35922
- }
35923
36032
  update(definitionUpdate) {
35924
36033
  const coreDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
35925
36034
  const definition = { ...coreDefinition, ...this.draft, ...definitionUpdate };
@@ -36002,8 +36111,9 @@ class PivotSpreadsheetSidePanel extends owl.Component {
36002
36111
  PivotLayoutConfigurator,
36003
36112
  Section,
36004
36113
  SelectionInput,
36005
- EditableName,
36006
36114
  Checkbox,
36115
+ PivotDeferUpdate,
36116
+ PivotTitleSection,
36007
36117
  };
36008
36118
  store;
36009
36119
  state;
@@ -36032,21 +36142,9 @@ class PivotSpreadsheetSidePanel extends owl.Component {
36032
36142
  get pivot() {
36033
36143
  return this.store.pivot;
36034
36144
  }
36035
- get name() {
36036
- return this.env.model.getters.getPivotName(this.props.pivotId);
36037
- }
36038
- get displayName() {
36039
- return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
36040
- }
36041
36145
  get definition() {
36042
36146
  return this.store.definition;
36043
36147
  }
36044
- get deferUpdatesLabel() {
36045
- return _t("Defer updates");
36046
- }
36047
- get deferUpdatesTooltip() {
36048
- return _t("Changing the pivot definition requires to reload the data. It may take some time.");
36049
- }
36050
36148
  onSelectionChanged(ranges) {
36051
36149
  this.state.rangeHasChanged = true;
36052
36150
  this.state.range = ranges[0];
@@ -36067,35 +36165,9 @@ class PivotSpreadsheetSidePanel extends owl.Component {
36067
36165
  this.store.applyUpdate();
36068
36166
  }
36069
36167
  }
36070
- duplicatePivot() {
36071
- const newPivotId = this.env.model.uuidGenerator.uuidv4();
36072
- const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
36073
- pivotId: this.props.pivotId,
36074
- newPivotId,
36075
- });
36076
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
36077
- const type = result.isSuccessful ? "success" : "danger";
36078
- this.env.notifyUser({
36079
- text,
36080
- sticky: false,
36081
- type,
36082
- });
36083
- if (result.isSuccessful) {
36084
- this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
36085
- }
36086
- }
36087
- onNameChanged(name) {
36088
- this.store.renamePivot(name);
36089
- }
36090
36168
  onDimensionsUpdated(definition) {
36091
36169
  this.store.update(definition);
36092
36170
  }
36093
- back() {
36094
- this.env.openSidePanel("PivotSidePanel", {});
36095
- }
36096
- delete() {
36097
- this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
36098
- }
36099
36171
  }
36100
36172
 
36101
36173
  const pivotSidePanelRegistry = new Registry();
@@ -36103,44 +36175,17 @@ pivotSidePanelRegistry.add("SPREADSHEET", {
36103
36175
  editor: PivotSpreadsheetSidePanel,
36104
36176
  });
36105
36177
 
36106
- css /* scss */ `
36107
- .o_pivot_list_item {
36108
- cursor: pointer;
36109
- &:hover {
36110
- background-color: #f1f3f4;
36111
- }
36112
- }
36113
- `;
36114
- class PivotListItem extends owl.Component {
36115
- static template = "o-spreadsheet-PivotListItem";
36116
- static props = { pivotId: String };
36117
- setup() {
36118
- const previewRef = owl.useRef("pivotListItem");
36119
- useHighlightsOnHover(previewRef, this);
36120
- }
36121
- selectPivot() {
36122
- this.env.openSidePanel("PivotSidePanel", { pivotId: this.props.pivotId });
36123
- }
36124
- get highlights() {
36125
- return getPivotHighlights(this.env.model.getters, this.props.pivotId);
36126
- }
36127
- }
36128
-
36129
36178
  class PivotSidePanel extends owl.Component {
36130
36179
  static template = "o-spreadsheet-PivotSidePanel";
36131
36180
  static props = {
36132
- pivotId: { type: String, optional: true },
36181
+ pivotId: String,
36133
36182
  onCloseSidePanel: Function,
36134
36183
  };
36135
36184
  static components = {
36136
36185
  PivotLayoutConfigurator,
36137
36186
  Section,
36138
- PivotListItem,
36139
36187
  };
36140
36188
  get sidePanelEditor() {
36141
- if (!this.props.pivotId) {
36142
- throw new Error("pivotId is required to call this function.");
36143
- }
36144
36189
  const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
36145
36190
  if (!pivot) {
36146
36191
  throw new Error("pivotId does not correspond to a pivot.");
@@ -36157,6 +36202,7 @@ css /* scss */ `
36157
36202
  class RemoveDuplicatesPanel extends owl.Component {
36158
36203
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36159
36204
  static components = { ValidationMessages, Section, Checkbox };
36205
+ static props = { onCloseSidePanel: Function };
36160
36206
  state = owl.useState({
36161
36207
  hasHeader: false,
36162
36208
  columns: {},
@@ -37299,21 +37345,15 @@ sidePanelRegistry.add("TableStyleEditorPanel", {
37299
37345
  });
37300
37346
  sidePanelRegistry.add("PivotSidePanel", {
37301
37347
  title: (env, props) => {
37302
- if (props.pivotId) {
37303
- return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37304
- }
37305
- return _t("List of Pivots");
37348
+ return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37306
37349
  },
37307
37350
  Body: PivotSidePanel,
37308
- computeState: (getters, initialProps) => {
37309
- if (!getters.getPivotIds().length) {
37310
- return { isOpen: false };
37311
- }
37312
- let { pivotId } = initialProps;
37313
- if (pivotId && !getters.isExistingPivot(pivotId)) {
37314
- pivotId = undefined;
37315
- }
37316
- return { isOpen: true, props: { pivotId }, key: `pivot_key_${pivotId}` };
37351
+ computeState: (getters, props) => {
37352
+ return {
37353
+ isOpen: getters.isExistingPivot(props.pivotId),
37354
+ props,
37355
+ key: `pivot_key_${props.pivotId}`,
37356
+ };
37317
37357
  },
37318
37358
  });
37319
37359
 
@@ -41571,133 +41611,6 @@ class Grid extends owl.Component {
41571
41611
  }
41572
41612
  }
41573
41613
 
41574
- const pivotTimeAdapterRegistry = new Registry();
41575
- function pivotTimeAdapter(granularity) {
41576
- return pivotTimeAdapterRegistry.get(granularity);
41577
- }
41578
- /**
41579
- * The Time Adapter: Managing Time Periods for Pivot Functions
41580
- *
41581
- * Overview:
41582
- * A time adapter is responsible for managing time periods associated with pivot functions.
41583
- * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
41584
- * The adapter's primary role is to normalize period values between spreadsheet functions,
41585
- * and the pivot.
41586
- * By normalizing the period value, it can be stored consistently in the pivot.
41587
- *
41588
- * Normalization Process:
41589
- * When working with functions in the spreadsheet, the time adapter normalizes
41590
- * the provided period to facilitate accurate lookup of values in the pivot.
41591
- * For instance, if the spreadsheet function represents a day period as a number generated
41592
- * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
41593
- *
41594
- */
41595
- /**
41596
- * Normalized value: "12/25/2023"
41597
- *
41598
- * Note: Those two format are equivalent:
41599
- * - "MM/dd/yyyy" (luxon format)
41600
- * - "mm/dd/yyyy" (spreadsheet format)
41601
- **/
41602
- const dayAdapter = {
41603
- normalizeFunctionValue(value) {
41604
- const date = toNumber(value, DEFAULT_LOCALE);
41605
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
41606
- },
41607
- getFormat(locale) {
41608
- return (locale ?? DEFAULT_LOCALE).dateFormat;
41609
- },
41610
- formatValue(normalizedValue, locale) {
41611
- locale = locale ?? DEFAULT_LOCALE;
41612
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41613
- return formatValue(value, { locale, format: this.getFormat(locale) });
41614
- },
41615
- toCellValue(normalizedValue) {
41616
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41617
- },
41618
- };
41619
- /**
41620
- * Normalized value: "2/2023" for week 2 of 2023
41621
- */
41622
- const weekAdapter = {
41623
- normalizeFunctionValue(value) {
41624
- const [week, year] = value.split("/");
41625
- return `${Number(week)}/${Number(year)}`;
41626
- },
41627
- getFormat() {
41628
- return undefined;
41629
- },
41630
- formatValue(normalizedValue) {
41631
- const [week, year] = normalizedValue.split("/");
41632
- return _t("W%(week)s %(year)s", { week, year });
41633
- },
41634
- toCellValue(normalizedValue) {
41635
- return this.formatValue(normalizedValue);
41636
- },
41637
- };
41638
- /**
41639
- * normalized month value is a string formatted as "MM/yyyy" (luxon format)
41640
- * e.g. "01/2020" for January 2020
41641
- */
41642
- const monthAdapter = {
41643
- normalizeFunctionValue(value) {
41644
- const date = toNumber(value, DEFAULT_LOCALE);
41645
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
41646
- },
41647
- getFormat() {
41648
- return "mmmm yyyy";
41649
- },
41650
- formatValue(normalizedValue, locale) {
41651
- locale = locale ?? DEFAULT_LOCALE;
41652
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41653
- return formatValue(value, { locale, format: this.getFormat(locale) });
41654
- },
41655
- toCellValue(normalizedValue) {
41656
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41657
- },
41658
- };
41659
- /**
41660
- * normalized quarter value is "quarter/year"
41661
- * e.g. "1/2020" for Q1 2020
41662
- */
41663
- const quarterAdapter = {
41664
- normalizeFunctionValue(value) {
41665
- const [quarter, year] = value.split("/");
41666
- return `${quarter}/${year}`;
41667
- },
41668
- getFormat() {
41669
- return undefined;
41670
- },
41671
- formatValue(normalizedValue) {
41672
- const [quarter, year] = normalizedValue.split("/");
41673
- return _t("Q%(quarter)s %(year)s", { quarter, year });
41674
- },
41675
- toCellValue(normalizedValue) {
41676
- return this.formatValue(normalizedValue);
41677
- },
41678
- };
41679
- const yearAdapter = {
41680
- normalizeFunctionValue(value) {
41681
- return toNumber(value, DEFAULT_LOCALE);
41682
- },
41683
- getFormat() {
41684
- return "0";
41685
- },
41686
- formatValue(normalizedValue, locale) {
41687
- locale = locale ?? DEFAULT_LOCALE;
41688
- return formatValue(normalizedValue, { locale, format: "0" });
41689
- },
41690
- toCellValue(normalizedValue) {
41691
- return normalizedValue;
41692
- },
41693
- };
41694
- pivotTimeAdapterRegistry
41695
- .add("day", dayAdapter)
41696
- .add("week", weekAdapter)
41697
- .add("month", monthAdapter)
41698
- .add("quarter", quarterAdapter)
41699
- .add("year", yearAdapter);
41700
-
41701
41614
  /**
41702
41615
  * Represent a raw XML string
41703
41616
  */
@@ -46896,9 +46809,14 @@ class CellPlugin extends CorePlugin {
46896
46809
  }
46897
46810
  createLiteralCell(id, content, format, style) {
46898
46811
  const locale = this.getters.getLocale();
46899
- format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
46812
+ const parsedValue = parseLiteral(content, locale);
46813
+ format =
46814
+ format ||
46815
+ (typeof parsedValue === "number"
46816
+ ? detectDateFormat(content, locale) || detectNumberFormat(content)
46817
+ : undefined);
46900
46818
  if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
46901
- content = toString(parseLiteral(content, locale));
46819
+ content = toString(parsedValue);
46902
46820
  }
46903
46821
  return {
46904
46822
  id,
@@ -46906,6 +46824,7 @@ class CellPlugin extends CorePlugin {
46906
46824
  style,
46907
46825
  format,
46908
46826
  isFormula: false,
46827
+ parsedValue,
46909
46828
  };
46910
46829
  }
46911
46830
  createFormulaCell(id, content, format, style, sheetId) {
@@ -51648,6 +51567,9 @@ class PositionMap {
51648
51567
  get({ sheetId, col, row }) {
51649
51568
  return this.map[sheetId]?.[col]?.[row];
51650
51569
  }
51570
+ getSheet(sheetId) {
51571
+ return this.map[sheetId];
51572
+ }
51651
51573
  has({ sheetId, col, row }) {
51652
51574
  return this.map[sheetId]?.[col]?.[row] !== undefined;
51653
51575
  }
@@ -51666,6 +51588,19 @@ class PositionMap {
51666
51588
  }
51667
51589
  return keys;
51668
51590
  }
51591
+ keysForSheet(sheetId) {
51592
+ const map = this.map[sheetId];
51593
+ if (!map) {
51594
+ return [];
51595
+ }
51596
+ const keys = [];
51597
+ for (const col in map) {
51598
+ for (const row in map[col]) {
51599
+ keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
51600
+ }
51601
+ }
51602
+ return keys;
51603
+ }
51669
51604
  }
51670
51605
 
51671
51606
  function quickselect(arr, k, left, right, compare) {
@@ -52744,6 +52679,9 @@ class Evaluator {
52744
52679
  getEvaluatedPositions() {
52745
52680
  return this.evaluatedCells.keys();
52746
52681
  }
52682
+ getEvaluatedPositionsInSheet(sheetId) {
52683
+ return this.evaluatedCells.keysForSheet(sheetId);
52684
+ }
52747
52685
  getArrayFormulaSpreadingOn(position) {
52748
52686
  if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
52749
52687
  return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
@@ -52752,6 +52690,9 @@ class Evaluator {
52752
52690
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
52753
52691
  }
52754
52692
  updateDependencies(position) {
52693
+ // removing dependencies is slow because it requires
52694
+ // to traverse the entire r-tree.
52695
+ // The data structure is optimized for searches the other way around
52755
52696
  this.formulaDependencies().removeAllDependencies(position);
52756
52697
  const dependencies = this.getDirectDependencies(position);
52757
52698
  this.formulaDependencies().addDependencies(position, dependencies);
@@ -52917,7 +52858,7 @@ class Evaluator {
52917
52858
  this.cellsBeingComputed.add(cellId);
52918
52859
  return cell.isFormula
52919
52860
  ? this.computeFormulaCell(position.sheetId, cell)
52920
- : evaluateLiteral(cell.content, localeFormat);
52861
+ : evaluateLiteral(cell, localeFormat);
52921
52862
  }
52922
52863
  catch (e) {
52923
52864
  e.value = e?.value || CellErrorType.GenericError;
@@ -53187,6 +53128,7 @@ class EvaluationPlugin extends UIPlugin {
53187
53128
  "getEvaluatedCell",
53188
53129
  "getEvaluatedCells",
53189
53130
  "getEvaluatedCellsInZone",
53131
+ "getEvaluatedCellsPositions",
53190
53132
  "getSpreadZone",
53191
53133
  "getArrayFormulaSpreadingOn",
53192
53134
  "isEmpty",
@@ -53278,13 +53220,12 @@ class EvaluationPlugin extends UIPlugin {
53278
53220
  return this.evaluator.getEvaluatedCell(position);
53279
53221
  }
53280
53222
  getEvaluatedCells(sheetId) {
53281
- const rawCells = this.getters.getCells(sheetId) || {};
53282
- const record = {};
53283
- for (let cellId of Object.keys(rawCells)) {
53284
- const position = this.getters.getCellPosition(cellId);
53285
- record[cellId] = this.getEvaluatedCell(position);
53286
- }
53287
- return record;
53223
+ return this.evaluator
53224
+ .getEvaluatedPositionsInSheet(sheetId)
53225
+ .map((position) => this.getEvaluatedCell(position));
53226
+ }
53227
+ getEvaluatedCellsPositions(sheetId) {
53228
+ return this.evaluator.getEvaluatedPositionsInSheet(sheetId);
53288
53229
  }
53289
53230
  getEvaluatedCellsInZone(sheetId, zone) {
53290
53231
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
@@ -54621,17 +54562,18 @@ class PivotUIPlugin extends UIPlugin {
54621
54562
  if (pivotCell.type === "EMPTY") {
54622
54563
  return undefined;
54623
54564
  }
54624
- const domain = pivotCell.domain;
54565
+ let domain = pivotCell.domain;
54625
54566
  if (domain.at(-1)?.field === "measure") {
54626
- return domain.slice(0, -1);
54567
+ domain = domain.slice(0, -1);
54627
54568
  }
54628
- return domain;
54569
+ return { domainArgs: domain, isHeader: pivotCell.type === "HEADER" };
54629
54570
  }
54630
- const domain = toPivotDomain(args.slice(functionName === "PIVOT.VALUE" ? 2 : 1).map((x) => `${x}`));
54571
+ let domain = toPivotDomain(args.slice(functionName === "PIVOT.VALUE" ? 2 : 1).map((x) => `${x}`));
54631
54572
  if (domain.at(-1)?.field === "measure") {
54632
- return domain.slice(0, -1);
54573
+ domain = domain.slice(0, -1);
54633
54574
  }
54634
- return domain;
54575
+ const isHeader = functionName === "PIVOT.HEADER";
54576
+ return { domainArgs: domain, isHeader };
54635
54577
  }
54636
54578
  getPivot(pivotId) {
54637
54579
  return this.pivots[pivotId];
@@ -55951,7 +55893,10 @@ class Session extends EventBus {
55951
55893
  /**
55952
55894
  * Notify the server that the user client left the collaborative session
55953
55895
  */
55954
- leave() {
55896
+ leave(data) {
55897
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55898
+ this.snapshot(data);
55899
+ }
55955
55900
  delete this.clients[this.clientId];
55956
55901
  this.transportService.leave(this.clientId);
55957
55902
  this.transportService.sendMessage({
@@ -56365,7 +56310,7 @@ class DataCleanupPlugin extends UIPlugin {
56365
56310
  bottom: rowIndex,
56366
56311
  }));
56367
56312
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
56368
- const data = handler.copy(getClipboardDataPositions(rowsToKeep));
56313
+ const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep));
56369
56314
  if (!data) {
56370
56315
  return;
56371
56316
  }
@@ -56378,7 +56323,7 @@ class DataCleanupPlugin extends UIPlugin {
56378
56323
  right: zone.left,
56379
56324
  bottom: zone.top,
56380
56325
  };
56381
- handler.paste({ zones: [zonePasted] }, data, { isCutOperation: false });
56326
+ handler.paste({ zones: [zonePasted], sheetId }, data, { isCutOperation: false });
56382
56327
  const remainingZone = {
56383
56328
  left: zone.left,
56384
56329
  top: zone.top - (hasHeader ? 1 : 0),
@@ -58252,12 +58197,14 @@ class ClipboardPlugin extends UIPlugin {
58252
58197
  }
58253
58198
  let zone = undefined;
58254
58199
  let selectedZones = [];
58200
+ const sheetId = this.getters.getActiveSheetId();
58255
58201
  let target = {
58202
+ sheetId,
58256
58203
  zones,
58257
58204
  };
58258
58205
  const handlers = this.selectClipboardHandlers(copiedData);
58259
58206
  for (const handler of handlers) {
58260
- const currentTarget = handler.getPasteTarget(zones, copiedData, options);
58207
+ const currentTarget = handler.getPasteTarget(sheetId, zones, copiedData, options);
58261
58208
  if (currentTarget.figureId) {
58262
58209
  target.figureId = currentTarget.figureId;
58263
58210
  }
@@ -58426,11 +58373,12 @@ class ClipboardPlugin extends UIPlugin {
58426
58373
  return { cut: [cut], paste: [paste] };
58427
58374
  }
58428
58375
  getClipboardData(zones) {
58376
+ const sheetId = this.getters.getActiveSheetId();
58429
58377
  const selectedFigureId = this.getters.getSelectedFigureId();
58430
58378
  if (selectedFigureId) {
58431
- return { figureId: selectedFigureId };
58379
+ return { figureId: selectedFigureId, sheetId };
58432
58380
  }
58433
- return getClipboardDataPositions(zones);
58381
+ return getClipboardDataPositions(sheetId, zones);
58434
58382
  }
58435
58383
  // ---------------------------------------------------------------------------
58436
58384
  // Grid rendering
@@ -59096,8 +59044,9 @@ class GridSelectionPlugin extends UIPlugin {
59096
59044
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
59097
59045
  },
59098
59046
  ];
59047
+ const sheetId = this.getActiveSheetId();
59099
59048
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
59100
- const data = handler.copy(getClipboardDataPositions(target));
59049
+ const data = handler.copy(getClipboardDataPositions(sheetId, target));
59101
59050
  if (!data) {
59102
59051
  return;
59103
59052
  }
@@ -59110,7 +59059,7 @@ class GridSelectionPlugin extends UIPlugin {
59110
59059
  bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
59111
59060
  },
59112
59061
  ];
59113
- handler.paste({ zones: pasteTarget }, data, { isCutOperation: true });
59062
+ handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
59114
59063
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
59115
59064
  let currentIndex = cmd.base;
59116
59065
  for (const element of toRemove) {
@@ -66474,7 +66423,7 @@ class Model extends EventBus {
66474
66423
  this.session.join(this.config.client);
66475
66424
  }
66476
66425
  leaveSession() {
66477
- this.session.leave();
66426
+ this.session.leave(this.exportData());
66478
66427
  }
66479
66428
  setupUiPlugin(Plugin) {
66480
66429
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66881,7 +66830,8 @@ const registries = {
66881
66830
  pivotRegistry,
66882
66831
  pivotTimeAdapterRegistry,
66883
66832
  pivotSidePanelRegistry,
66884
- supportedPivotExplodedFormulaRegistry,
66833
+ pivotNormalizationValueRegistry,
66834
+ supportedPivotPositionalFormulaRegistry,
66885
66835
  };
66886
66836
  const helpers = {
66887
66837
  arg,
@@ -66890,6 +66840,7 @@ const helpers = {
66890
66840
  toJsDate,
66891
66841
  toNumber,
66892
66842
  toString,
66843
+ toNormalizedPivotValue,
66893
66844
  toXC,
66894
66845
  toZone,
66895
66846
  toUnboundedZone,
@@ -66984,6 +66935,9 @@ const components = {
66984
66935
  PivotDimension,
66985
66936
  PivotLayoutConfigurator,
66986
66937
  EditableName,
66938
+ PivotDeferUpdate,
66939
+ PivotTitleSection,
66940
+ CogWheelMenu,
66987
66941
  };
66988
66942
  const hooks = {
66989
66943
  useDragAndDropListItems,
@@ -67067,6 +67021,6 @@ exports.tokenColors = tokenColors;
67067
67021
  exports.tokenize = tokenize;
67068
67022
 
67069
67023
 
67070
- __info__.version = "17.4.0-alpha.2";
67071
- __info__.date = "2024-06-06T13:31:21.327Z";
67072
- __info__.hash = "e07794d";
67024
+ __info__.version = "17.4.0-alpha.4";
67025
+ __info__.date = "2024-06-12T14:00:22.046Z";
67026
+ __info__.hash = "cefb0e4";