@odoo/o-spreadsheet 17.4.0-alpha.3 → 17.4.0-alpha.5

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.3
7
- * @date 2024-06-10T09:38:53.982Z
8
- * @hash a45ed6a
6
+ * @version 17.4.0-alpha.5
7
+ * @date 2024-06-14T10:01:40.605Z
8
+ * @hash 9ceed96
9
9
  */
10
10
 
11
11
  'use strict';
@@ -1828,22 +1828,28 @@ function isDateAfter(date, dateAfter) {
1828
1828
  */
1829
1829
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
1830
1830
  decimalSeparator = escapeRegExp(decimalSeparator);
1831
- return new RegExp(`(^-?\\d+(${decimalSeparator}?\\d*(e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1831
+ return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1832
1832
  });
1833
1833
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1834
1834
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1835
1835
  const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
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*" + pIntegerAndDecimals + "|" + pOnlyDecimals + ")" + pScientificFormat + pPercentFormat;
1841
- const pMinus = "(\\s*-)?"; // pattern that match negative symbol between zero and one time
1842
- 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*[\\$€])?";
1843
1849
  const p1 = pMinus + pCurrencyFormat + pNumber;
1844
1850
  const p2 = pMinus + pNumber + pCurrencyFormat;
1845
1851
  const p3 = pCurrencyFormat + pMinus + pNumber;
1846
- const pNumberExp = "^((" + [p1, p2, p3].join(")|(") + "))$";
1852
+ const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
1847
1853
  const numberRegexp = new RegExp(pNumberExp, "i");
1848
1854
  return numberRegexp;
1849
1855
  });
@@ -2781,7 +2787,7 @@ function evaluatePredicate(value, criterion) {
2781
2787
  return false;
2782
2788
  }
2783
2789
  if (typeof operand === "number" && operator === "=") {
2784
- return toString(value) === toString(operand);
2790
+ return value.toString() === operand.toString();
2785
2791
  }
2786
2792
  if (operator === "<>" || operator === "=") {
2787
2793
  let result;
@@ -2841,14 +2847,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2841
2847
  if (countArg % 2 === 1) {
2842
2848
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2843
2849
  }
2844
- const dimRow = args[0].length;
2845
- const dimCol = args[0][0].length;
2850
+ const firstArg = toMatrix(args[0]);
2851
+ const dimRow = firstArg.length;
2852
+ const dimCol = firstArg[0].length;
2846
2853
  let predicates = [];
2847
2854
  for (let i = 0; i < countArg - 1; i += 2) {
2848
- const criteriaRange = args[i];
2849
- if (!isMatrix(criteriaRange) ||
2850
- criteriaRange.length !== dimRow ||
2851
- criteriaRange[0].length !== dimCol) {
2855
+ const criteriaRange = toMatrix(args[i]);
2856
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2852
2857
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2853
2858
  }
2854
2859
  const description = toString(args[i + 1]);
@@ -2862,7 +2867,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2862
2867
  for (let j = 0; j < dimCol; j++) {
2863
2868
  let validatedPredicates = true;
2864
2869
  for (let k = 0; k < countArg - 1; k += 2) {
2865
- const criteriaValue = args[k][i][j].value;
2870
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2866
2871
  const criterion = predicates[k / 2];
2867
2872
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2868
2873
  if (!validatedPredicates) {
@@ -3527,10 +3532,8 @@ function detectDateFormat(content, locale) {
3527
3532
  const internalDate = parseDateTime(content, locale);
3528
3533
  return internalDate.format;
3529
3534
  }
3535
+ /** use this function only if the content corresponds to a number (means that isNumber(content) return true */
3530
3536
  function detectNumberFormat(content) {
3531
- if (!isNumber(content, DEFAULT_LOCALE)) {
3532
- return undefined;
3533
- }
3534
3537
  const digitBase = content.includes(".") ? "0.00" : "0";
3535
3538
  const matchedCurrencies = content.match(/[\$€]/);
3536
3539
  if (matchedCurrencies) {
@@ -4733,21 +4736,16 @@ function unionPositionsToZone(positions) {
4733
4736
  * Check if two zones are contiguous, ie. that they share a border
4734
4737
  */
4735
4738
  function areZoneContiguous(zone1, zone2) {
4736
- const u = union(zone1, zone2);
4737
4739
  if (zone1.right + 1 === zone2.left || zone1.left === zone2.right + 1) {
4738
- 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));
4739
4742
  }
4740
4743
  if (zone1.bottom + 1 === zone2.top || zone1.top === zone2.bottom + 1) {
4741
- 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));
4742
4746
  }
4743
4747
  return false;
4744
4748
  }
4745
- function getZoneHeight(zone) {
4746
- return zone.bottom - zone.top + 1;
4747
- }
4748
- function getZoneWidth(zone) {
4749
- return zone.right - zone.left + 1;
4750
- }
4751
4749
  /**
4752
4750
  * Merge contiguous and overlapping zones that are in the array into bigger zones
4753
4751
  */
@@ -5286,7 +5284,7 @@ function clipTextWithEllipsis(ctx, text, maxWidth) {
5286
5284
  return text;
5287
5285
  }
5288
5286
  const ellipsis = "…";
5289
- const ellipsisWidth = computeCachedTextWidth(ctx, text);
5287
+ const ellipsisWidth = computeCachedTextWidth(ctx, ellipsis);
5290
5288
  if (width <= ellipsisWidth) {
5291
5289
  return text;
5292
5290
  }
@@ -5503,7 +5501,7 @@ class Registry {
5503
5501
  }
5504
5502
  }
5505
5503
 
5506
- function getClipboardDataPositions(zones) {
5504
+ function getClipboardDataPositions(sheetId, zones) {
5507
5505
  const lefts = new Set(zones.map((z) => z.left));
5508
5506
  const rights = new Set(zones.map((z) => z.right));
5509
5507
  const tops = new Set(zones.map((z) => z.top));
@@ -5517,7 +5515,7 @@ function getClipboardDataPositions(zones) {
5517
5515
  const cellsPosition = clippedZones.map((zone) => positions(zone)).flat();
5518
5516
  const columnsIndexes = [...new Set(cellsPosition.map((p) => p.col))].sort((a, b) => a - b);
5519
5517
  const rowsIndexes = [...new Set(cellsPosition.map((p) => p.row))].sort((a, b) => a - b);
5520
- return { zones, clippedZones, columnsIndexes, rowsIndexes };
5518
+ return { sheetId, zones, clippedZones, columnsIndexes, rowsIndexes };
5521
5519
  }
5522
5520
  /**
5523
5521
  * The clipped zone is copied as many times as it fits in the target.
@@ -5567,8 +5565,8 @@ class ClipboardHandler {
5567
5565
  isCutAllowed(data) {
5568
5566
  return "Success" /* CommandResult.Success */;
5569
5567
  }
5570
- getPasteTarget(target, content, options) {
5571
- return { zones: [] };
5568
+ getPasteTarget(sheetId, target, content, options) {
5569
+ return { zones: [], sheetId };
5572
5570
  }
5573
5571
  convertOSClipboardData(data) {
5574
5572
  return;
@@ -5606,7 +5604,7 @@ class AbstractCellClipboardHandler extends ClipboardHandler {
5606
5604
 
5607
5605
  class BorderClipboardHandler extends AbstractCellClipboardHandler {
5608
5606
  copy(data) {
5609
- const sheetId = this.getters.getActiveSheetId();
5607
+ const sheetId = data.sheetId;
5610
5608
  if (data.zones.length === 0) {
5611
5609
  return;
5612
5610
  }
@@ -5626,7 +5624,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
5626
5624
  if (!content) {
5627
5625
  return;
5628
5626
  }
5629
- const sheetId = this.getters.getActiveSheetId();
5627
+ const sheetId = target.sheetId;
5630
5628
  if (options?.pasteOption === "asValue") {
5631
5629
  return;
5632
5630
  }
@@ -6156,7 +6154,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6156
6154
  if (!("zones" in data) || !data.zones.length) {
6157
6155
  return;
6158
6156
  }
6159
- const sheetId = this.getters.getActiveSheetId();
6157
+ const sheetId = data.sheetId;
6160
6158
  const zones = data.zones;
6161
6159
  if (!zones.length) {
6162
6160
  return {
@@ -6185,6 +6183,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6185
6183
  format: evaluatedCell.format,
6186
6184
  content,
6187
6185
  isFormula: false,
6186
+ parsedValue: evaluatedCell.value,
6188
6187
  };
6189
6188
  }
6190
6189
  cellsInRow.push({
@@ -6199,7 +6198,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6199
6198
  return {
6200
6199
  cells: clippedCells,
6201
6200
  zones: clippedZones,
6202
- sheetId: this.getters.getActiveSheetId(),
6201
+ sheetId: data.sheetId,
6203
6202
  };
6204
6203
  }
6205
6204
  isPasteAllowed(sheetId, target, content, clipboardOptions) {
@@ -6227,7 +6226,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6227
6226
  return;
6228
6227
  }
6229
6228
  const zones = target.zones;
6230
- const sheetId = this.getters.getActiveSheetId();
6229
+ const sheetId = target.sheetId;
6231
6230
  if (!options?.isCutOperation) {
6232
6231
  this.pasteFromCopy(sheetId, zones, content.cells, options);
6233
6232
  }
@@ -6235,11 +6234,12 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6235
6234
  this.pasteFromCut(sheetId, zones, content, options);
6236
6235
  }
6237
6236
  }
6238
- getPasteTarget(target, content, options) {
6237
+ getPasteTarget(sheetId, target, content, options) {
6239
6238
  const width = content.cells[0].length;
6240
6239
  const height = content.cells.length;
6241
6240
  if (options?.isCutOperation) {
6242
6241
  return {
6242
+ sheetId,
6243
6243
  zones: [
6244
6244
  {
6245
6245
  left: target[0].left,
@@ -6251,11 +6251,9 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6251
6251
  };
6252
6252
  }
6253
6253
  if (width === 1 && height === 1) {
6254
- return { zones: [] };
6254
+ return { zones: [], sheetId };
6255
6255
  }
6256
- return {
6257
- zones: getPasteZones(target, content.cells),
6258
- };
6256
+ return { sheetId, zones: getPasteZones(target, content.cells) };
6259
6257
  }
6260
6258
  pasteFromCut(sheetId, target, content, options) {
6261
6259
  this.clearClippedZones(content);
@@ -6378,7 +6376,7 @@ class AbstractFigureClipboardHandler extends ClipboardHandler {
6378
6376
 
6379
6377
  class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6380
6378
  copy(data) {
6381
- const sheetId = this.getters.getActiveSheetId();
6379
+ const sheetId = data.sheetId;
6382
6380
  const figure = this.getters.getFigure(sheetId, data.figureId);
6383
6381
  if (!figure) {
6384
6382
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6398,22 +6396,19 @@ class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6398
6396
  copiedChart,
6399
6397
  };
6400
6398
  }
6401
- getPasteTarget(target, content, options) {
6399
+ getPasteTarget(sheetId, target, content, options) {
6402
6400
  if (!content?.copiedFigure || !content?.copiedChart) {
6403
- return { zones: [] };
6401
+ return { zones: [], sheetId };
6404
6402
  }
6405
6403
  const newId = new UuidGenerator().uuidv4();
6406
- return {
6407
- zones: [],
6408
- figureId: newId,
6409
- };
6404
+ return { zones: [], figureId: newId, sheetId };
6410
6405
  }
6411
6406
  paste(target, clippedContent, options) {
6412
6407
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedChart || !target.figureId) {
6413
6408
  return;
6414
6409
  }
6415
6410
  const { zones, figureId } = target;
6416
- const sheetId = this.getters.getActiveSheetId();
6411
+ const sheetId = target.sheetId;
6417
6412
  const numCols = this.getters.getNumberCols(sheetId);
6418
6413
  const numRows = this.getters.getNumberRows(sheetId);
6419
6414
  const targetX = this.getters.getColDimensions(sheetId, zones[0].left).start;
@@ -6459,7 +6454,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6459
6454
  return;
6460
6455
  }
6461
6456
  const { rowsIndexes, columnsIndexes } = data;
6462
- const sheetId = this.getters.getActiveSheetId();
6457
+ const sheetId = data.sheetId;
6463
6458
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6464
6459
  return {
6465
6460
  cellPositions,
@@ -6473,7 +6468,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6473
6468
  return;
6474
6469
  }
6475
6470
  const zones = target.zones;
6476
- const sheetId = this.getters.getActiveSheetId();
6471
+ const sheetId = target.sheetId;
6477
6472
  if (!options?.isCutOperation) {
6478
6473
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6479
6474
  }
@@ -6554,7 +6549,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6554
6549
  return;
6555
6550
  }
6556
6551
  const { rowsIndexes, columnsIndexes } = data;
6557
- const sheetId = this.getters.getActiveSheetId();
6552
+ const sheetId = data.sheetId;
6558
6553
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6559
6554
  return {
6560
6555
  cellPositions,
@@ -6571,7 +6566,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6571
6566
  return;
6572
6567
  }
6573
6568
  const zones = target.zones;
6574
- const sheetId = this.getters.getActiveSheetId();
6569
+ const sheetId = target.sheetId;
6575
6570
  if (!options?.isCutOperation) {
6576
6571
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6577
6572
  }
@@ -6650,7 +6645,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6650
6645
 
6651
6646
  class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6652
6647
  copy(data) {
6653
- const sheetId = this.getters.getActiveSheetId();
6648
+ const sheetId = data.sheetId;
6654
6649
  const figure = this.getters.getFigure(sheetId, data.figureId);
6655
6650
  if (!figure) {
6656
6651
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6668,15 +6663,12 @@ class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6668
6663
  sheetId,
6669
6664
  };
6670
6665
  }
6671
- getPasteTarget(target, content, options) {
6666
+ getPasteTarget(sheetId, target, content, options) {
6672
6667
  if (!content?.copiedFigure || !content?.copiedImage) {
6673
- return { zones: [] };
6668
+ return { zones: [], sheetId };
6674
6669
  }
6675
6670
  const newId = new UuidGenerator().uuidv4();
6676
- return {
6677
- zones: [],
6678
- figureId: newId,
6679
- };
6671
+ return { sheetId, zones: [], figureId: newId };
6680
6672
  }
6681
6673
  paste(target, clippedContent, options) {
6682
6674
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedImage || !target.figureId) {
@@ -6747,8 +6739,7 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
6747
6739
  if (options?.isCutOperation || !("zones" in target) || !target.zones.length) {
6748
6740
  return;
6749
6741
  }
6750
- const sheetId = this.getters.getActiveSheetId();
6751
- this.pasteFromCopy(sheetId, target.zones, content.cells, options);
6742
+ this.pasteFromCopy(target.sheetId, target.zones, content.cells, options);
6752
6743
  }
6753
6744
  pasteZone(sheetId, col, row, cells) {
6754
6745
  for (const [r, rowCells] of cells.entries()) {
@@ -6808,7 +6799,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
6808
6799
 
6809
6800
  class TableClipboardHandler extends AbstractCellClipboardHandler {
6810
6801
  copy(data) {
6811
- const sheetId = this.getters.getActiveSheetId();
6802
+ const sheetId = data.sheetId;
6812
6803
  const { rowsIndexes, columnsIndexes, zones } = data;
6813
6804
  if (!zones || !rowsIndexes.length || !columnsIndexes.length) {
6814
6805
  return { tableCells: [[]], sheetId };
@@ -6850,7 +6841,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6850
6841
  }
6851
6842
  return {
6852
6843
  tableCells,
6853
- sheetId: this.getters.getActiveSheetId(),
6844
+ sheetId: data.sheetId,
6854
6845
  };
6855
6846
  }
6856
6847
  /**
@@ -6872,7 +6863,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6872
6863
  return;
6873
6864
  }
6874
6865
  const zones = target.zones;
6875
- const sheetId = this.getters.getActiveSheetId();
6866
+ const sheetId = target.sheetId;
6876
6867
  if (!options?.isCutOperation) {
6877
6868
  this.pasteFromCopy(sheetId, zones, content.tableCells, options);
6878
6869
  }
@@ -7634,10 +7625,8 @@ function detectLink(value) {
7634
7625
  return undefined;
7635
7626
  }
7636
7627
 
7637
- function evaluateLiteral(content = "", localeFormat) {
7638
- const value = localeFormat.format === PLAIN_TEXT_FORMAT
7639
- ? content
7640
- : parseLiteral(content, localeFormat.locale);
7628
+ function evaluateLiteral(literalCell, localeFormat) {
7629
+ const value = localeFormat.format === PLAIN_TEXT_FORMAT ? literalCell.content : literalCell.parsedValue;
7641
7630
  const fPayload = { value, format: localeFormat.format };
7642
7631
  return createEvaluatedCell(fPayload, localeFormat.locale);
7643
7632
  }
@@ -7649,10 +7638,11 @@ function parseLiteral(content, locale) {
7649
7638
  return null;
7650
7639
  }
7651
7640
  if (isNumber(content, DEFAULT_LOCALE)) {
7652
- return toNumber(content, DEFAULT_LOCALE);
7641
+ return parseNumber(content, DEFAULT_LOCALE);
7653
7642
  }
7654
- if (isDateTime(content, locale)) {
7655
- return toNumber(content, locale);
7643
+ const internalDate = parseDateTime(content, locale);
7644
+ if (internalDate) {
7645
+ return internalDate.value;
7656
7646
  }
7657
7647
  if (isBoolean(content)) {
7658
7648
  return content.toUpperCase() === "TRUE" ? true : false;
@@ -7664,9 +7654,14 @@ function createEvaluatedCell(fPayload, locale = DEFAULT_LOCALE, cell) {
7664
7654
  if (!link) {
7665
7655
  return _createEvaluatedCell(fPayload, locale, cell);
7666
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);
7667
7662
  const linkPayload = {
7668
- value: parseLiteral(link.label, locale),
7669
- format: fPayload.format || detectDateFormat(link.label, locale) || detectNumberFormat(link.label),
7663
+ value,
7664
+ format,
7670
7665
  };
7671
7666
  return {
7672
7667
  ..._createEvaluatedCell(linkPayload, locale, cell),
@@ -10429,6 +10424,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10429
10424
  function drawScoreChart(structure, canvas) {
10430
10425
  const ctx = canvas.getContext("2d");
10431
10426
  canvas.width = structure.canvas.width;
10427
+ const availableWidth = canvas.width - DEFAULT_CHART_PADDING;
10432
10428
  canvas.height = structure.canvas.height;
10433
10429
  ctx.fillStyle = structure.canvas.backgroundColor;
10434
10430
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
@@ -10437,7 +10433,7 @@ function drawScoreChart(structure, canvas) {
10437
10433
  ctx.fillStyle = structure.title.style.color;
10438
10434
  const baseline = ctx.textBaseline;
10439
10435
  ctx.textBaseline = "middle";
10440
- ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, canvas.width - structure.title.position.x), structure.title.position.x, structure.title.position.y);
10436
+ ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, availableWidth - structure.title.position.x), structure.title.position.x, structure.title.position.y);
10441
10437
  ctx.textBaseline = baseline;
10442
10438
  }
10443
10439
  if (structure.baseline) {
@@ -10527,13 +10523,16 @@ function createScorecardChartRuntime(chart, getters) {
10527
10523
  return {
10528
10524
  title: {
10529
10525
  ...chart.title,
10526
+ // chart titles are extracted from .json files and they are translated at runtime here
10530
10527
  text: _t(chart.title.text ?? ""),
10531
10528
  },
10532
10529
  keyValue: formattedKeyValue,
10533
10530
  baselineDisplay,
10534
10531
  baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
10535
10532
  baselineColor: getBaselineColor(baselineCell, chart.baselineMode, keyValueCell, chart.baselineColorUp, chart.baselineColorDown),
10536
- baselineDescr: chart.baselineMode !== "progress" && chart.baselineDescr ? _t(chart.baselineDescr) : "",
10533
+ baselineDescr: chart.baselineMode !== "progress" && chart.baselineDescr
10534
+ ? _t(chart.baselineDescr) // descriptions are extracted from .json files and they are translated at runtime here
10535
+ : "",
10537
10536
  fontColor,
10538
10537
  background,
10539
10538
  baselineStyle: chart.baselineMode !== "percentage" && chart.baselineMode !== "progress" && baseline
@@ -10562,7 +10561,7 @@ function createScorecardChartRuntime(chart, getters) {
10562
10561
  /* Sizes of boxes containing the texts, in percentage of the Chart size */
10563
10562
  const KEY_BOX_HEIGHT_RATIO = 0.8;
10564
10563
  /* Padding at the border of the chart */
10565
- const CHART_PADDING = DEFAULT_CHART_PADDING;
10564
+ const CHART_PADDING = 10;
10566
10565
  const BOTTOM_PADDING_RATIO = 0.05;
10567
10566
  /**
10568
10567
  * Line height (in em)
@@ -10712,6 +10711,7 @@ class ScorecardChartConfigBuilder {
10712
10711
  position: {
10713
10712
  x: (this.width - keyWidth) / 2,
10714
10713
  y: this.height * (0.5 - BOTTOM_PADDING_RATIO * 2) +
10714
+ CHART_PADDING / 2 +
10715
10715
  (titleHeight + keyHeight / (this.baseline || this.baselineDescr ? 2 : 1.2)) / 2,
10716
10716
  },
10717
10717
  };
@@ -10771,7 +10771,8 @@ class ScorecardChartConfigBuilder {
10771
10771
  const remainingWidth = maxLineWidth - baselineValueWidth;
10772
10772
  let baselineDescrFontSize = getFontSizeMatchingWidth(remainingWidth, baselineValueFontSize, (fontSize) => computeTextWidth(this.context, this.baselineDescr, { fontSize }));
10773
10773
  let isBaselineSplit = false;
10774
- if (baselineDescrFontSize < baselineValueFontSize / 2.5) {
10774
+ if (baselineDescrFontSize < baselineValueFontSize / 2.5 &&
10775
+ this.baselineDescr.trim().includes(" ")) {
10775
10776
  isBaselineSplit = true;
10776
10777
  baselineDescrFontSize = Math.floor(baselineValueFontSize / 2.5);
10777
10778
  for (const line of splitTextInTwoLines(this.baselineDescr)) {
@@ -10820,7 +10821,7 @@ class ScorecardChartConfigBuilder {
10820
10821
  /** Get the height of the chart minus all the vertical paddings */
10821
10822
  getDrawableHeight() {
10822
10823
  const verticalPadding = CHART_PADDING + this.height * BOTTOM_PADDING_RATIO;
10823
- let availableHeight = this.height - 2 * verticalPadding;
10824
+ let availableHeight = this.height - verticalPadding;
10824
10825
  availableHeight -= this.title ? DEFAULT_CHART_FONT_SIZE * LINE_HEIGHT : 0;
10825
10826
  return availableHeight;
10826
10827
  }
@@ -10862,6 +10863,11 @@ class ScorecardChart extends owl.Component {
10862
10863
  get runtime() {
10863
10864
  return this.env.model.getters.getChartRuntime(this.props.figure.id);
10864
10865
  }
10866
+ get title() {
10867
+ const title = this.env.model.getters.getChartDefinition(this.props.figure.id).title.text ?? "";
10868
+ // chart titles are extracted from .json files and they are translated at runtime here
10869
+ return _t(title);
10870
+ }
10865
10871
  setup() {
10866
10872
  owl.useEffect(this.createChart.bind(this), () => {
10867
10873
  const canvas = this.canvas.el;
@@ -10990,6 +10996,9 @@ function makeArg(str, description) {
10990
10996
  if (types.some((t) => t.startsWith("RANGE"))) {
10991
10997
  result.acceptMatrix = true;
10992
10998
  }
10999
+ if (types.every((t) => t.startsWith("RANGE"))) {
11000
+ result.acceptMatrixOnly = true;
11001
+ }
10993
11002
  return result;
10994
11003
  }
10995
11004
  /**
@@ -11244,7 +11253,6 @@ const ARRAY_CONSTRAIN = {
11244
11253
  arg("rows (number)", _t("The number of rows in the constrained array.")),
11245
11254
  arg("columns (number)", _t("The number of columns in the constrained array.")),
11246
11255
  ],
11247
- returns: ["RANGE<ANY>"],
11248
11256
  compute: function (array, rows, columns) {
11249
11257
  const _array = toMatrix(array);
11250
11258
  const _rowsArg = toInteger(rows?.value, this.locale);
@@ -11267,15 +11275,19 @@ const CHOOSECOLS = {
11267
11275
  arg("col_num (number, range<number>)", _t("The first column index of the columns to be returned.")),
11268
11276
  arg("col_num2 (number, range<number>, repeating)", _t("The columns indexes of the columns to be returned.")),
11269
11277
  ],
11270
- returns: ["RANGE<ANY>"],
11271
11278
  compute: function (array, ...columns) {
11272
11279
  const _array = toMatrix(array);
11273
11280
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11274
- 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()));
11281
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11282
+ 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(",")));
11275
11283
  const result = Array(_columns.length);
11276
11284
  for (let col = 0; col < _columns.length; col++) {
11277
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11278
- result[col] = _array[colIndex];
11285
+ if (_columns[col] > 0) {
11286
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11287
+ }
11288
+ else {
11289
+ result[col] = _array[_array.length + _columns[col]];
11290
+ }
11279
11291
  }
11280
11292
  return result;
11281
11293
  },
@@ -11291,13 +11303,18 @@ const CHOOSEROWS = {
11291
11303
  arg("row_num (number, range<number>)", _t("The first row index of the rows to be returned.")),
11292
11304
  arg("row_num2 (number, range<number>, repeating)", _t("The rows indexes of the rows to be returned.")),
11293
11305
  ],
11294
- returns: ["RANGE<ANY>"],
11295
11306
  compute: function (array, ...rows) {
11296
11307
  const _array = toMatrix(array);
11297
11308
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11298
11309
  const _nbColumns = _array.length;
11299
- 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()));
11300
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11310
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11311
+ 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(",")));
11312
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11313
+ if (_rows[row] > 0) {
11314
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11315
+ }
11316
+ return _array[col][_array[col].length + _rows[row]];
11317
+ });
11301
11318
  },
11302
11319
  isExported: true,
11303
11320
  };
@@ -11312,7 +11329,6 @@ const EXPAND = {
11312
11329
  arg("columns (number, optional)", _t("The number of columns in the expanded array. If missing, columns will not be expanded.")),
11313
11330
  arg("pad_with (any, default=0)", _t("The value with which to pad.")), // @compatibility: on Excel, pad with #N/A
11314
11331
  ],
11315
- returns: ["RANGE<ANY>"],
11316
11332
  compute: function (arg, rows, columns, padWith = { value: 0 } // TODO : Replace with #N/A errors once it's supported
11317
11333
  ) {
11318
11334
  const _array = toMatrix(arg);
@@ -11333,7 +11349,6 @@ const FLATTEN = {
11333
11349
  arg("range (any, range<any>)", _t("The first range to flatten.")),
11334
11350
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to flatten.")),
11335
11351
  ],
11336
- returns: ["RANGE<ANY>"],
11337
11352
  compute: function (...ranges) {
11338
11353
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
11339
11354
  },
@@ -11348,7 +11363,6 @@ const FREQUENCY = {
11348
11363
  arg("data (range<number>)", _t("The array of ranges containing the values to be counted.")),
11349
11364
  arg("classes (number, range<number>)", _t("The range containing the set of classes.")),
11350
11365
  ],
11351
- returns: ["RANGE<NUMBER>"],
11352
11366
  compute: function (data, classes) {
11353
11367
  const _data = flattenRowFirst([data], (data) => data.value).filter((val) => typeof val === "number");
11354
11368
  const _classes = flattenRowFirst([classes], (data) => data.value).filter((val) => typeof val === "number");
@@ -11396,7 +11410,6 @@ const HSTACK = {
11396
11410
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11397
11411
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11398
11412
  ],
11399
- returns: ["RANGE<ANY>"],
11400
11413
  compute: function (...ranges) {
11401
11414
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
11402
11415
  const result = [];
@@ -11423,7 +11436,6 @@ const MDETERM = {
11423
11436
  args: [
11424
11437
  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.")),
11425
11438
  ],
11426
- returns: ["NUMBER"],
11427
11439
  compute: function (matrix) {
11428
11440
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11429
11441
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11439,7 +11451,6 @@ const MINVERSE = {
11439
11451
  args: [
11440
11452
  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.")),
11441
11453
  ],
11442
- returns: ["RANGE<NUMBER>"],
11443
11454
  compute: function (matrix) {
11444
11455
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11445
11456
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11460,7 +11471,6 @@ const MMULT = {
11460
11471
  arg("matrix1 (number, range<number>)", _t("The first matrix in the matrix multiplication operation.")),
11461
11472
  arg("matrix2 (number, range<number>)", _t("The second matrix in the matrix multiplication operation.")),
11462
11473
  ],
11463
- returns: ["RANGE<NUMBER>"],
11464
11474
  compute: function (matrix1, matrix2) {
11465
11475
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11466
11476
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
@@ -11479,7 +11489,6 @@ const SUMPRODUCT = {
11479
11489
  arg("range1 (number, range<number>)", _t("The first range whose entries will be multiplied with corresponding entries in the other ranges.")),
11480
11490
  arg("range2 (number, range<number>, repeating)", _t("The other range whose entries will be multiplied with corresponding entries in the other ranges.")),
11481
11491
  ],
11482
- returns: ["NUMBER"],
11483
11492
  compute: function (...args) {
11484
11493
  assertSameDimensions(_t("All the ranges must have the same dimensions."), ...args);
11485
11494
  const _args = args.map(toMatrix);
@@ -11536,7 +11545,6 @@ const SUMX2MY2 = {
11536
11545
  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.")),
11537
11546
  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.")),
11538
11547
  ],
11539
- returns: ["NUMBER"],
11540
11548
  compute: function (arrayX, arrayY) {
11541
11549
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 - y ** 2);
11542
11550
  },
@@ -11551,7 +11559,6 @@ const SUMX2PY2 = {
11551
11559
  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.")),
11552
11560
  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.")),
11553
11561
  ],
11554
- returns: ["NUMBER"],
11555
11562
  compute: function (arrayX, arrayY) {
11556
11563
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 + y ** 2);
11557
11564
  },
@@ -11566,7 +11573,6 @@ const SUMXMY2 = {
11566
11573
  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.")),
11567
11574
  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.")),
11568
11575
  ],
11569
- returns: ["NUMBER"],
11570
11576
  compute: function (arrayX, arrayY) {
11571
11577
  return getSumXAndY(arrayX, arrayY, (x, y) => (x - y) ** 2);
11572
11578
  },
@@ -11602,7 +11608,6 @@ function shouldKeepValue(ignore) {
11602
11608
  const TOCOL = {
11603
11609
  description: _t("Transforms a range of cells into a single column."),
11604
11610
  args: TO_COL_ROW_ARGS,
11605
- returns: ["RANGE<ANY>"],
11606
11611
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11607
11612
  const _array = toMatrix(array);
11608
11613
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11623,7 +11628,6 @@ const TOCOL = {
11623
11628
  const TOROW = {
11624
11629
  description: _t("Transforms a range of cells into a single row."),
11625
11630
  args: TO_COL_ROW_ARGS,
11626
- returns: ["RANGE<ANY>"],
11627
11631
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11628
11632
  const _array = toMatrix(array);
11629
11633
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11645,7 +11649,6 @@ const TOROW = {
11645
11649
  const TRANSPOSE = {
11646
11650
  description: _t("Transposes the rows and columns of a range."),
11647
11651
  args: [arg("range (any, range<any>)", _t("The range to be transposed."))],
11648
- returns: ["RANGE"],
11649
11652
  compute: function (arg) {
11650
11653
  const _array = toMatrix(arg);
11651
11654
  const nbColumns = _array[0].length;
@@ -11663,7 +11666,6 @@ const VSTACK = {
11663
11666
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11664
11667
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11665
11668
  ],
11666
- returns: ["RANGE<ANY>"],
11667
11669
  compute: function (...ranges) {
11668
11670
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
11669
11671
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -11695,7 +11697,6 @@ const WRAPCOLS = {
11695
11697
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11696
11698
  _t("The value with which to fill the extra cells in the range.")),
11697
11699
  ],
11698
- returns: ["RANGE<ANY>"],
11699
11700
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11700
11701
  const _array = toMatrix(range);
11701
11702
  const nbRows = toInteger(wrapCount?.value, this.locale);
@@ -11720,7 +11721,6 @@ const WRAPROWS = {
11720
11721
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11721
11722
  _t("The value with which to fill the extra cells in the range.")),
11722
11723
  ],
11723
- returns: ["RANGE<ANY>"],
11724
11724
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11725
11725
  const _array = toMatrix(range);
11726
11726
  const nbColumns = toInteger(wrapCount?.value, this.locale);
@@ -11768,7 +11768,6 @@ const FORMAT_LARGE_NUMBER = {
11768
11768
  arg("value (number)", _t("The number.")),
11769
11769
  arg("unit (string, optional)", _t("The formatting unit. Use 'k', 'm', or 'b' to force the unit")),
11770
11770
  ],
11771
- returns: ["NUMBER"],
11772
11771
  compute: function (value, unite) {
11773
11772
  return {
11774
11773
  value: toNumber(value, this.locale),
@@ -11800,7 +11799,6 @@ const DECIMAL_REPRESENTATION = /^-?[a-z0-9]+$/i;
11800
11799
  const ABS = {
11801
11800
  description: _t("Absolute value of a number."),
11802
11801
  args: [arg("value (number)", _t("The number of which to return the absolute value."))],
11803
- returns: ["NUMBER"],
11804
11802
  compute: function (value) {
11805
11803
  return Math.abs(toNumber(value, this.locale));
11806
11804
  },
@@ -11814,7 +11812,6 @@ const ACOS = {
11814
11812
  args: [
11815
11813
  arg("value (number)", _t("The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.")),
11816
11814
  ],
11817
- returns: ["NUMBER"],
11818
11815
  compute: function (value) {
11819
11816
  const _value = toNumber(value, this.locale);
11820
11817
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11830,7 +11827,6 @@ const ACOSH = {
11830
11827
  args: [
11831
11828
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1.")),
11832
11829
  ],
11833
- returns: ["NUMBER"],
11834
11830
  compute: function (value) {
11835
11831
  const _value = toNumber(value, this.locale);
11836
11832
  assert(() => _value >= 1, _t("The value (%s) must be greater than or equal to 1.", _value.toString()));
@@ -11844,7 +11840,6 @@ const ACOSH = {
11844
11840
  const ACOT = {
11845
11841
  description: _t("Inverse cotangent of a value."),
11846
11842
  args: [arg("value (number)", _t("The value for which to calculate the inverse cotangent."))],
11847
- returns: ["NUMBER"],
11848
11843
  compute: function (value) {
11849
11844
  const _value = toNumber(value, this.locale);
11850
11845
  const sign = Math.sign(_value) || 1;
@@ -11863,7 +11858,6 @@ const ACOTH = {
11863
11858
  args: [
11864
11859
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cotangent. Must not be between -1 and 1, inclusive.")),
11865
11860
  ],
11866
- returns: ["NUMBER"],
11867
11861
  compute: function (value) {
11868
11862
  const _value = toNumber(value, this.locale);
11869
11863
  assert(() => Math.abs(_value) > 1, _t("The value (%s) cannot be between -1 and 1 inclusive.", _value.toString()));
@@ -11879,7 +11873,6 @@ const ASIN = {
11879
11873
  args: [
11880
11874
  arg("value (number)", _t("The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive.")),
11881
11875
  ],
11882
- returns: ["NUMBER"],
11883
11876
  compute: function (value) {
11884
11877
  const _value = toNumber(value, this.locale);
11885
11878
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11895,7 +11888,6 @@ const ASINH = {
11895
11888
  args: [
11896
11889
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic sine.")),
11897
11890
  ],
11898
- returns: ["NUMBER"],
11899
11891
  compute: function (value) {
11900
11892
  return Math.asinh(toNumber(value, this.locale));
11901
11893
  },
@@ -11907,7 +11899,6 @@ const ASINH = {
11907
11899
  const ATAN = {
11908
11900
  description: _t("Inverse tangent of a value, in radians."),
11909
11901
  args: [arg("value (number)", _t("The value for which to calculate the inverse tangent."))],
11910
- returns: ["NUMBER"],
11911
11902
  compute: function (value) {
11912
11903
  return Math.atan(toNumber(value, this.locale));
11913
11904
  },
@@ -11922,7 +11913,6 @@ const ATAN2 = {
11922
11913
  arg("x (number)", _t("The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11923
11914
  arg("y (number)", _t("The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11924
11915
  ],
11925
- returns: ["NUMBER"],
11926
11916
  compute: function (x, y) {
11927
11917
  const _x = toNumber(x, this.locale);
11928
11918
  const _y = toNumber(y, this.locale);
@@ -11939,7 +11929,6 @@ const ATANH = {
11939
11929
  args: [
11940
11930
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive.")),
11941
11931
  ],
11942
- returns: ["NUMBER"],
11943
11932
  compute: function (value) {
11944
11933
  const _value = toNumber(value, this.locale);
11945
11934
  assert(() => Math.abs(_value) < 1, _t("The value (%s) must be between -1 and 1 exclusive.", _value.toString()));
@@ -11956,7 +11945,6 @@ const CEILING = {
11956
11945
  arg("value (number)", _t("The value to round up to the nearest integer multiple of factor.")),
11957
11946
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
11958
11947
  ],
11959
- returns: ["NUMBER"],
11960
11948
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
11961
11949
  const _value = toNumber(value, this.locale);
11962
11950
  const _factor = toNumber(factor, this.locale);
@@ -11991,7 +11979,6 @@ const CEILING_MATH = {
11991
11979
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
11992
11980
  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.")),
11993
11981
  ],
11994
- returns: ["NUMBER"],
11995
11982
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
11996
11983
  const _significance = toNumber(significance, this.locale);
11997
11984
  const _number = toNumber(number, this.locale);
@@ -12012,7 +11999,6 @@ const CEILING_PRECISE = {
12012
11999
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12013
12000
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12014
12001
  ],
12015
- returns: ["NUMBER"],
12016
12002
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12017
12003
  const _significance = toNumber(significance, this.locale);
12018
12004
  const _number = toNumber(number, this.locale);
@@ -12029,7 +12015,6 @@ const CEILING_PRECISE = {
12029
12015
  const COS = {
12030
12016
  description: _t("Cosine of an angle provided in radians."),
12031
12017
  args: [arg("angle (number)", _t("The angle to find the cosine of, in radians."))],
12032
- returns: ["NUMBER"],
12033
12018
  compute: function (angle) {
12034
12019
  return Math.cos(toNumber(angle, this.locale));
12035
12020
  },
@@ -12041,7 +12026,6 @@ const COS = {
12041
12026
  const COSH = {
12042
12027
  description: _t("Hyperbolic cosine of any real number."),
12043
12028
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosine of."))],
12044
- returns: ["NUMBER"],
12045
12029
  compute: function (value) {
12046
12030
  return Math.cosh(toNumber(value, this.locale));
12047
12031
  },
@@ -12053,7 +12037,6 @@ const COSH = {
12053
12037
  const COT = {
12054
12038
  description: _t("Cotangent of an angle provided in radians."),
12055
12039
  args: [arg("angle (number)", _t("The angle to find the cotangent of, in radians."))],
12056
- returns: ["NUMBER"],
12057
12040
  compute: function (angle) {
12058
12041
  const _angle = toNumber(angle, this.locale);
12059
12042
  assertNotZero(_angle);
@@ -12067,7 +12050,6 @@ const COT = {
12067
12050
  const COTH = {
12068
12051
  description: _t("Hyperbolic cotangent of any real number."),
12069
12052
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cotangent of."))],
12070
- returns: ["NUMBER"],
12071
12053
  compute: function (value) {
12072
12054
  const _value = toNumber(value, this.locale);
12073
12055
  assertNotZero(_value);
@@ -12084,7 +12066,6 @@ const COUNTBLANK = {
12084
12066
  arg("value1 (any, range)", _t("The first value or range in which to count the number of blanks.")),
12085
12067
  arg("value2 (any, range, repeating)", _t("Additional values or ranges in which to count the number of blanks.")),
12086
12068
  ],
12087
- returns: ["NUMBER"],
12088
12069
  compute: function (...args) {
12089
12070
  return reduceAny(args, (acc, a) => {
12090
12071
  if (a === undefined) {
@@ -12110,7 +12091,6 @@ const COUNTIF = {
12110
12091
  arg("range (range)", _t("The range that is tested against criterion.")),
12111
12092
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12112
12093
  ],
12113
- returns: ["NUMBER"],
12114
12094
  compute: function (...args) {
12115
12095
  let count = 0;
12116
12096
  visitMatchingRanges(args, (i, j) => {
@@ -12131,7 +12111,6 @@ const COUNTIFS = {
12131
12111
  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.")),
12132
12112
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12133
12113
  ],
12134
- returns: ["NUMBER"],
12135
12114
  compute: function (...args) {
12136
12115
  let count = 0;
12137
12116
  visitMatchingRanges(args, (i, j) => {
@@ -12150,7 +12129,6 @@ const COUNTUNIQUE = {
12150
12129
  arg("value1 (any, range)", _t("The first value or range to consider for uniqueness.")),
12151
12130
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider for uniqueness.")),
12152
12131
  ],
12153
- returns: ["NUMBER"],
12154
12132
  compute: function (...args) {
12155
12133
  return countUnique(args);
12156
12134
  },
@@ -12167,7 +12145,6 @@ const COUNTUNIQUEIFS = {
12167
12145
  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.")),
12168
12146
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
12169
12147
  ],
12170
- returns: ["NUMBER"],
12171
12148
  compute: function (range, ...args) {
12172
12149
  let uniqueValues = new Set();
12173
12150
  visitMatchingRanges(args, (i, j) => {
@@ -12185,7 +12162,6 @@ const COUNTUNIQUEIFS = {
12185
12162
  const CSC = {
12186
12163
  description: _t("Cosecant of an angle provided in radians."),
12187
12164
  args: [arg("angle (number)", _t("The angle to find the cosecant of, in radians."))],
12188
- returns: ["NUMBER"],
12189
12165
  compute: function (angle) {
12190
12166
  const _angle = toNumber(angle, this.locale);
12191
12167
  assertNotZero(_angle);
@@ -12199,7 +12175,6 @@ const CSC = {
12199
12175
  const CSCH = {
12200
12176
  description: _t("Hyperbolic cosecant of any real number."),
12201
12177
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosecant of."))],
12202
- returns: ["NUMBER"],
12203
12178
  compute: function (value) {
12204
12179
  const _value = toNumber(value, this.locale);
12205
12180
  assertNotZero(_value);
@@ -12216,7 +12191,6 @@ const DECIMAL = {
12216
12191
  arg("value (string)", _t("The number to convert.")),
12217
12192
  arg("base (number)", _t("The base to convert the value from.")),
12218
12193
  ],
12219
- returns: ["NUMBER"],
12220
12194
  compute: function (value, base) {
12221
12195
  let _base = toNumber(base, this.locale);
12222
12196
  _base = Math.floor(_base);
@@ -12243,7 +12217,6 @@ const DECIMAL = {
12243
12217
  const DEGREES = {
12244
12218
  description: _t("Converts an angle value in radians to degrees."),
12245
12219
  args: [arg("angle (number)", _t("The angle to convert from radians to degrees."))],
12246
- returns: ["NUMBER"],
12247
12220
  compute: function (angle) {
12248
12221
  return (toNumber(angle, this.locale) * 180) / Math.PI;
12249
12222
  },
@@ -12255,7 +12228,6 @@ const DEGREES = {
12255
12228
  const EXP = {
12256
12229
  description: _t("Euler's number, e (~2.718) raised to a power."),
12257
12230
  args: [arg("value (number)", _t("The exponent to raise e."))],
12258
- returns: ["NUMBER"],
12259
12231
  compute: function (value) {
12260
12232
  return Math.exp(toNumber(value, this.locale));
12261
12233
  },
@@ -12270,7 +12242,6 @@ const FLOOR = {
12270
12242
  arg("value (number)", _t("The value to round down to the nearest integer multiple of factor.")),
12271
12243
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
12272
12244
  ],
12273
- returns: ["NUMBER"],
12274
12245
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
12275
12246
  const _value = toNumber(value, this.locale);
12276
12247
  const _factor = toNumber(factor, this.locale);
@@ -12305,7 +12276,6 @@ const FLOOR_MATH = {
12305
12276
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
12306
12277
  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.")),
12307
12278
  ],
12308
- returns: ["NUMBER"],
12309
12279
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
12310
12280
  const _significance = toNumber(significance, this.locale);
12311
12281
  const _number = toNumber(number, this.locale);
@@ -12326,7 +12296,6 @@ const FLOOR_PRECISE = {
12326
12296
  arg("number (number)", _t("The value to round down to the nearest integer multiple of significance.")),
12327
12297
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12328
12298
  ],
12329
- returns: ["NUMBER"],
12330
12299
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12331
12300
  const _significance = toNumber(significance, this.locale);
12332
12301
  const _number = toNumber(number, this.locale);
@@ -12343,7 +12312,6 @@ const FLOOR_PRECISE = {
12343
12312
  const ISEVEN = {
12344
12313
  description: _t("Whether the provided value is even."),
12345
12314
  args: [arg("value (number)", _t("The value to be verified as even."))],
12346
- returns: ["BOOLEAN"],
12347
12315
  compute: function (value) {
12348
12316
  const _value = strictToNumber(value, this.locale);
12349
12317
  return Math.floor(Math.abs(_value)) & 1 ? false : true;
@@ -12359,7 +12327,6 @@ const ISO_CEILING = {
12359
12327
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12360
12328
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12361
12329
  ],
12362
- returns: ["NUMBER"],
12363
12330
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12364
12331
  const _number = toNumber(number, this.locale);
12365
12332
  const _significance = toNumber(significance, this.locale);
@@ -12376,7 +12343,6 @@ const ISO_CEILING = {
12376
12343
  const ISODD = {
12377
12344
  description: _t("Whether the provided value is even."),
12378
12345
  args: [arg("value (number)", _t("The value to be verified as even."))],
12379
- returns: ["BOOLEAN"],
12380
12346
  compute: function (value) {
12381
12347
  const _value = strictToNumber(value, this.locale);
12382
12348
  return Math.floor(Math.abs(_value)) & 1 ? true : false;
@@ -12389,7 +12355,6 @@ const ISODD = {
12389
12355
  const LN = {
12390
12356
  description: _t("The logarithm of a number, base e (euler's number)."),
12391
12357
  args: [arg("value (number)", _t("The value for which to calculate the logarithm, base e."))],
12392
- returns: ["NUMBER"],
12393
12358
  compute: function (value) {
12394
12359
  const _value = toNumber(value, this.locale);
12395
12360
  assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
@@ -12415,7 +12380,6 @@ const MOD = {
12415
12380
  arg("dividend (number)", _t("The number to be divided to find the remainder.")),
12416
12381
  arg("divisor (number)", _t("The number to divide by.")),
12417
12382
  ],
12418
- returns: ["NUMBER"],
12419
12383
  compute: function (dividend, divisor) {
12420
12384
  const _divisor = toNumber(divisor, this.locale);
12421
12385
  const _dividend = toNumber(dividend, this.locale);
@@ -12434,7 +12398,6 @@ const MUNIT = {
12434
12398
  args: [
12435
12399
  arg("dimension (number)", _t("An integer specifying the dimension size of the unit matrix. It must be positive.")),
12436
12400
  ],
12437
- returns: ["RANGE<NUMBER>"],
12438
12401
  compute: function (n) {
12439
12402
  const _n = toInteger(n, this.locale);
12440
12403
  assertPositive(_t("The argument dimension must be positive"), _n);
@@ -12448,7 +12411,6 @@ const MUNIT = {
12448
12411
  const ODD = {
12449
12412
  description: _t("Rounds a number up to the nearest odd integer."),
12450
12413
  args: [arg("value (number)", _t("The value to round to the next greatest odd number."))],
12451
- returns: ["NUMBER"],
12452
12414
  compute: function (value) {
12453
12415
  const _value = toNumber(value, this.locale);
12454
12416
  let temp = Math.ceil(Math.abs(_value));
@@ -12466,7 +12428,6 @@ const ODD = {
12466
12428
  const PI = {
12467
12429
  description: _t("The number pi."),
12468
12430
  args: [],
12469
- returns: ["NUMBER"],
12470
12431
  compute: function () {
12471
12432
  return Math.PI;
12472
12433
  },
@@ -12481,7 +12442,6 @@ const POWER = {
12481
12442
  arg("base (number)", _t("The number to raise to the exponent power.")),
12482
12443
  arg("exponent (number)", _t("The exponent to raise base to.")),
12483
12444
  ],
12484
- returns: ["NUMBER"],
12485
12445
  compute: function (base, exponent) {
12486
12446
  const _base = toNumber(base, this.locale);
12487
12447
  const _exponent = toNumber(exponent, this.locale);
@@ -12499,7 +12459,6 @@ const PRODUCT = {
12499
12459
  arg("factor1 (number, range<number>)", _t("The first number or range to calculate for the product.")),
12500
12460
  arg("factor2 (number, range<number>, repeating)", _t("More numbers or ranges to calculate for the product.")),
12501
12461
  ],
12502
- returns: ["NUMBER"],
12503
12462
  compute: function (...factors) {
12504
12463
  let count = 0;
12505
12464
  let acc = 1;
@@ -12536,7 +12495,6 @@ const PRODUCT = {
12536
12495
  const RAND = {
12537
12496
  description: _t("A random number between 0 inclusive and 1 exclusive."),
12538
12497
  args: [],
12539
- returns: ["NUMBER"],
12540
12498
  compute: function () {
12541
12499
  return Math.random();
12542
12500
  },
@@ -12554,7 +12512,6 @@ const RANDARRAY = {
12554
12512
  arg("max (number, default=1)", _t("The maximum number you would like returned.")),
12555
12513
  arg("whole_number (number, default=FALSE)", _t("Return a whole number or a decimal value.")),
12556
12514
  ],
12557
- returns: ["RANGE<NUMBER>"],
12558
12515
  compute: function (rows = { value: 1 }, columns = { value: 1 }, min = { value: 0 }, max = { value: 1 }, wholeNumber = { value: false }) {
12559
12516
  const _cols = toInteger(columns, this.locale);
12560
12517
  const _rows = toInteger(rows, this.locale);
@@ -12592,7 +12549,6 @@ const RANDBETWEEN = {
12592
12549
  arg("low (number)", _t("The low end of the random range.")),
12593
12550
  arg("high (number)", _t("The high end of the random range.")),
12594
12551
  ],
12595
- returns: ["NUMBER"],
12596
12552
  compute: function (low, high) {
12597
12553
  let _low = toNumber(low, this.locale);
12598
12554
  if (!Number.isInteger(_low)) {
@@ -12619,7 +12575,6 @@ const ROUND = {
12619
12575
  arg("value (number)", _t("The value to round to places number of places.")),
12620
12576
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12621
12577
  ],
12622
- returns: ["NUMBER"],
12623
12578
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12624
12579
  const _value = toNumber(value, this.locale);
12625
12580
  let _places = toNumber(places, this.locale);
@@ -12650,7 +12605,6 @@ const ROUNDDOWN = {
12650
12605
  arg("value (number)", _t("The value to round to places number of places, always rounding down.")),
12651
12606
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12652
12607
  ],
12653
- returns: ["NUMBER"],
12654
12608
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12655
12609
  const _value = toNumber(value, this.locale);
12656
12610
  let _places = toNumber(places, this.locale);
@@ -12681,7 +12635,6 @@ const ROUNDUP = {
12681
12635
  arg("value (number)", _t("The value to round to places number of places, always rounding up.")),
12682
12636
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12683
12637
  ],
12684
- returns: ["NUMBER"],
12685
12638
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12686
12639
  const _value = toNumber(value, this.locale);
12687
12640
  let _places = toNumber(places, this.locale);
@@ -12709,7 +12662,6 @@ const ROUNDUP = {
12709
12662
  const SEC = {
12710
12663
  description: _t("Secant of an angle provided in radians."),
12711
12664
  args: [arg("angle (number)", _t("The angle to find the secant of, in radians."))],
12712
- returns: ["NUMBER"],
12713
12665
  compute: function (angle) {
12714
12666
  return 1 / Math.cos(toNumber(angle, this.locale));
12715
12667
  },
@@ -12721,7 +12673,6 @@ const SEC = {
12721
12673
  const SECH = {
12722
12674
  description: _t("Hyperbolic secant of any real number."),
12723
12675
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic secant of."))],
12724
- returns: ["NUMBER"],
12725
12676
  compute: function (value) {
12726
12677
  return 1 / Math.cosh(toNumber(value, this.locale));
12727
12678
  },
@@ -12733,7 +12684,6 @@ const SECH = {
12733
12684
  const SIN = {
12734
12685
  description: _t("Sine of an angle provided in radians."),
12735
12686
  args: [arg("angle (number)", _t("The angle to find the sine of, in radians."))],
12736
- returns: ["NUMBER"],
12737
12687
  compute: function (angle) {
12738
12688
  return Math.sin(toNumber(angle, this.locale));
12739
12689
  },
@@ -12745,7 +12695,6 @@ const SIN = {
12745
12695
  const SINH = {
12746
12696
  description: _t("Hyperbolic sine of any real number."),
12747
12697
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic sine of."))],
12748
- returns: ["NUMBER"],
12749
12698
  compute: function (value) {
12750
12699
  return Math.sinh(toNumber(value, this.locale));
12751
12700
  },
@@ -12757,7 +12706,6 @@ const SINH = {
12757
12706
  const SQRT = {
12758
12707
  description: _t("Positive square root of a positive number."),
12759
12708
  args: [arg("value (number)", _t("The number for which to calculate the positive square root."))],
12760
- returns: ["NUMBER"],
12761
12709
  compute: function (value) {
12762
12710
  const _value = toNumber(value, this.locale);
12763
12711
  assert(() => _value >= 0, _t("The value (%s) must be positive or null.", _value.toString()));
@@ -12774,7 +12722,6 @@ const SUM = {
12774
12722
  arg("value1 (number, range<number>)", _t("The first number or range to add together.")),
12775
12723
  arg("value2 (number, range<number>, repeating)", _t("Additional numbers or ranges to add to value1.")),
12776
12724
  ],
12777
- returns: ["NUMBER"],
12778
12725
  compute: function (...values) {
12779
12726
  const v1 = values[0];
12780
12727
  return {
@@ -12794,7 +12741,6 @@ const SUMIF = {
12794
12741
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12795
12742
  arg("sum_range (range, default=criteria_range)", _t("The range to be summed, if different from range.")),
12796
12743
  ],
12797
- returns: ["NUMBER"],
12798
12744
  compute: function (criteriaRange, criterion, sumRange) {
12799
12745
  if (sumRange === undefined) {
12800
12746
  sumRange = criteriaRange;
@@ -12822,7 +12768,6 @@ const SUMIFS = {
12822
12768
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges to check.")),
12823
12769
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12824
12770
  ],
12825
- returns: ["NUMBER"],
12826
12771
  compute: function (sumRange, ...criters) {
12827
12772
  let sum = 0;
12828
12773
  visitMatchingRanges(criters, (i, j) => {
@@ -12841,7 +12786,6 @@ const SUMIFS = {
12841
12786
  const TAN = {
12842
12787
  description: _t("Tangent of an angle provided in radians."),
12843
12788
  args: [arg("angle (number)", _t("The angle to find the tangent of, in radians."))],
12844
- returns: ["NUMBER"],
12845
12789
  compute: function (angle) {
12846
12790
  return Math.tan(toNumber(angle, this.locale));
12847
12791
  },
@@ -12853,7 +12797,6 @@ const TAN = {
12853
12797
  const TANH = {
12854
12798
  description: _t("Hyperbolic tangent of any real number."),
12855
12799
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic tangent of."))],
12856
- returns: ["NUMBER"],
12857
12800
  compute: function (value) {
12858
12801
  return Math.tanh(toNumber(value, this.locale));
12859
12802
  },
@@ -12877,7 +12820,6 @@ const TRUNC = {
12877
12820
  arg("value (number)", _t("The value to be truncated.")),
12878
12821
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of significant digits to the right of the decimal point to retain.")),
12879
12822
  ],
12880
- returns: ["NUMBER"],
12881
12823
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12882
12824
  const _value = toNumber(value, this.locale);
12883
12825
  const _places = toNumber(places, this.locale);
@@ -12891,7 +12833,6 @@ const TRUNC = {
12891
12833
  const INT = {
12892
12834
  description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
12893
12835
  args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
12894
- returns: ["NUMBER"],
12895
12836
  compute: function (value) {
12896
12837
  return Math.floor(toNumber(value, this.locale));
12897
12838
  },
@@ -13250,7 +13191,6 @@ const AVEDEV = {
13250
13191
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
13251
13192
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
13252
13193
  ],
13253
- returns: ["NUMBER"],
13254
13194
  compute: function (...values) {
13255
13195
  let count = 0;
13256
13196
  const sum = reduceNumbers(values, (acc, a) => {
@@ -13272,7 +13212,6 @@ const AVERAGE = {
13272
13212
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13273
13213
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13274
13214
  ],
13275
- returns: ["NUMBER"],
13276
13215
  compute: function (...values) {
13277
13216
  return {
13278
13217
  value: average(values, this.locale),
@@ -13294,7 +13233,6 @@ const AVERAGE_WEIGHTED = {
13294
13233
  arg("additional_values (number, range<number>, repeating)", _t("Additional values to average.")),
13295
13234
  arg("additional_weights (number, range<number>, repeating)", _t("Additional weights.")),
13296
13235
  ],
13297
- returns: ["NUMBER"],
13298
13236
  compute: function (...args) {
13299
13237
  let sum = 0;
13300
13238
  let count = 0;
@@ -13342,7 +13280,6 @@ const AVERAGEA = {
13342
13280
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13343
13281
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13344
13282
  ],
13345
- returns: ["NUMBER"],
13346
13283
  compute: function (...args) {
13347
13284
  let count = 0;
13348
13285
  const sum = reduceNumbersTextAs0(args, (acc, a) => {
@@ -13367,7 +13304,6 @@ const AVERAGEIF = {
13367
13304
  arg("criterion (string)", _t("The pattern or test to apply to criteria_range.")),
13368
13305
  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.")),
13369
13306
  ],
13370
- returns: ["NUMBER"],
13371
13307
  compute: function (criteriaRange, criterion, averageRange) {
13372
13308
  const _averageRange = averageRange === undefined ? toMatrix(criteriaRange) : toMatrix(averageRange);
13373
13309
  let count = 0;
@@ -13396,7 +13332,6 @@ const AVERAGEIFS = {
13396
13332
  arg("criteria_range2 (any, range, repeating)", _t("Additional criteria_range and criterion to check.")),
13397
13333
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13398
13334
  ],
13399
- returns: ["NUMBER"],
13400
13335
  compute: function (averageRange, ...args) {
13401
13336
  const _averageRange = toMatrix(averageRange);
13402
13337
  let count = 0;
@@ -13422,7 +13357,6 @@ const COUNT = {
13422
13357
  arg("value1 (number, range<number>)", _t("The first value or range to consider when counting.")),
13423
13358
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when counting.")),
13424
13359
  ],
13425
- returns: ["NUMBER"],
13426
13360
  compute: function (...values) {
13427
13361
  return countNumbers(values, this.locale);
13428
13362
  },
@@ -13437,7 +13371,6 @@ const COUNTA = {
13437
13371
  arg("value1 (any, range)", _t("The first value or range to consider when counting.")),
13438
13372
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when counting.")),
13439
13373
  ],
13440
- returns: ["NUMBER"],
13441
13374
  compute: function (...values) {
13442
13375
  return countAny(values);
13443
13376
  },
@@ -13454,7 +13387,6 @@ const COVAR = {
13454
13387
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13455
13388
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13456
13389
  ],
13457
- returns: ["NUMBER"],
13458
13390
  compute: function (dataY, dataX) {
13459
13391
  return covariance(dataY, dataX, false);
13460
13392
  },
@@ -13469,7 +13401,6 @@ const COVARIANCE_P = {
13469
13401
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13470
13402
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13471
13403
  ],
13472
- returns: ["NUMBER"],
13473
13404
  compute: function (dataY, dataX) {
13474
13405
  return covariance(dataY, dataX, false);
13475
13406
  },
@@ -13484,7 +13415,6 @@ const COVARIANCE_S = {
13484
13415
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13485
13416
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13486
13417
  ],
13487
- returns: ["NUMBER"],
13488
13418
  compute: function (dataY, dataX) {
13489
13419
  return covariance(dataY, dataX, true);
13490
13420
  },
@@ -13500,7 +13430,6 @@ const FORECAST = {
13500
13430
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13501
13431
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13502
13432
  ],
13503
- returns: ["NUMBER"],
13504
13433
  compute: function (x, dataY, dataX) {
13505
13434
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13506
13435
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
@@ -13518,7 +13447,6 @@ const GROWTH = {
13518
13447
  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.")),
13519
13448
  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.")),
13520
13449
  ],
13521
- returns: ["NUMBER"],
13522
13450
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13523
13451
  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)));
13524
13452
  },
@@ -13532,7 +13460,6 @@ const INTERCEPT = {
13532
13460
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13533
13461
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13534
13462
  ],
13535
- returns: ["NUMBER"],
13536
13463
  compute: function (dataY, dataX) {
13537
13464
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13538
13465
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -13549,7 +13476,6 @@ const LARGE = {
13549
13476
  arg("data (any, range)", _t("Array or range containing the dataset to consider.")),
13550
13477
  arg("n (number)", _t("The rank from largest to smallest of the element to return.")),
13551
13478
  ],
13552
- returns: ["NUMBER"],
13553
13479
  compute: function (data, n) {
13554
13480
  const _n = Math.trunc(toNumber(n?.value, this.locale));
13555
13481
  let largests = [];
@@ -13584,7 +13510,6 @@ const LINEST = {
13584
13510
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13585
13511
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13586
13512
  ],
13587
- returns: ["NUMBER"],
13588
13513
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13589
13514
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13590
13515
  },
@@ -13601,7 +13526,6 @@ const LOGEST = {
13601
13526
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13602
13527
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13603
13528
  ],
13604
- returns: ["NUMBER"],
13605
13529
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13606
13530
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13607
13531
  for (let i = 0; i < coeffs.length; i++) {
@@ -13620,7 +13544,6 @@ const MATTHEWS = {
13620
13544
  arg("data_x (range)", _t("The range representing the array or matrix of observed data.")),
13621
13545
  arg("data_y (range)", _t("The range representing the array or matrix of predicted data.")),
13622
13546
  ],
13623
- returns: ["NUMBER"],
13624
13547
  compute: function (dataX, dataY) {
13625
13548
  const flatX = dataX.flat();
13626
13549
  const flatY = dataY.flat();
@@ -13664,7 +13587,6 @@ const MAX = {
13664
13587
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the maximum value.")),
13665
13588
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13666
13589
  ],
13667
- returns: ["NUMBER"],
13668
13590
  compute: function (...values) {
13669
13591
  return {
13670
13592
  value: max(values, this.locale),
@@ -13682,7 +13604,6 @@ const MAXA = {
13682
13604
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the maximum value.")),
13683
13605
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13684
13606
  ],
13685
- returns: ["NUMBER"],
13686
13607
  compute: function (...args) {
13687
13608
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
13688
13609
  return Math.max(a, acc);
@@ -13703,7 +13624,6 @@ const MAXIFS = {
13703
13624
  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.")),
13704
13625
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13705
13626
  ],
13706
- returns: ["NUMBER"],
13707
13627
  compute: function (range, ...args) {
13708
13628
  let result = -Infinity;
13709
13629
  visitMatchingRanges(args, (i, j) => {
@@ -13725,7 +13645,6 @@ const MEDIAN = {
13725
13645
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the median value.")),
13726
13646
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the median value.")),
13727
13647
  ],
13728
- returns: ["NUMBER"],
13729
13648
  compute: function (...values) {
13730
13649
  let data = [];
13731
13650
  visitNumbers(values, (value) => {
@@ -13747,7 +13666,6 @@ const MIN = {
13747
13666
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13748
13667
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13749
13668
  ],
13750
- returns: ["NUMBER"],
13751
13669
  compute: function (...values) {
13752
13670
  return {
13753
13671
  value: min(values, this.locale),
@@ -13765,7 +13683,6 @@ const MINA = {
13765
13683
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13766
13684
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13767
13685
  ],
13768
- returns: ["NUMBER"],
13769
13686
  compute: function (...args) {
13770
13687
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
13771
13688
  return Math.min(a, acc);
@@ -13786,7 +13703,6 @@ const MINIFS = {
13786
13703
  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.")),
13787
13704
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13788
13705
  ],
13789
- returns: ["NUMBER"],
13790
13706
  compute: function (range, ...args) {
13791
13707
  let result = Infinity;
13792
13708
  visitMatchingRanges(args, (i, j) => {
@@ -13829,7 +13745,6 @@ const PEARSON = {
13829
13745
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13830
13746
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13831
13747
  ],
13832
- returns: ["NUMBER"],
13833
13748
  compute: function (dataY, dataX) {
13834
13749
  return pearson(dataY, dataX);
13835
13750
  },
@@ -13846,7 +13761,6 @@ const PERCENTILE = {
13846
13761
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13847
13762
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13848
13763
  ],
13849
- returns: ["NUMBER"],
13850
13764
  compute: function (data, percentile) {
13851
13765
  return PERCENTILE_INC.compute.bind(this)(data, percentile);
13852
13766
  },
@@ -13861,7 +13775,6 @@ const PERCENTILE_EXC = {
13861
13775
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13862
13776
  arg("percentile (number)", _t("The percentile, exclusive of 0 and 1, whose value within 'data' will be calculated and returned.")),
13863
13777
  ],
13864
- returns: ["NUMBER"],
13865
13778
  compute: function (data, percentile) {
13866
13779
  return {
13867
13780
  value: centile([data], percentile, false, this.locale),
@@ -13879,7 +13792,6 @@ const PERCENTILE_INC = {
13879
13792
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13880
13793
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13881
13794
  ],
13882
- returns: ["NUMBER"],
13883
13795
  compute: function (data, percentile) {
13884
13796
  return {
13885
13797
  value: centile([data], percentile, true, this.locale),
@@ -13899,7 +13811,6 @@ const POLYFIT_COEFFS = {
13899
13811
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13900
13812
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13901
13813
  ],
13902
- returns: ["RANGE<NUMBER>"],
13903
13814
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13904
13815
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13905
13816
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
@@ -13918,7 +13829,6 @@ const POLYFIT_FORECAST = {
13918
13829
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13919
13830
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13920
13831
  ],
13921
- returns: ["NUMBER"],
13922
13832
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13923
13833
  const _order = toNumber(order, this.locale);
13924
13834
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
@@ -13936,7 +13846,6 @@ const QUARTILE = {
13936
13846
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13937
13847
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13938
13848
  ],
13939
- returns: ["NUMBER"],
13940
13849
  compute: function (data, quartileNumber) {
13941
13850
  return QUARTILE_INC.compute.bind(this)(data, quartileNumber);
13942
13851
  },
@@ -13951,7 +13860,6 @@ const QUARTILE_EXC = {
13951
13860
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13952
13861
  arg("quartile_number (number)", _t("Which quartile value, exclusive of 0 and 4, to return.")),
13953
13862
  ],
13954
- returns: ["NUMBER"],
13955
13863
  compute: function (data, quartileNumber) {
13956
13864
  const _quartileNumber = Math.trunc(toNumber(quartileNumber, this.locale));
13957
13865
  const percent = { value: 0.25 * _quartileNumber };
@@ -13971,7 +13879,6 @@ const QUARTILE_INC = {
13971
13879
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13972
13880
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13973
13881
  ],
13974
- returns: ["NUMBER"],
13975
13882
  compute: function (data, quartileNumber) {
13976
13883
  const percent = { value: 0.25 * Math.trunc(toNumber(quartileNumber, this.locale)) };
13977
13884
  return {
@@ -13990,7 +13897,6 @@ const RANK = {
13990
13897
  arg("data (range)", _t("The range containing the dataset to consider.")),
13991
13898
  arg("is_ascending (boolean, default=FALSE)", _t("Whether to consider the values in data in descending or ascending order.")),
13992
13899
  ],
13993
- returns: ["ANY"],
13994
13900
  compute: function (value, data, isAscending = { value: false }) {
13995
13901
  const _isAscending = toBoolean(isAscending);
13996
13902
  const _value = toNumber(value, this.locale);
@@ -14026,7 +13932,6 @@ const RSQ = {
14026
13932
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14027
13933
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14028
13934
  ],
14029
- returns: ["NUMBER"],
14030
13935
  compute: function (dataY, dataX) {
14031
13936
  return Math.pow(pearson(dataX, dataY), 2.0);
14032
13937
  },
@@ -14041,7 +13946,6 @@ const SLOPE = {
14041
13946
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14042
13947
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14043
13948
  ],
14044
- returns: ["NUMBER"],
14045
13949
  compute: function (dataY, dataX) {
14046
13950
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14047
13951
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -14058,7 +13962,6 @@ const SMALL = {
14058
13962
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
14059
13963
  arg("n (number)", _t("The rank from smallest to largest of the element to return.")),
14060
13964
  ],
14061
- returns: ["NUMBER"],
14062
13965
  compute: function (data, n) {
14063
13966
  const _n = Math.trunc(toNumber(n?.value, this.locale));
14064
13967
  let largests = [];
@@ -14091,7 +13994,6 @@ const SPEARMAN = {
14091
13994
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14092
13995
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14093
13996
  ],
14094
- returns: ["NUMBER"],
14095
13997
  compute: function (dataX, dataY) {
14096
13998
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14097
13999
  const n = flatDataX.length;
@@ -14118,7 +14020,6 @@ const STDEV = {
14118
14020
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14119
14021
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14120
14022
  ],
14121
- returns: ["NUMBER"],
14122
14023
  compute: function (...args) {
14123
14024
  return Math.sqrt(VAR.compute.bind(this)(...args));
14124
14025
  },
@@ -14133,7 +14034,6 @@ const STDEV_P = {
14133
14034
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14134
14035
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14135
14036
  ],
14136
- returns: ["NUMBER"],
14137
14037
  compute: function (...args) {
14138
14038
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
14139
14039
  },
@@ -14148,7 +14048,6 @@ const STDEV_S = {
14148
14048
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14149
14049
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14150
14050
  ],
14151
- returns: ["NUMBER"],
14152
14051
  compute: function (...args) {
14153
14052
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
14154
14053
  },
@@ -14163,7 +14062,6 @@ const STDEVA = {
14163
14062
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14164
14063
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14165
14064
  ],
14166
- returns: ["NUMBER"],
14167
14065
  compute: function (...args) {
14168
14066
  return Math.sqrt(VARA.compute.bind(this)(...args));
14169
14067
  },
@@ -14178,7 +14076,6 @@ const STDEVP = {
14178
14076
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14179
14077
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14180
14078
  ],
14181
- returns: ["NUMBER"],
14182
14079
  compute: function (...args) {
14183
14080
  return Math.sqrt(VARP.compute.bind(this)(...args));
14184
14081
  },
@@ -14193,7 +14090,6 @@ const STDEVPA = {
14193
14090
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14194
14091
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14195
14092
  ],
14196
- returns: ["NUMBER"],
14197
14093
  compute: function (...args) {
14198
14094
  return Math.sqrt(VARPA.compute.bind(this)(...args));
14199
14095
  },
@@ -14208,7 +14104,6 @@ const STEYX = {
14208
14104
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14209
14105
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14210
14106
  ],
14211
- returns: ["NUMBER"],
14212
14107
  compute: function (dataY, dataX) {
14213
14108
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14214
14109
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
@@ -14227,7 +14122,6 @@ const TREND = {
14227
14122
  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.")),
14228
14123
  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.")),
14229
14124
  ],
14230
- returns: ["NUMBER"],
14231
14125
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
14232
14126
  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));
14233
14127
  },
@@ -14241,7 +14135,6 @@ const VAR = {
14241
14135
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14242
14136
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14243
14137
  ],
14244
- returns: ["NUMBER"],
14245
14138
  compute: function (...args) {
14246
14139
  return variance(args, true, false, this.locale);
14247
14140
  },
@@ -14256,7 +14149,6 @@ const VAR_P = {
14256
14149
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14257
14150
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14258
14151
  ],
14259
- returns: ["NUMBER"],
14260
14152
  compute: function (...args) {
14261
14153
  return variance(args, false, false, this.locale);
14262
14154
  },
@@ -14271,7 +14163,6 @@ const VAR_S = {
14271
14163
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14272
14164
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14273
14165
  ],
14274
- returns: ["NUMBER"],
14275
14166
  compute: function (...args) {
14276
14167
  return variance(args, true, false, this.locale);
14277
14168
  },
@@ -14286,7 +14177,6 @@ const VARA = {
14286
14177
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14287
14178
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14288
14179
  ],
14289
- returns: ["NUMBER"],
14290
14180
  compute: function (...args) {
14291
14181
  return variance(args, true, true, this.locale);
14292
14182
  },
@@ -14301,7 +14191,6 @@ const VARP = {
14301
14191
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14302
14192
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14303
14193
  ],
14304
- returns: ["NUMBER"],
14305
14194
  compute: function (...args) {
14306
14195
  return variance(args, false, false, this.locale);
14307
14196
  },
@@ -14316,7 +14205,6 @@ const VARPA = {
14316
14205
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14317
14206
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14318
14207
  ],
14319
- returns: ["NUMBER"],
14320
14208
  compute: function (...args) {
14321
14209
  return variance(args, false, true, this.locale);
14322
14210
  },
@@ -14482,7 +14370,6 @@ const databaseArgs = [
14482
14370
  const DAVERAGE = {
14483
14371
  description: _t("Average of a set of values from a table-like range."),
14484
14372
  args: databaseArgs,
14485
- returns: ["NUMBER"],
14486
14373
  compute: function (database, field, criteria) {
14487
14374
  const cells = getMatchingCells(database, field, criteria, this.locale);
14488
14375
  return AVERAGE.compute.bind(this)([cells]);
@@ -14495,7 +14382,6 @@ const DAVERAGE = {
14495
14382
  const DCOUNT = {
14496
14383
  description: _t("Counts values from a table-like range."),
14497
14384
  args: databaseArgs,
14498
- returns: ["NUMBER"],
14499
14385
  compute: function (database, field, criteria) {
14500
14386
  const cells = getMatchingCells(database, field, criteria, this.locale);
14501
14387
  return COUNT.compute.bind(this)([cells]);
@@ -14508,7 +14394,6 @@ const DCOUNT = {
14508
14394
  const DCOUNTA = {
14509
14395
  description: _t("Counts values and text from a table-like range."),
14510
14396
  args: databaseArgs,
14511
- returns: ["NUMBER"],
14512
14397
  compute: function (database, field, criteria) {
14513
14398
  const cells = getMatchingCells(database, field, criteria, this.locale);
14514
14399
  return COUNTA.compute.bind(this)([cells]);
@@ -14521,7 +14406,6 @@ const DCOUNTA = {
14521
14406
  const DGET = {
14522
14407
  description: _t("Single value from a table-like range."),
14523
14408
  args: databaseArgs,
14524
- returns: ["NUMBER"],
14525
14409
  compute: function (database, field, criteria) {
14526
14410
  const cells = getMatchingCells(database, field, criteria, this.locale);
14527
14411
  assert(() => cells.length === 1, _t("More than one match found in DGET evaluation."));
@@ -14535,7 +14419,6 @@ const DGET = {
14535
14419
  const DMAX = {
14536
14420
  description: _t("Maximum of values from a table-like range."),
14537
14421
  args: databaseArgs,
14538
- returns: ["NUMBER"],
14539
14422
  compute: function (database, field, criteria) {
14540
14423
  const cells = getMatchingCells(database, field, criteria, this.locale);
14541
14424
  return MAX.compute.bind(this)([cells]);
@@ -14548,7 +14431,6 @@ const DMAX = {
14548
14431
  const DMIN = {
14549
14432
  description: _t("Minimum of values from a table-like range."),
14550
14433
  args: databaseArgs,
14551
- returns: ["NUMBER"],
14552
14434
  compute: function (database, field, criteria) {
14553
14435
  const cells = getMatchingCells(database, field, criteria, this.locale);
14554
14436
  return MIN.compute.bind(this)([cells]);
@@ -14561,7 +14443,6 @@ const DMIN = {
14561
14443
  const DPRODUCT = {
14562
14444
  description: _t("Product of values from a table-like range."),
14563
14445
  args: databaseArgs,
14564
- returns: ["NUMBER"],
14565
14446
  compute: function (database, field, criteria) {
14566
14447
  const cells = getMatchingCells(database, field, criteria, this.locale);
14567
14448
  return PRODUCT.compute.bind(this)([cells]);
@@ -14574,7 +14455,6 @@ const DPRODUCT = {
14574
14455
  const DSTDEV = {
14575
14456
  description: _t("Standard deviation of population sample from table."),
14576
14457
  args: databaseArgs,
14577
- returns: ["NUMBER"],
14578
14458
  compute: function (database, field, criteria) {
14579
14459
  const cells = getMatchingCells(database, field, criteria, this.locale);
14580
14460
  return STDEV.compute.bind(this)([cells]);
@@ -14587,7 +14467,6 @@ const DSTDEV = {
14587
14467
  const DSTDEVP = {
14588
14468
  description: _t("Standard deviation of entire population from table."),
14589
14469
  args: databaseArgs,
14590
- returns: ["NUMBER"],
14591
14470
  compute: function (database, field, criteria) {
14592
14471
  const cells = getMatchingCells(database, field, criteria, this.locale);
14593
14472
  return STDEVP.compute.bind(this)([cells]);
@@ -14600,7 +14479,6 @@ const DSTDEVP = {
14600
14479
  const DSUM = {
14601
14480
  description: _t("Sum of values from a table-like range."),
14602
14481
  args: databaseArgs,
14603
- returns: ["NUMBER"],
14604
14482
  compute: function (database, field, criteria) {
14605
14483
  const cells = getMatchingCells(database, field, criteria, this.locale);
14606
14484
  return SUM.compute.bind(this)([cells]);
@@ -14613,7 +14491,6 @@ const DSUM = {
14613
14491
  const DVAR = {
14614
14492
  description: _t("Variance of population sample from table-like range."),
14615
14493
  args: databaseArgs,
14616
- returns: ["NUMBER"],
14617
14494
  compute: function (database, field, criteria) {
14618
14495
  const cells = getMatchingCells(database, field, criteria, this.locale);
14619
14496
  return VAR.compute.bind(this)([cells]);
@@ -14626,7 +14503,6 @@ const DVAR = {
14626
14503
  const DVARP = {
14627
14504
  description: _t("Variance of a population from a table-like range."),
14628
14505
  args: databaseArgs,
14629
- returns: ["NUMBER"],
14630
14506
  compute: function (database, field, criteria) {
14631
14507
  const cells = getMatchingCells(database, field, criteria, this.locale);
14632
14508
  return VARP.compute.bind(this)([cells]);
@@ -14671,7 +14547,6 @@ const DATE = {
14671
14547
  arg("month (number)", _t("The month component of the date.")),
14672
14548
  arg("day (number)", _t("The day component of the date.")),
14673
14549
  ],
14674
- returns: ["DATE"],
14675
14550
  compute: function (year, month, day) {
14676
14551
  let _year = Math.trunc(toNumber(year, this.locale));
14677
14552
  const _month = Math.trunc(toNumber(month, this.locale));
@@ -14702,7 +14577,6 @@ const DATEDIF = {
14702
14577
  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.")),
14703
14578
  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).')),
14704
14579
  ],
14705
- returns: ["NUMBER"],
14706
14580
  compute: function (startDate, endDate, unit) {
14707
14581
  const _unit = toString(unit).toUpperCase();
14708
14582
  assert(() => Object.values(TIME_UNIT).includes(_unit), expectStringSetError(Object.values(TIME_UNIT), toString(unit)));
@@ -14755,7 +14629,6 @@ const DATEDIF = {
14755
14629
  const DATEVALUE = {
14756
14630
  description: _t("Converts a date string to a date value."),
14757
14631
  args: [arg("date_string (string)", _t("The string representing the date."))],
14758
- returns: ["NUMBER"],
14759
14632
  compute: function (dateString) {
14760
14633
  const _dateString = toString(dateString);
14761
14634
  const internalDate = parseDateTime(_dateString, this.locale);
@@ -14770,7 +14643,6 @@ const DATEVALUE = {
14770
14643
  const DAY = {
14771
14644
  description: _t("Day of the month that a specific date falls on."),
14772
14645
  args: [arg("date (string)", _t("The date from which to extract the day."))],
14773
- returns: ["NUMBER"],
14774
14646
  compute: function (date) {
14775
14647
  return toJsDate(date, this.locale).getDate();
14776
14648
  },
@@ -14785,7 +14657,6 @@ const DAYS = {
14785
14657
  arg("end_date (date)", _t("The end of the date range.")),
14786
14658
  arg("start_date (date)", _t("The start of the date range.")),
14787
14659
  ],
14788
- returns: ["NUMBER"],
14789
14660
  compute: function (endDate, startDate) {
14790
14661
  const _endDate = toJsDate(endDate, this.locale);
14791
14662
  const _startDate = toJsDate(startDate, this.locale);
@@ -14805,7 +14676,6 @@ const DAYS360 = {
14805
14676
  arg("end_date (date)", _t("The end date to consider in the calculation.")),
14806
14677
  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")),
14807
14678
  ],
14808
- returns: ["NUMBER"],
14809
14679
  compute: function (startDate, endDate, method = { value: DEFAULT_DAY_COUNT_METHOD }) {
14810
14680
  const _startDate = Math.trunc(toNumber(startDate, this.locale));
14811
14681
  const _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -14824,7 +14694,6 @@ const EDATE = {
14824
14694
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14825
14695
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to calculate.")),
14826
14696
  ],
14827
- returns: ["DATE"],
14828
14697
  compute: function (startDate, months) {
14829
14698
  const _startDate = toJsDate(startDate, this.locale);
14830
14699
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14845,7 +14714,6 @@ const EOMONTH = {
14845
14714
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14846
14715
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to consider.")),
14847
14716
  ],
14848
- returns: ["DATE"],
14849
14717
  compute: function (startDate, months) {
14850
14718
  const _startDate = toJsDate(startDate, this.locale);
14851
14719
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14865,7 +14733,6 @@ const EOMONTH = {
14865
14733
  const HOUR = {
14866
14734
  description: _t("Hour component of a specific time."),
14867
14735
  args: [arg("time (date)", _t("The time from which to calculate the hour component."))],
14868
- returns: ["NUMBER"],
14869
14736
  compute: function (date) {
14870
14737
  return toJsDate(date, this.locale).getHours();
14871
14738
  },
@@ -14879,7 +14746,6 @@ const ISOWEEKNUM = {
14879
14746
  args: [
14880
14747
  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.")),
14881
14748
  ],
14882
- returns: ["NUMBER"],
14883
14749
  compute: function (date) {
14884
14750
  const _date = toJsDate(date, this.locale);
14885
14751
  const y = _date.getFullYear();
@@ -14951,7 +14817,6 @@ const ISOWEEKNUM = {
14951
14817
  const MINUTE = {
14952
14818
  description: _t("Minute component of a specific time."),
14953
14819
  args: [arg("time (date)", _t("The time from which to calculate the minute component."))],
14954
- returns: ["NUMBER"],
14955
14820
  compute: function (date) {
14956
14821
  return toJsDate(date, this.locale).getMinutes();
14957
14822
  },
@@ -14963,7 +14828,6 @@ const MINUTE = {
14963
14828
  const MONTH = {
14964
14829
  description: _t("Month of the year a specific date falls in"),
14965
14830
  args: [arg("date (date)", _t("The date from which to extract the month."))],
14966
- returns: ["NUMBER"],
14967
14831
  compute: function (date) {
14968
14832
  return toJsDate(date, this.locale).getMonth() + 1;
14969
14833
  },
@@ -14979,7 +14843,6 @@ const NETWORKDAYS = {
14979
14843
  arg("end_date (date)", _t("The end date of the period from which to calculate the number of net working days.")),
14980
14844
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the date serial numbers to consider holidays.")),
14981
14845
  ],
14982
- returns: ["NUMBER"],
14983
14846
  compute: function (startDate, endDate, holidays) {
14984
14847
  return NETWORKDAYS_INTL.compute.bind(this)(startDate, endDate, { value: 1 }, holidays);
14985
14848
  },
@@ -15060,7 +14923,6 @@ const NETWORKDAYS_INTL = {
15060
14923
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15061
14924
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider as holidays.")),
15062
14925
  ],
15063
- returns: ["NUMBER"],
15064
14926
  compute: function (startDate, endDate, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15065
14927
  const _startDate = toJsDate(startDate, this.locale);
15066
14928
  const _endDate = toJsDate(endDate, this.locale);
@@ -15095,7 +14957,6 @@ const NETWORKDAYS_INTL = {
15095
14957
  const NOW = {
15096
14958
  description: _t("Current date and time as a date value."),
15097
14959
  args: [],
15098
- returns: ["DATE"],
15099
14960
  compute: function () {
15100
14961
  const today = DateTime.now();
15101
14962
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
@@ -15113,7 +14974,6 @@ const NOW = {
15113
14974
  const SECOND = {
15114
14975
  description: _t("Minute component of a specific time."),
15115
14976
  args: [arg("time (date)", _t("The time from which to calculate the second component."))],
15116
- returns: ["NUMBER"],
15117
14977
  compute: function (date) {
15118
14978
  return toJsDate(date, this.locale).getSeconds();
15119
14979
  },
@@ -15129,7 +14989,6 @@ const TIME = {
15129
14989
  arg("minute (number)", _t("The minute component of the time.")),
15130
14990
  arg("second (number)", _t("The second component of the time.")),
15131
14991
  ],
15132
- returns: ["DATE"],
15133
14992
  compute: function (hour, minute, second) {
15134
14993
  let _hour = Math.trunc(toNumber(hour, this.locale));
15135
14994
  let _minute = Math.trunc(toNumber(minute, this.locale));
@@ -15153,7 +15012,6 @@ const TIME = {
15153
15012
  const TIMEVALUE = {
15154
15013
  description: _t("Converts a time string into its serial number representation."),
15155
15014
  args: [arg("time_string (string)", _t("The string that holds the time representation."))],
15156
- returns: ["NUMBER"],
15157
15015
  compute: function (timeString) {
15158
15016
  const _timeString = toString(timeString);
15159
15017
  const internalDate = parseDateTime(_timeString, this.locale);
@@ -15169,7 +15027,6 @@ const TIMEVALUE = {
15169
15027
  const TODAY = {
15170
15028
  description: _t("Current date as a date value."),
15171
15029
  args: [],
15172
- returns: ["DATE"],
15173
15030
  compute: function () {
15174
15031
  const today = DateTime.now();
15175
15032
  const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
@@ -15189,7 +15046,6 @@ const WEEKDAY = {
15189
15046
  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.")),
15190
15047
  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.")),
15191
15048
  ],
15192
- returns: ["NUMBER"],
15193
15049
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15194
15050
  const _date = toJsDate(date, this.locale);
15195
15051
  const _type = Math.round(toNumber(type, this.locale));
@@ -15212,7 +15068,6 @@ const WEEKNUM = {
15212
15068
  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.")),
15213
15069
  arg(`type (number, default=${DEFAULT_TYPE})`, _t("A number representing the day that a week starts on. Sunday = 1.")),
15214
15070
  ],
15215
- returns: ["NUMBER"],
15216
15071
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15217
15072
  const _date = toJsDate(date, this.locale);
15218
15073
  const _type = Math.round(toNumber(type, this.locale));
@@ -15253,7 +15108,6 @@ const WORKDAY = {
15253
15108
  arg("num_days (number)", _t("The number of working days to advance from start_date. If negative, counts backwards.")),
15254
15109
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15255
15110
  ],
15256
- returns: ["NUMBER"],
15257
15111
  compute: function (startDate, numDays, holidays = { value: null }) {
15258
15112
  return WORKDAY_INTL.compute.bind(this)(startDate, numDays, { value: 1 }, holidays);
15259
15113
  },
@@ -15270,7 +15124,6 @@ const WORKDAY_INTL = {
15270
15124
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15271
15125
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15272
15126
  ],
15273
- returns: ["DATE"],
15274
15127
  compute: function (startDate, numDays, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15275
15128
  let _startDate = toJsDate(startDate, this.locale);
15276
15129
  let _numDays = Math.trunc(toNumber(numDays, this.locale));
@@ -15310,7 +15163,6 @@ const WORKDAY_INTL = {
15310
15163
  const YEAR = {
15311
15164
  description: _t("Year specified by a given date."),
15312
15165
  args: [arg("date (date)", _t("The date from which to extract the year."))],
15313
- returns: ["NUMBER"],
15314
15166
  compute: function (date) {
15315
15167
  return toJsDate(date, this.locale).getFullYear();
15316
15168
  },
@@ -15327,7 +15179,6 @@ const YEARFRAC = {
15327
15179
  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.")),
15328
15180
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION$1})`, _t("An indicator of what day count method to use.")),
15329
15181
  ],
15330
- returns: ["NUMBER"],
15331
15182
  compute: function (startDate, endDate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION$1 }) {
15332
15183
  let _startDate = Math.trunc(toNumber(startDate, this.locale));
15333
15184
  let _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -15344,7 +15195,6 @@ const YEARFRAC = {
15344
15195
  const MONTH_START = {
15345
15196
  description: _t("First day of the month preceding a date."),
15346
15197
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15347
- returns: ["DATE"],
15348
15198
  compute: function (date) {
15349
15199
  const _startDate = toJsDate(date, this.locale);
15350
15200
  const yStart = _startDate.getFullYear();
@@ -15362,7 +15212,6 @@ const MONTH_START = {
15362
15212
  const MONTH_END = {
15363
15213
  description: _t("Last day of the month following a date."),
15364
15214
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15365
- returns: ["DATE"],
15366
15215
  compute: function (date) {
15367
15216
  return EOMONTH.compute.bind(this)(date, { value: 0 });
15368
15217
  },
@@ -15373,7 +15222,6 @@ const MONTH_END = {
15373
15222
  const QUARTER = {
15374
15223
  description: _t("Quarter of the year a specific date falls in"),
15375
15224
  args: [arg("date (date)", _t("The date from which to extract the quarter."))],
15376
- returns: ["NUMBER"],
15377
15225
  compute: function (date) {
15378
15226
  return Math.ceil((toJsDate(date, this.locale).getMonth() + 1) / 3);
15379
15227
  },
@@ -15384,7 +15232,6 @@ const QUARTER = {
15384
15232
  const QUARTER_START = {
15385
15233
  description: _t("First day of the quarter of the year a specific date falls in."),
15386
15234
  args: [arg("date (date)", _t("The date from which to calculate the start of quarter."))],
15387
- returns: ["DATE"],
15388
15235
  compute: function (date) {
15389
15236
  const quarter = QUARTER.compute.bind(this)(date);
15390
15237
  const year = YEAR.compute.bind(this)(date);
@@ -15401,7 +15248,6 @@ const QUARTER_START = {
15401
15248
  const QUARTER_END = {
15402
15249
  description: _t("Last day of the quarter of the year a specific date falls in."),
15403
15250
  args: [arg("date (date)", _t("The date from which to calculate the end of quarter."))],
15404
- returns: ["DATE"],
15405
15251
  compute: function (date) {
15406
15252
  const quarter = QUARTER.compute.bind(this)(date);
15407
15253
  const year = YEAR.compute.bind(this)(date);
@@ -15418,7 +15264,6 @@ const QUARTER_END = {
15418
15264
  const YEAR_START = {
15419
15265
  description: _t("First day of the year a specific date falls in."),
15420
15266
  args: [arg("date (date)", _t("The date from which to calculate the start of the year."))],
15421
- returns: ["DATE"],
15422
15267
  compute: function (date) {
15423
15268
  const year = YEAR.compute.bind(this)(date);
15424
15269
  const jsDate = new DateTime(year, 0, 1);
@@ -15434,7 +15279,6 @@ const YEAR_START = {
15434
15279
  const YEAR_END = {
15435
15280
  description: _t("Last day of the year a specific date falls in."),
15436
15281
  args: [arg("date (date)", _t("The date from which to calculate the end of the year."))],
15437
- returns: ["DATE"],
15438
15282
  compute: function (date) {
15439
15283
  const year = YEAR.compute.bind(this)(date);
15440
15284
  const jsDate = new DateTime(year + 1, 0, 0);
@@ -15491,7 +15335,6 @@ const DELTA = {
15491
15335
  arg("number1 (number)", _t("The first number to compare.")),
15492
15336
  arg(`number2 (number, default=${DEFAULT_DELTA_ARG})`, _t("The second number to compare.")),
15493
15337
  ],
15494
- returns: ["NUMBER"],
15495
15338
  compute: function (number1, number2 = { value: DEFAULT_DELTA_ARG }) {
15496
15339
  const _number1 = toNumber(number1, this.locale);
15497
15340
  const _number2 = toNumber(number2, this.locale);
@@ -15682,7 +15525,6 @@ const FILTER = {
15682
15525
  arg("condition1 (boolean, range<boolean>)", _t("A column or row containing true or false values corresponding to the first column or row of range.")),
15683
15526
  arg("condition2 (boolean, range<boolean>, repeating)", _t("Additional column or row containing true or false values.")),
15684
15527
  ],
15685
- returns: ["RANGE<ANY>"],
15686
15528
  compute: function (range, ...conditions) {
15687
15529
  let _array = toMatrix(range);
15688
15530
  const _conditionsMatrices = conditions.map((cond) => matrixMap(toMatrix(cond), (data) => data.value));
@@ -15716,7 +15558,6 @@ const SORT = {
15716
15558
  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.")),
15717
15559
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15718
15560
  ],
15719
- returns: ["RANGE"],
15720
15561
  compute: function (range, ...sortingCriteria) {
15721
15562
  const _range = transposeMatrix(range);
15722
15563
  return transposeMatrix(sortMatrix(_range, this.locale, ...sortingCriteria));
@@ -15735,7 +15576,6 @@ const SORTN = {
15735
15576
  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.")),
15736
15577
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15737
15578
  ],
15738
- returns: ["RANGE"],
15739
15579
  compute: function (range, n, displayTiesMode, ...sortingCriteria) {
15740
15580
  const _n = toNumber(n?.value ?? 1, this.locale);
15741
15581
  assert(() => _n >= 0, _t("Wrong value of 'n'. Expected a positive number. Got %s.", _n));
@@ -15803,7 +15643,6 @@ const UNIQUE = {
15803
15643
  arg("by_column (boolean, default=FALSE)", _t("Whether to filter the data by columns or by rows.")),
15804
15644
  arg("exactly_once (boolean, default=FALSE)", _t("Whether to return only entries with no duplicates.")),
15805
15645
  ],
15806
- returns: ["RANGE<NUMBER>"],
15807
15646
  compute: function (range = { value: "" }, byColumn, exactlyOnce) {
15808
15647
  if (!isMatrix(range)) {
15809
15648
  return [[range]];
@@ -16028,7 +15867,6 @@ const ACCRINTM = {
16028
15867
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16029
15868
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16030
15869
  ],
16031
- returns: ["NUMBER"],
16032
15870
  compute: function (issue, maturity, rate, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16033
15871
  const start = Math.trunc(toNumber(issue, this.locale));
16034
15872
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16059,7 +15897,6 @@ const AMORLINC = {
16059
15897
  arg("rate (number)", _t("The deprecation rate.")),
16060
15898
  arg("day_count_convention (number, optional)", _t("An indicator of what day count method to use.")),
16061
15899
  ],
16062
- returns: ["NUMBER"],
16063
15900
  compute: function (cost, purchaseDate, firstPeriodEnd, salvage, period, rate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16064
15901
  dayCountConvention = dayCountConvention || 0;
16065
15902
  const _cost = toNumber(cost, this.locale);
@@ -16108,7 +15945,6 @@ const AMORLINC = {
16108
15945
  const COUPDAYS = {
16109
15946
  description: _t("Days in coupon period containing settlement date."),
16110
15947
  args: COUPON_FUNCTION_ARGS,
16111
- returns: ["NUMBER"],
16112
15948
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16113
15949
  dayCountConvention = dayCountConvention || 0;
16114
15950
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16135,7 +15971,6 @@ const COUPDAYS = {
16135
15971
  const COUPDAYBS = {
16136
15972
  description: _t("Days from settlement until next coupon."),
16137
15973
  args: COUPON_FUNCTION_ARGS,
16138
- returns: ["NUMBER"],
16139
15974
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16140
15975
  dayCountConvention = dayCountConvention || 0;
16141
15976
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16192,7 +16027,6 @@ const COUPDAYBS = {
16192
16027
  const COUPDAYSNC = {
16193
16028
  description: _t("Days from settlement until next coupon."),
16194
16029
  args: COUPON_FUNCTION_ARGS,
16195
- returns: ["NUMBER"],
16196
16030
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16197
16031
  dayCountConvention = dayCountConvention || 0;
16198
16032
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16222,7 +16056,6 @@ const COUPDAYSNC = {
16222
16056
  const COUPNCD = {
16223
16057
  description: _t("Next coupon date after the settlement date."),
16224
16058
  args: COUPON_FUNCTION_ARGS,
16225
- returns: ["NUMBER"],
16226
16059
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16227
16060
  dayCountConvention = dayCountConvention || 0;
16228
16061
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16248,7 +16081,6 @@ const COUPNCD = {
16248
16081
  const COUPNUM = {
16249
16082
  description: _t("Number of coupons between settlement and maturity."),
16250
16083
  args: COUPON_FUNCTION_ARGS,
16251
- returns: ["NUMBER"],
16252
16084
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16253
16085
  dayCountConvention = dayCountConvention || 0;
16254
16086
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16275,7 +16107,6 @@ const COUPNUM = {
16275
16107
  const COUPPCD = {
16276
16108
  description: _t("Last coupon date prior to or on the settlement date."),
16277
16109
  args: COUPON_FUNCTION_ARGS,
16278
- returns: ["NUMBER"],
16279
16110
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16280
16111
  dayCountConvention = dayCountConvention || 0;
16281
16112
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16308,7 +16139,6 @@ const CUMIPMT = {
16308
16139
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16309
16140
  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.")),
16310
16141
  ],
16311
- returns: ["NUMBER"],
16312
16142
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16313
16143
  const first = toNumber(firstPeriod, this.locale);
16314
16144
  const last = toNumber(lastPeriod, this.locale);
@@ -16340,7 +16170,6 @@ const CUMPRINC = {
16340
16170
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16341
16171
  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.")),
16342
16172
  ],
16343
- returns: ["NUMBER"],
16344
16173
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16345
16174
  const first = toNumber(firstPeriod, this.locale);
16346
16175
  const last = toNumber(lastPeriod, this.locale);
@@ -16371,7 +16200,6 @@ const DB = {
16371
16200
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16372
16201
  arg("month (number, optional)", _t("The number of months in the first year of depreciation.")),
16373
16202
  ],
16374
- returns: ["NUMBER"],
16375
16203
  // to do: replace by dollar format
16376
16204
  compute: function (cost, salvage, life, period, ...args) {
16377
16205
  const _cost = toNumber(cost, this.locale);
@@ -16440,7 +16268,6 @@ const DDB = {
16440
16268
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16441
16269
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The factor by which depreciation decreases.")),
16442
16270
  ],
16443
- returns: ["NUMBER"],
16444
16271
  compute: function (cost, salvage, life, period, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }) {
16445
16272
  const _cost = toNumber(cost, this.locale);
16446
16273
  const _salvage = toNumber(salvage, this.locale);
@@ -16466,7 +16293,6 @@ const DISC = {
16466
16293
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16467
16294
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16468
16295
  ],
16469
- returns: ["NUMBER"],
16470
16296
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16471
16297
  dayCountConvention = dayCountConvention || 0;
16472
16298
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -16502,7 +16328,6 @@ const DOLLARDE = {
16502
16328
  arg("fractional_price (number)", _t("The price quotation given using fractional decimal conventions.")),
16503
16329
  arg("unit (number)", _t("The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16504
16330
  ],
16505
- returns: ["NUMBER"],
16506
16331
  compute: function (fractionalPrice, unit) {
16507
16332
  const price = toNumber(fractionalPrice, this.locale);
16508
16333
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16523,7 +16348,6 @@ const DOLLARFR = {
16523
16348
  arg("decimal_price (number)", _t("The price quotation given as a decimal value.")),
16524
16349
  arg("unit (number)", _t("The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16525
16350
  ],
16526
- returns: ["NUMBER"],
16527
16351
  compute: function (decimalPrice, unit) {
16528
16352
  const price = toNumber(decimalPrice, this.locale);
16529
16353
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16548,7 +16372,6 @@ const DURATION = {
16548
16372
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16549
16373
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16550
16374
  ],
16551
- returns: ["NUMBER"],
16552
16375
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16553
16376
  const start = Math.trunc(toNumber(settlement, this.locale));
16554
16377
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16589,7 +16412,6 @@ const EFFECT = {
16589
16412
  arg("nominal_rate (number)", _t("The nominal interest rate per year.")),
16590
16413
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16591
16414
  ],
16592
- returns: ["NUMBER"],
16593
16415
  compute: function (nominal_rate, periods_per_year) {
16594
16416
  const nominal = toNumber(nominal_rate, this.locale);
16595
16417
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16619,7 +16441,6 @@ const FV = {
16619
16441
  arg(`present_value (number, default=${DEFAULT_PRESENT_VALUE})`, _t("The current value of the annuity.")),
16620
16442
  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.")),
16621
16443
  ],
16622
- returns: ["NUMBER"],
16623
16444
  // to do: replace by dollar format
16624
16445
  compute: function (rate, numberOfPeriods, paymentAmount, presentValue = { value: DEFAULT_PRESENT_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16625
16446
  presentValue = presentValue || 0;
@@ -16645,7 +16466,6 @@ const FVSCHEDULE = {
16645
16466
  arg("principal (number)", _t("The amount of initial capital or value to compound against.")),
16646
16467
  arg("rate_schedule (number, range<number>)", _t("A series of interest rates to compound against the principal.")),
16647
16468
  ],
16648
- returns: ["NUMBER"],
16649
16469
  compute: function (principalAmount, rateSchedule) {
16650
16470
  const principal = toNumber(principalAmount, this.locale);
16651
16471
  return reduceAny([rateSchedule], (acc, rate) => acc * (1 + toNumber(rate, this.locale)), principal);
@@ -16664,7 +16484,6 @@ const INTRATE = {
16664
16484
  arg("redemption (number)", _t("The amount to be received at maturity.")),
16665
16485
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16666
16486
  ],
16667
- returns: ["NUMBER"],
16668
16487
  compute: function (settlement, maturity, investment, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16669
16488
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
16670
16489
  const _maturity = Math.trunc(toNumber(maturity, this.locale));
@@ -16703,7 +16522,6 @@ const IPMT = {
16703
16522
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16704
16523
  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.")),
16705
16524
  ],
16706
- returns: ["NUMBER"],
16707
16525
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16708
16526
  const r = toNumber(rate, this.locale);
16709
16527
  const period = toNumber(currentPeriod, this.locale);
@@ -16728,7 +16546,6 @@ const IRR = {
16728
16546
  arg("cashflow_amounts (number, range<number>)", _t("An array or range containing the income or payments associated with the investment.")),
16729
16547
  arg(`rate_guess (number, default=${DEFAULT_RATE_GUESS})`, _t("An estimate for what the internal rate of return will be.")),
16730
16548
  ],
16731
- returns: ["NUMBER"],
16732
16549
  compute: function (cashFlowAmounts, rateGuess = { value: DEFAULT_RATE_GUESS }) {
16733
16550
  const _rateGuess = toNumber(rateGuess, this.locale);
16734
16551
  assertRateGuessStrictlyGreaterThanMinusOne(_rateGuess);
@@ -16790,7 +16607,6 @@ const ISPMT = {
16790
16607
  arg("number_of_periods (number)", _t("The number of payments to be made.")),
16791
16608
  arg("present_value (number)", _t("The current value of the annuity.")),
16792
16609
  ],
16793
- returns: ["NUMBER"],
16794
16610
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue) {
16795
16611
  const interestRate = toNumber(rate, this.locale);
16796
16612
  const period = toNumber(currentPeriod, this.locale);
@@ -16815,7 +16631,6 @@ const MDURATION = {
16815
16631
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16816
16632
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16817
16633
  ],
16818
- returns: ["NUMBER"],
16819
16634
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16820
16635
  const duration = DURATION.compute.bind(this)(settlement, maturity, rate, securityYield, frequency, dayCountConvention);
16821
16636
  const y = toNumber(securityYield, this.locale);
@@ -16834,7 +16649,6 @@ const MIRR = {
16834
16649
  arg("financing_rate (number)", _t("The interest rate paid on funds invested.")),
16835
16650
  arg("reinvestment_return_rate (number)", _t("The return (as a percentage) earned on reinvestment of income received from the investment.")),
16836
16651
  ],
16837
- returns: ["NUMBER"],
16838
16652
  compute: function (cashflowAmount, financingRate, reinvestmentRate) {
16839
16653
  const fRate = toNumber(financingRate, this.locale);
16840
16654
  const rRate = toNumber(reinvestmentRate, this.locale);
@@ -16886,7 +16700,6 @@ const NOMINAL = {
16886
16700
  arg("effective_rate (number)", _t("The effective interest rate per year.")),
16887
16701
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16888
16702
  ],
16889
- returns: ["NUMBER"],
16890
16703
  compute: function (effective_rate, periods_per_year) {
16891
16704
  const effective = toNumber(effective_rate, this.locale);
16892
16705
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16909,7 +16722,6 @@ const NPER = {
16909
16722
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16910
16723
  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.")),
16911
16724
  ],
16912
- returns: ["NUMBER"],
16913
16725
  compute: function (rate, paymentAmount, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16914
16726
  futureValue = futureValue || 0;
16915
16727
  endOrBeginning = endOrBeginning || 0;
@@ -16957,7 +16769,6 @@ const NPV = {
16957
16769
  arg("cashflow1 (number, range<number>)", _t("The first future cash flow.")),
16958
16770
  arg("cashflow2 (number, range<number>, repeating)", _t("Additional future cash flows.")),
16959
16771
  ],
16960
- returns: ["NUMBER"],
16961
16772
  // to do: replace by dollar format
16962
16773
  compute: function (discount, ...values) {
16963
16774
  const _discount = toNumber(discount, this.locale);
@@ -16979,7 +16790,6 @@ const PDURATION = {
16979
16790
  arg("present_value (number)", _t("The investment's current value.")),
16980
16791
  arg("future_value (number)", _t("The investment's desired future value.")),
16981
16792
  ],
16982
- returns: ["NUMBER"],
16983
16793
  compute: function (rate, presentValue, futureValue) {
16984
16794
  const _rate = toNumber(rate, this.locale);
16985
16795
  const _presentValue = toNumber(presentValue, this.locale);
@@ -17019,7 +16829,6 @@ const PMT = {
17019
16829
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17020
16830
  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.")),
17021
16831
  ],
17022
- returns: ["NUMBER"],
17023
16832
  compute: function (rate, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17024
16833
  const n = toNumber(numberOfPeriods, this.locale);
17025
16834
  const r = toNumber(rate, this.locale);
@@ -17055,7 +16864,6 @@ const PPMT = {
17055
16864
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17056
16865
  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.")),
17057
16866
  ],
17058
- returns: ["NUMBER"],
17059
16867
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17060
16868
  const n = toNumber(numberOfPeriods, this.locale);
17061
16869
  const r = toNumber(rate, this.locale);
@@ -17082,7 +16890,6 @@ const PV = {
17082
16890
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17083
16891
  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.")),
17084
16892
  ],
17085
- returns: ["NUMBER"],
17086
16893
  // to do: replace by dollar format
17087
16894
  compute: function (rate, numberOfPeriods, paymentAmount, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17088
16895
  futureValue = futureValue || 0;
@@ -17116,7 +16923,6 @@ const PRICE = {
17116
16923
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17117
16924
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17118
16925
  ],
17119
- returns: ["NUMBER"],
17120
16926
  compute: function (settlement, maturity, rate, securityYield, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17121
16927
  dayCountConvention = dayCountConvention || 0;
17122
16928
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17164,7 +16970,6 @@ const PRICEDISC = {
17164
16970
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17165
16971
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17166
16972
  ],
17167
- returns: ["NUMBER"],
17168
16973
  compute: function (settlement, maturity, discount, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17169
16974
  dayCountConvention = dayCountConvention || 0;
17170
16975
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17202,7 +17007,6 @@ const PRICEMAT = {
17202
17007
  arg("yield (number)", _t("The expected annual yield of the security.")),
17203
17008
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17204
17009
  ],
17205
- returns: ["NUMBER"],
17206
17010
  compute: function (settlement, maturity, issue, rate, securityYield, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17207
17011
  dayCountConvention = dayCountConvention || 0;
17208
17012
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17266,7 +17070,6 @@ const RATE = {
17266
17070
  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.")),
17267
17071
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the interest rate will be.")),
17268
17072
  ],
17269
- returns: ["NUMBER"],
17270
17073
  compute: function (numberOfPeriods, paymentPerPeriod, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17271
17074
  const n = toNumber(numberOfPeriods, this.locale);
17272
17075
  const payment = toNumber(paymentPerPeriod, this.locale);
@@ -17312,7 +17115,6 @@ const RECEIVED = {
17312
17115
  arg("discount (number)", _t("The discount rate of the security invested in.")),
17313
17116
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17314
17117
  ],
17315
- returns: ["NUMBER"],
17316
17118
  compute: function (settlement, maturity, investment, discount, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17317
17119
  dayCountConvention = dayCountConvention || 0;
17318
17120
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17350,7 +17152,6 @@ const RRI = {
17350
17152
  arg("present_value (number)", _t("The present value of the investment.")),
17351
17153
  arg("future_value (number)", _t("The future value of the investment.")),
17352
17154
  ],
17353
- returns: ["NUMBER"],
17354
17155
  compute: function (numberOfPeriods, presentValue, futureValue) {
17355
17156
  const n = toNumber(numberOfPeriods, this.locale);
17356
17157
  const pv = toNumber(presentValue, this.locale);
@@ -17375,7 +17176,6 @@ const SLN = {
17375
17176
  arg("salvage (number)", _t("The value of the asset at the end of depreciation.")),
17376
17177
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17377
17178
  ],
17378
- returns: ["NUMBER"],
17379
17179
  compute: function (cost, salvage, life) {
17380
17180
  const _cost = toNumber(cost, this.locale);
17381
17181
  const _salvage = toNumber(salvage, this.locale);
@@ -17400,7 +17200,6 @@ const SYD = {
17400
17200
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17401
17201
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
17402
17202
  ],
17403
- returns: ["NUMBER"],
17404
17203
  compute: function (cost, salvage, life, period) {
17405
17204
  const _cost = toNumber(cost, this.locale);
17406
17205
  const _salvage = toNumber(salvage, this.locale);
@@ -17449,7 +17248,6 @@ const TBILLPRICE = {
17449
17248
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17450
17249
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17451
17250
  ],
17452
- returns: ["NUMBER"],
17453
17251
  compute: function (settlement, maturity, discount) {
17454
17252
  const start = Math.trunc(toNumber(settlement, this.locale));
17455
17253
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17472,7 +17270,6 @@ const TBILLEQ = {
17472
17270
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17473
17271
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17474
17272
  ],
17475
- returns: ["NUMBER"],
17476
17273
  compute: function (settlement, maturity, discount) {
17477
17274
  const start = Math.trunc(toNumber(settlement, this.locale));
17478
17275
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17530,7 +17327,6 @@ const TBILLYIELD = {
17530
17327
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17531
17328
  arg("price (number)", _t("The price at which the security is bought per 100 face value.")),
17532
17329
  ],
17533
- returns: ["NUMBER"],
17534
17330
  compute: function (settlement, maturity, price) {
17535
17331
  const start = Math.trunc(toNumber(settlement, this.locale));
17536
17332
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17570,7 +17366,6 @@ const VDB = {
17570
17366
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The number of months in the first year of depreciation.")),
17571
17367
  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.")),
17572
17368
  ],
17573
- returns: ["NUMBER"],
17574
17369
  compute: function (cost, salvage, life, startPeriod, endPeriod, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }, noSwitch = { value: DEFAULT_VDB_NO_SWITCH }) {
17575
17370
  factor = factor || 0;
17576
17371
  const _cost = toNumber(cost, this.locale);
@@ -17635,7 +17430,6 @@ const XIRR = {
17635
17430
  arg("cashflow_dates (range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17636
17431
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the internal rate of return will be.")),
17637
17432
  ],
17638
- returns: ["NUMBER"],
17639
17433
  compute: function (cashflowAmounts, cashflowDates, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17640
17434
  const guess = toNumber(rateGuess, this.locale);
17641
17435
  const _cashFlows = cashflowAmounts.flat().map((val) => toNumber(val, this.locale));
@@ -17706,7 +17500,6 @@ const XNPV = {
17706
17500
  arg("cashflow_amounts (number, range<number>)", _t("An range containing the income or payments associated with the investment.")),
17707
17501
  arg("cashflow_dates (number, range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17708
17502
  ],
17709
- returns: ["NUMBER"],
17710
17503
  compute: function (discount, cashflowAmounts, cashflowDates) {
17711
17504
  const rate = toNumber(discount, this.locale);
17712
17505
  const _cashFlows = isMatrix(cashflowAmounts)
@@ -17773,7 +17566,6 @@ const YIELD = {
17773
17566
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17774
17567
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17775
17568
  ],
17776
- returns: ["NUMBER"],
17777
17569
  compute: function (settlement, maturity, rate, price, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17778
17570
  dayCountConvention = dayCountConvention || 0;
17779
17571
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17848,7 +17640,6 @@ const YIELDDISC = {
17848
17640
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17849
17641
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17850
17642
  ],
17851
- returns: ["NUMBER"],
17852
17643
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17853
17644
  dayCountConvention = dayCountConvention || 0;
17854
17645
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17885,7 +17676,6 @@ const YIELDMAT = {
17885
17676
  arg("price (number)", _t("The price at which the security is bought.")),
17886
17677
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17887
17678
  ],
17888
- returns: ["NUMBER"],
17889
17679
  compute: function (settlement, maturity, issue, rate, price, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17890
17680
  dayCountConvention = dayCountConvention || 0;
17891
17681
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17972,7 +17762,6 @@ const CELL = {
17972
17762
  arg("info_type (string)", _t("The type of information requested. Can be one of %s", CELL_INFO_TYPES.join(", "))),
17973
17763
  arg("reference (meta)", _t("The reference to the cell.")),
17974
17764
  ],
17975
- returns: ["ANY"],
17976
17765
  compute: function (info, reference) {
17977
17766
  const _info = toString(info).toLowerCase();
17978
17767
  assert(() => CELL_INFO_TYPES.includes(_info), _t("The info_type should be one of %s.", CELL_INFO_TYPES.join(", ")));
@@ -18023,7 +17812,6 @@ const CELL = {
18023
17812
  const ISERR = {
18024
17813
  description: _t("Whether a value is an error other than #N/A."),
18025
17814
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18026
- returns: ["BOOLEAN"],
18027
17815
  compute: function (data) {
18028
17816
  const value = data?.value;
18029
17817
  return isEvaluationError(value) && value !== CellErrorType.NotAvailable;
@@ -18036,7 +17824,6 @@ const ISERR = {
18036
17824
  const ISERROR = {
18037
17825
  description: _t("Whether a value is an error."),
18038
17826
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18039
- returns: ["BOOLEAN"],
18040
17827
  compute: function (data) {
18041
17828
  const value = data?.value;
18042
17829
  return isEvaluationError(value);
@@ -18049,7 +17836,6 @@ const ISERROR = {
18049
17836
  const ISLOGICAL = {
18050
17837
  description: _t("Whether a value is `true` or `false`."),
18051
17838
  args: [arg("value (any)", _t("The value to be verified as a logical TRUE or FALSE."))],
18052
- returns: ["BOOLEAN"],
18053
17839
  compute: function (value) {
18054
17840
  return typeof value?.value === "boolean";
18055
17841
  },
@@ -18061,7 +17847,6 @@ const ISLOGICAL = {
18061
17847
  const ISNA = {
18062
17848
  description: _t("Whether a value is the error #N/A."),
18063
17849
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18064
- returns: ["BOOLEAN"],
18065
17850
  compute: function (data) {
18066
17851
  return data?.value === CellErrorType.NotAvailable;
18067
17852
  },
@@ -18073,7 +17858,6 @@ const ISNA = {
18073
17858
  const ISNONTEXT = {
18074
17859
  description: _t("Whether a value is non-textual."),
18075
17860
  args: [arg("value (any)", _t("The value to be checked."))],
18076
- returns: ["BOOLEAN"],
18077
17861
  compute: function (value) {
18078
17862
  return !ISTEXT.compute.bind(this)(value);
18079
17863
  },
@@ -18085,7 +17869,6 @@ const ISNONTEXT = {
18085
17869
  const ISNUMBER = {
18086
17870
  description: _t("Whether a value is a number."),
18087
17871
  args: [arg("value (any)", _t("The value to be verified as a number."))],
18088
- returns: ["BOOLEAN"],
18089
17872
  compute: function (value) {
18090
17873
  return typeof value?.value === "number";
18091
17874
  },
@@ -18097,7 +17880,6 @@ const ISNUMBER = {
18097
17880
  const ISTEXT = {
18098
17881
  description: _t("Whether a value is text."),
18099
17882
  args: [arg("value (any)", _t("The value to be verified as text."))],
18100
- returns: ["BOOLEAN"],
18101
17883
  compute: function (value) {
18102
17884
  return typeof value?.value === "string" && isEvaluationError(value?.value) === false;
18103
17885
  },
@@ -18109,7 +17891,6 @@ const ISTEXT = {
18109
17891
  const ISBLANK = {
18110
17892
  description: _t("Whether the referenced cell is empty"),
18111
17893
  args: [arg("value (any)", _t("Reference to the cell that will be checked for emptiness."))],
18112
- returns: ["BOOLEAN"],
18113
17894
  compute: function (value) {
18114
17895
  return value?.value === null;
18115
17896
  },
@@ -18121,7 +17902,6 @@ const ISBLANK = {
18121
17902
  const NA = {
18122
17903
  description: _t("Returns the error value #N/A."),
18123
17904
  args: [],
18124
- returns: ["BOOLEAN"],
18125
17905
  compute: function () {
18126
17906
  return { value: CellErrorType.NotAvailable };
18127
17907
  },
@@ -18178,7 +17958,6 @@ const AND = {
18178
17958
  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.")),
18179
17959
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that represent logical values.")),
18180
17960
  ],
18181
- returns: ["BOOLEAN"],
18182
17961
  compute: function (...logicalExpressions) {
18183
17962
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18184
17963
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18192,7 +17971,6 @@ const AND = {
18192
17971
  const FALSE = {
18193
17972
  description: _t("Logical value `false`."),
18194
17973
  args: [],
18195
- returns: ["BOOLEAN"],
18196
17974
  compute: function () {
18197
17975
  return false;
18198
17976
  },
@@ -18208,7 +17986,6 @@ const IF = {
18208
17986
  arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18209
17987
  arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18210
17988
  ],
18211
- returns: ["ANY"],
18212
17989
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18213
17990
  const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18214
17991
  if (result === undefined) {
@@ -18230,7 +18007,6 @@ const IFERROR = {
18230
18007
  arg("value (any)", _t("The value to return if value itself is not an error.")),
18231
18008
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18232
18009
  ],
18233
- returns: ["ANY"],
18234
18010
  compute: function (value, valueIfError = { value: "" }) {
18235
18011
  const result = isEvaluationError(value?.value) ? valueIfError : value;
18236
18012
  if (result === undefined) {
@@ -18252,7 +18028,6 @@ const IFNA = {
18252
18028
  arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18253
18029
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18254
18030
  ],
18255
- returns: ["ANY"],
18256
18031
  compute: function (value, valueIfError = { value: "" }) {
18257
18032
  const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18258
18033
  if (result === undefined) {
@@ -18276,7 +18051,6 @@ const IFS = {
18276
18051
  arg("condition2 (boolean, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18277
18052
  arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18278
18053
  ],
18279
- returns: ["ANY"],
18280
18054
  compute: function (...values) {
18281
18055
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18282
18056
  for (let n = 0; n < values.length - 1; n += 2) {
@@ -18303,7 +18077,6 @@ const NOT = {
18303
18077
  args: [
18304
18078
  arg("logical_expression (boolean)", _t("An expression or reference to a cell holding an expression that represents some logical value.")),
18305
18079
  ],
18306
- returns: ["BOOLEAN"],
18307
18080
  compute: function (logicalExpression) {
18308
18081
  return !toBoolean(logicalExpression);
18309
18082
  },
@@ -18318,7 +18091,6 @@ const OR = {
18318
18091
  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.")),
18319
18092
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18320
18093
  ],
18321
- returns: ["BOOLEAN"],
18322
18094
  compute: function (...logicalExpressions) {
18323
18095
  const { result, foundBoolean } = boolOr(logicalExpressions);
18324
18096
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18332,7 +18104,6 @@ const OR = {
18332
18104
  const TRUE = {
18333
18105
  description: _t("Logical value `true`."),
18334
18106
  args: [],
18335
- returns: ["BOOLEAN"],
18336
18107
  compute: function () {
18337
18108
  return true;
18338
18109
  },
@@ -18347,7 +18118,6 @@ const XOR = {
18347
18118
  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.")),
18348
18119
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18349
18120
  ],
18350
- returns: ["BOOLEAN"],
18351
18121
  compute: function (...logicalExpressions) {
18352
18122
  let foundBoolean = false;
18353
18123
  let acc = false;
@@ -18376,9 +18146,229 @@ var logical = /*#__PURE__*/Object.freeze({
18376
18146
  XOR: XOR
18377
18147
  });
18378
18148
 
18379
- //TODO This registry is only used to disable the support of exploded pivot for spreadsheet
18380
- const supportedPivotExplodedFormulaRegistry = new Registry();
18381
- supportedPivotExplodedFormulaRegistry.add("SPREADSHEET", false);
18149
+ const pivotTimeAdapterRegistry = new Registry();
18150
+ function pivotTimeAdapter(granularity) {
18151
+ return pivotTimeAdapterRegistry.get(granularity);
18152
+ }
18153
+ /**
18154
+ * The Time Adapter: Managing Time Periods for Pivot Functions
18155
+ *
18156
+ * Overview:
18157
+ * A time adapter is responsible for managing time periods associated with pivot functions.
18158
+ * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
18159
+ * The adapter's primary role is to normalize period values between spreadsheet functions,
18160
+ * and the pivot.
18161
+ * By normalizing the period value, it can be stored consistently in the pivot.
18162
+ *
18163
+ * Normalization Process:
18164
+ * When working with functions in the spreadsheet, the time adapter normalizes
18165
+ * the provided period to facilitate accurate lookup of values in the pivot.
18166
+ * For instance, if the spreadsheet function represents a day period as a number generated
18167
+ * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
18168
+ *
18169
+ */
18170
+ /**
18171
+ * Normalized value: "12/25/2023"
18172
+ *
18173
+ * Note: Those two format are equivalent:
18174
+ * - "MM/dd/yyyy" (luxon format)
18175
+ * - "mm/dd/yyyy" (spreadsheet format)
18176
+ **/
18177
+ const dayAdapter = {
18178
+ normalizeFunctionValue(value) {
18179
+ const date = toNumber(value, DEFAULT_LOCALE);
18180
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
18181
+ },
18182
+ getFormat(locale) {
18183
+ return (locale ?? DEFAULT_LOCALE).dateFormat;
18184
+ },
18185
+ formatValue(normalizedValue, locale) {
18186
+ locale = locale ?? DEFAULT_LOCALE;
18187
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18188
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18189
+ },
18190
+ toCellValue(normalizedValue) {
18191
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18192
+ },
18193
+ };
18194
+ /**
18195
+ * normalizes day of month number
18196
+ */
18197
+ const dayOfMonthAdapter = {
18198
+ normalizeFunctionValue(value) {
18199
+ const day = toNumber(value, DEFAULT_LOCALE);
18200
+ if (day < 1 || day > 31) {
18201
+ throw new EvaluationError(_t("%s is not a valid day of month (it should be a number between 1 and 31)", day));
18202
+ }
18203
+ return day;
18204
+ },
18205
+ getFormat() {
18206
+ return "0";
18207
+ },
18208
+ formatValue(normalizedValue, locale) {
18209
+ locale = locale ?? DEFAULT_LOCALE;
18210
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18211
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18212
+ },
18213
+ toCellValue(normalizedValue) {
18214
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18215
+ },
18216
+ };
18217
+ /**
18218
+ * Normalized value: "2/2023" for week 2 of 2023
18219
+ */
18220
+ const weekAdapter = {
18221
+ normalizeFunctionValue(value) {
18222
+ const [week, year] = value.split("/");
18223
+ return `${Number(week)}/${Number(year)}`;
18224
+ },
18225
+ getFormat() {
18226
+ return undefined;
18227
+ },
18228
+ formatValue(normalizedValue) {
18229
+ const [week, year] = normalizedValue.split("/");
18230
+ return _t("W%(week)s %(year)s", { week, year });
18231
+ },
18232
+ toCellValue(normalizedValue) {
18233
+ return this.formatValue(normalizedValue);
18234
+ },
18235
+ };
18236
+ /**
18237
+ * normalizes iso week number
18238
+ */
18239
+ const isoWeekNumberAdapter = {
18240
+ normalizeFunctionValue(value) {
18241
+ const isoWeek = toNumber(value, DEFAULT_LOCALE);
18242
+ if (isoWeek < 0 || isoWeek > 53) {
18243
+ throw new EvaluationError(_t("%s is not a valid week (it should be a number between 0 and 53)", isoWeek));
18244
+ }
18245
+ return isoWeek;
18246
+ },
18247
+ getFormat() {
18248
+ return "0";
18249
+ },
18250
+ formatValue(normalizedValue, locale) {
18251
+ locale = locale ?? DEFAULT_LOCALE;
18252
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18253
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18254
+ },
18255
+ toCellValue(normalizedValue) {
18256
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18257
+ },
18258
+ };
18259
+ /**
18260
+ * normalized month value is a string formatted as "MM/yyyy" (luxon format)
18261
+ * e.g. "01/2020" for January 2020
18262
+ */
18263
+ const monthAdapter = {
18264
+ normalizeFunctionValue(value) {
18265
+ const date = toNumber(value, DEFAULT_LOCALE);
18266
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
18267
+ },
18268
+ getFormat() {
18269
+ return "mmmm yyyy";
18270
+ },
18271
+ formatValue(normalizedValue, locale) {
18272
+ locale = locale ?? DEFAULT_LOCALE;
18273
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18274
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18275
+ },
18276
+ toCellValue(normalizedValue) {
18277
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18278
+ },
18279
+ };
18280
+ /**
18281
+ * normalizes month number
18282
+ */
18283
+ const monthNumberAdapter = {
18284
+ normalizeFunctionValue(value) {
18285
+ const month = toNumber(value, DEFAULT_LOCALE);
18286
+ if (month < 1 || month > 12) {
18287
+ throw new EvaluationError(_t("%s is not a valid month (it should be a number between 1 and 12)", month));
18288
+ }
18289
+ return month;
18290
+ },
18291
+ getFormat() {
18292
+ return "0";
18293
+ },
18294
+ formatValue(normalizedValue, locale) {
18295
+ locale = locale ?? DEFAULT_LOCALE;
18296
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18297
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18298
+ },
18299
+ toCellValue(normalizedValue) {
18300
+ return MONTHS[toNumber(normalizedValue, DEFAULT_LOCALE) - 1].toString();
18301
+ },
18302
+ };
18303
+ /**
18304
+ * normalized quarter value is "quarter/year"
18305
+ * e.g. "1/2020" for Q1 2020
18306
+ */
18307
+ const quarterAdapter = {
18308
+ normalizeFunctionValue(value) {
18309
+ const [quarter, year] = value.split("/");
18310
+ return `${quarter}/${year}`;
18311
+ },
18312
+ getFormat() {
18313
+ return undefined;
18314
+ },
18315
+ formatValue(normalizedValue) {
18316
+ const [quarter, year] = normalizedValue.split("/");
18317
+ return _t("Q%(quarter)s %(year)s", { quarter, year });
18318
+ },
18319
+ toCellValue(normalizedValue) {
18320
+ return this.formatValue(normalizedValue);
18321
+ },
18322
+ };
18323
+ /**
18324
+ * normalizes quarter number
18325
+ */
18326
+ const quarterNumberAdapter = {
18327
+ normalizeFunctionValue(value) {
18328
+ const quarter = toNumber(value, DEFAULT_LOCALE);
18329
+ if (quarter < 1 || quarter > 4) {
18330
+ throw new EvaluationError(_t("%s is not a valid quarter (it should be a number between 1 and 4)", quarter));
18331
+ }
18332
+ return quarter;
18333
+ },
18334
+ getFormat() {
18335
+ return "0";
18336
+ },
18337
+ formatValue(normalizedValue, locale) {
18338
+ locale = locale ?? DEFAULT_LOCALE;
18339
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18340
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18341
+ },
18342
+ toCellValue(normalizedValue) {
18343
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18344
+ },
18345
+ };
18346
+ const yearAdapter = {
18347
+ normalizeFunctionValue(value) {
18348
+ return toNumber(value, DEFAULT_LOCALE);
18349
+ },
18350
+ getFormat() {
18351
+ return "0";
18352
+ },
18353
+ formatValue(normalizedValue, locale) {
18354
+ locale = locale ?? DEFAULT_LOCALE;
18355
+ return formatValue(normalizedValue, { locale, format: "0" });
18356
+ },
18357
+ toCellValue(normalizedValue) {
18358
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18359
+ },
18360
+ };
18361
+ pivotTimeAdapterRegistry
18362
+ .add("day", dayAdapter)
18363
+ .add("week", weekAdapter)
18364
+ .add("month", monthAdapter)
18365
+ .add("quarter", quarterAdapter)
18366
+ .add("year", yearAdapter)
18367
+ .add("day_of_month", dayOfMonthAdapter)
18368
+ .add("iso_week_number", isoWeekNumberAdapter)
18369
+ .add("month_number", monthNumberAdapter)
18370
+ .add("quarter_number", quarterNumberAdapter)
18371
+ .add("year_number", yearAdapter);
18382
18372
 
18383
18373
  const AGGREGATOR_NAMES = {
18384
18374
  count: _t("Count"),
@@ -18394,7 +18384,7 @@ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "
18394
18384
  const AGGREGATORS_BY_FIELD_TYPE = {
18395
18385
  integer: NUMBER_CHAR_AGGREGATORS,
18396
18386
  char: NUMBER_CHAR_AGGREGATORS,
18397
- //TODO Support for date and boolean
18387
+ boolean: ["count_distinct", "count", "bool_and", "bool_or"],
18398
18388
  };
18399
18389
  const AGGREGATORS = {};
18400
18390
  for (const type in AGGREGATORS_BY_FIELD_TYPE) {
@@ -18504,6 +18494,44 @@ function toPivotDomain(domainStr) {
18504
18494
  function flatPivotDomain(domain) {
18505
18495
  return domain.flatMap((arg) => [arg.field, arg.value]);
18506
18496
  }
18497
+ /**
18498
+ * Parses the value defining a pivot group in a PIVOT formula
18499
+ * e.g. given the following formula PIVOT.VALUE("1", "stage_id", "42", "status", "won"),
18500
+ * the two group values are "42" and "won".
18501
+ */
18502
+ function toNormalizedPivotValue(dimension, groupValue) {
18503
+ if (groupValue === null || groupValue === "null") {
18504
+ return null;
18505
+ }
18506
+ const groupValueString = typeof groupValue === "boolean"
18507
+ ? toString(groupValue).toLocaleLowerCase()
18508
+ : toString(groupValue);
18509
+ if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
18510
+ throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
18511
+ field: dimension.displayName,
18512
+ type: dimension.type,
18513
+ }));
18514
+ }
18515
+ // represents a field which is not set (=False server side)
18516
+ if (groupValueString === "false") {
18517
+ return false;
18518
+ }
18519
+ const normalizer = pivotNormalizationValueRegistry.get(dimension.type);
18520
+ return normalizer(groupValueString, dimension.granularity);
18521
+ }
18522
+ function normalizeDateTime(value, granularity) {
18523
+ if (!granularity) {
18524
+ throw "";
18525
+ }
18526
+ return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
18527
+ }
18528
+ const pivotNormalizationValueRegistry = new Registry();
18529
+ pivotNormalizationValueRegistry
18530
+ .add("date", normalizeDateTime)
18531
+ .add("datetime", normalizeDateTime)
18532
+ .add("integer", (value) => toNumber(value, DEFAULT_LOCALE))
18533
+ .add("boolean", (value) => toBoolean(value))
18534
+ .add("char", (value) => toString(value));
18507
18535
 
18508
18536
  /**
18509
18537
  * Get the pivot ID from the formula pivot ID.
@@ -18580,7 +18608,6 @@ const ADDRESS = {
18580
18608
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18581
18609
  arg("sheet (string, optional)", _t("A string indicating the name of the sheet into which the address points.")),
18582
18610
  ],
18583
- returns: ["STRING"],
18584
18611
  compute: function (row, column, absoluteRelativeMode = { value: DEFAULT_ABSOLUTE_RELATIVE_MODE }, useA1Notation = { value: true }, sheet) {
18585
18612
  const rowNumber = strictToInteger(row, this.locale);
18586
18613
  const colNumber = strictToInteger(column, this.locale);
@@ -18617,7 +18644,6 @@ const COLUMN = {
18617
18644
  args: [
18618
18645
  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.")),
18619
18646
  ],
18620
- returns: ["NUMBER"],
18621
18647
  compute: function (cellReference) {
18622
18648
  if (isEvaluationError(cellReference?.value)) {
18623
18649
  throw cellReference;
@@ -18635,7 +18661,6 @@ const COLUMN = {
18635
18661
  const COLUMNS = {
18636
18662
  description: _t("Number of columns in a specified array or range."),
18637
18663
  args: [arg("range (meta)", _t("The range whose column count will be returned."))],
18638
- returns: ["NUMBER"],
18639
18664
  compute: function (range) {
18640
18665
  if (isEvaluationError(range?.value)) {
18641
18666
  throw range;
@@ -18656,7 +18681,6 @@ const HLOOKUP = {
18656
18681
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18657
18682
  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.")),
18658
18683
  ],
18659
- returns: ["ANY"],
18660
18684
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18661
18685
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18662
18686
  assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18686,7 +18710,6 @@ const INDEX = {
18686
18710
  arg("row (number, default=0)", _t("The index of the row to be returned from within the reference range of cells.")),
18687
18711
  arg("column (number, default=0)", _t("The index of the column to be returned from within the reference range of cells.")),
18688
18712
  ],
18689
- returns: ["ANY"],
18690
18713
  compute: function (reference, row = { value: 0 }, column = { value: 0 }) {
18691
18714
  const _reference = toMatrix(reference);
18692
18715
  const _row = toNumber(row.value, this.locale);
@@ -18717,7 +18740,6 @@ const INDIRECT = {
18717
18740
  arg("reference (string)", _t("The range of cells from which the values are returned.")),
18718
18741
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18719
18742
  ],
18720
- returns: ["ANY"],
18721
18743
  compute: function (reference, useA1Notation = { value: true }) {
18722
18744
  let _reference = reference?.value?.toString();
18723
18745
  if (!_reference) {
@@ -18772,7 +18794,6 @@ const LOOKUP = {
18772
18794
  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.")),
18773
18795
  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.")),
18774
18796
  ],
18775
- returns: ["ANY"],
18776
18797
  compute: function (searchKey, searchArray, resultRange) {
18777
18798
  let nbCol = searchArray.length;
18778
18799
  let nbRow = searchArray[0].length;
@@ -18813,7 +18834,6 @@ const MATCH = {
18813
18834
  arg("range (any, range)", _t("The one-dimensional array to be searched.")),
18814
18835
  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.")),
18815
18836
  ],
18816
- returns: ["NUMBER"],
18817
18837
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18818
18838
  let _searchType = toNumber(searchType, this.locale);
18819
18839
  const nbCol = range.length;
@@ -18852,7 +18872,6 @@ const ROW = {
18852
18872
  args: [
18853
18873
  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.")),
18854
18874
  ],
18855
- returns: ["NUMBER"],
18856
18875
  compute: function (cellReference) {
18857
18876
  if (isEvaluationError(cellReference?.value)) {
18858
18877
  throw cellReference;
@@ -18870,7 +18889,6 @@ const ROW = {
18870
18889
  const ROWS = {
18871
18890
  description: _t("Number of rows in a specified array or range."),
18872
18891
  args: [arg("range (meta)", _t("The range whose row count will be returned."))],
18873
- returns: ["NUMBER"],
18874
18892
  compute: function (range) {
18875
18893
  if (isEvaluationError(range?.value)) {
18876
18894
  throw range;
@@ -18891,7 +18909,6 @@ const VLOOKUP = {
18891
18909
  arg("index (number)", _t("The column index of the value to be returned, where the first column in range is numbered 1.")),
18892
18910
  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.")),
18893
18911
  ],
18894
- returns: ["ANY"],
18895
18912
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18896
18913
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18897
18914
  assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18937,7 +18954,6 @@ const XLOOKUP = {
18937
18954
  (-2) Perform a binary search that relies on lookup_array being sorted in descending order. If not sorted, invalid results will be returned.\
18938
18955
  ")),
18939
18956
  ],
18940
- returns: ["ANY"],
18941
18957
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18942
18958
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18943
18959
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
@@ -18993,12 +19009,6 @@ const PIVOT_VALUE = {
18993
19009
  assertDomainLength(_domainArgs);
18994
19010
  const pivot = this.getters.getPivot(pivotId);
18995
19011
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18996
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
18997
- return {
18998
- value: CellErrorType.GenericError,
18999
- message: _t("This pivot does not support PIVOT.VALUE formula"),
19000
- };
19001
- }
19002
19012
  addPivotDependencies(this, coreDefinition);
19003
19013
  const error = pivot.assertIsValid({ throwOnError: false });
19004
19014
  if (error) {
@@ -19014,7 +19024,6 @@ const PIVOT_VALUE = {
19014
19024
  }
19015
19025
  return { value, format };
19016
19026
  },
19017
- returns: ["NUMBER", "STRING"],
19018
19027
  };
19019
19028
  const PIVOT_HEADER = {
19020
19029
  description: _t("Get the header of a pivot."),
@@ -19030,12 +19039,6 @@ const PIVOT_HEADER = {
19030
19039
  assertDomainLength(_domainArgs);
19031
19040
  const pivot = this.getters.getPivot(_pivotId);
19032
19041
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19033
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
19034
- return {
19035
- value: CellErrorType.GenericError,
19036
- message: _t("This pivot does not support PIVOT.VALUE formula"),
19037
- };
19038
- }
19039
19042
  addPivotDependencies(this, coreDefinition);
19040
19043
  const error = pivot.assertIsValid({ throwOnError: false });
19041
19044
  if (error) {
@@ -19060,7 +19063,6 @@ const PIVOT_HEADER = {
19060
19063
  : format,
19061
19064
  };
19062
19065
  },
19063
- returns: ["NUMBER", "STRING"],
19064
19066
  };
19065
19067
  const PIVOT = {
19066
19068
  description: _t("Get a pivot table."),
@@ -19127,7 +19129,6 @@ const PIVOT = {
19127
19129
  }
19128
19130
  return result;
19129
19131
  },
19130
- returns: ["RANGE<ANY>"],
19131
19132
  };
19132
19133
 
19133
19134
  var lookup = /*#__PURE__*/Object.freeze({
@@ -19158,7 +19159,6 @@ const ADD = {
19158
19159
  arg("value1 (number)", _t("The first addend.")),
19159
19160
  arg("value2 (number)", _t("The second addend.")),
19160
19161
  ],
19161
- returns: ["NUMBER"],
19162
19162
  compute: function (value1, value2) {
19163
19163
  return {
19164
19164
  value: toNumber(value1, this.locale) + toNumber(value2, this.locale),
@@ -19175,7 +19175,6 @@ const CONCAT = {
19175
19175
  arg("value1 (string)", _t("The value to which value2 will be appended.")),
19176
19176
  arg("value2 (string)", _t("The value to append to value1.")),
19177
19177
  ],
19178
- returns: ["STRING"],
19179
19178
  compute: function (value1, value2) {
19180
19179
  return toString(value1) + toString(value2);
19181
19180
  },
@@ -19190,7 +19189,6 @@ const DIVIDE = {
19190
19189
  arg("dividend (number)", _t("The number to be divided.")),
19191
19190
  arg("divisor (number)", _t("The number to divide by.")),
19192
19191
  ],
19193
- returns: ["NUMBER"],
19194
19192
  compute: function (dividend, divisor) {
19195
19193
  const _divisor = toNumber(divisor, this.locale);
19196
19194
  assert(() => _divisor !== 0, _t("The divisor must be different from zero."), CellErrorType.DivisionByZero);
@@ -19213,7 +19211,6 @@ const EQ = {
19213
19211
  arg("value1 (any)", _t("The first value.")),
19214
19212
  arg("value2 (any)", _t("The value to test against value1 for equality.")),
19215
19213
  ],
19216
- returns: ["BOOLEAN"],
19217
19214
  compute: function (value1, value2) {
19218
19215
  let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
19219
19216
  let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
@@ -19266,7 +19263,6 @@ const GT = {
19266
19263
  arg("value1 (any)", _t("The value to test as being greater than value2.")),
19267
19264
  arg("value2 (any)", _t("The second value.")),
19268
19265
  ],
19269
- returns: ["BOOLEAN"],
19270
19266
  compute: function (value1, value2) {
19271
19267
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19272
19268
  return v1 > v2;
@@ -19282,7 +19278,6 @@ const GTE = {
19282
19278
  arg("value1 (any)", _t("The value to test as being greater than or equal to value2.")),
19283
19279
  arg("value2 (any)", _t("The second value.")),
19284
19280
  ],
19285
- returns: ["BOOLEAN"],
19286
19281
  compute: function (value1, value2) {
19287
19282
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19288
19283
  return v1 >= v2;
@@ -19298,7 +19293,6 @@ const LT = {
19298
19293
  arg("value1 (any)", _t("The value to test as being less than value2.")),
19299
19294
  arg("value2 (any)", _t("The second value.")),
19300
19295
  ],
19301
- returns: ["BOOLEAN"],
19302
19296
  compute: function (value1, value2) {
19303
19297
  return !GTE.compute.bind(this)(value1, value2);
19304
19298
  },
@@ -19312,7 +19306,6 @@ const LTE = {
19312
19306
  arg("value1 (any)", _t("The value to test as being less than or equal to value2.")),
19313
19307
  arg("value2 (any)", _t("The second value.")),
19314
19308
  ],
19315
- returns: ["BOOLEAN"],
19316
19309
  compute: function (value1, value2) {
19317
19310
  return !GT.compute.bind(this)(value1, value2);
19318
19311
  },
@@ -19326,7 +19319,6 @@ const MINUS = {
19326
19319
  arg("value1 (number)", _t("The minuend, or number to be subtracted from.")),
19327
19320
  arg("value2 (number)", _t("The subtrahend, or number to subtract from value1.")),
19328
19321
  ],
19329
- returns: ["NUMBER"],
19330
19322
  compute: function (value1, value2) {
19331
19323
  return {
19332
19324
  value: toNumber(value1, this.locale) - toNumber(value2, this.locale),
@@ -19343,7 +19335,6 @@ const MULTIPLY = {
19343
19335
  arg("factor1 (number)", _t("The first multiplicand.")),
19344
19336
  arg("factor2 (number)", _t("The second multiplicand.")),
19345
19337
  ],
19346
- returns: ["NUMBER"],
19347
19338
  compute: function (factor1, factor2) {
19348
19339
  return {
19349
19340
  value: toNumber(factor1, this.locale) * toNumber(factor2, this.locale),
@@ -19360,7 +19351,6 @@ const NE = {
19360
19351
  arg("value1 (any)", _t("The first value.")),
19361
19352
  arg("value2 (any)", _t("The value to test against value1 for inequality.")),
19362
19353
  ],
19363
- returns: ["BOOLEAN"],
19364
19354
  compute: function (value1, value2) {
19365
19355
  return !EQ.compute.bind(this)(value1, value2);
19366
19356
  },
@@ -19374,7 +19364,6 @@ const POW = {
19374
19364
  arg("base (number)", _t("The number to raise to the exponent power.")),
19375
19365
  arg("exponent (number)", _t("The exponent to raise base to.")),
19376
19366
  ],
19377
- returns: ["NUMBER"],
19378
19367
  compute: function (base, exponent) {
19379
19368
  return POWER.compute.bind(this)(base, exponent);
19380
19369
  },
@@ -19387,7 +19376,6 @@ const UMINUS = {
19387
19376
  args: [
19388
19377
  arg("value (number)", _t("The number to have its sign reversed. Equivalently, the number to multiply by -1.")),
19389
19378
  ],
19390
- returns: ["NUMBER"],
19391
19379
  compute: function (value) {
19392
19380
  return {
19393
19381
  value: -toNumber(value, this.locale),
@@ -19401,7 +19389,6 @@ const UMINUS = {
19401
19389
  const UNARY_PERCENT = {
19402
19390
  description: _t("Value interpreted as a percentage."),
19403
19391
  args: [arg("percentage (number)", _t("The value to interpret as a percentage."))],
19404
- returns: ["NUMBER"],
19405
19392
  compute: function (percentage) {
19406
19393
  return toNumber(percentage, this.locale) / 100;
19407
19394
  },
@@ -19412,7 +19399,6 @@ const UNARY_PERCENT = {
19412
19399
  const UPLUS = {
19413
19400
  description: _t("A specified number, unchanged."),
19414
19401
  args: [arg("value (any)", _t("The number to return."))],
19415
- returns: ["ANY"],
19416
19402
  compute: function (value = { value: null }) {
19417
19403
  return value;
19418
19404
  },
@@ -19448,7 +19434,6 @@ const CHAR = {
19448
19434
  args: [
19449
19435
  arg("table_number (number)", _t("The number of the character to look up from the current Unicode table in decimal format.")),
19450
19436
  ],
19451
- returns: ["STRING"],
19452
19437
  compute: function (tableNumber) {
19453
19438
  const _tableNumber = Math.trunc(toNumber(tableNumber, this.locale));
19454
19439
  assert(() => _tableNumber >= 1, _t("The table_number (%s) is out of range.", _tableNumber.toString()));
@@ -19462,7 +19447,6 @@ const CHAR = {
19462
19447
  const CLEAN = {
19463
19448
  description: _t("Remove non-printable characters from a piece of text."),
19464
19449
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
19465
- returns: ["STRING"],
19466
19450
  compute: function (text) {
19467
19451
  const _text = toString(text);
19468
19452
  let cleanedStr = "";
@@ -19484,7 +19468,6 @@ const CONCATENATE = {
19484
19468
  arg("string1 (string, range<string>)", _t("The initial string.")),
19485
19469
  arg("string2 (string, range<string>, repeating)", _t("More strings to append in sequence.")),
19486
19470
  ],
19487
- returns: ["STRING"],
19488
19471
  compute: function (...datas) {
19489
19472
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
19490
19473
  },
@@ -19499,7 +19482,6 @@ const EXACT = {
19499
19482
  arg("string1 (string)", _t("The first string to compare.")),
19500
19483
  arg("string2 (string)", _t("The second string to compare.")),
19501
19484
  ],
19502
- returns: ["BOOLEAN"],
19503
19485
  compute: function (string1, string2) {
19504
19486
  return toString(string1) === toString(string2);
19505
19487
  },
@@ -19515,7 +19497,6 @@ const FIND = {
19515
19497
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19516
19498
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19517
19499
  ],
19518
- returns: ["NUMBER"],
19519
19500
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19520
19501
  const _searchFor = toString(searchFor);
19521
19502
  const _textToSearch = toString(textToSearch);
@@ -19538,7 +19519,6 @@ const JOIN = {
19538
19519
  arg("value_or_array1 (string, range<string>)", _t("The value or values to be appended using delimiter.")),
19539
19520
  arg("value_or_array2 (string, range<string>, repeating)", _t("More values to be appended using delimiter.")),
19540
19521
  ],
19541
- returns: ["STRING"],
19542
19522
  compute: function (delimiter, ...valuesOrArrays) {
19543
19523
  const _delimiter = toString(delimiter);
19544
19524
  return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
@@ -19553,7 +19533,6 @@ const LEFT = {
19553
19533
  arg("text (string)", _t("The string from which the left portion will be returned.")),
19554
19534
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the left side of string.")),
19555
19535
  ],
19556
- returns: ["STRING"],
19557
19536
  compute: function (text, ...args) {
19558
19537
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19559
19538
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19567,7 +19546,6 @@ const LEFT = {
19567
19546
  const LEN = {
19568
19547
  description: _t("Length of a string."),
19569
19548
  args: [arg("text (string)", _t("The string whose length will be returned."))],
19570
- returns: ["NUMBER"],
19571
19549
  compute: function (text) {
19572
19550
  return toString(text).length;
19573
19551
  },
@@ -19579,7 +19557,6 @@ const LEN = {
19579
19557
  const LOWER = {
19580
19558
  description: _t("Converts a specified string to lowercase."),
19581
19559
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
19582
- returns: ["STRING"],
19583
19560
  compute: function (text) {
19584
19561
  return toString(text).toLowerCase();
19585
19562
  },
@@ -19595,7 +19572,6 @@ const MID = {
19595
19572
  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.")),
19596
19573
  arg("extract_length (number)", _t("The length of the segment to extract.")),
19597
19574
  ],
19598
- returns: ["STRING"],
19599
19575
  compute: function (text, starting_at, extract_length) {
19600
19576
  const _text = toString(text);
19601
19577
  const _starting_at = toNumber(starting_at, this.locale);
@@ -19614,7 +19590,6 @@ const PROPER = {
19614
19590
  args: [
19615
19591
  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.")),
19616
19592
  ],
19617
- returns: ["STRING"],
19618
19593
  compute: function (text) {
19619
19594
  const _text = toString(text);
19620
19595
  return _text.replace(wordRegex, (word) => {
@@ -19634,7 +19609,6 @@ const REPLACE = {
19634
19609
  arg("length (number)", _t("The number of characters in the text to be replaced.")),
19635
19610
  arg("new_text (string)", _t("The text which will be inserted into the original text.")),
19636
19611
  ],
19637
- returns: ["STRING"],
19638
19612
  compute: function (text, position, length, newText) {
19639
19613
  const _position = toNumber(position, this.locale);
19640
19614
  assert(() => _position >= 1, _t("The position (%s) must be greater than or equal to 1.", _position.toString()));
@@ -19654,7 +19628,6 @@ const RIGHT = {
19654
19628
  arg("text (string)", _t("The string from which the right portion will be returned.")),
19655
19629
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the right side of string.")),
19656
19630
  ],
19657
- returns: ["STRING"],
19658
19631
  compute: function (text, ...args) {
19659
19632
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19660
19633
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19674,7 +19647,6 @@ const SEARCH = {
19674
19647
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19675
19648
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19676
19649
  ],
19677
- returns: ["NUMBER"],
19678
19650
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19679
19651
  const _searchFor = toString(searchFor).toLowerCase();
19680
19652
  const _textToSearch = toString(textToSearch).toLowerCase();
@@ -19701,7 +19673,6 @@ const SPLIT = {
19701
19673
  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 \
19702
19674
  consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters.")),
19703
19675
  ],
19704
- returns: ["RANGE<STRING>"],
19705
19676
  compute: function (text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
19706
19677
  const _text = toString(text);
19707
19678
  const _delimiter = escapeRegExp(toString(delimiter));
@@ -19728,7 +19699,6 @@ const SUBSTITUTE = {
19728
19699
  arg("replace_with (string)", _t("The string that will replace search_for.")),
19729
19700
  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.")),
19730
19701
  ],
19731
- returns: ["NUMBER"],
19732
19702
  compute: function (textToSearch, searchFor, replaceWith, occurrenceNumber) {
19733
19703
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
19734
19704
  assert(() => _occurrenceNumber >= 0, _t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber.toString()));
@@ -19758,7 +19728,6 @@ const TEXTJOIN = {
19758
19728
  arg("text1 (string, range<string>)", _t("Any text item. This could be a string, or an array of strings in a range.")),
19759
19729
  arg("text2 (string, range<string>, repeating)", _t("Additional text item(s).")),
19760
19730
  ],
19761
- returns: ["STRING"],
19762
19731
  compute: function (delimiter, ignoreEmpty, ...textsOrArrays) {
19763
19732
  const _delimiter = toString(delimiter);
19764
19733
  const _ignoreEmpty = toBoolean(ignoreEmpty);
@@ -19775,7 +19744,6 @@ const TRIM = {
19775
19744
  args: [
19776
19745
  arg("text (string)", _t("The text or reference to a cell containing text to be trimmed.")),
19777
19746
  ],
19778
- returns: ["STRING"],
19779
19747
  compute: function (text) {
19780
19748
  return trimContent(toString(text));
19781
19749
  },
@@ -19787,7 +19755,6 @@ const TRIM = {
19787
19755
  const UPPER = {
19788
19756
  description: _t("Converts a specified string to uppercase."),
19789
19757
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
19790
- returns: ["STRING"],
19791
19758
  compute: function (text) {
19792
19759
  return toString(text).toUpperCase();
19793
19760
  },
@@ -19802,7 +19769,6 @@ const TEXT = {
19802
19769
  arg("number (number)", _t("The number, date or time to format.")),
19803
19770
  arg("format (string)", _t("The pattern by which to format the number, enclosed in quotation marks.")),
19804
19771
  ],
19805
- returns: ["STRING"],
19806
19772
  compute: function (number, format) {
19807
19773
  const _number = toNumber(number, this.locale);
19808
19774
  return formatValue(_number, { format: toString(format), locale: this.locale });
@@ -19843,7 +19809,6 @@ const HYPERLINK = {
19843
19809
  arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")),
19844
19810
  arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks.")),
19845
19811
  ],
19846
- returns: ["STRING"],
19847
19812
  compute: function (url, linkLabel) {
19848
19813
  const processedUrl = toString(url).trim();
19849
19814
  const processedLabel = toString(linkLabel) || processedUrl;
@@ -19902,6 +19867,9 @@ function addInputHandling(descr) {
19902
19867
  }
19903
19868
  args[i] = arg[0][0];
19904
19869
  }
19870
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19871
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19872
+ }
19905
19873
  }
19906
19874
  return descr.compute.apply(this, args);
19907
19875
  }
@@ -21496,12 +21464,6 @@ function compileTokens(tokens) {
21496
21464
  // detect when an argument need to be evaluated as a meta argument
21497
21465
  const isMeta = argTypes.includes("META");
21498
21466
  const hasRange = argTypes.some((t) => isRangeType(t));
21499
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21500
- if (isRangeOnly) {
21501
- if (!isRangeInput(currentArg)) {
21502
- 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 }));
21503
- }
21504
- }
21505
21467
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21506
21468
  }
21507
21469
  return compiledArgs;
@@ -21666,16 +21628,6 @@ function assertEnoughArgs(ast) {
21666
21628
  function isRangeType(type) {
21667
21629
  return type.startsWith("RANGE");
21668
21630
  }
21669
- function isRangeInput(arg) {
21670
- if (arg.type === "REFERENCE") {
21671
- return true;
21672
- }
21673
- if (arg.type === "FUNCALL") {
21674
- const fnDef = functions$1[arg.value.toUpperCase()];
21675
- return fnDef && isRangeType(fnDef.returns[0]);
21676
- }
21677
- return false;
21678
- }
21679
21631
 
21680
21632
  const functions = functionRegistry.content;
21681
21633
  function isExportableToExcel(tokens) {
@@ -21719,11 +21671,14 @@ const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
21719
21671
  function makeFieldProposal(field, granularity) {
21720
21672
  const groupBy = granularity ? `${field.name}:${granularity}` : field.name;
21721
21673
  const quotedGroupBy = `"${groupBy}"`;
21674
+ const fuzzySearchKey = field.string !== field.name
21675
+ ? field.string + quotedGroupBy // search on translated name and on technical name
21676
+ : quotedGroupBy;
21722
21677
  return {
21723
21678
  text: quotedGroupBy,
21724
21679
  description: field.string + (field.help ? ` (${field.help})` : ""),
21725
21680
  htmlContent: [{ value: quotedGroupBy, color: tokenColors.STRING }],
21726
- fuzzySearchKey: field.string + quotedGroupBy, // search on translated name and on technical name
21681
+ fuzzySearchKey,
21727
21682
  };
21728
21683
  }
21729
21684
  /**
@@ -21783,6 +21738,14 @@ function getNumberOfPivotFunctions(tokens) {
21783
21738
  return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS).length;
21784
21739
  }
21785
21740
 
21741
+ /**
21742
+ * Registry to enable or disable the support of positional arguments
21743
+ * (with a leading #) in pivot functions
21744
+ * e.g. =PIVOT.VALUE(1,"probability","#stage",1)
21745
+ */
21746
+ const supportedPivotPositionalFormulaRegistry = new Registry();
21747
+ supportedPivotPositionalFormulaRegistry.add("SPREADSHEET", false);
21748
+
21786
21749
  autoCompleteProviders.add("pivot_ids", {
21787
21750
  sequence: 50,
21788
21751
  autoSelectFirstProposal: true,
@@ -21801,10 +21764,6 @@ autoCompleteProviders.add("pivot_ids", {
21801
21764
  return pivotIds
21802
21765
  .map((pivotId) => {
21803
21766
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21804
- if (functionContext.parent.toUpperCase() !== "PIVOT" &&
21805
- !supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21806
- return undefined;
21807
- }
21808
21767
  const formulaId = this.getters.getPivotFormulaId(pivotId);
21809
21768
  const str = `${formulaId}`;
21810
21769
  return {
@@ -21832,15 +21791,13 @@ autoCompleteProviders.add("pivot_measures", {
21832
21791
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21833
21792
  return [];
21834
21793
  }
21835
- const dataSource = this.getters.getPivot(pivotId);
21836
- const fields = dataSource.getFields();
21794
+ const pivot = this.getters.getPivot(pivotId);
21795
+ pivot.init();
21796
+ const fields = pivot.getFields();
21837
21797
  if (!fields) {
21838
21798
  return [];
21839
21799
  }
21840
21800
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21841
- if (!supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21842
- return [];
21843
- }
21844
21801
  return definition.measures
21845
21802
  .map((measure) => {
21846
21803
  if (measure.name === "__count") {
@@ -21876,16 +21833,13 @@ autoCompleteProviders.add("pivot_group_fields", {
21876
21833
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21877
21834
  return;
21878
21835
  }
21879
- const dataSource = this.getters.getPivot(pivotId);
21880
- const fields = dataSource.getFields();
21836
+ const pivot = this.getters.getPivot(pivotId);
21837
+ pivot.init();
21838
+ const fields = pivot.getFields();
21881
21839
  if (!fields) {
21882
21840
  return;
21883
21841
  }
21884
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21885
- const { columns, rows } = dataSource.definition;
21886
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21887
- return [];
21888
- }
21842
+ const { columns, rows } = pivot.definition;
21889
21843
  let args = functionContext.args;
21890
21844
  if (functionContext?.parent.toUpperCase() === "PIVOT.VALUE") {
21891
21845
  args = args.filter((ast, index) => index % 2 === 0); // keep only the field names
@@ -21922,6 +21876,9 @@ autoCompleteProviders.add("pivot_group_fields", {
21922
21876
  return field ? makeFieldProposal(field, granularity) : undefined;
21923
21877
  })
21924
21878
  .concat(groupBys.map((groupBy) => {
21879
+ if (!supportedPivotPositionalFormulaRegistry.get(pivot.type)) {
21880
+ return undefined;
21881
+ }
21925
21882
  const fieldName = groupBy.split(":")[0];
21926
21883
  const field = fields[fieldName];
21927
21884
  if (!field) {
@@ -21970,12 +21927,8 @@ autoCompleteProviders.add("pivot_group_values", {
21970
21927
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21971
21928
  return;
21972
21929
  }
21973
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21974
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21975
- return [];
21976
- }
21977
- const dataSource = this.getters.getPivot(pivotId);
21978
- if (!dataSource.isValid()) {
21930
+ const pivot = this.getters.getPivot(pivotId);
21931
+ if (!pivot.isValid()) {
21979
21932
  return;
21980
21933
  }
21981
21934
  const argPosition = functionContext.argPosition;
@@ -21983,7 +21936,46 @@ autoCompleteProviders.add("pivot_group_values", {
21983
21936
  if (!groupByField) {
21984
21937
  return;
21985
21938
  }
21986
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21939
+ let dimension;
21940
+ try {
21941
+ dimension = pivot.definition.getDimension(groupByField);
21942
+ }
21943
+ catch (error) {
21944
+ return undefined;
21945
+ }
21946
+ if (dimension.granularity === "month_number") {
21947
+ return Object.values(MONTHS).map((monthDisplayName, index) => ({
21948
+ text: `${index + 1}`,
21949
+ fuzzySearchKey: monthDisplayName.toString(),
21950
+ description: monthDisplayName.toString(),
21951
+ htmlContent: [{ value: `${index + 1}`, color: tokenColors.NUMBER }],
21952
+ }));
21953
+ }
21954
+ else if (dimension.granularity === "quarter_number") {
21955
+ return [1, 2, 3, 4].map((quarter) => ({
21956
+ text: `${quarter}`,
21957
+ fuzzySearchKey: `${quarter}`,
21958
+ description: _t("Quarter %s", quarter),
21959
+ htmlContent: [{ value: `${quarter}`, color: tokenColors.NUMBER }],
21960
+ }));
21961
+ }
21962
+ else if (dimension.granularity === "day_of_month") {
21963
+ return range(1, 32).map((dayOfMonth) => ({
21964
+ text: `${dayOfMonth}`,
21965
+ fuzzySearchKey: `${dayOfMonth}`,
21966
+ description: "",
21967
+ htmlContent: [{ value: `${dayOfMonth}`, color: tokenColors.NUMBER }],
21968
+ }));
21969
+ }
21970
+ else if (dimension.granularity === "iso_week_number") {
21971
+ return range(0, 54).map((isoWeekNumber) => ({
21972
+ text: `${isoWeekNumber}`,
21973
+ fuzzySearchKey: `${isoWeekNumber}`,
21974
+ description: "",
21975
+ htmlContent: [{ value: `${isoWeekNumber}`, color: tokenColors.NUMBER }],
21976
+ }));
21977
+ }
21978
+ return pivot.getPossibleFieldValues(dimension).map(({ value, label }) => {
21987
21979
  const isString = typeof value === "string";
21988
21980
  const text = isString ? `"${value}"` : value.toString();
21989
21981
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -22090,7 +22082,9 @@ autofillModifiersRegistry
22090
22082
  tooltip: content
22091
22083
  ? {
22092
22084
  props: {
22093
- content: evaluateLiteral(data.cell?.content, localeFormat).formattedValue,
22085
+ content: data.cell
22086
+ ? evaluateLiteral(data.cell, localeFormat).formattedValue
22087
+ : "",
22094
22088
  },
22095
22089
  }
22096
22090
  : undefined,
@@ -22153,9 +22147,7 @@ function getGroup(cell, cells, filter) {
22153
22147
  if (x === cell) {
22154
22148
  found = true;
22155
22149
  }
22156
- const cellValue = x?.isFormula
22157
- ? undefined
22158
- : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
22150
+ const cellValue = x === undefined || x.isFormula ? undefined : evaluateLiteral(x, { locale: DEFAULT_LOCALE });
22159
22151
  if (cellValue && filter(cellValue)) {
22160
22152
  group.push(cellValue);
22161
22153
  }
@@ -22203,7 +22195,7 @@ autofillRulesRegistry
22203
22195
  })
22204
22196
  .add("increment_alphanumeric_value", {
22205
22197
  condition: (cell) => !cell.isFormula &&
22206
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22198
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22207
22199
  alphaNumericValueRegExp.test(cell.content),
22208
22200
  generateRule: (cell, cells) => {
22209
22201
  const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
@@ -22226,7 +22218,7 @@ autofillRulesRegistry
22226
22218
  })
22227
22219
  .add("copy_text", {
22228
22220
  condition: (cell) => !cell.isFormula &&
22229
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22221
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22230
22222
  generateRule: () => {
22231
22223
  return { type: "COPY_MODIFIER" };
22232
22224
  },
@@ -22241,11 +22233,11 @@ autofillRulesRegistry
22241
22233
  })
22242
22234
  .add("increment_number", {
22243
22235
  condition: (cell) => !cell.isFormula &&
22244
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22236
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22245
22237
  generateRule: (cell, cells) => {
22246
22238
  const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
22247
22239
  const increment = calculateIncrementBasedOnGroup(group);
22248
- const evaluation = evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE });
22240
+ const evaluation = evaluateLiteral(cell, { locale: DEFAULT_LOCALE });
22249
22241
  return {
22250
22242
  type: "INCREMENT_MODIFIER",
22251
22243
  increment,
@@ -25469,7 +25461,7 @@ class Popover extends owl.Component {
25469
25461
  if (!anchor)
25470
25462
  return;
25471
25463
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25472
- const elDims = {
25464
+ let elDims = {
25473
25465
  width: el.getBoundingClientRect().width,
25474
25466
  height: el.getBoundingClientRect().height,
25475
25467
  };
@@ -25477,7 +25469,14 @@ class Popover extends owl.Component {
25477
25469
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25478
25470
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25479
25471
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25480
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25472
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
25473
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
25474
+ // Re-compute the dimensions after setting the max-width and max-height
25475
+ elDims = {
25476
+ width: el.getBoundingClientRect().width,
25477
+ height: el.getBoundingClientRect().height,
25478
+ };
25479
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25481
25480
  for (const property of Object.keys(style)) {
25482
25481
  el.style[property] = style[property];
25483
25482
  }
@@ -25540,8 +25539,6 @@ class PopoverPositionContext {
25540
25539
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25541
25540
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25542
25541
  const cssProperties = {
25543
- "max-height": maxHeight + "px",
25544
- "max-width": maxWidth + "px",
25545
25542
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25546
25543
  this.spreadsheetOffset.y -
25547
25544
  verticalOffset +
@@ -31355,10 +31352,8 @@ class ChartTitle extends owl.Component {
31355
31352
 
31356
31353
  class AxisDesignEditor extends owl.Component {
31357
31354
  static template = "o-spreadsheet-AxisDesignEditor";
31358
- static components = {
31359
- Section,
31360
- ChartTitle,
31361
- };
31355
+ static components = { Section, ChartTitle };
31356
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31362
31357
  state = owl.useState({ currentAxis: "x" });
31363
31358
  get axisTitleStyle() {
31364
31359
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31509,6 +31504,12 @@ class ChartWithAxisDesignPanel extends owl.Component {
31509
31504
  AxisDesignEditor,
31510
31505
  RoundColorPicker,
31511
31506
  };
31507
+ static props = {
31508
+ figureId: String,
31509
+ definition: Object,
31510
+ canUpdateChart: Function,
31511
+ updateChart: Function,
31512
+ };
31512
31513
  state = owl.useState({ index: 0 });
31513
31514
  get axesList() {
31514
31515
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -31690,14 +31691,6 @@ class GaugeChartDesignPanel extends owl.Component {
31690
31691
  const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
31691
31692
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
31692
31693
  }
31693
- updateBackgroundColor(color) {
31694
- this.props.updateChart(this.props.figureId, {
31695
- background: color,
31696
- });
31697
- }
31698
- updateTitle(content) {
31699
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31700
- }
31701
31694
  isRangeMinInvalid() {
31702
31695
  return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
31703
31696
  this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */) ||
@@ -31737,9 +31730,6 @@ class GaugeChartDesignPanel extends owl.Component {
31737
31730
  sectionRule,
31738
31731
  });
31739
31732
  }
31740
- get backgroundColorTitle() {
31741
- return ChartTerms.BackgroundColor;
31742
- }
31743
31733
  }
31744
31734
 
31745
31735
  class LineConfigPanel extends GenericChartConfigPanel {
@@ -31922,9 +31912,6 @@ class ScorecardChartDesignPanel extends owl.Component {
31922
31912
  get humanizeNumbersLabel() {
31923
31913
  return _t("Humanize numbers");
31924
31914
  }
31925
- updateTitle(content) {
31926
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31927
- }
31928
31915
  updateHumanizeNumbers(humanize) {
31929
31916
  this.props.updateChart(this.props.figureId, { humanize });
31930
31917
  }
@@ -31947,9 +31934,6 @@ class ScorecardChartDesignPanel extends owl.Component {
31947
31934
  break;
31948
31935
  }
31949
31936
  }
31950
- get backgroundColorTitle() {
31951
- return ChartTerms.BackgroundColor;
31952
- }
31953
31937
  }
31954
31938
 
31955
31939
  class WaterfallChartDesignPanel extends owl.Component {
@@ -33453,13 +33437,17 @@ class SelectMenu extends owl.Component {
33453
33437
  class: { type: String, optional: true },
33454
33438
  };
33455
33439
  static components = { Menu };
33440
+ menuId = new UuidGenerator().uuidv4();
33456
33441
  selectRef = owl.useRef("select");
33457
33442
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33458
33443
  state = owl.useState({
33459
33444
  isMenuOpen: false,
33460
33445
  });
33461
- onClick() {
33462
- this.state.isMenuOpen = true;
33446
+ onClick(ev) {
33447
+ if (ev.closedMenuId === this.menuId) {
33448
+ return;
33449
+ }
33450
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33463
33451
  }
33464
33452
  onMenuClosed() {
33465
33453
  this.state.isMenuOpen = false;
@@ -33467,7 +33455,7 @@ class SelectMenu extends owl.Component {
33467
33455
  get menuPosition() {
33468
33456
  return {
33469
33457
  x: this.selectRect.x,
33470
- y: this.selectRect.y,
33458
+ y: this.selectRect.y + this.selectRect.height,
33471
33459
  };
33472
33460
  }
33473
33461
  }
@@ -34407,9 +34395,9 @@ class FindAndReplacePanel extends owl.Component {
34407
34395
  static props = {
34408
34396
  onCloseSidePanel: Function,
34409
34397
  };
34410
- dataRange = "";
34411
34398
  searchInput = owl.useRef("searchInput");
34412
34399
  store;
34400
+ state;
34413
34401
  get hasSearchResult() {
34414
34402
  return this.store.selectedMatchIndex !== null;
34415
34403
  }
@@ -34439,6 +34427,7 @@ class FindAndReplacePanel extends owl.Component {
34439
34427
  }
34440
34428
  setup() {
34441
34429
  this.store = useLocalStore(FindAndReplaceStore);
34430
+ this.state = owl.useState({ dataRange: "" });
34442
34431
  owl.onMounted(() => this.searchInput.el?.focus());
34443
34432
  }
34444
34433
  onFocusSearch() {
@@ -34475,13 +34464,13 @@ class FindAndReplacePanel extends owl.Component {
34475
34464
  this.store.updateSearchOptions({ searchScope });
34476
34465
  }
34477
34466
  onSearchRangeChanged(ranges) {
34478
- this.dataRange = ranges[0];
34467
+ this.state.dataRange = ranges[0];
34479
34468
  }
34480
34469
  updateDataRange() {
34481
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34470
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34482
34471
  return;
34483
34472
  }
34484
- const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange);
34473
+ const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
34485
34474
  this.store.updateSearchOptions({ specificRange });
34486
34475
  }
34487
34476
  }
@@ -34526,31 +34515,6 @@ class MoreFormatsPanel extends owl.Component {
34526
34515
  }
34527
34516
  }
34528
34517
 
34529
- /** @odoo-module */
34530
- class EditableName extends owl.Component {
34531
- static template = "o-spreadsheet-EditableName";
34532
- static props = {
34533
- name: String,
34534
- displayName: String,
34535
- onChanged: Function,
34536
- };
34537
- state;
34538
- setup() {
34539
- this.state = owl.useState({
34540
- isEditing: false,
34541
- name: "",
34542
- });
34543
- }
34544
- rename() {
34545
- this.state.isEditing = true;
34546
- this.state.name = this.props.name;
34547
- }
34548
- save() {
34549
- this.props.onChanged(this.state.name.trim());
34550
- this.state.isEditing = false;
34551
- }
34552
- }
34553
-
34554
34518
  css /* scss */ `
34555
34519
  .pivot-defer-update {
34556
34520
  min-height: 35px;
@@ -34916,6 +34880,135 @@ class PivotLayoutConfigurator extends owl.Component {
34916
34880
  }
34917
34881
  }
34918
34882
 
34883
+ css /* scss */ `
34884
+ .os-cog-wheel-menu-icon {
34885
+ cursor: pointer;
34886
+ }
34887
+
34888
+ .os-cog-wheel-menu {
34889
+ background: white;
34890
+ .btn-link {
34891
+ text-decoration: none;
34892
+ color: #017e84;
34893
+ font-weight: 500;
34894
+ &:hover {
34895
+ color: #01585c;
34896
+ }
34897
+ }
34898
+ }
34899
+ `;
34900
+ class CogWheelMenu extends owl.Component {
34901
+ static template = "o-spreadsheet-CogWheelMenu";
34902
+ static components = { Popover };
34903
+ static props = {
34904
+ items: Array,
34905
+ };
34906
+ buttonRef = owl.useRef("button");
34907
+ popover = owl.useState({ isOpen: false });
34908
+ setup() {
34909
+ owl.useExternalListener(window, "click", (ev) => {
34910
+ if (ev.target !== this.buttonRef.el) {
34911
+ this.popover.isOpen = false;
34912
+ }
34913
+ });
34914
+ }
34915
+ get popoverProps() {
34916
+ const { x, y, width, height } = this.buttonRef.el.getBoundingClientRect();
34917
+ return {
34918
+ anchorRect: { x, y, width, height },
34919
+ positioning: "BottomLeft",
34920
+ };
34921
+ }
34922
+ togglePopover() {
34923
+ this.popover.isOpen = !this.popover.isOpen;
34924
+ }
34925
+ }
34926
+
34927
+ /** @odoo-module */
34928
+ class EditableName extends owl.Component {
34929
+ static template = "o-spreadsheet-EditableName";
34930
+ static props = {
34931
+ name: String,
34932
+ displayName: String,
34933
+ onChanged: Function,
34934
+ };
34935
+ state;
34936
+ setup() {
34937
+ this.state = owl.useState({
34938
+ isEditing: false,
34939
+ name: "",
34940
+ });
34941
+ }
34942
+ rename() {
34943
+ this.state.isEditing = true;
34944
+ this.state.name = this.props.name;
34945
+ }
34946
+ save() {
34947
+ this.props.onChanged(this.state.name.trim());
34948
+ this.state.isEditing = false;
34949
+ }
34950
+ }
34951
+
34952
+ class PivotTitleSection extends owl.Component {
34953
+ static template = "o-spreadsheet-PivotTitleSection";
34954
+ static components = { CogWheelMenu, Section, EditableName };
34955
+ static props = {
34956
+ pivotId: String,
34957
+ };
34958
+ get cogWheelMenuItems() {
34959
+ return [
34960
+ {
34961
+ name: "Duplicate",
34962
+ icon: "fa-copy",
34963
+ onClick: () => this.duplicatePivot(),
34964
+ },
34965
+ {
34966
+ name: "Delete",
34967
+ icon: "fa-trash",
34968
+ onClick: () => this.delete(),
34969
+ },
34970
+ ];
34971
+ }
34972
+ get name() {
34973
+ return this.env.model.getters.getPivotName(this.props.pivotId);
34974
+ }
34975
+ get displayName() {
34976
+ return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
34977
+ }
34978
+ duplicatePivot() {
34979
+ const newPivotId = this.env.model.uuidGenerator.uuidv4();
34980
+ const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
34981
+ pivotId: this.props.pivotId,
34982
+ newPivotId,
34983
+ });
34984
+ const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
34985
+ const type = result.isSuccessful ? "success" : "danger";
34986
+ this.env.notifyUser({
34987
+ text,
34988
+ sticky: false,
34989
+ type,
34990
+ });
34991
+ if (result.isSuccessful) {
34992
+ this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
34993
+ }
34994
+ }
34995
+ delete() {
34996
+ this.env.askConfirmation(_t("Are you sure you want to delete this pivot?"), () => {
34997
+ this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
34998
+ });
34999
+ }
35000
+ onNameChanged(name) {
35001
+ const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
35002
+ this.env.model.dispatch("UPDATE_PIVOT", {
35003
+ pivotId: this.props.pivotId,
35004
+ pivot: {
35005
+ ...pivot,
35006
+ name,
35007
+ },
35008
+ });
35009
+ }
35010
+ }
35011
+
34919
35012
  /**
34920
35013
  * Represent a pivot runtime definition. A pivot runtime definition is a pivot
34921
35014
  * definition that has been enriched to include the display name of its attributes
@@ -35220,7 +35313,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
35220
35313
  }
35221
35314
  const row = rows[index];
35222
35315
  const rowName = row.nameWithGranularity;
35223
- const groups = groupBy(dataEntries, row);
35316
+ const groups = groupPivotDataEntriesBy(dataEntries, row);
35224
35317
  const orderedKeys = orderDataEntriesKeys(groups, row);
35225
35318
  const pivotTableRows = [];
35226
35319
  const _fields = fields.concat(rowName);
@@ -35250,7 +35343,7 @@ function dataEntriesToColumnsTree(dataEntries, columns, index) {
35250
35343
  }
35251
35344
  const column = columns[index];
35252
35345
  const colName = columns[index].nameWithGranularity;
35253
- const groups = groupBy(dataEntries, column);
35346
+ const groups = groupPivotDataEntriesBy(dataEntries, column);
35254
35347
  const orderedKeys = orderDataEntriesKeys(groups, columns[index]);
35255
35348
  return orderedKeys.map((value) => {
35256
35349
  return {
@@ -35348,7 +35441,7 @@ function columnsTreeToColumns(mainTree, definition) {
35348
35441
  /**
35349
35442
  * Group the dataEntries based on the given dimension
35350
35443
  */
35351
- function groupBy(dataEntries, dimension) {
35444
+ function groupPivotDataEntriesBy(dataEntries, dimension) {
35352
35445
  return Object.groupBy(dataEntries, keySelector(dimension));
35353
35446
  }
35354
35447
  /**
@@ -35398,7 +35491,7 @@ function createDate(dimension, value, locale) {
35398
35491
  number = Math.floor(date.getMonth() / 3) + 1;
35399
35492
  break;
35400
35493
  case "month_number":
35401
- number = date.getMonth();
35494
+ number = date.getMonth() + 1;
35402
35495
  break;
35403
35496
  case "iso_week_number":
35404
35497
  number = date.getIsoWeek();
@@ -35410,7 +35503,7 @@ function createDate(dimension, value, locale) {
35410
35503
  number = Math.floor(toNumber(value, locale));
35411
35504
  break;
35412
35505
  }
35413
- MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = number;
35506
+ MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = toNormalizedPivotValue(dimension, number);
35414
35507
  }
35415
35508
  return MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`];
35416
35509
  }
@@ -35556,7 +35649,7 @@ class SpreadsheetPivot {
35556
35649
  return this._definition;
35557
35650
  }
35558
35651
  isValid() {
35559
- if (this.invalidRangeError || !this._definition) {
35652
+ if (this.invalidRangeError || !this.definition) {
35560
35653
  return false;
35561
35654
  }
35562
35655
  for (const measure of this.definition.measures) {
@@ -35613,25 +35706,19 @@ class SpreadsheetPivot {
35613
35706
  const dimension = this.getDimension(lastNode.field);
35614
35707
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
35615
35708
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
35709
+ if (dimension.type === "date") {
35710
+ const adapter = pivotTimeAdapter(dimension.granularity);
35711
+ return {
35712
+ value: adapter.toCellValue(toNormalizedPivotValue(dimension, lastNode.value)),
35713
+ format: adapter.getFormat(this.getters.getLocale()),
35714
+ };
35715
+ }
35616
35716
  if (!finalCell) {
35617
35717
  return { value: "" };
35618
35718
  }
35619
35719
  if (finalCell.value === null) {
35620
35720
  return { value: _t("(Undefined)") };
35621
35721
  }
35622
- if (dimension.type === "date") {
35623
- if (dimension.granularity === "day") {
35624
- return {
35625
- value: toNumber(finalCell.value, this.getters.getLocale()),
35626
- format: this.getters.getLocale().dateFormat,
35627
- };
35628
- }
35629
- if (dimension.granularity === "month_number") {
35630
- return {
35631
- value: MONTHS[toNumber(finalCell.value, this.getters.getLocale())].toString(),
35632
- };
35633
- }
35634
- }
35635
35722
  return {
35636
35723
  value: finalCell.value,
35637
35724
  format: finalCell.format,
@@ -35656,9 +35743,12 @@ class SpreadsheetPivot {
35656
35743
  format: operator.format(values[0]),
35657
35744
  };
35658
35745
  }
35659
- getPossibleFieldValues(groupBy) {
35660
- //TODO This method should be implemented for the autocomplete feature
35661
- throw new Error("Method not implemented.");
35746
+ getPossibleFieldValues(dimension) {
35747
+ const values = [];
35748
+ for (const value in groupPivotDataEntriesBy(this.dataEntries, dimension)) {
35749
+ values.push({ value, label: "" });
35750
+ }
35751
+ return values;
35662
35752
  }
35663
35753
  getTableStructure() {
35664
35754
  if (!this.isValid()) {
@@ -35678,7 +35768,8 @@ class SpreadsheetPivot {
35678
35768
  filterDataEntriesFromDomainNode(dataEntries, domain) {
35679
35769
  const { field, value } = domain;
35680
35770
  const dimension = this.getDimension(field);
35681
- return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` === value);
35771
+ return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` ===
35772
+ `${toNormalizedPivotValue(dimension, value)}`);
35682
35773
  }
35683
35774
  getDimension(nameWithGranularity) {
35684
35775
  return this.definition.getDimension(nameWithGranularity);
@@ -35814,15 +35905,8 @@ pivotRegistry.add("SPREADSHEET", {
35814
35905
 
35815
35906
  class PivotSidePanelStore extends SpreadsheetStore {
35816
35907
  pivotId;
35817
- mutators = [
35818
- "reset",
35819
- "deferUpdates",
35820
- "applyUpdate",
35821
- "discardPendingUpdate",
35822
- "renamePivot",
35823
- "update",
35824
- ];
35825
- updatesAreDeferred = true;
35908
+ mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
35909
+ updatesAreDeferred = false;
35826
35910
  draft = null;
35827
35911
  constructor(get, pivotId) {
35828
35912
  super(get);
@@ -35939,16 +36023,6 @@ class PivotSidePanelStore extends SpreadsheetStore {
35939
36023
  discardPendingUpdate() {
35940
36024
  this.draft = null;
35941
36025
  }
35942
- renamePivot(name) {
35943
- const pivot = this.getters.getPivotCoreDefinition(this.pivotId);
35944
- this.model.dispatch("UPDATE_PIVOT", {
35945
- pivotId: this.pivotId,
35946
- pivot: {
35947
- ...pivot,
35948
- name,
35949
- },
35950
- });
35951
- }
35952
36026
  update(definitionUpdate) {
35953
36027
  const coreDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
35954
36028
  const definition = { ...coreDefinition, ...this.draft, ...definitionUpdate };
@@ -36031,9 +36105,9 @@ class PivotSpreadsheetSidePanel extends owl.Component {
36031
36105
  PivotLayoutConfigurator,
36032
36106
  Section,
36033
36107
  SelectionInput,
36034
- EditableName,
36035
36108
  Checkbox,
36036
36109
  PivotDeferUpdate,
36110
+ PivotTitleSection,
36037
36111
  };
36038
36112
  store;
36039
36113
  state;
@@ -36062,12 +36136,6 @@ class PivotSpreadsheetSidePanel extends owl.Component {
36062
36136
  get pivot() {
36063
36137
  return this.store.pivot;
36064
36138
  }
36065
- get name() {
36066
- return this.env.model.getters.getPivotName(this.props.pivotId);
36067
- }
36068
- get displayName() {
36069
- return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
36070
- }
36071
36139
  get definition() {
36072
36140
  return this.store.definition;
36073
36141
  }
@@ -36091,35 +36159,9 @@ class PivotSpreadsheetSidePanel extends owl.Component {
36091
36159
  this.store.applyUpdate();
36092
36160
  }
36093
36161
  }
36094
- duplicatePivot() {
36095
- const newPivotId = this.env.model.uuidGenerator.uuidv4();
36096
- const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
36097
- pivotId: this.props.pivotId,
36098
- newPivotId,
36099
- });
36100
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
36101
- const type = result.isSuccessful ? "success" : "danger";
36102
- this.env.notifyUser({
36103
- text,
36104
- sticky: false,
36105
- type,
36106
- });
36107
- if (result.isSuccessful) {
36108
- this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
36109
- }
36110
- }
36111
- onNameChanged(name) {
36112
- this.store.renamePivot(name);
36113
- }
36114
36162
  onDimensionsUpdated(definition) {
36115
36163
  this.store.update(definition);
36116
36164
  }
36117
- back() {
36118
- this.env.openSidePanel("PivotSidePanel", {});
36119
- }
36120
- delete() {
36121
- this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
36122
- }
36123
36165
  }
36124
36166
 
36125
36167
  const pivotSidePanelRegistry = new Registry();
@@ -36127,44 +36169,17 @@ pivotSidePanelRegistry.add("SPREADSHEET", {
36127
36169
  editor: PivotSpreadsheetSidePanel,
36128
36170
  });
36129
36171
 
36130
- css /* scss */ `
36131
- .o_pivot_list_item {
36132
- cursor: pointer;
36133
- &:hover {
36134
- background-color: #f1f3f4;
36135
- }
36136
- }
36137
- `;
36138
- class PivotListItem extends owl.Component {
36139
- static template = "o-spreadsheet-PivotListItem";
36140
- static props = { pivotId: String };
36141
- setup() {
36142
- const previewRef = owl.useRef("pivotListItem");
36143
- useHighlightsOnHover(previewRef, this);
36144
- }
36145
- selectPivot() {
36146
- this.env.openSidePanel("PivotSidePanel", { pivotId: this.props.pivotId });
36147
- }
36148
- get highlights() {
36149
- return getPivotHighlights(this.env.model.getters, this.props.pivotId);
36150
- }
36151
- }
36152
-
36153
36172
  class PivotSidePanel extends owl.Component {
36154
36173
  static template = "o-spreadsheet-PivotSidePanel";
36155
36174
  static props = {
36156
- pivotId: { type: String, optional: true },
36175
+ pivotId: String,
36157
36176
  onCloseSidePanel: Function,
36158
36177
  };
36159
36178
  static components = {
36160
36179
  PivotLayoutConfigurator,
36161
36180
  Section,
36162
- PivotListItem,
36163
36181
  };
36164
36182
  get sidePanelEditor() {
36165
- if (!this.props.pivotId) {
36166
- throw new Error("pivotId is required to call this function.");
36167
- }
36168
36183
  const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
36169
36184
  if (!pivot) {
36170
36185
  throw new Error("pivotId does not correspond to a pivot.");
@@ -36181,6 +36196,7 @@ css /* scss */ `
36181
36196
  class RemoveDuplicatesPanel extends owl.Component {
36182
36197
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36183
36198
  static components = { ValidationMessages, Section, Checkbox };
36199
+ static props = { onCloseSidePanel: Function };
36184
36200
  state = owl.useState({
36185
36201
  hasHeader: false,
36186
36202
  columns: {},
@@ -37323,21 +37339,15 @@ sidePanelRegistry.add("TableStyleEditorPanel", {
37323
37339
  });
37324
37340
  sidePanelRegistry.add("PivotSidePanel", {
37325
37341
  title: (env, props) => {
37326
- if (props.pivotId) {
37327
- return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37328
- }
37329
- return _t("List of Pivots");
37342
+ return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37330
37343
  },
37331
37344
  Body: PivotSidePanel,
37332
- computeState: (getters, initialProps) => {
37333
- if (!getters.getPivotIds().length) {
37334
- return { isOpen: false };
37335
- }
37336
- let { pivotId } = initialProps;
37337
- if (pivotId && !getters.isExistingPivot(pivotId)) {
37338
- pivotId = undefined;
37339
- }
37340
- return { isOpen: true, props: { pivotId }, key: `pivot_key_${pivotId}` };
37345
+ computeState: (getters, props) => {
37346
+ return {
37347
+ isOpen: getters.isExistingPivot(props.pivotId),
37348
+ props,
37349
+ key: `pivot_key_${props.pivotId}`,
37350
+ };
37341
37351
  },
37342
37352
  });
37343
37353
 
@@ -38605,7 +38615,7 @@ class FiguresContainer extends owl.Component {
38605
38615
  });
38606
38616
  }
38607
38617
  getContainerRect(container) {
38608
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
38618
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
38609
38619
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
38610
38620
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
38611
38621
  const width = viewWidth - x;
@@ -41595,133 +41605,6 @@ class Grid extends owl.Component {
41595
41605
  }
41596
41606
  }
41597
41607
 
41598
- const pivotTimeAdapterRegistry = new Registry();
41599
- function pivotTimeAdapter(granularity) {
41600
- return pivotTimeAdapterRegistry.get(granularity);
41601
- }
41602
- /**
41603
- * The Time Adapter: Managing Time Periods for Pivot Functions
41604
- *
41605
- * Overview:
41606
- * A time adapter is responsible for managing time periods associated with pivot functions.
41607
- * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
41608
- * The adapter's primary role is to normalize period values between spreadsheet functions,
41609
- * and the pivot.
41610
- * By normalizing the period value, it can be stored consistently in the pivot.
41611
- *
41612
- * Normalization Process:
41613
- * When working with functions in the spreadsheet, the time adapter normalizes
41614
- * the provided period to facilitate accurate lookup of values in the pivot.
41615
- * For instance, if the spreadsheet function represents a day period as a number generated
41616
- * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
41617
- *
41618
- */
41619
- /**
41620
- * Normalized value: "12/25/2023"
41621
- *
41622
- * Note: Those two format are equivalent:
41623
- * - "MM/dd/yyyy" (luxon format)
41624
- * - "mm/dd/yyyy" (spreadsheet format)
41625
- **/
41626
- const dayAdapter = {
41627
- normalizeFunctionValue(value) {
41628
- const date = toNumber(value, DEFAULT_LOCALE);
41629
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
41630
- },
41631
- getFormat(locale) {
41632
- return (locale ?? DEFAULT_LOCALE).dateFormat;
41633
- },
41634
- formatValue(normalizedValue, locale) {
41635
- locale = locale ?? DEFAULT_LOCALE;
41636
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41637
- return formatValue(value, { locale, format: this.getFormat(locale) });
41638
- },
41639
- toCellValue(normalizedValue) {
41640
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41641
- },
41642
- };
41643
- /**
41644
- * Normalized value: "2/2023" for week 2 of 2023
41645
- */
41646
- const weekAdapter = {
41647
- normalizeFunctionValue(value) {
41648
- const [week, year] = value.split("/");
41649
- return `${Number(week)}/${Number(year)}`;
41650
- },
41651
- getFormat() {
41652
- return undefined;
41653
- },
41654
- formatValue(normalizedValue) {
41655
- const [week, year] = normalizedValue.split("/");
41656
- return _t("W%(week)s %(year)s", { week, year });
41657
- },
41658
- toCellValue(normalizedValue) {
41659
- return this.formatValue(normalizedValue);
41660
- },
41661
- };
41662
- /**
41663
- * normalized month value is a string formatted as "MM/yyyy" (luxon format)
41664
- * e.g. "01/2020" for January 2020
41665
- */
41666
- const monthAdapter = {
41667
- normalizeFunctionValue(value) {
41668
- const date = toNumber(value, DEFAULT_LOCALE);
41669
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
41670
- },
41671
- getFormat() {
41672
- return "mmmm yyyy";
41673
- },
41674
- formatValue(normalizedValue, locale) {
41675
- locale = locale ?? DEFAULT_LOCALE;
41676
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41677
- return formatValue(value, { locale, format: this.getFormat(locale) });
41678
- },
41679
- toCellValue(normalizedValue) {
41680
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41681
- },
41682
- };
41683
- /**
41684
- * normalized quarter value is "quarter/year"
41685
- * e.g. "1/2020" for Q1 2020
41686
- */
41687
- const quarterAdapter = {
41688
- normalizeFunctionValue(value) {
41689
- const [quarter, year] = value.split("/");
41690
- return `${quarter}/${year}`;
41691
- },
41692
- getFormat() {
41693
- return undefined;
41694
- },
41695
- formatValue(normalizedValue) {
41696
- const [quarter, year] = normalizedValue.split("/");
41697
- return _t("Q%(quarter)s %(year)s", { quarter, year });
41698
- },
41699
- toCellValue(normalizedValue) {
41700
- return this.formatValue(normalizedValue);
41701
- },
41702
- };
41703
- const yearAdapter = {
41704
- normalizeFunctionValue(value) {
41705
- return toNumber(value, DEFAULT_LOCALE);
41706
- },
41707
- getFormat() {
41708
- return "0";
41709
- },
41710
- formatValue(normalizedValue, locale) {
41711
- locale = locale ?? DEFAULT_LOCALE;
41712
- return formatValue(normalizedValue, { locale, format: "0" });
41713
- },
41714
- toCellValue(normalizedValue) {
41715
- return normalizedValue;
41716
- },
41717
- };
41718
- pivotTimeAdapterRegistry
41719
- .add("day", dayAdapter)
41720
- .add("week", weekAdapter)
41721
- .add("month", monthAdapter)
41722
- .add("quarter", quarterAdapter)
41723
- .add("year", yearAdapter);
41724
-
41725
41608
  /**
41726
41609
  * Represent a raw XML string
41727
41610
  */
@@ -46920,9 +46803,14 @@ class CellPlugin extends CorePlugin {
46920
46803
  }
46921
46804
  createLiteralCell(id, content, format, style) {
46922
46805
  const locale = this.getters.getLocale();
46923
- format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
46806
+ const parsedValue = parseLiteral(content, locale);
46807
+ format =
46808
+ format ||
46809
+ (typeof parsedValue === "number"
46810
+ ? detectDateFormat(content, locale) || detectNumberFormat(content)
46811
+ : undefined);
46924
46812
  if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
46925
- content = toString(parseLiteral(content, locale));
46813
+ content = toString(parsedValue);
46926
46814
  }
46927
46815
  return {
46928
46816
  id,
@@ -46930,6 +46818,7 @@ class CellPlugin extends CorePlugin {
46930
46818
  style,
46931
46819
  format,
46932
46820
  isFormula: false,
46821
+ parsedValue,
46933
46822
  };
46934
46823
  }
46935
46824
  createFormulaCell(id, content, format, style, sheetId) {
@@ -51227,22 +51116,6 @@ class PivotCorePlugin extends CorePlugin {
51227
51116
  this.addPivotFormula(cellPosition, formulaId, pivotCell);
51228
51117
  }
51229
51118
  }
51230
- const pivotZone = {
51231
- top: position.row,
51232
- bottom: position.row + pivotCells[0].length - 1,
51233
- left: position.col,
51234
- right: position.col + pivotCells.length - 1,
51235
- };
51236
- const numberOfHeaders = table.columns.length - 1;
51237
- const cmdContent = {
51238
- sheetId: position.sheetId,
51239
- ranges: [this.getters.getRangeDataFromZone(position.sheetId, pivotZone)],
51240
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
51241
- tableType: "static",
51242
- };
51243
- if (this.canDispatch("CREATE_TABLE", cmdContent).isSuccessful) {
51244
- this.dispatch("CREATE_TABLE", cmdContent);
51245
- }
51246
51119
  }
51247
51120
  resizeSheet(sheetId, { col, row }, table) {
51248
51121
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -51672,6 +51545,9 @@ class PositionMap {
51672
51545
  get({ sheetId, col, row }) {
51673
51546
  return this.map[sheetId]?.[col]?.[row];
51674
51547
  }
51548
+ getSheet(sheetId) {
51549
+ return this.map[sheetId];
51550
+ }
51675
51551
  has({ sheetId, col, row }) {
51676
51552
  return this.map[sheetId]?.[col]?.[row] !== undefined;
51677
51553
  }
@@ -51690,6 +51566,19 @@ class PositionMap {
51690
51566
  }
51691
51567
  return keys;
51692
51568
  }
51569
+ keysForSheet(sheetId) {
51570
+ const map = this.map[sheetId];
51571
+ if (!map) {
51572
+ return [];
51573
+ }
51574
+ const keys = [];
51575
+ for (const col in map) {
51576
+ for (const row in map[col]) {
51577
+ keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
51578
+ }
51579
+ }
51580
+ return keys;
51581
+ }
51693
51582
  }
51694
51583
 
51695
51584
  function quickselect(arr, k, left, right, compare) {
@@ -52768,6 +52657,9 @@ class Evaluator {
52768
52657
  getEvaluatedPositions() {
52769
52658
  return this.evaluatedCells.keys();
52770
52659
  }
52660
+ getEvaluatedPositionsInSheet(sheetId) {
52661
+ return this.evaluatedCells.keysForSheet(sheetId);
52662
+ }
52771
52663
  getArrayFormulaSpreadingOn(position) {
52772
52664
  if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
52773
52665
  return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
@@ -52776,6 +52668,9 @@ class Evaluator {
52776
52668
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
52777
52669
  }
52778
52670
  updateDependencies(position) {
52671
+ // removing dependencies is slow because it requires
52672
+ // to traverse the entire r-tree.
52673
+ // The data structure is optimized for searches the other way around
52779
52674
  this.formulaDependencies().removeAllDependencies(position);
52780
52675
  const dependencies = this.getDirectDependencies(position);
52781
52676
  this.formulaDependencies().addDependencies(position, dependencies);
@@ -52941,7 +52836,7 @@ class Evaluator {
52941
52836
  this.cellsBeingComputed.add(cellId);
52942
52837
  return cell.isFormula
52943
52838
  ? this.computeFormulaCell(position.sheetId, cell)
52944
- : evaluateLiteral(cell.content, localeFormat);
52839
+ : evaluateLiteral(cell, localeFormat);
52945
52840
  }
52946
52841
  catch (e) {
52947
52842
  e.value = e?.value || CellErrorType.GenericError;
@@ -53211,6 +53106,7 @@ class EvaluationPlugin extends UIPlugin {
53211
53106
  "getEvaluatedCell",
53212
53107
  "getEvaluatedCells",
53213
53108
  "getEvaluatedCellsInZone",
53109
+ "getEvaluatedCellsPositions",
53214
53110
  "getSpreadZone",
53215
53111
  "getArrayFormulaSpreadingOn",
53216
53112
  "isEmpty",
@@ -53302,13 +53198,12 @@ class EvaluationPlugin extends UIPlugin {
53302
53198
  return this.evaluator.getEvaluatedCell(position);
53303
53199
  }
53304
53200
  getEvaluatedCells(sheetId) {
53305
- const rawCells = this.getters.getCells(sheetId) || {};
53306
- const record = {};
53307
- for (let cellId of Object.keys(rawCells)) {
53308
- const position = this.getters.getCellPosition(cellId);
53309
- record[cellId] = this.getEvaluatedCell(position);
53310
- }
53311
- return record;
53201
+ return this.evaluator
53202
+ .getEvaluatedPositionsInSheet(sheetId)
53203
+ .map((position) => this.getEvaluatedCell(position));
53204
+ }
53205
+ getEvaluatedCellsPositions(sheetId) {
53206
+ return this.evaluator.getEvaluatedPositionsInSheet(sheetId);
53312
53207
  }
53313
53208
  getEvaluatedCellsInZone(sheetId, zone) {
53314
53209
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
@@ -55976,7 +55871,10 @@ class Session extends EventBus {
55976
55871
  /**
55977
55872
  * Notify the server that the user client left the collaborative session
55978
55873
  */
55979
- leave() {
55874
+ leave(data) {
55875
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55876
+ this.snapshot(data);
55877
+ }
55980
55878
  delete this.clients[this.clientId];
55981
55879
  this.transportService.leave(this.clientId);
55982
55880
  this.transportService.sendMessage({
@@ -55989,6 +55887,9 @@ class Session extends EventBus {
55989
55887
  * Send a snapshot of the spreadsheet to the collaboration server
55990
55888
  */
55991
55889
  snapshot(data) {
55890
+ if (this.pendingMessages.length !== 0) {
55891
+ return;
55892
+ }
55992
55893
  const snapshotId = this.uuidGenerator.uuidv4();
55993
55894
  this.transportService.sendMessage({
55994
55895
  type: "SNAPSHOT",
@@ -56390,7 +56291,7 @@ class DataCleanupPlugin extends UIPlugin {
56390
56291
  bottom: rowIndex,
56391
56292
  }));
56392
56293
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
56393
- const data = handler.copy(getClipboardDataPositions(rowsToKeep));
56294
+ const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep));
56394
56295
  if (!data) {
56395
56296
  return;
56396
56297
  }
@@ -56403,7 +56304,7 @@ class DataCleanupPlugin extends UIPlugin {
56403
56304
  right: zone.left,
56404
56305
  bottom: zone.top,
56405
56306
  };
56406
- handler.paste({ zones: [zonePasted] }, data, { isCutOperation: false });
56307
+ handler.paste({ zones: [zonePasted], sheetId }, data, { isCutOperation: false });
56407
56308
  const remainingZone = {
56408
56309
  left: zone.left,
56409
56310
  top: zone.top - (hasHeader ? 1 : 0),
@@ -58277,12 +58178,14 @@ class ClipboardPlugin extends UIPlugin {
58277
58178
  }
58278
58179
  let zone = undefined;
58279
58180
  let selectedZones = [];
58181
+ const sheetId = this.getters.getActiveSheetId();
58280
58182
  let target = {
58183
+ sheetId,
58281
58184
  zones,
58282
58185
  };
58283
58186
  const handlers = this.selectClipboardHandlers(copiedData);
58284
58187
  for (const handler of handlers) {
58285
- const currentTarget = handler.getPasteTarget(zones, copiedData, options);
58188
+ const currentTarget = handler.getPasteTarget(sheetId, zones, copiedData, options);
58286
58189
  if (currentTarget.figureId) {
58287
58190
  target.figureId = currentTarget.figureId;
58288
58191
  }
@@ -58451,11 +58354,12 @@ class ClipboardPlugin extends UIPlugin {
58451
58354
  return { cut: [cut], paste: [paste] };
58452
58355
  }
58453
58356
  getClipboardData(zones) {
58357
+ const sheetId = this.getters.getActiveSheetId();
58454
58358
  const selectedFigureId = this.getters.getSelectedFigureId();
58455
58359
  if (selectedFigureId) {
58456
- return { figureId: selectedFigureId };
58360
+ return { figureId: selectedFigureId, sheetId };
58457
58361
  }
58458
- return getClipboardDataPositions(zones);
58362
+ return getClipboardDataPositions(sheetId, zones);
58459
58363
  }
58460
58364
  // ---------------------------------------------------------------------------
58461
58365
  // Grid rendering
@@ -59121,8 +59025,9 @@ class GridSelectionPlugin extends UIPlugin {
59121
59025
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
59122
59026
  },
59123
59027
  ];
59028
+ const sheetId = this.getActiveSheetId();
59124
59029
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
59125
- const data = handler.copy(getClipboardDataPositions(target));
59030
+ const data = handler.copy(getClipboardDataPositions(sheetId, target));
59126
59031
  if (!data) {
59127
59032
  return;
59128
59033
  }
@@ -59135,7 +59040,7 @@ class GridSelectionPlugin extends UIPlugin {
59135
59040
  bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
59136
59041
  },
59137
59042
  ];
59138
- handler.paste({ zones: pasteTarget }, data, { isCutOperation: true });
59043
+ handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
59139
59044
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
59140
59045
  let currentIndex = cmd.base;
59141
59046
  for (const element of toRemove) {
@@ -66499,7 +66404,7 @@ class Model extends EventBus {
66499
66404
  this.session.join(this.config.client);
66500
66405
  }
66501
66406
  leaveSession() {
66502
- this.session.leave();
66407
+ this.session.leave(this.exportData());
66503
66408
  }
66504
66409
  setupUiPlugin(Plugin) {
66505
66410
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66906,7 +66811,8 @@ const registries = {
66906
66811
  pivotRegistry,
66907
66812
  pivotTimeAdapterRegistry,
66908
66813
  pivotSidePanelRegistry,
66909
- supportedPivotExplodedFormulaRegistry,
66814
+ pivotNormalizationValueRegistry,
66815
+ supportedPivotPositionalFormulaRegistry,
66910
66816
  };
66911
66817
  const helpers = {
66912
66818
  arg,
@@ -66915,6 +66821,7 @@ const helpers = {
66915
66821
  toJsDate,
66916
66822
  toNumber,
66917
66823
  toString,
66824
+ toNormalizedPivotValue,
66918
66825
  toXC,
66919
66826
  toZone,
66920
66827
  toUnboundedZone,
@@ -67010,6 +66917,8 @@ const components = {
67010
66917
  PivotLayoutConfigurator,
67011
66918
  EditableName,
67012
66919
  PivotDeferUpdate,
66920
+ PivotTitleSection,
66921
+ CogWheelMenu,
67013
66922
  };
67014
66923
  const hooks = {
67015
66924
  useDragAndDropListItems,
@@ -67093,6 +67002,6 @@ exports.tokenColors = tokenColors;
67093
67002
  exports.tokenize = tokenize;
67094
67003
 
67095
67004
 
67096
- __info__.version = "17.4.0-alpha.3";
67097
- __info__.date = "2024-06-10T09:38:53.982Z";
67098
- __info__.hash = "a45ed6a";
67005
+ __info__.version = "17.4.0-alpha.5";
67006
+ __info__.date = "2024-06-14T10:01:40.605Z";
67007
+ __info__.hash = "9ceed96";